Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@samchon/openapi

Package Overview
Dependencies
Maintainers
0
Versions
146
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@samchon/openapi - npm Package Compare versions

Comparing version 2.0.0-dev.20241123 to 2.0.0-dev.20241124

lib/converters/LlmSchemaConverter.d.ts

5

lib/converters/ChatGptConverter.d.ts
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">;
config: IChatGptSchema.IConfig;
components: OpenApi.IComponents;

@@ -11,3 +10,3 @@ schema: OpenApi.IJsonSchema.IObject;

const schema: (props: {
options: Omit<ILlmApplication.IChatGptOptions, "separate">;
config: IChatGptSchema.IConfig;
components: OpenApi.IComponents;

@@ -14,0 +13,0 @@ $defs: Record<string, IChatGptSchema>;

243

lib/converters/ChatGptConverter.js

@@ -13,2 +13,13 @@ "use strict";

};
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var __read = (this && this.__read) || function (o, n) {

@@ -30,37 +41,77 @@ var m = typeof Symbol === "function" && o[Symbol.iterator];

};
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChatGptConverter = void 0;
var ChatGptTypeChecker_1 = require("../utils/ChatGptTypeChecker");
var OpenApiContraintShifter_1 = require("../utils/OpenApiContraintShifter");
var LlmTypeCheckerV3_1_1 = require("../utils/LlmTypeCheckerV3_1");
var OpenApiTypeChecker_1 = require("../utils/OpenApiTypeChecker");
var LlmConverterV3_1_1 = require("./LlmConverterV3_1");
var ChatGptConverter;
(function (ChatGptConverter) {
ChatGptConverter.parameters = function (props) {
var $defs = {};
var res = ChatGptConverter.schema({
options: props.options,
var e_1, _a, e_2, _b;
var params = LlmConverterV3_1_1.LlmConverterV3_1.parameters({
config: props.config,
components: props.components,
schema: props.schema,
$defs: $defs,
});
if (res === null)
if (params === null)
return null;
else if (Object.keys($defs).length)
res.$defs = $defs;
return res;
try {
for (var _c = __values(Object.keys(params.$defs)), _d = _c.next(); !_d.done; _d = _c.next()) {
var key = _d.value;
params.$defs[key] = transform(params.$defs[key]);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
}
finally { if (e_1) throw e_1.error; }
}
try {
for (var _e = __values(Object.keys(params.properties)), _f = _e.next(); !_f.done; _f = _e.next()) {
var key = _f.value;
params.properties[key] = transform(params.properties[key]);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
}
finally { if (e_2) throw e_2.error; }
}
return params;
};
ChatGptConverter.schema = function (props) {
var e_3, _a;
var oldbie = new Set(Object.keys(props.$defs));
var schema = LlmConverterV3_1_1.LlmConverterV3_1.schema({
config: props.config,
components: props.components,
$defs: props.$defs,
schema: props.schema,
});
if (schema === null)
return null;
try {
for (var _b = __values(Object.keys(props.$defs)), _c = _b.next(); !_c.done; _c = _b.next()) {
var key = _c.value;
if (oldbie.has(key) === false)
props.$defs[key] = transform(props.$defs[key]);
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_3) throw e_3.error; }
}
return transform(schema);
};
var transform = function (schema) {
var union = [];
var attribute = __assign({ title: props.schema.title, description: props.schema.description, example: props.schema.example, examples: props.schema.examples }, Object.fromEntries(Object.entries(props.schema).filter(function (_a) {
var attribute = __assign({ title: schema.title, description: schema.description, example: schema.example, examples: schema.examples }, Object.fromEntries(Object.entries(schema).filter(function (_a) {
var _b = __read(_a, 2), key = _b[0], value = _b[1];

@@ -70,118 +121,18 @@ return key.startsWith("x-") && value !== undefined;

var visit = function (input) {
var _a;
if (OpenApiTypeChecker_1.OpenApiTypeChecker.isOneOf(input)) {
if (LlmTypeCheckerV3_1_1.LlmTypeCheckerV3_1.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;
if (props.options.reference === true ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isRecursiveReference({
components: props.components,
schema: input,
})) {
var out = function () {
return union.push(__assign(__assign({}, input), { $ref: "#/$defs/".concat(key_1), title: undefined, description: undefined }));
};
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: target,
});
if (converted === null)
return union.push(null);
converted.description = OpenApiTypeChecker_1.OpenApiTypeChecker.writeReferenceDescription({
components: props.components,
$ref: input.$ref,
description: converted.description,
escape: false,
});
props.$defs[key_1] = converted;
return out();
}
else {
var length_1 = union.length;
visit(target);
if (length_1 === union.length - 1 && union[union.length - 1] !== null)
union[union.length - 1] = __assign(__assign({}, union[union.length - 1]), { description: OpenApiTypeChecker_1.OpenApiTypeChecker.writeReferenceDescription({
components: props.components,
$ref: input.$ref,
description: union[union.length - 1].description,
escape: true,
}) });
else
attribute.description =
OpenApiTypeChecker_1.OpenApiTypeChecker.writeReferenceDescription({
components: props.components,
$ref: input.$ref,
description: attribute.description,
escape: true,
});
return union.length;
}
}
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,
$defs: props.$defs,
schema: value,
});
if (converted === null)
return acc;
acc[key] = converted;
return acc;
}, {});
if (Object.values(properties).some(function (v) { return v === null; }))
return union.push(null);
if (!!input.additionalProperties === null)
return union.push(null);
return union.push(__assign(__assign({}, input), { properties: properties, additionalProperties: false, required: Object.keys(properties) }));
}
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(null);
return union.push((props.options.constraint
? function (x) { return x; }
: function (x) {
return OpenApiContraintShifter_1.OpenApiContraintShifter.shiftArray(x);
})(__assign(__assign({}, input), { items: items })));
}
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isString(input))
return union.push((props.options.constraint
? function (x) { return x; }
: function (x) {
return OpenApiContraintShifter_1.OpenApiContraintShifter.shiftString(x);
})(__assign({}, input)));
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isNumber(input) ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isInteger(input))
return union.push((props.options.constraint
? function (x) { return x; }
: function (x) {
return OpenApiContraintShifter_1.OpenApiContraintShifter.shiftNumeric(x);
})(__assign({}, input)));
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isConstant(input))
return 0;
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isTuple(input))
return union.push(null);
else
return union.push(__assign({}, input));
else if (LlmTypeCheckerV3_1_1.LlmTypeCheckerV3_1.isArray(input))
union.push(__assign(__assign({}, input), { items: transform(input.items) }));
else if (LlmTypeCheckerV3_1_1.LlmTypeCheckerV3_1.isObject(input))
union.push(__assign(__assign({}, input), { properties: Object.fromEntries(Object.entries(input.properties).map(function (_a) {
var _b = __read(_a, 2), key = _b[0], value = _b[1];
return [
key,
transform(value),
];
})) }));
else if (LlmTypeCheckerV3_1_1.LlmTypeCheckerV3_1.isConstant(input) === false)
union.push(input);
};
var visitConstant = function (input) {
var _a;
var insert = function (value) {

@@ -207,18 +158,6 @@ var _a;

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);
}
};
visit(props.schema);
visitConstant(props.schema);
if (union.some(function (u) { return u === null; }))
return null;
else if (union.length === 0)
visit(schema);
visitConstant(schema);
if (union.length === 0)
return __assign(__assign({}, attribute), { type: undefined });

@@ -273,3 +212,3 @@ else if (union.length === 1)

var separateObject = function (props) {
var e_1, _a;
var e_4, _a;
var _b;

@@ -292,3 +231,3 @@ var llm = __assign(__assign({}, props.schema), { properties: {} });

}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {

@@ -298,3 +237,3 @@ try {

}
finally { if (e_1) throw e_1.error; }
finally { if (e_4) throw e_4.error; }
}

@@ -301,0 +240,0 @@ llm.additionalProperties = false;

@@ -7,3 +7,3 @@ import { OpenApi } from "../OpenApi";

schema: OpenApi.IJsonSchema;
recursive: false | number;
config: IGeminiSchema.IConfig;
}) => IGeminiSchema.IParameters | null;

@@ -13,3 +13,3 @@ const schema: (props: {

schema: OpenApi.IJsonSchema;
recursive: false | number;
config: IGeminiSchema.IConfig;
}) => IGeminiSchema | null;

@@ -16,0 +16,0 @@ const separate: (props: {

@@ -13,3 +13,10 @@ "use strict";

GeminiConverter.schema = function (props) {
var schema = LlmConverterV3_1.LlmConverterV3.schema(props);
var schema = LlmConverterV3_1.LlmConverterV3.schema({
components: props.components,
schema: props.schema,
config: {
recursive: props.config.recursive,
constraint: false,
},
});
if (schema === null)

@@ -16,0 +23,0 @@ return null;

@@ -7,8 +7,8 @@ import { OpenApi } from "../OpenApi";

export declare namespace HttpLlmConverter {
const compose: <Model extends IHttpLlmApplication.Model, Parameters extends IHttpLlmApplication.ModelParameters[Model] = IHttpLlmApplication.ModelParameters[Model], Operation extends OpenApi.IOperation = OpenApi.IOperation<OpenApi.IJsonSchema>, Route extends IHttpMigrateRoute = IHttpMigrateRoute<OpenApi.IJsonSchema, Operation>>(props: {
const application: <Model extends IHttpLlmApplication.Model, Parameters extends IHttpLlmApplication.ModelParameters[Model] = IHttpLlmApplication.ModelParameters[Model], Operation extends OpenApi.IOperation = OpenApi.IOperation<OpenApi.IJsonSchema>, Route extends IHttpMigrateRoute = IHttpMigrateRoute<OpenApi.IJsonSchema, Operation>>(props: {
model: Model;
migrate: IHttpMigrateApplication<OpenApi.IJsonSchema, Operation>;
options: IHttpLlmApplication.IOptions<Model, Parameters["properties"][string] extends IHttpLlmApplication.ModelSchema[Model] ? Parameters["properties"][string] : IHttpLlmApplication.ModelSchema[Model]>;
options: IHttpLlmApplication.IOptions<Model>;
}) => IHttpLlmApplication<Model, Parameters, Operation, Route>;
const separateParameters: <Model extends IHttpLlmApplication.Model, Parameters extends IHttpLlmApplication.ModelParameters[Model] = IHttpLlmApplication.ModelParameters[Model]>(props: {
const separate: <Model extends IHttpLlmApplication.Model, Parameters extends IHttpLlmApplication.ModelParameters[Model] = IHttpLlmApplication.ModelParameters[Model]>(props: {
model: Model;

@@ -15,0 +15,0 @@ parameters: Parameters;

@@ -44,5 +44,6 @@ "use strict";

var LlmConverterV3_1_1 = require("./LlmConverterV3_1");
var LlmSchemaConverter_1 = require("./LlmSchemaConverter");
var HttpLlmConverter;
(function (HttpLlmConverter) {
HttpLlmConverter.compose = function (props) {
HttpLlmConverter.application = function (props) {
// COMPOSE FUNCTIONS

@@ -110,3 +111,3 @@ var errors = props.migrate.errors.map(function (e) { return ({

};
HttpLlmConverter.separateParameters = function (props) {
HttpLlmConverter.separate = function (props) {
var separator = SEPARATORS[props.model];

@@ -126,4 +127,4 @@ var _a = __read(separator({

var cast = function (s) {
return CASTERS[props.model]({
options: props.options,
return LlmSchemaConverter_1.LlmSchemaConverter.schema(props.model)({
config: props.options,
schema: s,

@@ -186,3 +187,3 @@ components: props.components,

separated: props.options.separate
? HttpLlmConverter.separateParameters({
? HttpLlmConverter.separate({
model: props.model,

@@ -212,33 +213,2 @@ predicate: props.options.separate,

})(HttpLlmConverter || (exports.HttpLlmConverter = HttpLlmConverter = {}));
var CASTERS = {
"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,
});
},
};
var SEPARATORS = {

@@ -245,0 +215,0 @@ "3.0": LlmConverterV3_2.LlmConverterV3.separate,

@@ -5,10 +5,11 @@ import { OpenApi } from "../OpenApi";

const parameters: (props: {
config: ILlmSchemaV3_1.IConfig;
components: OpenApi.IComponents;
schema: OpenApi.IJsonSchema.IObject;
recursive: false | number;
}) => ILlmSchemaV3_1.IParameters | null;
const schema: (props: {
config: ILlmSchemaV3_1.IConfig;
components: OpenApi.IComponents;
$defs: Record<string, ILlmSchemaV3_1>;
schema: OpenApi.IJsonSchema;
recursive: false | number;
}) => ILlmSchemaV3_1 | null;

@@ -15,0 +16,0 @@ const separate: (props: {

@@ -43,9 +43,154 @@ "use strict";

var LlmTypeCheckerV3_1_1 = require("../utils/LlmTypeCheckerV3_1");
var OpenApiContraintShifter_1 = require("../utils/OpenApiContraintShifter");
var OpenApiTypeChecker_1 = require("../utils/OpenApiTypeChecker");
var JsonDescriptionUtil_1 = require("../utils/internal/JsonDescriptionUtil");
var LlmConverterV3_1;
(function (LlmConverterV3_1) {
LlmConverterV3_1.parameters = function (props) {
return LlmConverterV3_1.schema(props);
var $defs = {};
var res = LlmConverterV3_1.schema({
config: props.config,
components: props.components,
schema: props.schema,
$defs: $defs,
});
if (res === null)
return null;
res.$defs = $defs;
return res;
};
LlmConverterV3_1.schema = function (props) { return OpenApiTypeChecker_1.OpenApiTypeChecker.escape(props); };
LlmConverterV3_1.schema = function (props) {
var union = [];
var attribute = __assign({ title: props.schema.title, description: props.schema.description, example: props.schema.example, examples: props.schema.examples }, Object.fromEntries(Object.entries(props.schema).filter(function (_a) {
var _b = __read(_a, 2), key = _b[0], value = _b[1];
return key.startsWith("x-") && value !== undefined;
})));
var visit = function (input) {
var _a;
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;
if (props.config.reference === true ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isRecursiveReference({
components: props.components,
schema: input,
})) {
var out = function () {
return union.push(__assign(__assign({}, input), { $ref: "#/$defs/".concat(key_1), title: undefined, description: undefined }));
};
if (props.$defs[key_1] !== undefined)
return out();
props.$defs[key_1] = {};
var converted = LlmConverterV3_1.schema({
config: props.config,
components: props.components,
$defs: props.$defs,
schema: target,
});
if (converted === null)
return union.push(null);
converted.description = JsonDescriptionUtil_1.JsonDescriptionUtil.cascade({
prefix: "#/components/schemas/",
components: props.components,
$ref: input.$ref,
description: converted.description,
escape: false,
});
props.$defs[key_1] = converted;
return out();
}
else {
var length_1 = union.length;
visit(target);
if (length_1 === union.length - 1 && union[union.length - 1] !== null)
union[union.length - 1] = __assign(__assign({}, union[union.length - 1]), { description: JsonDescriptionUtil_1.JsonDescriptionUtil.cascade({
prefix: "#/components/schemas/",
components: props.components,
$ref: input.$ref,
description: union[union.length - 1].description,
escape: true,
}) });
else
attribute.description = JsonDescriptionUtil_1.JsonDescriptionUtil.cascade({
prefix: "#/components/schemas/",
components: props.components,
$ref: input.$ref,
description: attribute.description,
escape: true,
});
return union.length;
}
}
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 = LlmConverterV3_1.schema({
config: props.config,
components: props.components,
$defs: props.$defs,
schema: value,
});
if (converted === null)
return acc;
acc[key] = converted;
return acc;
}, {});
if (Object.values(properties).some(function (v) { return v === null; }))
return union.push(null);
if (!!input.additionalProperties === null)
return union.push(null);
return union.push(__assign(__assign({}, input), { properties: properties, additionalProperties: false, required: Object.keys(properties) }));
}
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isArray(input)) {
var items = LlmConverterV3_1.schema({
config: props.config,
components: props.components,
$defs: props.$defs,
schema: input.items,
});
if (items === null)
return union.push(null);
return union.push((props.config.constraint
? function (x) { return x; }
: function (x) {
return OpenApiContraintShifter_1.OpenApiContraintShifter.shiftArray(x);
})(__assign(__assign({}, input), { items: items })));
}
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isString(input))
return union.push((props.config.constraint
? function (x) { return x; }
: function (x) {
return OpenApiContraintShifter_1.OpenApiContraintShifter.shiftString(x);
})(__assign({}, input)));
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isNumber(input) ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isInteger(input))
return union.push((props.config.constraint
? function (x) { return x; }
: function (x) {
return OpenApiContraintShifter_1.OpenApiContraintShifter.shiftNumeric(x);
})(__assign({}, input)));
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isTuple(input))
return union.push(null);
else
return union.push(__assign({}, input));
};
visit(props.schema);
if (union.some(function (u) { return u === null; }))
return null;
else if (union.length === 0)
return __assign(__assign({}, attribute), { type: undefined });
else if (union.length === 1)
return __assign(__assign(__assign({}, attribute), union[0]), { description: LlmTypeCheckerV3_1_1.LlmTypeCheckerV3_1.isReference(union[0])
? undefined
: union[0].description });
return __assign(__assign({}, attribute), { oneOf: union.map(function (u) { return (__assign(__assign({}, u), { description: LlmTypeCheckerV3_1_1.LlmTypeCheckerV3_1.isReference(u)
? undefined
: u.description })); }) });
};
LlmConverterV3_1.separate = function (props) {

@@ -106,26 +251,7 @@ if (props.predicate(props.schema) === true)

}
if (typeof props.schema.additionalProperties === "object" &&
props.schema.additionalProperties !== null) {
var _g = __read(LlmConverterV3_1.separate({
predicate: props.predicate,
schema: props.schema.additionalProperties,
}), 2), x = _g[0], y = _g[1];
if (x !== null)
llm.additionalProperties = x;
if (y !== null)
human.additionalProperties = y;
}
else {
llm.additionalProperties = false;
human.additionalProperties = false;
}
llm.additionalProperties = false;
human.additionalProperties = false;
return [
Object.keys(llm.properties).length === 0 &&
llm.additionalProperties === false
? null
: shrinkRequired(llm),
Object.keys(human.properties).length === 0 &&
human.additionalProperties === false
? null
: shrinkRequired(human),
Object.keys(llm.properties).length === 0 ? null : shrinkRequired(llm),
Object.keys(human.properties).length === 0 ? null : shrinkRequired(human),
];

@@ -132,0 +258,0 @@ };

@@ -7,3 +7,3 @@ import { OpenApi } from "../OpenApi";

schema: OpenApi.IJsonSchema.IObject;
recursive: false | number;
config: ILlmSchemaV3.IConfig;
}) => ILlmSchemaV3.IParameters | null;

@@ -13,3 +13,3 @@ const schema: (props: {

schema: OpenApi.IJsonSchema;
recursive: false | number;
config: Omit<ILlmSchemaV3.IConfig, "separate">;
}) => ILlmSchemaV3 | null;

@@ -16,0 +16,0 @@ const separate: (props: {

@@ -54,3 +54,3 @@ "use strict";

schema: props.schema,
recursive: props.recursive,
recursive: props.config.recursive,
});

@@ -60,3 +60,5 @@ if (resolved === null)

var downgraded = OpenApiV3Downgrader_1.OpenApiV3Downgrader.downgradeSchema({
original: {},
original: {
schemas: {},
},
downgraded: {},

@@ -63,0 +65,0 @@ })(resolved);

@@ -262,5 +262,6 @@ "use strict";

----------------------------------------------------------- */
var convertComponents = function (input) { return ({
schemas: input.schemas
? Object.fromEntries(Object.entries(input.schemas)
var convertComponents = function (input) {
var _a;
return ({
schemas: Object.fromEntries(Object.entries((_a = input.schemas) !== null && _a !== void 0 ? _a : {})
.filter(function (_a) {

@@ -273,6 +274,6 @@ var _b = __read(_a, 2), _ = _b[0], v = _b[1];

return [key, convertSchema(input)(value)];
}))
: undefined,
securitySchemes: input.securitySchemes,
}); };
})),
securitySchemes: input.securitySchemes,
});
};
var convertSchema = function (components) {

@@ -279,0 +280,0 @@ return function (input) {

@@ -238,5 +238,6 @@ "use strict";

----------------------------------------------------------- */
OpenApiV3Converter.convertComponents = function (input) { return ({
schemas: input.schemas
? Object.fromEntries(Object.entries(input.schemas)
OpenApiV3Converter.convertComponents = function (input) {
var _a;
return ({
schemas: Object.fromEntries(Object.entries((_a = input.schemas) !== null && _a !== void 0 ? _a : {})
.filter(function (_a) {

@@ -249,6 +250,6 @@ var _b = __read(_a, 2), _ = _b[0], v = _b[1];

return [key, OpenApiV3Converter.convertSchema(input)(value)];
}))
: undefined,
securitySchemes: input.securitySchemes,
}); };
})),
securitySchemes: input.securitySchemes,
});
};
OpenApiV3Converter.convertSchema = function (components) {

@@ -255,0 +256,0 @@ return function (input) {

@@ -203,5 +203,6 @@ "use strict";

----------------------------------------------------------- */
var convertComponents = function (input) { return ({
schemas: input.definitions
? Object.fromEntries(Object.entries(input.definitions)
var convertComponents = function (input) {
var _a;
return ({
schemas: Object.fromEntries(Object.entries((_a = input.definitions) !== null && _a !== void 0 ? _a : {})
.filter(function (_a) {

@@ -214,20 +215,20 @@ var _b = __read(_a, 2), _ = _b[0], v = _b[1];

return [key, SwaggerV2Converter.convertSchema(value)];
}))
: undefined,
securitySchemes: input.securityDefinitions
? Object.fromEntries(Object.entries(input.securityDefinitions)
.filter(function (_a) {
var _b = __read(_a, 2), _ = _b[0], v = _b[1];
return v !== undefined;
})
.map(function (_a) {
var _b = __read(_a, 2), key = _b[0], value = _b[1];
return [key, convertSecurityScheme(value)];
})
.filter(function (_a) {
var _b = __read(_a, 2), _ = _b[0], v = _b[1];
return v !== undefined;
}))
: undefined,
}); };
})),
securitySchemes: input.securityDefinitions
? Object.fromEntries(Object.entries(input.securityDefinitions)
.filter(function (_a) {
var _b = __read(_a, 2), _ = _b[0], v = _b[1];
return v !== undefined;
})
.map(function (_a) {
var _b = __read(_a, 2), key = _b[0], value = _b[1];
return [key, convertSecurityScheme(value)];
})
.filter(function (_a) {
var _b = __read(_a, 2), _ = _b[0], v = _b[1];
return v !== undefined;
}))
: undefined,
});
};
var convertSecurityScheme = function (input) {

@@ -234,0 +235,0 @@ if (input.type === "apiKey")

@@ -66,6 +66,6 @@ "use strict";

: props.document;
return HttpLlmConverter_1.HttpLlmConverter.compose({
return HttpLlmConverter_1.HttpLlmConverter.application({
migrate: migrate,
model: props.model,
options: (props.model === "chatgpt"
options: (props.model === "chatgpt" || props.model === "3.1"
? {

@@ -72,0 +72,0 @@ separate: (_b = (_a = props.options) === null || _a === void 0 ? void 0 : _a.separate) !== null && _b !== void 0 ? _b : null,

@@ -15,4 +15,6 @@ export * from "./OpenApi";

export * from "./structures/ILlmApplication";
export * from "./structures/ILlmFunction";
export * from "./structures/IChatGptSchema";
export * from "./structures/IGeminiSchema";
export * from "./structures/ILlmSchema";
export * from "./structures/ILlmSchemaV3";

@@ -19,0 +21,0 @@ export * from "./structures/ILlmSchemaV3_1";

@@ -40,4 +40,6 @@ "use strict";

__exportStar(require("./structures/ILlmApplication"), exports);
__exportStar(require("./structures/ILlmFunction"), exports);
__exportStar(require("./structures/IChatGptSchema"), exports);
__exportStar(require("./structures/IGeminiSchema"), exports);
__exportStar(require("./structures/ILlmSchema"), exports);
__exportStar(require("./structures/ILlmSchemaV3"), exports);

@@ -44,0 +46,0 @@ __exportStar(require("./structures/ILlmSchemaV3_1"), exports);

@@ -22,3 +22,3 @@ /**

*
* If compare with the {@link OpenApi.IJsonSchema}, the emended JSON schema type of
* If compare with the {@link OpenApi.IJsonSchema}, the emended JSON schema specification,
*

@@ -32,3 +32,3 @@ * - {@link IChatGptSchema.IAnyOf} instead of the {@link OpenApi.IJsonSchema.IOneOf}

* For reference, if you've composed the `IChatGptSchema` type with the
* {@link ILlmApplication.IChatGptOptions.reference} `false` option (default is `false`),
* {@link IChatGptSchema.IConfig.reference} `false` option (default is `false`),
* only the recursived named types would be archived into the

@@ -39,3 +39,3 @@ * {@link IChatGptSchema.IParameters.$defs}, and the others would be ecaped from the

* Also, if you've composed the `IChatGptSchema` type with the
* {@link ILlmApplication.IChatGptOptions.constraint} `false` option (default `false`),
* {@link IChatGptSchema.IConfig.constraint} `false` option (default `false`),
* the `IChatGptSchema` would not compose these properties. Instead, these

@@ -70,2 +70,9 @@ * properties would be written on {@link IChatGptSchema.__IAttribute.descripotion}

* Type of the function parameters.
*
* `IChatGptSchema.IParameters` is a type defining a function's parameters
* as a keyworded object type.
*
* It also can be utilized for the structured output metadata.
*
* @reference https://platform.openai.com/docs/guides/structured-outputs
*/

@@ -76,3 +83,3 @@ interface IParameters extends IObject {

*/
$defs?: Record<string, IChatGptSchema>;
$defs: Record<string, IChatGptSchema>;
}

@@ -323,3 +330,3 @@ /**

*/
interface IReference<Key = string> extends __IAttribute {
interface IReference extends __IAttribute {
/**

@@ -331,3 +338,3 @@ * Reference to the named schema.

* starts with `#/$defs/` which means the type is stored in
* the {@link IChatGptSchema.ITop.$defs} object.
* the {@link IChatGptSchema.IParameters.$defs} object.
*

@@ -337,3 +344,3 @@ * - `#/$defs/SomeObject`

*/
$ref: Key;
$ref: string;
}

@@ -407,2 +414,56 @@ /**

}
/**
* Configuration for ChatGPT schema composition.
*/
interface IConfig {
/**
* 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;
/**
* 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;
}
}
/**
* Type schema info of the Gemini.
* Type schema info for the Gemini function calling.
*
* `IGeminiSchema` iis a type metadata of LLM (Large Language Model)
* `IGeminiSchema` is a type metadata for the LLM (Large Language Model)
* function calling in the Geminimi.

@@ -51,2 +51,3 @@ *

* @reference https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/function-calling
* @reference https://ai.google.dev/gemini-api/docs/structured-output
* @warning Specified not by the official documentation, but by my experiments.

@@ -62,2 +63,9 @@ * Therefore, its definitions can be inaccurate or be changed in the

* Type of the function parameters.
*
* `IGeminiSchema.IParameters` is a type defining a function's parameters
* as a keyworded object type.
*
* It also can be utilized for the structured output metadata.
*
* @reference https://ai.google.dev/gemini-api/docs/structured-output
*/

@@ -250,2 +258,18 @@ type IParameters = IObject;

}
/**
* Configuration for the Gemini schema composition.
*/
interface IConfig {
/**
* 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: false | number;
}
}
import { OpenApi } from "../OpenApi";
import { IChatGptSchema } from "./IChatGptSchema";
import { IGeminiSchema } from "./IGeminiSchema";
import { IHttpLlmFunction } from "./IHttpLlmFunction";
import { IHttpMigrateRoute } from "./IHttpMigrateRoute";
import { ILlmApplication } from "./ILlmApplication";
import { ILlmSchemaV3 } from "./ILlmSchemaV3";
import { ILlmSchemaV3_1 } from "./ILlmSchemaV3_1";
/**

@@ -21,7 +17,7 @@ * Application of LLM function call from OpenAPI document.

* {@link IHttpLlmFunction} type which represents LLM function calling schema.
* By the way, if tehre're some recursive types which can't escape the
* {@link OpenApi.IJsonSchema.IReference} type, the operation would be failed and
* pushed into the {@link IHttpLlmApplication.errors}. Otherwise not, the operation
* would be successfully converted to {@link IHttpLlmFunction} and its type schemas
* are downgraded to {@link OpenApiV3.IJsonSchema} and converted to {@link ILlmSchemaV3}.
* By the way, if there're some types which does not supported by LLM, the operation
* would be failed and pushed into the {@link IHttpLlmApplication.errors}. Otherwise not,
* the operation would be successfully converted to {@link IHttpLlmFunction} and its
* type schemas are downgraded to {@link OpenApiV3.IJsonSchema} and converted to
* {@link ILlmSchemaV3}.
*

@@ -92,6 +88,3 @@ * About the options, if you've configured {@link IHttpLlmApplication.options.keyword}

/**
* Options for the application.
*
* Adjusted options when composing the application through
* {@link HttpLlm.application} function.
* Configuration for the application.
*/

@@ -101,15 +94,7 @@ options: IHttpLlmApplication.IOptions<Model, Parameters["properties"][string] extends IHttpLlmApplication.ModelSchema[Model] ? Parameters["properties"][string] : IHttpLlmApplication.ModelSchema[Model]>;

export declare namespace IHttpLlmApplication {
type Model = "3.0" | "3.1" | "chatgpt" | "gemini";
type ModelParameters = {
"3.0": ILlmSchemaV3.IParameters;
"3.1": ILlmSchemaV3_1.IParameters;
chatgpt: IChatGptSchema.IParameters;
gemini: IGeminiSchema.IParameters;
};
type ModelSchema = {
"3.0": ILlmSchemaV3;
"3.1": ILlmSchemaV3_1;
chatgpt: IChatGptSchema;
gemini: IGeminiSchema;
};
export import Model = ILlmApplication.Model;
export import ModelParameters = ILlmApplication.ModelParameters;
export import ModelSchema = ILlmApplication.ModelSchema;
export import ModelConfig = ILlmApplication.ModelConfig;
export import IOptions = ILlmApplication.IOptions;
/**

@@ -149,5 +134,2 @@ * Error occurred in the composition.

}
export import IOptions = ILlmApplication.IOptions;
export import ICommonOptions = ILlmApplication.ICommonOptions;
export import IChatGptOptions = ILlmApplication.IChatGptOptions;
}

@@ -14,9 +14,2 @@ import { IChatGptSchema } from "./IChatGptSchema";

*
* By the way, the LLM function calling application composition, converting
* `ILlmApplication` instance from TypeScript interface (or class) type is not always
* successful. As LLM provider like OpenAI cannot understand the recursive reference
* type that is embodied by {@link IOpenApiSchemachema.IReference}, if there're some
* recursive types in the TypeScript interface (or class) type, the conversion would
* be failed.
*
* Also, there can be some parameters (or their nested properties) which must be

@@ -49,3 +42,3 @@ * composed by Human, not by LLM. File uploading feature or some sensitive information

/**
* Options for the application.
* Configuration for the application.
*/

@@ -68,22 +61,13 @@ options: ILlmApplication.IOptions<Model, Parameters["properties"][string] extends ILlmApplication.ModelSchema[Model] ? Parameters["properties"][string] : ILlmApplication.ModelSchema[Model]>;

};
type ModelConfig = {
"3.0": ILlmSchemaV3.IConfig;
"3.1": ILlmSchemaV3_1.IConfig;
chatgpt: IChatGptSchema.IConfig;
gemini: IGeminiSchema.IConfig;
};
/**
* Options for composing the LLM application.
* Options for application composition.
*/
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]> {
type IOptions<Model extends ILlmApplication.Model, Schema extends ModelSchema[Model] = 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: false | number;
/**
* Separator function for the parameters.

@@ -93,38 +77,6 @@ *

* 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).
* or LLM cannot understand the parameter.
*
* 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 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);
}
/**
* 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
* For example, if the parameter type has configured
* {@link IGeminiSchema.IString.contentMediaType} which indicates file
* uploading, it must be composed by human, not by LLM

@@ -143,3 +95,3 @@ * (Large Language Model).

* composing the value. Also, when predicating the schema, it would
* better to utilize the {@link ChatGptTypeChecker} features.
* better to utilize the {@link GeminiTypeChecker} like features.
*

@@ -151,52 +103,3 @@ * @param schema Schema to be separated.

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;
}
} & ModelConfig[Model];
}

@@ -1,11 +0,72 @@

export type ILlmSchemaV3_1 = ILlmSchemaV3_1.IBoolean | ILlmSchemaV3_1.IInteger | ILlmSchemaV3_1.INumber | ILlmSchemaV3_1.IString | ILlmSchemaV3_1.IArray | ILlmSchemaV3_1.ITuple | ILlmSchemaV3_1.IObject | ILlmSchemaV3_1.IOneOf | ILlmSchemaV3_1.INull | ILlmSchemaV3_1.IUnknown;
/**
* Type schema based on OpenAPI v3.1 for LLM function calling.
*
* `ILlmSchemaV3_1` is a type metadata for LLM (Large Language Model)
* function calling, based on the OpenAPI v3.1 speicification. This type
* is not the final type for the LLM function calling, but the intermediate
* structure for the conversion to the final type like {@link IChatGptSchema}.
*
* 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 `ILlmSchemaV3_1` 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.IAnyOf} to {@link ILlmSchemaV3_1.IOneOf}
* - Merge {@link OpenApiV3_1.IJsonSchema.IAllOf} to {@link ILlmSchemaV3_1.IObject}
* - Merge {@link OpenApiV3_1.IJsonSchema.IRecursiveReference} to {@link ILlmSchemaV3_1.IReference}
* - Do not support {@link OpenApiV3_1.IJsonSchema.ITuple} type
*
* If compare with the {@link OpenApi.IJsonSchema}, the emended JSON schema specification,
*
* - {@link ILlmSchemaV3_1.IParameters.$defs} instead of the {@link OpenApi.IJsonSchema.schemas}
* - Do not support {@link OpenApi.IJsonSchema.ITuple} type
*
* For reference, if you've composed the `ILlmSchemaV3_1` type with the
* {@link ILlmSchemaV3_1.IConfig.reference} `false` option (default is `false`),
* only the recursived named types would be archived into the
* {@link ILlmSchemaV3_1.IParameters.$defs}, and the others would be ecaped from the
* {@link ILlmSchemaV3_1.IReference} type.
*
* Also, if you've composed the `ILlmSchemaV3_1` type with the
* {@link ILlmSchemaV3_1.IConfig.constraint} `false` option (default `false`),
* the `ILlmSchemaV3_1` would not compose these properties. Instead, these
* properties would be written on {@link ILlmSchemaV3_1.__IAttribute.descripotion}
* field like `@format uuid` case.
*
* - {@link ILlmSchemaV3_1.INumber.minimum}
* - {@link ILlmSchemaV3_1.INumber.maximum}
* - {@link ILlmSchemaV3_1.INumber.multipleOf}
* - {@link ILlmSchemaV3_1.IString.minLength}
* - {@link ILlmSchemaV3_1.IString.maxLength}
* - {@link ILlmSchemaV3_1.IString.format}
* - {@link ILlmSchemaV3_1.IString.pattern}
* - {@link ILlmSchemaV3_1.IString.contentMediaType}
* - {@link ILlmSchemaV3_1.IArray.minItems}
* - {@link ILlmSchemaV3_1.IArray.maxItems}
* - {@link ILlmSchemaV3_1.IArray.unique}
*
* @reference https://platform.openai.com/docs/guides/function-calling
* @reference https://platform.openai.com/docs/guides/structured-outputs
* @author Jeongho Nam - https://github.com/samchon
*/
export type ILlmSchemaV3_1 = ILlmSchemaV3_1.IBoolean | ILlmSchemaV3_1.IInteger | ILlmSchemaV3_1.INumber | ILlmSchemaV3_1.IString | ILlmSchemaV3_1.IArray | ILlmSchemaV3_1.IObject | ILlmSchemaV3_1.IOneOf | ILlmSchemaV3_1.IReference | ILlmSchemaV3_1.INull | ILlmSchemaV3_1.IUnknown;
export declare namespace ILlmSchemaV3_1 {
/**
* Type of the function parameters.
*
* `ILlmSchemaV3_1.IParameters` is a type defining a function's parameters
* as a keyworded object type.
*
* It also can be utilized for the structured output metadata.
*
* @reference https://platform.openai.com/docs/guides/structured-outputs
*/
interface IParameters extends Omit<IObject, "additionalProperties"> {
interface IParameters extends IObject {
/**
* Do not allow additional properties in the parameters.
* Collection of the named types.
*/
additionalProperties: false;
$defs: Record<string, ILlmSchemaV3_1>;
}

@@ -187,55 +248,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: ILlmSchemaV3_1[];
/**
* 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 | ILlmSchemaV3_1;
/**
* 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.

@@ -261,11 +269,6 @@ */

*
* If the value is `true`, it means that the additional properties are not
* restricted. They can be any type. Otherwise, if the value is
* {@link IOpenAiSchema} type, it means that the additional properties must
* follow the type schema info.
*
* - `true`: `Record<string, any>`
* - `IOpenAiSchema`: `Record<string, T>`
* By the way, as LLM function calling does not support such dynamic key
* typed properties, the `additionalProperties` becomes always `false`.
*/
additionalProperties?: boolean | ILlmSchemaV3_1;
additionalProperties: false;
/**

@@ -307,2 +310,19 @@ * List of key values of the required properties.

/**
* Reference type directing named schema.
*/
interface IReference extends __IAttribute {
/**
* Reference to the named schema.
*
* The `ref` is a reference to the named schema. Format of the `$ref` is
* following the JSON Pointer specification. In the OpenAPI, the `$ref`
* starts with `#/$defs/` which means the type is stored in
* the {@link ILlmSchemaV3_1.IParameters.$defs} object.
*
* - `#/$defs/SomeObject`
* - `#/$defs/AnotherObject`
*/
$ref: string;
}
/**
* Union type.

@@ -398,2 +418,56 @@ *

}
/**
* Configuration for OpenAPI v3.1 based LLM schema composition.
*/
interface IConfig {
/**
* 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 ILlmSchemaV3_1.__IAttribute.description} property
* as a comment string like `"@format uuid"`.
*
* This is because the some LLM model's 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 ILlmSchemaV3_1.INumber.minimum}
* - {@link ILlmSchemaV3_1.INumber.maximum}
* - {@link ILlmSchemaV3_1.INumber.multipleOf}
* - {@link ILlmSchemaV3_1.IString.minLength}
* - {@link ILlmSchemaV3_1.IString.maxLength}
* - {@link ILlmSchemaV3_1.IString.format}
* - {@link ILlmSchemaV3_1.IString.pattern}
* - {@link ILlmSchemaV3_1.IString.contentMediaType}
* - {@link ILlmSchemaV3_1.IArray.minItems}
* - {@link ILlmSchemaV3_1.IArray.maxItems}
* - {@link ILlmSchemaV3_1.IArray.unique}
*
* @default false
*/
constraint: boolean;
/**
* Whether to allow reference type in everywhere.
*
* If you configure this property to `false`, most of reference types
* represented by {@link ILlmSchemaV3_1.IReference} would be escaped to
* a plain type unless recursive type case.
*
* This is because some low sized LLM models does not understand the
* reference type well, and even the large size LLM models 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 large size of LLM model,
* and want to reduce the LLM token cost, you can configure this property to
* `true`.
*
* @default false
*/
reference: boolean;
}
}
/**
* Type schema info of LLM function call.
* Type schema based on OpenAPI v3.0 for LLM function calling.
*
* `ILlmSchemaV3` is a type metadata of LLM (Large Language Model)
* function calling.
* `ILlmSchemaV3` is a type metadata for LLM (Large Language Model)
* function calling, based on the OpenAPI v3.0 speicification. This type
* is not the final type for the LLM function calling, but the intermediate
* structure for the conversion to the final type like {@link IGeminiSchema}.
*

@@ -10,3 +12,6 @@ * `ILlmSchemaV3` basically follows the JSON schema definition of OpenAPI

* does not have the reference type; {@link OpenApiV3.IJsonSchema.IReference}.
* It's because the LLM cannot compose the reference typed arguments.
* It's because the LLM cannot compose the reference typed arguments. If
* recursive type comes, its type would be repeated in
* {@link ILlmSchemaV3.IConfig.recursive} times. Otherwise you've configured
* it to `false`, the recursive types are not allowed.
*

@@ -18,2 +23,19 @@ * For reference, the OpenAPI v3.0 based JSON schema definition can't

*
* Also, if you configure {@link ILlmSchemaV3.IConfig.constraint} to `false`,
* tehse properties would be banned and written to the
* {@link ILlmSchemaV3.__IAttribute.description} property instead. It's because
* there are some LLM models which does not support the constraint properties.
*
* - {@link ILlmSchemaV3.INumber.minimum}
* - {@link ILlmSchemaV3.INumber.maximum}
* - {@link ILlmSchemaV3.INumber.multipleOf}
* - {@link ILlmSchemaV3.IString.minLength}
* - {@link ILlmSchemaV3.IString.maxLength}
* - {@link ILlmSchemaV3.IString.format}
* - {@link ILlmSchemaV3.IString.pattern}
* - {@link ILlmSchemaV3.IString.contentMediaType}
* - {@link ILlmSchemaV3.IArray.minItems}
* - {@link ILlmSchemaV3.IArray.maxItems}
* - {@link ILlmSchemaV3.IArray.unique}
*
* @reference https://platform.openai.com/docs/guides/function-calling

@@ -26,9 +48,11 @@ * @author Jeongho Nam - https://github.com/samchon

* Type of the function parameters.
*
* `ILlmSchemaV3.IParameters` is a type defining a function's parameters
* as a keyworded object type.
*
* It also can be utilized for the structured output metadata.
*
* @reference https://platform.openai.com/docs/guides/structured-outputs
*/
interface IParameters extends Omit<IObject, "additionalProperties"> {
/**
* Do not allow additional properties in the parameters.
*/
additionalProperties: false;
}
type IParameters = IObject;
/**

@@ -354,2 +378,48 @@ * Boolean type schema info.

}
/**
* Configuration for OpenAPI v3.0 based LLM schema composition.
*/
interface IConfig {
/**
* 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 ILlmSchemaV3.__IAttribute.description} property
* as a comment string like `"@format uuid"`.
*
* This is because the some LLM model's 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 ILlmSchemaV3.INumber.minimum}
* - {@link ILlmSchemaV3.INumber.maximum}
* - {@link ILlmSchemaV3.INumber.multipleOf}
* - {@link ILlmSchemaV3.IString.minLength}
* - {@link ILlmSchemaV3.IString.maxLength}
* - {@link ILlmSchemaV3.IString.format}
* - {@link ILlmSchemaV3.IString.pattern}
* - {@link ILlmSchemaV3.IString.contentMediaType}
* - {@link ILlmSchemaV3.IArray.minItems}
* - {@link ILlmSchemaV3.IArray.maxItems}
* - {@link ILlmSchemaV3.IArray.unique}
*
* @default false
*/
constraint: boolean;
/**
* 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: false | number;
}
}

@@ -11,5 +11,24 @@ import { ILlmSchemaV3_1 } from "../structures/ILlmSchemaV3_1";

const isArray: (schema: ILlmSchemaV3_1) => schema is ILlmSchemaV3_1.IArray;
const isTuple: (schema: ILlmSchemaV3_1) => schema is ILlmSchemaV3_1.ITuple;
const isObject: (schema: ILlmSchemaV3_1) => schema is ILlmSchemaV3_1.IObject;
const isReference: (schema: ILlmSchemaV3_1) => schema is ILlmSchemaV3_1.IReference;
const isOneOf: (schema: ILlmSchemaV3_1) => schema is ILlmSchemaV3_1.IOneOf;
const isRecursiveReference: (props: {
$defs?: Record<string, ILlmSchemaV3_1>;
schema: ILlmSchemaV3_1;
}) => boolean;
const escape: (props: {
$defs?: Record<string, ILlmSchemaV3_1>;
schema: ILlmSchemaV3_1;
recursive: false | number;
}) => ILlmSchemaV3_1 | null;
const visit: (props: {
closure: (schema: ILlmSchemaV3_1) => void;
$defs?: Record<string, ILlmSchemaV3_1>;
schema: ILlmSchemaV3_1;
}) => void;
const covers: (props: {
$defs?: Record<string, ILlmSchemaV3_1>;
x: ILlmSchemaV3_1;
y: ILlmSchemaV3_1;
}) => boolean;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LlmTypeCheckerV3_1 = void 0;
var OpenApiTypeCheckerBase_1 = require("./internal/OpenApiTypeCheckerBase");
var LlmTypeCheckerV3_1;

@@ -9,39 +10,71 @@ (function (LlmTypeCheckerV3_1) {

----------------------------------------------------------- */
LlmTypeCheckerV3_1.isNull = function (schema) {
return schema.type === "null";
};
LlmTypeCheckerV3_1.isNull = function (schema) { return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isNull(schema); };
LlmTypeCheckerV3_1.isUnknown = function (schema) {
return schema.type === undefined &&
!LlmTypeCheckerV3_1.isConstant(schema) &&
!LlmTypeCheckerV3_1.isOneOf(schema);
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isUnknown(schema);
};
LlmTypeCheckerV3_1.isConstant = function (schema) {
return schema.const !== undefined;
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isConstant(schema);
};
LlmTypeCheckerV3_1.isBoolean = function (schema) {
return schema.type === "boolean";
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isBoolean(schema);
};
LlmTypeCheckerV3_1.isInteger = function (schema) {
return schema.type === "integer";
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isInteger(schema);
};
LlmTypeCheckerV3_1.isNumber = function (schema) {
return schema.type === "number";
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isNumber(schema);
};
LlmTypeCheckerV3_1.isString = function (schema) {
return schema.type === "string";
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isString(schema);
};
LlmTypeCheckerV3_1.isArray = function (schema) {
return schema.type === "array" &&
schema.items !== undefined;
LlmTypeCheckerV3_1.isArray = function (schema) { return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isArray(schema); };
LlmTypeCheckerV3_1.isObject = function (schema) {
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isObject(schema);
};
LlmTypeCheckerV3_1.isTuple = function (schema) {
return schema.type === "array" &&
schema.prefixItems !== undefined;
LlmTypeCheckerV3_1.isReference = function (schema) {
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isReference(schema);
};
LlmTypeCheckerV3_1.isObject = function (schema) {
return schema.type === "object";
LlmTypeCheckerV3_1.isOneOf = function (schema) { return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isOneOf(schema); };
LlmTypeCheckerV3_1.isRecursiveReference = function (props) {
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isRecursiveReference({
prefix: "#/$defs/",
components: {
schemas: props.$defs,
},
schema: props.schema,
});
};
LlmTypeCheckerV3_1.isOneOf = function (schema) {
return schema.oneOf !== undefined;
/* -----------------------------------------------------------
OPERATORS
----------------------------------------------------------- */
LlmTypeCheckerV3_1.escape = function (props) {
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.escape({
prefix: "#/$defs/",
components: {
schemas: props.$defs,
},
schema: props.schema,
recursive: props.recursive,
});
};
LlmTypeCheckerV3_1.visit = function (props) {
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.visit({
prefix: "#/$defs/",
closure: props.closure,
components: {
schemas: props.$defs,
},
schema: props.schema,
});
};
LlmTypeCheckerV3_1.covers = function (props) {
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.covers({
prefix: "#/$defs/",
components: {
schemas: props.$defs,
},
x: props.x,
y: props.y,
});
};
})(LlmTypeCheckerV3_1 || (exports.LlmTypeCheckerV3_1 = LlmTypeCheckerV3_1 = {}));
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
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 });
exports.OpenApiTypeChecker = void 0;
var MapUtil_1 = require("./MapUtil");
var OpenApiTypeCheckerBase_1 = require("./internal/OpenApiTypeCheckerBase");
var OpenApiTypeChecker;

@@ -58,59 +11,43 @@ (function (OpenApiTypeChecker) {

OpenApiTypeChecker.isNull = function (schema) {
return schema.type === "null";
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isNull(schema);
};
OpenApiTypeChecker.isUnknown = function (schema) {
return schema.type === undefined &&
!OpenApiTypeChecker.isConstant(schema) &&
!OpenApiTypeChecker.isOneOf(schema) &&
!OpenApiTypeChecker.isReference(schema);
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isUnknown(schema);
};
OpenApiTypeChecker.isConstant = function (schema) {
return schema.const !== undefined;
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isConstant(schema);
};
OpenApiTypeChecker.isBoolean = function (schema) {
return schema.type === "boolean";
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isBoolean(schema);
};
OpenApiTypeChecker.isInteger = function (schema) {
return schema.type === "integer";
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isInteger(schema);
};
OpenApiTypeChecker.isNumber = function (schema) {
return schema.type === "number";
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isNumber(schema);
};
OpenApiTypeChecker.isString = function (schema) {
return schema.type === "string";
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isString(schema);
};
OpenApiTypeChecker.isArray = function (schema) {
return schema.type === "array" &&
schema.items !== undefined;
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isArray(schema);
};
OpenApiTypeChecker.isTuple = function (schema) {
return schema.type === "array" &&
schema.prefixItems !== undefined;
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isTuple(schema);
};
OpenApiTypeChecker.isObject = function (schema) {
return schema.type === "object";
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isObject(schema);
};
OpenApiTypeChecker.isReference = function (schema) {
return schema.$ref !== undefined;
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isReference(schema);
};
OpenApiTypeChecker.isOneOf = function (schema) {
return schema.oneOf !== undefined;
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isOneOf(schema);
};
OpenApiTypeChecker.isRecursiveReference = function (props) {
if (OpenApiTypeChecker.isReference(props.schema) === false)
return false;
var current = props.schema.$ref.split("#/components/schemas/")[1];
var counter = 0;
OpenApiTypeChecker.visit({
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.isRecursiveReference({
prefix: "#/components/schemas/",
components: props.components,
schema: props.schema,
closure: function (schema) {
if (OpenApiTypeChecker.isReference(schema)) {
var next = schema.$ref.split("#/components/schemas/")[1];
if (current === next)
++counter;
}
},
});
return counter > 1;
};

@@ -121,474 +58,25 @@ /* -----------------------------------------------------------

OpenApiTypeChecker.escape = function (props) {
return escapeSchema({
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.escape({
prefix: "#/components/schemas/",
components: props.components,
schema: props.schema,
recursive: props.recursive,
visited: new Map(),
}) || null;
});
};
OpenApiTypeChecker.visit = function (props) {
var already = new Set();
var next = function (schema) {
var e_1, _a;
var _b, _c, _d;
props.closure(schema);
if (OpenApiTypeChecker.isReference(schema)) {
var key = schema.$ref.split("#/components/schemas/").pop();
if (already.has(key) === true)
return;
already.add(key);
var found = (_b = props.components.schemas) === null || _b === void 0 ? void 0 : _b[key];
if (found !== undefined)
next(found);
}
else if (OpenApiTypeChecker.isOneOf(schema))
schema.oneOf.forEach(next);
else if (OpenApiTypeChecker.isObject(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;
next(value);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_f && !_f.done && (_a = _e.return)) _a.call(_e);
}
finally { if (e_1) throw e_1.error; }
}
if (typeof schema.additionalProperties === "object" &&
schema.additionalProperties !== null)
next(schema.additionalProperties);
}
else if (OpenApiTypeChecker.isArray(schema))
next(schema.items);
else if (OpenApiTypeChecker.isTuple(schema)) {
((_d = schema.prefixItems) !== null && _d !== void 0 ? _d : []).forEach(next);
if (typeof schema.additionalItems === "object" &&
schema.additionalItems !== null)
next(schema.additionalItems);
}
};
next(props.schema);
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.visit({
prefix: "#/components/schemas/",
closure: props.closure,
components: props.components,
schema: props.schema,
});
};
OpenApiTypeChecker.covers = function (props) {
return coverStation({
return OpenApiTypeCheckerBase_1.OpenApiTypeCheckerBase.covers({
prefix: "#/components/schemas/",
components: props.components,
x: props.x,
y: props.y,
visited: new Map(),
});
};
var escapeSchema = function (props) {
var _a, _b;
if (OpenApiTypeChecker.isReference(props.schema)) {
// REFERENCE
var name_1 = props.schema.$ref.split("#/components/schemas/")[1];
var target = (_a = props.components.schemas) === null || _a === void 0 ? void 0 : _a[name_1];
if (target === undefined)
return null;
else if (props.visited.has(name_1) === true) {
if (props.recursive === false)
return null;
var depth = props.visited.get(name_1);
if (depth > props.recursive)
return undefined;
props.visited.set(name_1, depth + 1);
var res_1 = escapeSchema({
components: props.components,
schema: target,
recursive: props.recursive,
visited: props.visited,
});
return res_1
? __assign(__assign({}, res_1), { description: OpenApiTypeChecker.writeReferenceDescription({
components: props.components,
$ref: props.schema.$ref,
description: res_1.description,
escape: true,
}) }) : res_1;
}
var res = escapeSchema({
components: props.components,
schema: target,
recursive: props.recursive,
visited: new Map(__spreadArray(__spreadArray([], __read(props.visited), false), [[name_1, 1]], false)),
});
return res
? __assign(__assign({}, res), { description: OpenApiTypeChecker.writeReferenceDescription({
components: props.components,
$ref: props.schema.$ref,
description: res.description,
escape: true,
}) }) : res;
}
else if (OpenApiTypeChecker.isOneOf(props.schema)) {
// UNION
var elements = props.schema.oneOf.map(function (schema) {
return escapeSchema({
components: props.components,
schema: schema,
recursive: props.recursive,
visited: props.visited,
});
});
if (elements.some(function (v) { return v === null; }))
return null;
var filtered = elements.filter(function (v) { return v !== undefined; });
if (filtered.length === 0)
return undefined;
return __assign(__assign({}, props), { oneOf: filtered.map(function (v) { return flatSchema(props.components, v); }).flat() });
}
else if (OpenApiTypeChecker.isObject(props.schema)) {
// OBJECT
var object_1 = props.schema;
var properties_1 = Object.entries((_b = object_1.properties) !== null && _b !== void 0 ? _b : {}).map(function (_a) {
var _b = __read(_a, 2), key = _b[0], value = _b[1];
return [
key,
escapeSchema({
components: props.components,
schema: value,
recursive: props.recursive,
visited: props.visited,
}),
];
});
var additionalProperties = object_1.additionalProperties
? typeof object_1.additionalProperties === "object" &&
object_1.additionalProperties !== null
? escapeSchema({
components: props.components,
schema: object_1.additionalProperties,
recursive: props.recursive,
visited: props.visited,
})
: object_1.additionalProperties
: false;
if (properties_1.some(function (_a) {
var _b = __read(_a, 2), _k = _b[0], v = _b[1];
return v === null;
}) ||
additionalProperties === null)
return null;
else if (properties_1.some(function (_a) {
var _b = __read(_a, 2), k = _b[0], v = _b[1];
return v === undefined && object_1.required.includes(k) === true;
}) === true)
return undefined;
return __assign(__assign({}, object_1), { properties: Object.fromEntries(properties_1.filter(function (_a) {
var _b = __read(_a, 2), _k = _b[0], v = _b[1];
return v !== undefined;
})), additionalProperties: additionalProperties !== null && additionalProperties !== void 0 ? additionalProperties : false, required: object_1.required.filter(function (k) {
return properties_1.some(function (_a) {
var _b = __read(_a, 2), key = _b[0], value = _b[1];
return key === k && value !== undefined;
});
}) });
}
else if (OpenApiTypeChecker.isTuple(props.schema)) {
// TUPLE
var elements = props.schema.prefixItems.map(function (schema) {
return escapeSchema({
components: props.components,
schema: schema,
recursive: props.recursive,
visited: props.visited,
});
});
var additionalItems = props.schema.additionalItems
? typeof props.schema.additionalItems === "object" &&
props.schema.additionalItems !== null
? escapeSchema({
components: props.components,
schema: props.schema.additionalItems,
recursive: props.recursive,
visited: props.visited,
})
: props.schema.additionalItems
: false;
if (elements.some(function (v) { return v === null; }) || additionalItems === null)
return null;
else if (elements.some(function (v) { return v === undefined; }))
return undefined;
return __assign(__assign({}, props.schema), { prefixItems: elements, additionalItems: additionalItems !== null && additionalItems !== void 0 ? additionalItems : false });
}
else if (OpenApiTypeChecker.isArray(props.schema)) {
// ARRAY
var items = escapeSchema({
components: props.components,
schema: props.schema.items,
recursive: props.recursive,
visited: props.visited,
});
if (items === null)
return null;
else if (items === undefined)
return __assign(__assign({}, props.schema), { minItems: undefined, maxItems: 0, items: {} });
return __assign(__assign({}, props.schema), { items: items });
}
return props.schema;
};
var coverStation = function (p) {
var _a;
var cache = (_a = p.visited.get(p.x)) === null || _a === void 0 ? void 0 : _a.get(p.y);
if (cache !== undefined)
return cache;
// FOR RECURSIVE CASE
var nested = MapUtil_1.MapUtil.take(p.visited)(p.x)(function () { return new Map(); });
nested.set(p.y, true);
// COMPUTE IT
var result = coverSchema(p);
nested.set(p.y, result);
return result;
};
var coverSchema = function (p) {
// CHECK EQUALITY
if (p.x === p.y)
return true;
else if (OpenApiTypeChecker.isReference(p.x) && OpenApiTypeChecker.isReference(p.y) && p.x.$ref === p.y.$ref)
return true;
// COMPARE WITH FLATTENING
var alpha = flatSchema(p.components, p.x);
var beta = flatSchema(p.components, p.y);
if (alpha.some(function (x) { return OpenApiTypeChecker.isUnknown(x); }))
return true;
else if (beta.some(function (x) { return OpenApiTypeChecker.isUnknown(x); }))
return false;
return beta.every(function (b) {
return alpha.some(function (a) {
return coverEscapedSchema({
components: p.components,
visited: p.visited,
x: a,
y: b,
});
});
});
};
var coverEscapedSchema = function (p) {
// CHECK EQUALITY
if (p.x === p.y)
return true;
else if (OpenApiTypeChecker.isUnknown(p.x))
return true;
else if (OpenApiTypeChecker.isUnknown(p.y))
return false;
else if (OpenApiTypeChecker.isNull(p.x))
return OpenApiTypeChecker.isNull(p.y);
// ATOMIC CASE
else if (OpenApiTypeChecker.isConstant(p.x))
return OpenApiTypeChecker.isConstant(p.y) && p.x.const === p.y.const;
else if (OpenApiTypeChecker.isBoolean(p.x))
return (OpenApiTypeChecker.isBoolean(p.y) || (OpenApiTypeChecker.isConstant(p.y) && typeof p.y.const === "boolean"));
else if (OpenApiTypeChecker.isInteger(p.x))
return (OpenApiTypeChecker.isInteger(p.y) || OpenApiTypeChecker.isConstant(p.y)) && coverInteger(p.x, p.y);
else if (OpenApiTypeChecker.isNumber(p.x))
return ((OpenApiTypeChecker.isConstant(p.y) || OpenApiTypeChecker.isInteger(p.y) || OpenApiTypeChecker.isNumber(p.y)) &&
coverNumber(p.x, p.y));
else if (OpenApiTypeChecker.isString(p.x))
return (OpenApiTypeChecker.isConstant(p.y) || OpenApiTypeChecker.isString(p.y)) && coverString(p.x, p.y);
// INSTANCE CASE
else if (OpenApiTypeChecker.isArray(p.x))
return ((OpenApiTypeChecker.isArray(p.y) || OpenApiTypeChecker.isTuple(p.y)) &&
coverArray({
components: p.components,
visited: p.visited,
x: p.x,
y: p.y,
}));
else if (OpenApiTypeChecker.isObject(p.x))
return (OpenApiTypeChecker.isObject(p.y) &&
coverObject({
components: p.components,
visited: p.visited,
x: p.x,
y: p.y,
}));
else if (OpenApiTypeChecker.isReference(p.x))
return OpenApiTypeChecker.isReference(p.y) && p.x.$ref === p.y.$ref;
return false;
};
var coverArray = function (p) {
if (OpenApiTypeChecker.isTuple(p.y))
return (p.y.prefixItems.every(function (v) {
return coverStation({
components: p.components,
visited: p.visited,
x: p.x.items,
y: v,
});
}) &&
(p.y.additionalItems === undefined ||
(typeof p.y.additionalItems === "object" &&
coverStation({
components: p.components,
visited: p.visited,
x: p.x.items,
y: p.y.additionalItems,
}))));
else if (!(p.x.minItems === undefined ||
(p.y.minItems !== undefined && p.x.minItems <= p.y.minItems)))
return false;
else if (!(p.x.maxItems === undefined ||
(p.y.maxItems !== undefined && p.x.maxItems >= p.y.maxItems)))
return false;
return coverStation({
components: p.components,
visited: p.visited,
x: p.x.items,
y: p.y.items,
});
};
var coverObject = function (p) {
var _a;
if (!p.x.additionalProperties && !!p.y.additionalProperties)
return false;
else if (!!p.x.additionalProperties &&
!!p.y.additionalProperties &&
((typeof p.x.additionalProperties === "object" &&
p.y.additionalProperties === true) ||
(typeof p.x.additionalProperties === "object" &&
typeof p.y.additionalProperties === "object" &&
!coverStation({
components: p.components,
visited: p.visited,
x: p.x.additionalProperties,
y: p.y.additionalProperties,
}))))
return false;
return Object.entries((_a = p.y.properties) !== null && _a !== void 0 ? _a : {}).every(function (_a) {
var _b;
var _c = __read(_a, 2), key = _c[0], b = _c[1];
var a = (_b = p.x.properties) === null || _b === void 0 ? void 0 : _b[key];
if (a === undefined)
return false;
else if (p.x.required.includes(key) === true &&
p.y.required.includes(key) === false)
return false;
return coverStation({
components: p.components,
visited: p.visited,
x: a,
y: b,
});
});
};
var coverInteger = function (x, y) {
if (OpenApiTypeChecker.isConstant(y))
return typeof y.const === "number" && Number.isInteger(y.const);
return [
x.type === y.type,
x.minimum === undefined ||
(y.minimum !== undefined && x.minimum <= y.minimum),
x.maximum === undefined ||
(y.maximum !== undefined && x.maximum >= y.maximum),
x.exclusiveMinimum !== true ||
x.minimum === undefined ||
(y.minimum !== undefined &&
(y.exclusiveMinimum === true || x.minimum < y.minimum)),
x.exclusiveMaximum !== true ||
x.maximum === undefined ||
(y.maximum !== undefined &&
(y.exclusiveMaximum === true || x.maximum > y.maximum)),
x.multipleOf === undefined ||
(y.multipleOf !== undefined &&
y.multipleOf / x.multipleOf ===
Math.floor(y.multipleOf / x.multipleOf)),
].every(function (v) { return v; });
};
var coverNumber = function (x, y) {
if (OpenApiTypeChecker.isConstant(y))
return typeof y.const === "number";
return [
x.type === y.type || (x.type === "number" && y.type === "integer"),
x.minimum === undefined ||
(y.minimum !== undefined && x.minimum <= y.minimum),
x.maximum === undefined ||
(y.maximum !== undefined && x.maximum >= y.maximum),
x.exclusiveMinimum !== true ||
x.minimum === undefined ||
(y.minimum !== undefined &&
(y.exclusiveMinimum === true || x.minimum < y.minimum)),
x.exclusiveMaximum !== true ||
x.maximum === undefined ||
(y.maximum !== undefined &&
(y.exclusiveMaximum === true || x.maximum > y.maximum)),
x.multipleOf === undefined ||
(y.multipleOf !== undefined &&
y.multipleOf / x.multipleOf ===
Math.floor(y.multipleOf / x.multipleOf)),
].every(function (v) { return v; });
};
var coverString = function (x, y) {
if (OpenApiTypeChecker.isConstant(y))
return typeof y.const === "string";
return [
x.format === undefined ||
(y.format !== undefined && coverFormat(x.format, y.format)),
x.pattern === undefined || x.pattern === y.pattern,
x.minLength === undefined ||
(y.minLength !== undefined && x.minLength <= y.minLength),
x.maxLength === undefined ||
(y.maxLength !== undefined && x.maxLength >= y.maxLength),
].every(function (v) { return v; });
};
var coverFormat = function (x, y) {
return x === y ||
(x === "idn-email" && y === "email") ||
(x === "idn-hostname" && y === "hostname") ||
(["uri", "iri"].includes(x) && y === "url") ||
(x === "iri" && y === "uri") ||
(x === "iri-reference" && y === "uri-reference");
};
var flatSchema = function (components, schema) {
schema = escapeReferenceOfFlatSchema(components, schema);
if (OpenApiTypeChecker.isOneOf(schema))
return schema.oneOf.map(function (v) { return flatSchema(components, v); }).flat();
return [schema];
};
var escapeReferenceOfFlatSchema = function (components, schema) {
var _a, _b;
if (OpenApiTypeChecker.isReference(schema) === false)
return schema;
var key = schema.$ref.replace("#/components/schemas/", "");
var found = escapeReferenceOfFlatSchema(components, (_b = (_a = components.schemas) === null || _a === void 0 ? void 0 : _a[key]) !== null && _b !== void 0 ? _b : {});
if (found === undefined)
throw new Error("Reference type not found: ".concat(JSON.stringify(schema.$ref)));
return escapeReferenceOfFlatSchema(components, found);
};
/**
* @internal
*/
OpenApiTypeChecker.writeReferenceDescription = function (props) {
var _a;
var index = props.$ref.lastIndexOf(".");
if (index === -1)
return props.description;
var accessors = props.$ref
.split("#/components/schemas/")[1]
.split(".");
var pReferences = accessors
.slice(0, props.escape ? accessors.length : accessors.length - 1)
.map(function (_, i, array) { return array.slice(0, i + 1).join("."); })
.map(function (key) {
var _a, _b;
return ({
key: key,
description: (_b = (_a = props.components.schemas) === null || _a === void 0 ? void 0 : _a[key]) === null || _b === void 0 ? void 0 : _b.description,
});
})
.filter(function (schema) { return !!(schema === null || schema === void 0 ? void 0 : schema.description); })
.reverse();
if (pReferences.length === 0)
return props.description;
return __spreadArray(__spreadArray([], __read((((_a = props.description) === null || _a === void 0 ? void 0 : _a.length) ? [props.description] : [])), false), __read(pReferences.map(function (pRef, i) {
return "Description of the ".concat(i === 0 && props.escape ? "current" : "parent", " {@link ").concat(pRef.key, "} type:\n\n") +
pRef.description
.split("\n")
.map(function (str) { return "> ".concat(str); })
.join("\n");
})), false).join("\n\n------------------------------\n\n");
};
})(OpenApiTypeChecker || (exports.OpenApiTypeChecker = OpenApiTypeChecker = {}));
{
"name": "@samchon/openapi",
"version": "2.0.0-dev.20241123",
"version": "2.0.0-dev.20241124",
"description": "OpenAPI definitions and converters for 'typia' and 'nestia'.",

@@ -64,3 +64,3 @@ "main": "./lib/index.js",

"typescript-transform-paths": "^3.4.7",
"typia": "7.0.0-dev.20241115",
"typia": "7.0.0-dev.20241123",
"uuid": "^10.0.0"

@@ -67,0 +67,0 @@ },

@@ -46,7 +46,8 @@ > ## Next version is coming.

- ✔️[`IChatGptSchema`](https://github.com/samchon/openapi/blob/master/src/structures/IChatGptSchema.ts): OpenAI ChatGPT
- ✍️`IClaudeSchema`: Anthropic Claude
- ✔️[`IGeminiSchema`](https://github.com/samchon/openapi/blob/master/src/structures/IGeminiSchema.ts): Google Gemini
- ✍️`ILlamaSchema`: Meta (Facebook) Llama
- ✍️`IClaudeSchema`: Anthropic Claude
- ✔️[`ILlmSchemaV3`](https://github.com/samchon/openapi/blob/master/src/structures/ILlmSchemaV3.ts): middle layer of OpenAPI v3.0
- ✔️[`ILlmSchemaV3_1`](https://github.com/samchon/openapi/blob/master/src/structures/ILlmSchemaV3_1.ts): middle layer of OpenAPI v3.1
- Midldle layer schemas
- ✔️[`ILlmSchemaV3`](https://github.com/samchon/openapi/blob/master/src/structures/ILlmSchemaV3.ts): middle layer based on OpenAPI v3.0 specification
- ✔️[`ILlmSchemaV3_1`](https://github.com/samchon/openapi/blob/master/src/structures/ILlmSchemaV3_1.ts): middle layer based on OpenAPI v3.1 specification

@@ -76,2 +77,3 @@ > [!TIP]

HttpLlm,
IChatGptSchema,
IHttpLlmApplication,

@@ -100,9 +102,13 @@ IHttpLlmFunction,

const document: OpenApi.IDocument = OpenApi.convert(swagger);
const application: IHttpLlmApplication = HttpLlm.application(document);
const application: IHttpLlmApplication<"chatgpt"> = HttpLlm.application({
model: "chatgpt",
document,
});
// Let's imagine that LLM has selected a function to call
const func: IHttpLlmFunction | undefined = application.functions.find(
// (f) => f.name === "llm_selected_fuction_name"
(f) => f.path === "/bbs/articles" && f.method === "post",
);
const func: IHttpLlmFunction<IChatGptSchema.IParameters> | undefined =
application.functions.find(
// (f) => f.name === "llm_selected_fuction_name"
(f) => f.path === "/bbs/articles" && f.method === "post",
);
if (func === undefined) throw new Error("No matched function exists.");

@@ -109,0 +115,0 @@

import { OpenApi } from "../OpenApi";
import { IChatGptSchema } from "../structures/IChatGptSchema";
import { ILlmApplication } from "../structures/ILlmApplication";
import { ILlmSchemaV3_1 } from "../structures/ILlmSchemaV3_1";
import { ChatGptTypeChecker } from "../utils/ChatGptTypeChecker";
import { OpenApiContraintShifter } from "../utils/OpenApiContraintShifter";
import { LlmTypeCheckerV3_1 } from "../utils/LlmTypeCheckerV3_1";
import { OpenApiTypeChecker } from "../utils/OpenApiTypeChecker";
import { LlmConverterV3_1 } from "./LlmConverterV3_1";
export namespace ChatGptConverter {
export const parameters = (props: {
options: Omit<ILlmApplication.IChatGptOptions, "separate">;
config: IChatGptSchema.IConfig;
components: OpenApi.IComponents;
schema: OpenApi.IJsonSchema.IObject;
}): IChatGptSchema.IParameters | null => {
const $defs: Record<string, IChatGptSchema> = {};
const res: IChatGptSchema.IParameters | null = schema({
options: props.options,
components: props.components,
schema: props.schema,
$defs,
}) as IChatGptSchema.IParameters | null;
if (res === null) return null;
else if (Object.keys($defs).length) res.$defs = $defs;
return res;
const params: ILlmSchemaV3_1.IParameters | null =
LlmConverterV3_1.parameters({
config: props.config,
components: props.components,
schema: props.schema,
});
if (params === null) return null;
for (const key of Object.keys(params.$defs))
params.$defs[key] = transform(params.$defs[key]);
for (const key of Object.keys(params.properties))
params.properties[key] = transform(params.properties[key]);
return params;
};
export const schema = (props: {
options: Omit<ILlmApplication.IChatGptOptions, "separate">;
config: IChatGptSchema.IConfig;
components: OpenApi.IComponents;

@@ -32,10 +35,25 @@ $defs: Record<string, IChatGptSchema>;

}): IChatGptSchema | null => {
const union: Array<IChatGptSchema | null> = [];
const oldbie: Set<string> = new Set(Object.keys(props.$defs));
const schema: ILlmSchemaV3_1 | null = LlmConverterV3_1.schema({
config: props.config,
components: props.components,
$defs: props.$defs,
schema: props.schema,
});
if (schema === null) return null;
for (const key of Object.keys(props.$defs))
if (oldbie.has(key) === false)
props.$defs[key] = transform(props.$defs[key]);
return transform(schema);
};
const transform = (schema: ILlmSchemaV3_1): IChatGptSchema => {
const union: Array<IChatGptSchema> = [];
const attribute: IChatGptSchema.__IAttribute = {
title: props.schema.title,
description: props.schema.description,
example: props.schema.example,
examples: props.schema.examples,
title: schema.title,
description: schema.description,
example: schema.example,
examples: schema.examples,
...Object.fromEntries(
Object.entries(props.schema).filter(
Object.entries(schema).filter(
([key, value]) => key.startsWith("x-") && value !== undefined,

@@ -45,133 +63,23 @@ ),

};
const visit = (input: OpenApi.IJsonSchema): number => {
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;
if (
props.options.reference === true ||
OpenApiTypeChecker.isRecursiveReference({
components: props.components,
schema: input,
})
) {
const out = () =>
union.push({
...input,
$ref: `#/$defs/${key}`,
title: undefined,
description: undefined,
});
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(null);
converted.description = OpenApiTypeChecker.writeReferenceDescription({
components: props.components,
$ref: input.$ref,
description: converted.description,
escape: false,
});
props.$defs[key] = converted;
return out();
} else {
const length: number = union.length;
visit(target);
if (length === union.length - 1 && union[union.length - 1] !== null)
union[union.length - 1] = {
...union[union.length - 1]!,
description: OpenApiTypeChecker.writeReferenceDescription({
components: props.components,
$ref: input.$ref,
description: union[union.length - 1]!.description,
escape: true,
}),
};
else
attribute.description =
OpenApiTypeChecker.writeReferenceDescription({
components: props.components,
$ref: input.$ref,
description: attribute.description,
escape: true,
});
return union.length;
}
} else if (OpenApiTypeChecker.isObject(input)) {
const properties: Record<string, IChatGptSchema | null> =
Object.entries(input.properties || {}).reduce(
(acc, [key, value]) => {
const converted: IChatGptSchema | null = schema({
options: props.options,
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 union.push(null);
if (!!input.additionalProperties === null) return union.push(null);
return union.push({
const visit = (input: ILlmSchemaV3_1): void => {
if (LlmTypeCheckerV3_1.isOneOf(input)) input.oneOf.forEach(visit);
else if (LlmTypeCheckerV3_1.isArray(input))
union.push({
...input,
properties: properties as Record<string, IChatGptSchema>,
additionalProperties: false,
required: Object.keys(properties),
items: transform(input.items),
});
} else if (OpenApiTypeChecker.isArray(input)) {
const items: IChatGptSchema | null = schema({
options: props.options,
components: props.components,
$defs: props.$defs,
schema: input.items,
else if (LlmTypeCheckerV3_1.isObject(input))
union.push({
...input,
properties: Object.fromEntries(
Object.entries(input.properties).map(([key, value]) => [
key,
transform(value),
]),
),
});
if (items === null) return union.push(null);
return union.push(
(props.options.constraint
? (x: IChatGptSchema.IArray) => x
: (x: IChatGptSchema.IArray) =>
OpenApiContraintShifter.shiftArray(x))({
...input,
items,
}),
);
} else if (OpenApiTypeChecker.isString(input))
return union.push(
(props.options.constraint
? (x: IChatGptSchema.IString) => x
: (x: IChatGptSchema.IString) =>
OpenApiContraintShifter.shiftString(x))({
...input,
}),
);
else if (
OpenApiTypeChecker.isNumber(input) ||
OpenApiTypeChecker.isInteger(input)
)
return union.push(
(props.options.constraint
? (x: IChatGptSchema.INumber | IChatGptSchema.IInteger) => x
: (x: IChatGptSchema.INumber | IChatGptSchema.IInteger) =>
OpenApiContraintShifter.shiftNumeric(x))({
...input,
}),
);
else if (OpenApiTypeChecker.isConstant(input)) return 0;
else if (OpenApiTypeChecker.isTuple(input)) return union.push(null);
else return union.push({ ...input });
else if (LlmTypeCheckerV3_1.isConstant(input) === false)
union.push(input);
};
const visitConstant = (input: OpenApi.IJsonSchema): void => {
const visitConstant = (input: ILlmSchemaV3_1): void => {
const insert = (value: any): void => {

@@ -195,22 +103,6 @@ const matched: IChatGptSchema.IString | undefined = union.find(

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);
}
};
visit(props.schema);
visitConstant(props.schema);
if (union.some((u) => u === null)) return null;
else if (union.length === 0)
visit(schema);
visitConstant(schema);
if (union.length === 0)
return {

@@ -223,6 +115,6 @@ ...attribute,

...attribute,
...union[0]!,
...union[0],
description: ChatGptTypeChecker.isReference(union[0]!)
? undefined
: union[0]!.description,
: union[0].description,
};

@@ -232,6 +124,6 @@ return {

anyOf: union.map((u) => ({
...u!,
description: ChatGptTypeChecker.isReference(u!)
...u,
description: ChatGptTypeChecker.isReference(u)
? undefined
: u!.description,
: u.description,
})),

@@ -238,0 +130,0 @@ };

@@ -12,3 +12,3 @@ import { OpenApi } from "../OpenApi";

schema: OpenApi.IJsonSchema;
recursive: false | number;
config: IGeminiSchema.IConfig;
}): IGeminiSchema.IParameters | null =>

@@ -20,5 +20,12 @@ schema(props) as IGeminiSchema.IParameters | null;

schema: OpenApi.IJsonSchema;
recursive: false | number;
config: IGeminiSchema.IConfig;
}): IGeminiSchema | null => {
const schema: ILlmSchemaV3 | null = LlmConverterV3.schema(props);
const schema: ILlmSchemaV3 | null = LlmConverterV3.schema({
components: props.components,
schema: props.schema,
config: {
recursive: props.config.recursive,
constraint: false,
},
});
if (schema === null) return null;

@@ -25,0 +32,0 @@

@@ -11,5 +11,6 @@ import { OpenApi } from "../OpenApi";

import { LlmConverterV3_1 } from "./LlmConverterV3_1";
import { LlmSchemaConverter } from "./LlmSchemaConverter";
export namespace HttpLlmConverter {
export const compose = <
export const application = <
Model extends IHttpLlmApplication.Model,

@@ -26,8 +27,3 @@ Parameters extends

migrate: IHttpMigrateApplication<OpenApi.IJsonSchema, Operation>;
options: IHttpLlmApplication.IOptions<
Model,
Parameters["properties"][string] extends IHttpLlmApplication.ModelSchema[Model]
? Parameters["properties"][string]
: IHttpLlmApplication.ModelSchema[Model]
>;
options: IHttpLlmApplication.IOptions<Model>;
}): IHttpLlmApplication<Model, Parameters, Operation, Route> => {

@@ -100,3 +96,3 @@ // COMPOSE FUNCTIONS

export const separateParameters = <
export const separate = <
Model extends IHttpLlmApplication.Model,

@@ -140,8 +136,3 @@ Parameters extends

route: IHttpMigrateRoute<OpenApi.IJsonSchema, Operation>;
options: IHttpLlmApplication.IOptions<
Model,
Parameters["properties"][string] extends IHttpLlmApplication.ModelSchema[Model]
? Parameters["properties"][string]
: IHttpLlmApplication.ModelSchema[Model]
>;
options: IHttpLlmApplication.IOptions<Model>;
}): IHttpLlmFunction<Parameters, Operation, Route> | null => {

@@ -152,4 +143,4 @@ const $defs: Record<string, IChatGptSchema> = {};

): Parameters["properties"][string] | null =>
CASTERS[props.model]({
options: props.options as any,
LlmSchemaConverter.schema(props.model)({
config: props.options as any,
schema: s,

@@ -225,3 +216,3 @@ components: props.components,

separated: props.options.separate
? separateParameters({
? separate({
model: props.model,

@@ -251,47 +242,2 @@ predicate: props.options.separate as any,

const CASTERS = {
"3.0": (props: {
components: OpenApi.IComponents;
schema: OpenApi.IJsonSchema;
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;
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;
$defs: Record<string, IChatGptSchema>;
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;
options: IHttpLlmApplication.IOptions<"gemini">;
}) =>
GeminiConverter.schema({
components: props.components,
schema: props.schema,
recursive: props.options.recursive,
}),
};
const SEPARATORS = {

@@ -298,0 +244,0 @@ "3.0": LlmConverterV3.separate,

import { OpenApi } from "../OpenApi";
import { ILlmSchemaV3_1 } from "../structures/ILlmSchemaV3_1";
import { LlmTypeCheckerV3_1 } from "../utils/LlmTypeCheckerV3_1";
import { OpenApiContraintShifter } from "../utils/OpenApiContraintShifter";
import { OpenApiTypeChecker } from "../utils/OpenApiTypeChecker";
import { JsonDescriptionUtil } from "../utils/internal/JsonDescriptionUtil";
export namespace LlmConverterV3_1 {
export const parameters = (props: {
config: ILlmSchemaV3_1.IConfig;
components: OpenApi.IComponents;
schema: OpenApi.IJsonSchema.IObject;
recursive: false | number;
}): ILlmSchemaV3_1.IParameters | null =>
schema(props) as ILlmSchemaV3_1.IParameters | null;
}): ILlmSchemaV3_1.IParameters | null => {
const $defs: Record<string, ILlmSchemaV3_1> = {};
const res: ILlmSchemaV3_1.IParameters | null = schema({
config: props.config,
components: props.components,
schema: props.schema,
$defs,
}) as ILlmSchemaV3_1.IParameters | null;
if (res === null) return null;
res.$defs = $defs;
return res;
};
export const schema = (props: {
config: ILlmSchemaV3_1.IConfig;
components: OpenApi.IComponents;
$defs: Record<string, ILlmSchemaV3_1>;
schema: OpenApi.IJsonSchema;
recursive: false | number;
}): ILlmSchemaV3_1 | null => OpenApiTypeChecker.escape(props);
}): ILlmSchemaV3_1 | null => {
const union: Array<ILlmSchemaV3_1 | null> = [];
const attribute: ILlmSchemaV3_1.__IAttribute = {
title: props.schema.title,
description: props.schema.description,
example: props.schema.example,
examples: props.schema.examples,
...Object.fromEntries(
Object.entries(props.schema).filter(
([key, value]) => key.startsWith("x-") && value !== undefined,
),
),
};
const visit = (input: OpenApi.IJsonSchema): number => {
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;
if (
props.config.reference === true ||
OpenApiTypeChecker.isRecursiveReference({
components: props.components,
schema: input,
})
) {
const out = () =>
union.push({
...input,
$ref: `#/$defs/${key}`,
title: undefined,
description: undefined,
});
if (props.$defs[key] !== undefined) return out();
props.$defs[key] = {};
const converted: ILlmSchemaV3_1 | null = schema({
config: props.config,
components: props.components,
$defs: props.$defs,
schema: target,
});
if (converted === null) return union.push(null);
converted.description = JsonDescriptionUtil.cascade({
prefix: "#/components/schemas/",
components: props.components,
$ref: input.$ref,
description: converted.description,
escape: false,
});
props.$defs[key] = converted;
return out();
} else {
const length: number = union.length;
visit(target);
if (length === union.length - 1 && union[union.length - 1] !== null)
union[union.length - 1] = {
...union[union.length - 1]!,
description: JsonDescriptionUtil.cascade({
prefix: "#/components/schemas/",
components: props.components,
$ref: input.$ref,
description: union[union.length - 1]!.description,
escape: true,
}),
};
else
attribute.description = JsonDescriptionUtil.cascade({
prefix: "#/components/schemas/",
components: props.components,
$ref: input.$ref,
description: attribute.description,
escape: true,
});
return union.length;
}
} else if (OpenApiTypeChecker.isObject(input)) {
const properties: Record<string, ILlmSchemaV3_1 | null> =
Object.entries(input.properties || {}).reduce(
(acc, [key, value]) => {
const converted: ILlmSchemaV3_1 | null = schema({
config: props.config,
components: props.components,
$defs: props.$defs,
schema: value,
});
if (converted === null) return acc;
acc[key] = converted;
return acc;
},
{} as Record<string, ILlmSchemaV3_1 | null>,
);
if (Object.values(properties).some((v) => v === null))
return union.push(null);
if (!!input.additionalProperties === null) return union.push(null);
return union.push({
...input,
properties: properties as Record<string, ILlmSchemaV3_1>,
additionalProperties: false,
required: Object.keys(properties),
});
} else if (OpenApiTypeChecker.isArray(input)) {
const items: ILlmSchemaV3_1 | null = schema({
config: props.config,
components: props.components,
$defs: props.$defs,
schema: input.items,
});
if (items === null) return union.push(null);
return union.push(
(props.config.constraint
? (x: ILlmSchemaV3_1.IArray) => x
: (x: ILlmSchemaV3_1.IArray) =>
OpenApiContraintShifter.shiftArray(x))({
...input,
items,
}),
);
} else if (OpenApiTypeChecker.isString(input))
return union.push(
(props.config.constraint
? (x: ILlmSchemaV3_1.IString) => x
: (x: ILlmSchemaV3_1.IString) =>
OpenApiContraintShifter.shiftString(x))({
...input,
}),
);
else if (
OpenApiTypeChecker.isNumber(input) ||
OpenApiTypeChecker.isInteger(input)
)
return union.push(
(props.config.constraint
? (x: ILlmSchemaV3_1.INumber | ILlmSchemaV3_1.IInteger) => x
: (x: ILlmSchemaV3_1.INumber | ILlmSchemaV3_1.IInteger) =>
OpenApiContraintShifter.shiftNumeric(x))({
...input,
}),
);
else if (OpenApiTypeChecker.isTuple(input)) return union.push(null);
else return union.push({ ...input });
};
visit(props.schema);
if (union.some((u) => u === null)) return null;
else if (union.length === 0)
return {
...attribute,
type: undefined,
};
else if (union.length === 1)
return {
...attribute,
...union[0]!,
description: LlmTypeCheckerV3_1.isReference(union[0]!)
? undefined
: union[0]!.description,
};
return {
...attribute,
oneOf: union.map((u) => ({
...u!,
description: LlmTypeCheckerV3_1.isReference(u!)
? undefined
: u!.description,
})),
};
};
export const separate = (props: {

@@ -87,25 +269,7 @@ predicate: (schema: ILlmSchemaV3_1) => boolean;

}
if (
typeof props.schema.additionalProperties === "object" &&
props.schema.additionalProperties !== null
) {
const [x, y] = separate({
predicate: props.predicate,
schema: props.schema.additionalProperties,
});
if (x !== null) llm.additionalProperties = x;
if (y !== null) human.additionalProperties = y;
} else {
llm.additionalProperties = false;
human.additionalProperties = false;
}
llm.additionalProperties = false;
human.additionalProperties = false;
return [
Object.keys(llm.properties).length === 0 &&
llm.additionalProperties === false
? null
: shrinkRequired(llm),
Object.keys(human.properties).length === 0 &&
human.additionalProperties === false
? null
: shrinkRequired(human),
Object.keys(llm.properties).length === 0 ? null : shrinkRequired(llm),
Object.keys(human.properties).length === 0 ? null : shrinkRequired(human),
];

@@ -112,0 +276,0 @@ };

@@ -11,3 +11,3 @@ import { OpenApi } from "../OpenApi";

schema: OpenApi.IJsonSchema.IObject;
recursive: false | number;
config: ILlmSchemaV3.IConfig;
}): ILlmSchemaV3.IParameters | null =>

@@ -19,3 +19,3 @@ schema(props) as ILlmSchemaV3.IParameters | null;

schema: OpenApi.IJsonSchema;
recursive: false | number;
config: Omit<ILlmSchemaV3.IConfig, "separate">;
}): ILlmSchemaV3 | null => {

@@ -25,7 +25,9 @@ const resolved: OpenApi.IJsonSchema | null = OpenApiTypeChecker.escape({

schema: props.schema,
recursive: props.recursive,
recursive: props.config.recursive,
});
if (resolved === null) return null;
const downgraded: ILlmSchemaV3 = OpenApiV3Downgrader.downgradeSchema({
original: {},
original: {
schemas: {},
},
downgraded: {},

@@ -32,0 +34,0 @@ })(resolved) as ILlmSchemaV3;

@@ -262,9 +262,7 @@ import { OpenApi } from "../OpenApi";

): OpenApi.IComponents => ({
schemas: input.schemas
? Object.fromEntries(
Object.entries(input.schemas)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, convertSchema(input)(value)] as const),
)
: undefined,
schemas: Object.fromEntries(
Object.entries(input.schemas ?? {})
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, convertSchema(input)(value)] as const),
),
securitySchemes: input.securitySchemes,

@@ -271,0 +269,0 @@ });

@@ -235,9 +235,7 @@ import { OpenApi } from "../OpenApi";

): OpenApi.IComponents => ({
schemas: input.schemas
? Object.fromEntries(
Object.entries(input.schemas)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, convertSchema(input)(value)]),
)
: undefined,
schemas: Object.fromEntries(
Object.entries(input.schemas ?? {})
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, convertSchema(input)(value)]),
),
securitySchemes: input.securitySchemes,

@@ -244,0 +242,0 @@ });

@@ -178,9 +178,7 @@ import { OpenApi } from "../OpenApi";

): OpenApi.IComponents => ({
schemas: input.definitions
? Object.fromEntries(
Object.entries(input.definitions)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, convertSchema(value)]),
)
: undefined,
schemas: Object.fromEntries(
Object.entries(input.definitions ?? {})
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, convertSchema(value)]),
),
securitySchemes: input.securityDefinitions

@@ -187,0 +185,0 @@ ? Object.fromEntries(

@@ -93,34 +93,27 @@ import { HttpMigration } from "./HttpMigration";

: (props.document as IHttpMigrateApplication);
return HttpLlmConverter.compose<Model, Parameters>({
return HttpLlmConverter.application<Model, Parameters>({
migrate,
model: props.model,
options: (props.model === "chatgpt"
options: (props.model === "chatgpt" || props.model === "3.1"
? ({
separate:
(props.options
?.separate as IHttpLlmApplication.IChatGptOptions["separate"]) ??
?.separate as IHttpLlmApplication.IOptions<any>["separate"]) ??
null,
reference:
(props.options as IHttpLlmApplication.IChatGptOptions | undefined)
(props.options as IHttpLlmApplication.IOptions<any> | undefined)
?.reference ?? false,
constraint:
(props.options as IHttpLlmApplication.IChatGptOptions | undefined)
(props.options as IHttpLlmApplication.IOptions<any> | undefined)
?.constraint ?? false,
} satisfies IHttpLlmApplication.IChatGptOptions)
} satisfies IHttpLlmApplication.IOptions<any>)
: ({
separate:
(props.options?.separate as IHttpLlmApplication.ICommonOptions<
Exclude<Model, "chatgpt">
>["separate"]) ?? null,
(props.options
?.separate as IHttpLlmApplication.IOptions<any>["separate"]) ??
null,
recursive:
(
props.options as
| IHttpLlmApplication.ICommonOptions<
Exclude<Model, "chatgpt">
>
| undefined
)?.recursive ?? 3,
} satisfies IHttpLlmApplication.ICommonOptions<
Exclude<Model, "chatgpt">
>)) as IHttpLlmApplication.IOptions<Model>,
(props.options as IHttpLlmApplication.IOptions<any> | undefined)
?.recursive ?? 3,
} satisfies IHttpLlmApplication.IOptions<any>)) as IHttpLlmApplication.IOptions<any>,
});

@@ -127,0 +120,0 @@ };

@@ -29,5 +29,7 @@ //----

export * from "./structures/ILlmApplication";
export * from "./structures/ILlmFunction";
export * from "./structures/IChatGptSchema";
export * from "./structures/IGeminiSchema";
export * from "./structures/ILlmSchema";
export * from "./structures/ILlmSchemaV3";

@@ -34,0 +36,0 @@ export * from "./structures/ILlmSchemaV3_1";

@@ -22,3 +22,3 @@ /**

*
* If compare with the {@link OpenApi.IJsonSchema}, the emended JSON schema type of
* If compare with the {@link OpenApi.IJsonSchema}, the emended JSON schema specification,
*

@@ -32,3 +32,3 @@ * - {@link IChatGptSchema.IAnyOf} instead of the {@link OpenApi.IJsonSchema.IOneOf}

* For reference, if you've composed the `IChatGptSchema` type with the
* {@link ILlmApplication.IChatGptOptions.reference} `false` option (default is `false`),
* {@link IChatGptSchema.IConfig.reference} `false` option (default is `false`),
* only the recursived named types would be archived into the

@@ -39,3 +39,3 @@ * {@link IChatGptSchema.IParameters.$defs}, and the others would be ecaped from the

* Also, if you've composed the `IChatGptSchema` type with the
* {@link ILlmApplication.IChatGptOptions.constraint} `false` option (default `false`),
* {@link IChatGptSchema.IConfig.constraint} `false` option (default `false`),
* the `IChatGptSchema` would not compose these properties. Instead, these

@@ -80,2 +80,9 @@ * properties would be written on {@link IChatGptSchema.__IAttribute.descripotion}

* Type of the function parameters.
*
* `IChatGptSchema.IParameters` is a type defining a function's parameters
* as a keyworded object type.
*
* It also can be utilized for the structured output metadata.
*
* @reference https://platform.openai.com/docs/guides/structured-outputs
*/

@@ -86,3 +93,3 @@ export interface IParameters extends IObject {

*/
$defs?: Record<string, IChatGptSchema>;
$defs: Record<string, IChatGptSchema>;
}

@@ -388,3 +395,3 @@

*/
export interface IReference<Key = string> extends __IAttribute {
export interface IReference extends __IAttribute {
/**

@@ -396,3 +403,3 @@ * Reference to the named schema.

* starts with `#/$defs/` which means the type is stored in
* the {@link IChatGptSchema.ITop.$defs} object.
* the {@link IChatGptSchema.IParameters.$defs} object.
*

@@ -402,3 +409,3 @@ * - `#/$defs/SomeObject`

*/
$ref: Key;
$ref: string;
}

@@ -481,2 +488,58 @@

}
/**
* Configuration for ChatGPT schema composition.
*/
export interface IConfig {
/**
* 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;
/**
* 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;
}
}
/**
* Type schema info of the Gemini.
* Type schema info for the Gemini function calling.
*
* `IGeminiSchema` iis a type metadata of LLM (Large Language Model)
* `IGeminiSchema` is a type metadata for the LLM (Large Language Model)
* function calling in the Geminimi.

@@ -51,2 +51,3 @@ *

* @reference https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/function-calling
* @reference https://ai.google.dev/gemini-api/docs/structured-output
* @warning Specified not by the official documentation, but by my experiments.

@@ -70,2 +71,9 @@ * Therefore, its definitions can be inaccurate or be changed in the

* Type of the function parameters.
*
* `IGeminiSchema.IParameters` is a type defining a function's parameters
* as a keyworded object type.
*
* It also can be utilized for the structured output metadata.
*
* @reference https://ai.google.dev/gemini-api/docs/structured-output
*/

@@ -277,2 +285,19 @@ export type IParameters = IObject;

}
/**
* Configuration for the Gemini schema composition.
*/
export interface IConfig {
/**
* 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: false | number;
}
}
import { OpenApi } from "../OpenApi";
import { IChatGptSchema } from "./IChatGptSchema";
import { IGeminiSchema } from "./IGeminiSchema";
import { IHttpLlmFunction } from "./IHttpLlmFunction";

@@ -8,3 +6,2 @@ import { IHttpMigrateRoute } from "./IHttpMigrateRoute";

import { ILlmSchemaV3 } from "./ILlmSchemaV3";
import { ILlmSchemaV3_1 } from "./ILlmSchemaV3_1";

@@ -23,7 +20,7 @@ /**

* {@link IHttpLlmFunction} type which represents LLM function calling schema.
* By the way, if tehre're some recursive types which can't escape the
* {@link OpenApi.IJsonSchema.IReference} type, the operation would be failed and
* pushed into the {@link IHttpLlmApplication.errors}. Otherwise not, the operation
* would be successfully converted to {@link IHttpLlmFunction} and its type schemas
* are downgraded to {@link OpenApiV3.IJsonSchema} and converted to {@link ILlmSchemaV3}.
* By the way, if there're some types which does not supported by LLM, the operation
* would be failed and pushed into the {@link IHttpLlmApplication.errors}. Otherwise not,
* the operation would be successfully converted to {@link IHttpLlmFunction} and its
* type schemas are downgraded to {@link OpenApiV3.IJsonSchema} and converted to
* {@link ILlmSchemaV3}.
*

@@ -103,6 +100,3 @@ * About the options, if you've configured {@link IHttpLlmApplication.options.keyword}

/**
* Options for the application.
*
* Adjusted options when composing the application through
* {@link HttpLlm.application} function.
* Configuration for the application.
*/

@@ -117,16 +111,9 @@ options: IHttpLlmApplication.IOptions<

export namespace IHttpLlmApplication {
export type Model = "3.0" | "3.1" | "chatgpt" | "gemini";
export type ModelParameters = {
"3.0": ILlmSchemaV3.IParameters;
"3.1": ILlmSchemaV3_1.IParameters;
chatgpt: IChatGptSchema.IParameters;
gemini: IGeminiSchema.IParameters;
};
export type ModelSchema = {
"3.0": ILlmSchemaV3;
"3.1": ILlmSchemaV3_1;
chatgpt: IChatGptSchema;
gemini: IGeminiSchema;
};
export import Model = ILlmApplication.Model;
export import ModelParameters = ILlmApplication.ModelParameters;
export import ModelSchema = ILlmApplication.ModelSchema;
export import ModelConfig = ILlmApplication.ModelConfig;
export import IOptions = ILlmApplication.IOptions;
/**

@@ -173,6 +160,2 @@ * Error occurred in the composition.

}
export import IOptions = ILlmApplication.IOptions;
export import ICommonOptions = ILlmApplication.ICommonOptions;
export import IChatGptOptions = ILlmApplication.IChatGptOptions;
}

@@ -15,9 +15,2 @@ import { IChatGptSchema } from "./IChatGptSchema";

*
* By the way, the LLM function calling application composition, converting
* `ILlmApplication` instance from TypeScript interface (or class) type is not always
* successful. As LLM provider like OpenAI cannot understand the recursive reference
* type that is embodied by {@link IOpenApiSchemachema.IReference}, if there're some
* recursive types in the TypeScript interface (or class) type, the conversion would
* be failed.
*
* Also, there can be some parameters (or their nested properties) which must be

@@ -56,3 +49,3 @@ * composed by Human, not by LLM. File uploading feature or some sensitive information

/**
* Options for the application.
* Configuration for the application.
*/

@@ -80,40 +73,17 @@ options: ILlmApplication.IOptions<

};
export type ModelConfig = {
"3.0": ILlmSchemaV3.IConfig;
"3.1": ILlmSchemaV3_1.IConfig;
chatgpt: IChatGptSchema.IConfig;
gemini: IGeminiSchema.IConfig;
};
/**
* Options for composing the LLM application.
* Options for application composition.
*/
export 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.
*/
export interface ICommonOptions<
Model extends Exclude<ILlmApplication.Model, "chatgpt">,
Schema extends
ILlmApplication.ModelSchema[Model] = ILlmApplication.ModelSchema[Model],
> {
Schema extends ModelSchema[Model] = 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: false | number;
/**
* Separator function for the parameters.

@@ -123,41 +93,6 @@ *

* 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).
* or LLM cannot understand the parameter.
*
* 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 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);
}
/**
* 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
* For example, if the parameter type has configured
* {@link IGeminiSchema.IString.contentMediaType} which indicates file
* uploading, it must be composed by human, not by LLM

@@ -176,3 +111,3 @@ * (Large Language Model).

* composing the value. Also, when predicating the schema, it would
* better to utilize the {@link ChatGptTypeChecker} features.
* better to utilize the {@link GeminiTypeChecker} like features.
*

@@ -184,54 +119,3 @@ * @param schema Schema to be separated.

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;
}
} & ModelConfig[Model];
}

@@ -0,1 +1,55 @@

/**
* Type schema based on OpenAPI v3.1 for LLM function calling.
*
* `ILlmSchemaV3_1` is a type metadata for LLM (Large Language Model)
* function calling, based on the OpenAPI v3.1 speicification. This type
* is not the final type for the LLM function calling, but the intermediate
* structure for the conversion to the final type like {@link IChatGptSchema}.
*
* 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 `ILlmSchemaV3_1` 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.IAnyOf} to {@link ILlmSchemaV3_1.IOneOf}
* - Merge {@link OpenApiV3_1.IJsonSchema.IAllOf} to {@link ILlmSchemaV3_1.IObject}
* - Merge {@link OpenApiV3_1.IJsonSchema.IRecursiveReference} to {@link ILlmSchemaV3_1.IReference}
* - Do not support {@link OpenApiV3_1.IJsonSchema.ITuple} type
*
* If compare with the {@link OpenApi.IJsonSchema}, the emended JSON schema specification,
*
* - {@link ILlmSchemaV3_1.IParameters.$defs} instead of the {@link OpenApi.IJsonSchema.schemas}
* - Do not support {@link OpenApi.IJsonSchema.ITuple} type
*
* For reference, if you've composed the `ILlmSchemaV3_1` type with the
* {@link ILlmSchemaV3_1.IConfig.reference} `false` option (default is `false`),
* only the recursived named types would be archived into the
* {@link ILlmSchemaV3_1.IParameters.$defs}, and the others would be ecaped from the
* {@link ILlmSchemaV3_1.IReference} type.
*
* Also, if you've composed the `ILlmSchemaV3_1` type with the
* {@link ILlmSchemaV3_1.IConfig.constraint} `false` option (default `false`),
* the `ILlmSchemaV3_1` would not compose these properties. Instead, these
* properties would be written on {@link ILlmSchemaV3_1.__IAttribute.descripotion}
* field like `@format uuid` case.
*
* - {@link ILlmSchemaV3_1.INumber.minimum}
* - {@link ILlmSchemaV3_1.INumber.maximum}
* - {@link ILlmSchemaV3_1.INumber.multipleOf}
* - {@link ILlmSchemaV3_1.IString.minLength}
* - {@link ILlmSchemaV3_1.IString.maxLength}
* - {@link ILlmSchemaV3_1.IString.format}
* - {@link ILlmSchemaV3_1.IString.pattern}
* - {@link ILlmSchemaV3_1.IString.contentMediaType}
* - {@link ILlmSchemaV3_1.IArray.minItems}
* - {@link ILlmSchemaV3_1.IArray.maxItems}
* - {@link ILlmSchemaV3_1.IArray.unique}
*
* @reference https://platform.openai.com/docs/guides/function-calling
* @reference https://platform.openai.com/docs/guides/structured-outputs
* @author Jeongho Nam - https://github.com/samchon
*/
export type ILlmSchemaV3_1 =

@@ -7,5 +61,5 @@ | ILlmSchemaV3_1.IBoolean

| ILlmSchemaV3_1.IArray
| ILlmSchemaV3_1.ITuple
| ILlmSchemaV3_1.IObject
| ILlmSchemaV3_1.IOneOf
| ILlmSchemaV3_1.IReference
| ILlmSchemaV3_1.INull

@@ -16,8 +70,15 @@ | ILlmSchemaV3_1.IUnknown;

* Type of the function parameters.
*
* `ILlmSchemaV3_1.IParameters` is a type defining a function's parameters
* as a keyworded object type.
*
* It also can be utilized for the structured output metadata.
*
* @reference https://platform.openai.com/docs/guides/structured-outputs
*/
export interface IParameters extends Omit<IObject, "additionalProperties"> {
export interface IParameters extends IObject {
/**
* Do not allow additional properties in the parameters.
* Collection of the named types.
*/
additionalProperties: false;
$defs: Record<string, ILlmSchemaV3_1>;
}

@@ -248,60 +309,2 @@

/**
* 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: ILlmSchemaV3_1[];
/**
* 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 | ILlmSchemaV3_1;
/**
* 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.

@@ -328,11 +331,6 @@ */

*
* If the value is `true`, it means that the additional properties are not
* restricted. They can be any type. Otherwise, if the value is
* {@link IOpenAiSchema} type, it means that the additional properties must
* follow the type schema info.
*
* - `true`: `Record<string, any>`
* - `IOpenAiSchema`: `Record<string, T>`
* By the way, as LLM function calling does not support such dynamic key
* typed properties, the `additionalProperties` becomes always `false`.
*/
additionalProperties?: boolean | ILlmSchemaV3_1;
additionalProperties: false;

@@ -376,2 +374,20 @@ /**

/**
* Reference type directing named schema.
*/
export interface IReference extends __IAttribute {
/**
* Reference to the named schema.
*
* The `ref` is a reference to the named schema. Format of the `$ref` is
* following the JSON Pointer specification. In the OpenAPI, the `$ref`
* starts with `#/$defs/` which means the type is stored in
* the {@link ILlmSchemaV3_1.IParameters.$defs} object.
*
* - `#/$defs/SomeObject`
* - `#/$defs/AnotherObject`
*/
$ref: string;
}
/**
* Union type.

@@ -477,2 +493,58 @@ *

}
/**
* Configuration for OpenAPI v3.1 based LLM schema composition.
*/
export interface IConfig {
/**
* 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 ILlmSchemaV3_1.__IAttribute.description} property
* as a comment string like `"@format uuid"`.
*
* This is because the some LLM model's 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 ILlmSchemaV3_1.INumber.minimum}
* - {@link ILlmSchemaV3_1.INumber.maximum}
* - {@link ILlmSchemaV3_1.INumber.multipleOf}
* - {@link ILlmSchemaV3_1.IString.minLength}
* - {@link ILlmSchemaV3_1.IString.maxLength}
* - {@link ILlmSchemaV3_1.IString.format}
* - {@link ILlmSchemaV3_1.IString.pattern}
* - {@link ILlmSchemaV3_1.IString.contentMediaType}
* - {@link ILlmSchemaV3_1.IArray.minItems}
* - {@link ILlmSchemaV3_1.IArray.maxItems}
* - {@link ILlmSchemaV3_1.IArray.unique}
*
* @default false
*/
constraint: boolean;
/**
* Whether to allow reference type in everywhere.
*
* If you configure this property to `false`, most of reference types
* represented by {@link ILlmSchemaV3_1.IReference} would be escaped to
* a plain type unless recursive type case.
*
* This is because some low sized LLM models does not understand the
* reference type well, and even the large size LLM models 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 large size of LLM model,
* and want to reduce the LLM token cost, you can configure this property to
* `true`.
*
* @default false
*/
reference: boolean;
}
}
/**
* Type schema info of LLM function call.
* Type schema based on OpenAPI v3.0 for LLM function calling.
*
* `ILlmSchemaV3` is a type metadata of LLM (Large Language Model)
* function calling.
* `ILlmSchemaV3` is a type metadata for LLM (Large Language Model)
* function calling, based on the OpenAPI v3.0 speicification. This type
* is not the final type for the LLM function calling, but the intermediate
* structure for the conversion to the final type like {@link IGeminiSchema}.
*

@@ -10,3 +12,6 @@ * `ILlmSchemaV3` basically follows the JSON schema definition of OpenAPI

* does not have the reference type; {@link OpenApiV3.IJsonSchema.IReference}.
* It's because the LLM cannot compose the reference typed arguments.
* It's because the LLM cannot compose the reference typed arguments. If
* recursive type comes, its type would be repeated in
* {@link ILlmSchemaV3.IConfig.recursive} times. Otherwise you've configured
* it to `false`, the recursive types are not allowed.
*

@@ -18,2 +23,19 @@ * For reference, the OpenAPI v3.0 based JSON schema definition can't

*
* Also, if you configure {@link ILlmSchemaV3.IConfig.constraint} to `false`,
* tehse properties would be banned and written to the
* {@link ILlmSchemaV3.__IAttribute.description} property instead. It's because
* there are some LLM models which does not support the constraint properties.
*
* - {@link ILlmSchemaV3.INumber.minimum}
* - {@link ILlmSchemaV3.INumber.maximum}
* - {@link ILlmSchemaV3.INumber.multipleOf}
* - {@link ILlmSchemaV3.IString.minLength}
* - {@link ILlmSchemaV3.IString.maxLength}
* - {@link ILlmSchemaV3.IString.format}
* - {@link ILlmSchemaV3.IString.pattern}
* - {@link ILlmSchemaV3.IString.contentMediaType}
* - {@link ILlmSchemaV3.IArray.minItems}
* - {@link ILlmSchemaV3.IArray.maxItems}
* - {@link ILlmSchemaV3.IArray.unique}
*
* @reference https://platform.openai.com/docs/guides/function-calling

@@ -35,9 +57,11 @@ * @author Jeongho Nam - https://github.com/samchon

* Type of the function parameters.
*
* `ILlmSchemaV3.IParameters` is a type defining a function's parameters
* as a keyworded object type.
*
* It also can be utilized for the structured output metadata.
*
* @reference https://platform.openai.com/docs/guides/structured-outputs
*/
export interface IParameters extends Omit<IObject, "additionalProperties"> {
/**
* Do not allow additional properties in the parameters.
*/
additionalProperties: false;
}
export type IParameters = IObject;

@@ -431,2 +455,50 @@ /**

}
/**
* Configuration for OpenAPI v3.0 based LLM schema composition.
*/
export interface IConfig {
/**
* 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 ILlmSchemaV3.__IAttribute.description} property
* as a comment string like `"@format uuid"`.
*
* This is because the some LLM model's 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 ILlmSchemaV3.INumber.minimum}
* - {@link ILlmSchemaV3.INumber.maximum}
* - {@link ILlmSchemaV3.INumber.multipleOf}
* - {@link ILlmSchemaV3.IString.minLength}
* - {@link ILlmSchemaV3.IString.maxLength}
* - {@link ILlmSchemaV3.IString.format}
* - {@link ILlmSchemaV3.IString.pattern}
* - {@link ILlmSchemaV3.IString.contentMediaType}
* - {@link ILlmSchemaV3.IArray.minItems}
* - {@link ILlmSchemaV3.IArray.maxItems}
* - {@link ILlmSchemaV3.IArray.unique}
*
* @default false
*/
constraint: boolean;
/**
* 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: false | number;
}
}

@@ -12,2 +12,3 @@ import { IChatGptSchema } from "../structures/IChatGptSchema";

(schema as IChatGptSchema.INull).type === "null";
export const isUnknown = (

@@ -24,2 +25,3 @@ schema: IChatGptSchema,

(schema as IChatGptSchema.IBoolean).type === "boolean";
export const isInteger = (

@@ -29,2 +31,3 @@ schema: IChatGptSchema,

(schema as IChatGptSchema.IInteger).type === "integer";
export const isNumber = (

@@ -34,2 +37,3 @@ schema: IChatGptSchema,

(schema as IChatGptSchema.INumber).type === "number";
export const isString = (

@@ -45,2 +49,3 @@ schema: IChatGptSchema,

(schema as IChatGptSchema.IArray).items !== undefined;
export const isObject = (

@@ -50,5 +55,7 @@ schema: IChatGptSchema,

(schema as IChatGptSchema.IObject).type === "object";
export const isReference = (
schema: IChatGptSchema,
): schema is IChatGptSchema.IReference => (schema as any).$ref !== undefined;
export const isAnyOf = (

@@ -55,0 +62,0 @@ schema: IChatGptSchema,

@@ -0,2 +1,4 @@

import { OpenApi } from "../OpenApi";
import { ILlmSchemaV3_1 } from "../structures/ILlmSchemaV3_1";
import { OpenApiTypeCheckerBase } from "./internal/OpenApiTypeCheckerBase";

@@ -9,4 +11,3 @@ export namespace LlmTypeCheckerV3_1 {

schema: ILlmSchemaV3_1,
): schema is ILlmSchemaV3_1.INull =>
(schema as ILlmSchemaV3_1.INull).type === "null";
): schema is ILlmSchemaV3_1.INull => OpenApiTypeCheckerBase.isNull(schema);

@@ -16,5 +17,3 @@ export const isUnknown = (

): schema is ILlmSchemaV3_1.IUnknown =>
(schema as ILlmSchemaV3_1.IUnknown).type === undefined &&
!isConstant(schema) &&
!isOneOf(schema);
OpenApiTypeCheckerBase.isUnknown(schema);

@@ -24,3 +23,3 @@ export const isConstant = (

): schema is ILlmSchemaV3_1.IConstant =>
(schema as ILlmSchemaV3_1.IConstant).const !== undefined;
OpenApiTypeCheckerBase.isConstant(schema);

@@ -30,3 +29,3 @@ export const isBoolean = (

): schema is ILlmSchemaV3_1.IBoolean =>
(schema as ILlmSchemaV3_1.IBoolean).type === "boolean";
OpenApiTypeCheckerBase.isBoolean(schema);

@@ -36,3 +35,3 @@ export const isInteger = (

): schema is ILlmSchemaV3_1.IInteger =>
(schema as ILlmSchemaV3_1.IInteger).type === "integer";
OpenApiTypeCheckerBase.isInteger(schema);

@@ -42,3 +41,3 @@ export const isNumber = (

): schema is ILlmSchemaV3_1.INumber =>
(schema as ILlmSchemaV3_1.INumber).type === "number";
OpenApiTypeCheckerBase.isNumber(schema);

@@ -48,25 +47,78 @@ export const isString = (

): schema is ILlmSchemaV3_1.IString =>
(schema as ILlmSchemaV3_1.IString).type === "string";
OpenApiTypeCheckerBase.isString(schema);
export const isArray = (
schema: ILlmSchemaV3_1,
): schema is ILlmSchemaV3_1.IArray =>
(schema as ILlmSchemaV3_1.IArray).type === "array" &&
(schema as ILlmSchemaV3_1.IArray).items !== undefined;
): schema is ILlmSchemaV3_1.IArray => OpenApiTypeCheckerBase.isArray(schema);
export const isTuple = (
schema: ILlmSchemaV3_1,
): schema is ILlmSchemaV3_1.ITuple =>
(schema as ILlmSchemaV3_1.ITuple).type === "array" &&
(schema as ILlmSchemaV3_1.ITuple).prefixItems !== undefined;
export const isObject = (
schema: ILlmSchemaV3_1,
): schema is ILlmSchemaV3_1.IObject =>
(schema as ILlmSchemaV3_1.IObject).type === "object";
OpenApiTypeCheckerBase.isObject(schema);
export const isReference = (
schema: ILlmSchemaV3_1,
): schema is ILlmSchemaV3_1.IReference =>
OpenApiTypeCheckerBase.isReference(schema);
export const isOneOf = (
schema: ILlmSchemaV3_1,
): schema is ILlmSchemaV3_1.IOneOf =>
(schema as ILlmSchemaV3_1.IOneOf).oneOf !== undefined;
): schema is ILlmSchemaV3_1.IOneOf => OpenApiTypeCheckerBase.isOneOf(schema);
export const isRecursiveReference = (props: {
$defs?: Record<string, ILlmSchemaV3_1>;
schema: ILlmSchemaV3_1;
}): boolean =>
OpenApiTypeCheckerBase.isRecursiveReference({
prefix: "#/$defs/",
components: {
schemas: props.$defs,
},
schema: props.schema,
});
/* -----------------------------------------------------------
OPERATORS
----------------------------------------------------------- */
export const escape = (props: {
$defs?: Record<string, ILlmSchemaV3_1>;
schema: ILlmSchemaV3_1;
recursive: false | number;
}): ILlmSchemaV3_1 | null =>
OpenApiTypeCheckerBase.escape({
prefix: "#/$defs/",
components: {
schemas: props.$defs,
},
schema: props.schema,
recursive: props.recursive,
}) as ILlmSchemaV3_1 | null;
export const visit = (props: {
closure: (schema: ILlmSchemaV3_1) => void;
$defs?: Record<string, ILlmSchemaV3_1>;
schema: ILlmSchemaV3_1;
}): void =>
OpenApiTypeCheckerBase.visit({
prefix: "#/$defs/",
closure: props.closure as (schema: OpenApi.IJsonSchema) => void,
components: {
schemas: props.$defs,
},
schema: props.schema,
});
export const covers = (props: {
$defs?: Record<string, ILlmSchemaV3_1>;
x: ILlmSchemaV3_1;
y: ILlmSchemaV3_1;
}): boolean =>
OpenApiTypeCheckerBase.covers({
prefix: "#/$defs/",
components: {
schemas: props.$defs,
},
x: props.x,
y: props.y,
});
}
import { OpenApi } from "../OpenApi";
import { MapUtil } from "./MapUtil";
import { OpenApiTypeCheckerBase } from "./internal/OpenApiTypeCheckerBase";

@@ -11,3 +11,3 @@ export namespace OpenApiTypeChecker {

): schema is OpenApi.IJsonSchema.INull =>
(schema as OpenApi.IJsonSchema.INull).type === "null";
OpenApiTypeCheckerBase.isNull(schema);

@@ -17,6 +17,3 @@ export const isUnknown = (

): schema is OpenApi.IJsonSchema.IUnknown =>
(schema as OpenApi.IJsonSchema.IUnknown).type === undefined &&
!isConstant(schema) &&
!isOneOf(schema) &&
!isReference(schema);
OpenApiTypeCheckerBase.isUnknown(schema);

@@ -26,3 +23,3 @@ export const isConstant = (

): schema is OpenApi.IJsonSchema.IConstant =>
(schema as OpenApi.IJsonSchema.IConstant).const !== undefined;
OpenApiTypeCheckerBase.isConstant(schema);

@@ -32,3 +29,3 @@ export const isBoolean = (

): schema is OpenApi.IJsonSchema.IBoolean =>
(schema as OpenApi.IJsonSchema.IBoolean).type === "boolean";
OpenApiTypeCheckerBase.isBoolean(schema);

@@ -38,3 +35,3 @@ export const isInteger = (

): schema is OpenApi.IJsonSchema.IInteger =>
(schema as OpenApi.IJsonSchema.IInteger).type === "integer";
OpenApiTypeCheckerBase.isInteger(schema);

@@ -44,3 +41,3 @@ export const isNumber = (

): schema is OpenApi.IJsonSchema.INumber =>
(schema as OpenApi.IJsonSchema.INumber).type === "number";
OpenApiTypeCheckerBase.isNumber(schema);

@@ -50,3 +47,3 @@ export const isString = (

): schema is OpenApi.IJsonSchema.IString =>
(schema as OpenApi.IJsonSchema.IString).type === "string";
OpenApiTypeCheckerBase.isString(schema);

@@ -56,4 +53,3 @@ export const isArray = (

): schema is OpenApi.IJsonSchema.IArray =>
(schema as OpenApi.IJsonSchema.IArray).type === "array" &&
(schema as OpenApi.IJsonSchema.IArray).items !== undefined;
OpenApiTypeCheckerBase.isArray(schema);

@@ -63,4 +59,3 @@ export const isTuple = (

): schema is OpenApi.IJsonSchema.ITuple =>
(schema as OpenApi.IJsonSchema.ITuple).type === "array" &&
(schema as OpenApi.IJsonSchema.ITuple).prefixItems !== undefined;
OpenApiTypeCheckerBase.isTuple(schema);

@@ -70,3 +65,3 @@ export const isObject = (

): schema is OpenApi.IJsonSchema.IObject =>
(schema as OpenApi.IJsonSchema.IObject).type === "object";
OpenApiTypeCheckerBase.isObject(schema);

@@ -76,3 +71,3 @@ export const isReference = (

): schema is OpenApi.IJsonSchema.IReference =>
(schema as any).$ref !== undefined;
OpenApiTypeCheckerBase.isReference(schema);

@@ -82,3 +77,3 @@ export const isOneOf = (

): schema is OpenApi.IJsonSchema.IOneOf =>
(schema as OpenApi.IJsonSchema.IOneOf).oneOf !== undefined;
OpenApiTypeCheckerBase.isOneOf(schema);

@@ -88,18 +83,8 @@ export const isRecursiveReference = (props: {

schema: OpenApi.IJsonSchema;
}): boolean => {
if (isReference(props.schema) === false) return false;
const current: string = props.schema.$ref.split("#/components/schemas/")[1];
let counter: number = 0;
visit({
}): boolean =>
OpenApiTypeCheckerBase.isRecursiveReference({
prefix: "#/components/schemas/",
components: props.components,
schema: props.schema,
closure: (schema) => {
if (OpenApiTypeChecker.isReference(schema)) {
const next: string = schema.$ref.split("#/components/schemas/")[1];
if (current === next) ++counter;
}
},
});
return counter > 1;
};

@@ -114,8 +99,8 @@ /* -----------------------------------------------------------

}): OpenApi.IJsonSchema | null =>
escapeSchema({
OpenApiTypeCheckerBase.escape({
prefix: "#/components/schemas/",
components: props.components,
schema: props.schema,
recursive: props.recursive,
visited: new Map(),
}) || null;
});

@@ -126,33 +111,9 @@ export const visit = (props: {

schema: OpenApi.IJsonSchema;
}): void => {
const already: Set<string> = new Set();
const next = (schema: OpenApi.IJsonSchema): void => {
props.closure(schema);
if (OpenApiTypeChecker.isReference(schema)) {
const key: string = schema.$ref.split("#/components/schemas/").pop()!;
if (already.has(key) === true) return;
already.add(key);
const found: OpenApi.IJsonSchema | undefined =
props.components.schemas?.[key];
if (found !== undefined) next(found);
} else if (OpenApiTypeChecker.isOneOf(schema)) schema.oneOf.forEach(next);
else if (OpenApiTypeChecker.isObject(schema)) {
for (const value of Object.values(schema.properties ?? {})) next(value);
if (
typeof schema.additionalProperties === "object" &&
schema.additionalProperties !== null
)
next(schema.additionalProperties);
} else if (OpenApiTypeChecker.isArray(schema)) next(schema.items);
else if (OpenApiTypeChecker.isTuple(schema)) {
(schema.prefixItems ?? []).forEach(next);
if (
typeof schema.additionalItems === "object" &&
schema.additionalItems !== null
)
next(schema.additionalItems);
}
};
next(props.schema);
};
}): void =>
OpenApiTypeCheckerBase.visit({
prefix: "#/components/schemas/",
closure: props.closure,
components: props.components,
schema: props.schema,
});

@@ -164,529 +125,8 @@ export const covers = (props: {

}): boolean =>
coverStation({
OpenApiTypeCheckerBase.covers({
prefix: "#/components/schemas/",
components: props.components,
x: props.x,
y: props.y,
visited: new Map(),
});
const escapeSchema = (props: {
components: OpenApi.IComponents;
schema: OpenApi.IJsonSchema;
recursive: false | number;
visited: Map<string, number>;
}): OpenApi.IJsonSchema | null | undefined => {
if (isReference(props.schema)) {
// REFERENCE
const name: string = props.schema.$ref.split("#/components/schemas/")[1];
const target: OpenApi.IJsonSchema | undefined =
props.components.schemas?.[name];
if (target === undefined) return null;
else if (props.visited.has(name) === true) {
if (props.recursive === false) return null;
const depth: number = props.visited.get(name)!;
if (depth > props.recursive) return undefined;
props.visited.set(name, depth + 1);
const res: OpenApi.IJsonSchema | null | undefined = escapeSchema({
components: props.components,
schema: target,
recursive: props.recursive,
visited: props.visited,
});
return res
? {
...res,
description: writeReferenceDescription({
components: props.components,
$ref: props.schema.$ref,
description: res.description,
escape: true,
}),
}
: res;
}
const res: OpenApi.IJsonSchema | null | undefined = escapeSchema({
components: props.components,
schema: target,
recursive: props.recursive,
visited: new Map([...props.visited, [name, 1]]),
});
return res
? {
...res,
description: writeReferenceDescription({
components: props.components,
$ref: props.schema.$ref,
description: res.description,
escape: true,
}),
}
: res;
} else if (isOneOf(props.schema)) {
// UNION
const elements: Array<OpenApi.IJsonSchema | null | undefined> =
props.schema.oneOf.map((schema) =>
escapeSchema({
components: props.components,
schema: schema,
recursive: props.recursive,
visited: props.visited,
}),
);
if (elements.some((v) => v === null)) return null;
const filtered: OpenApi.IJsonSchema[] = elements.filter(
(v) => v !== undefined,
) as OpenApi.IJsonSchema[];
if (filtered.length === 0) return undefined;
return {
...props,
oneOf: filtered.map((v) => flatSchema(props.components, v)).flat(),
};
} else if (isObject(props.schema)) {
// OBJECT
const object: OpenApi.IJsonSchema.IObject = props.schema;
const properties: Array<
[string, OpenApi.IJsonSchema | null | undefined]
> = Object.entries(object.properties ?? {}).map(([key, value]) => [
key,
escapeSchema({
components: props.components,
schema: value,
recursive: props.recursive,
visited: props.visited,
}),
]);
const additionalProperties:
| OpenApi.IJsonSchema
| null
| boolean
| undefined = object.additionalProperties
? typeof object.additionalProperties === "object" &&
object.additionalProperties !== null
? escapeSchema({
components: props.components,
schema: object.additionalProperties,
recursive: props.recursive,
visited: props.visited,
})
: object.additionalProperties
: false;
if (
properties.some(([_k, v]) => v === null) ||
additionalProperties === null
)
return null;
else if (
properties.some(
([k, v]) => v === undefined && object.required.includes(k) === true,
) === true
)
return undefined;
return {
...object,
properties: Object.fromEntries(
properties.filter(([_k, v]) => v !== undefined) as Array<
[string, OpenApi.IJsonSchema]
>,
),
additionalProperties: additionalProperties ?? false,
required: object.required.filter((k) =>
properties.some(([key, value]) => key === k && value !== undefined),
),
};
} else if (isTuple(props.schema)) {
// TUPLE
const elements: Array<OpenApi.IJsonSchema | null | undefined> =
props.schema.prefixItems.map((schema) =>
escapeSchema({
components: props.components,
schema: schema,
recursive: props.recursive,
visited: props.visited,
}),
);
const additionalItems: OpenApi.IJsonSchema | null | boolean | undefined =
props.schema.additionalItems
? typeof props.schema.additionalItems === "object" &&
props.schema.additionalItems !== null
? escapeSchema({
components: props.components,
schema: props.schema.additionalItems,
recursive: props.recursive,
visited: props.visited,
})
: props.schema.additionalItems
: false;
if (elements.some((v) => v === null) || additionalItems === null)
return null;
else if (elements.some((v) => v === undefined)) return undefined;
return {
...props.schema,
prefixItems: elements as OpenApi.IJsonSchema[],
additionalItems: additionalItems ?? false,
};
} else if (isArray(props.schema)) {
// ARRAY
const items: OpenApi.IJsonSchema | null | undefined = escapeSchema({
components: props.components,
schema: props.schema.items,
recursive: props.recursive,
visited: props.visited,
});
if (items === null) return null;
else if (items === undefined)
return {
...props.schema,
minItems: undefined,
maxItems: 0,
items: {},
};
return {
...props.schema,
items: items,
};
}
return props.schema;
};
const coverStation = (p: {
components: OpenApi.IComponents;
visited: Map<OpenApi.IJsonSchema, Map<OpenApi.IJsonSchema, boolean>>;
x: OpenApi.IJsonSchema;
y: OpenApi.IJsonSchema;
}): boolean => {
const cache: boolean | undefined = p.visited.get(p.x)?.get(p.y);
if (cache !== undefined) return cache;
// FOR RECURSIVE CASE
const nested: Map<OpenApi.IJsonSchema, boolean> = MapUtil.take(p.visited)(
p.x,
)(() => new Map());
nested.set(p.y, true);
// COMPUTE IT
const result: boolean = coverSchema(p);
nested.set(p.y, result);
return result;
};
const coverSchema = (p: {
components: OpenApi.IComponents;
visited: Map<OpenApi.IJsonSchema, Map<OpenApi.IJsonSchema, boolean>>;
x: OpenApi.IJsonSchema;
y: OpenApi.IJsonSchema;
}): boolean => {
// CHECK EQUALITY
if (p.x === p.y) return true;
else if (isReference(p.x) && isReference(p.y) && p.x.$ref === p.y.$ref)
return true;
// COMPARE WITH FLATTENING
const alpha: OpenApi.IJsonSchema[] = flatSchema(p.components, p.x);
const beta: OpenApi.IJsonSchema[] = flatSchema(p.components, p.y);
if (alpha.some((x) => isUnknown(x))) return true;
else if (beta.some((x) => isUnknown(x))) return false;
return beta.every((b) =>
alpha.some((a) =>
coverEscapedSchema({
components: p.components,
visited: p.visited,
x: a,
y: b,
}),
),
);
};
const coverEscapedSchema = (p: {
components: OpenApi.IComponents;
visited: Map<OpenApi.IJsonSchema, Map<OpenApi.IJsonSchema, boolean>>;
x: OpenApi.IJsonSchema;
y: OpenApi.IJsonSchema;
}): boolean => {
// CHECK EQUALITY
if (p.x === p.y) return true;
else if (isUnknown(p.x)) return true;
else if (isUnknown(p.y)) return false;
else if (isNull(p.x)) return isNull(p.y);
// ATOMIC CASE
else if (isConstant(p.x)) return isConstant(p.y) && p.x.const === p.y.const;
else if (isBoolean(p.x))
return (
isBoolean(p.y) || (isConstant(p.y) && typeof p.y.const === "boolean")
);
else if (isInteger(p.x))
return (isInteger(p.y) || isConstant(p.y)) && coverInteger(p.x, p.y);
else if (isNumber(p.x))
return (
(isConstant(p.y) || isInteger(p.y) || isNumber(p.y)) &&
coverNumber(p.x, p.y)
);
else if (isString(p.x))
return (isConstant(p.y) || isString(p.y)) && coverString(p.x, p.y);
// INSTANCE CASE
else if (isArray(p.x))
return (
(isArray(p.y) || isTuple(p.y)) &&
coverArray({
components: p.components,
visited: p.visited,
x: p.x,
y: p.y,
})
);
else if (isObject(p.x))
return (
isObject(p.y) &&
coverObject({
components: p.components,
visited: p.visited,
x: p.x,
y: p.y,
})
);
else if (isReference(p.x)) return isReference(p.y) && p.x.$ref === p.y.$ref;
return false;
};
const coverArray = (p: {
components: OpenApi.IComponents;
visited: Map<OpenApi.IJsonSchema, Map<OpenApi.IJsonSchema, boolean>>;
x: OpenApi.IJsonSchema.IArray;
y: OpenApi.IJsonSchema.IArray | OpenApi.IJsonSchema.ITuple;
}): boolean => {
if (isTuple(p.y))
return (
p.y.prefixItems.every((v) =>
coverStation({
components: p.components,
visited: p.visited,
x: p.x.items,
y: v,
}),
) &&
(p.y.additionalItems === undefined ||
(typeof p.y.additionalItems === "object" &&
coverStation({
components: p.components,
visited: p.visited,
x: p.x.items,
y: p.y.additionalItems,
})))
);
else if (
!(
p.x.minItems === undefined ||
(p.y.minItems !== undefined && p.x.minItems <= p.y.minItems)
)
)
return false;
else if (
!(
p.x.maxItems === undefined ||
(p.y.maxItems !== undefined && p.x.maxItems >= p.y.maxItems)
)
)
return false;
return coverStation({
components: p.components,
visited: p.visited,
x: p.x.items,
y: p.y.items,
});
};
const coverObject = (p: {
components: OpenApi.IComponents;
visited: Map<OpenApi.IJsonSchema, Map<OpenApi.IJsonSchema, boolean>>;
x: OpenApi.IJsonSchema.IObject;
y: OpenApi.IJsonSchema.IObject;
}): boolean => {
if (!p.x.additionalProperties && !!p.y.additionalProperties) return false;
else if (
!!p.x.additionalProperties &&
!!p.y.additionalProperties &&
((typeof p.x.additionalProperties === "object" &&
p.y.additionalProperties === true) ||
(typeof p.x.additionalProperties === "object" &&
typeof p.y.additionalProperties === "object" &&
!coverStation({
components: p.components,
visited: p.visited,
x: p.x.additionalProperties,
y: p.y.additionalProperties,
})))
)
return false;
return Object.entries(p.y.properties ?? {}).every(([key, b]) => {
const a: OpenApi.IJsonSchema | undefined = p.x.properties?.[key];
if (a === undefined) return false;
else if (
p.x.required.includes(key) === true &&
p.y.required.includes(key) === false
)
return false;
return coverStation({
components: p.components,
visited: p.visited,
x: a,
y: b,
});
});
};
const coverInteger = (
x: OpenApi.IJsonSchema.IInteger,
y: OpenApi.IJsonSchema.IConstant | OpenApi.IJsonSchema.IInteger,
): boolean => {
if (isConstant(y))
return typeof y.const === "number" && Number.isInteger(y.const);
return [
x.type === y.type,
x.minimum === undefined ||
(y.minimum !== undefined && x.minimum <= y.minimum),
x.maximum === undefined ||
(y.maximum !== undefined && x.maximum >= y.maximum),
x.exclusiveMinimum !== true ||
x.minimum === undefined ||
(y.minimum !== undefined &&
(y.exclusiveMinimum === true || x.minimum < y.minimum)),
x.exclusiveMaximum !== true ||
x.maximum === undefined ||
(y.maximum !== undefined &&
(y.exclusiveMaximum === true || x.maximum > y.maximum)),
x.multipleOf === undefined ||
(y.multipleOf !== undefined &&
y.multipleOf / x.multipleOf ===
Math.floor(y.multipleOf / x.multipleOf)),
].every((v) => v);
};
const coverNumber = (
x: OpenApi.IJsonSchema.INumber,
y:
| OpenApi.IJsonSchema.IConstant
| OpenApi.IJsonSchema.IInteger
| OpenApi.IJsonSchema.INumber,
): boolean => {
if (isConstant(y)) return typeof y.const === "number";
return [
x.type === y.type || (x.type === "number" && y.type === "integer"),
x.minimum === undefined ||
(y.minimum !== undefined && x.minimum <= y.minimum),
x.maximum === undefined ||
(y.maximum !== undefined && x.maximum >= y.maximum),
x.exclusiveMinimum !== true ||
x.minimum === undefined ||
(y.minimum !== undefined &&
(y.exclusiveMinimum === true || x.minimum < y.minimum)),
x.exclusiveMaximum !== true ||
x.maximum === undefined ||
(y.maximum !== undefined &&
(y.exclusiveMaximum === true || x.maximum > y.maximum)),
x.multipleOf === undefined ||
(y.multipleOf !== undefined &&
y.multipleOf / x.multipleOf ===
Math.floor(y.multipleOf / x.multipleOf)),
].every((v) => v);
};
const coverString = (
x: OpenApi.IJsonSchema.IString,
y: OpenApi.IJsonSchema.IConstant | OpenApi.IJsonSchema.IString,
): boolean => {
if (isConstant(y)) return typeof y.const === "string";
return [
x.format === undefined ||
(y.format !== undefined && coverFormat(x.format, y.format)),
x.pattern === undefined || x.pattern === y.pattern,
x.minLength === undefined ||
(y.minLength !== undefined && x.minLength <= y.minLength),
x.maxLength === undefined ||
(y.maxLength !== undefined && x.maxLength >= y.maxLength),
].every((v) => v);
};
const coverFormat = (
x: Required<OpenApi.IJsonSchema.IString>["format"],
y: Required<OpenApi.IJsonSchema.IString>["format"],
): boolean =>
x === y ||
(x === "idn-email" && y === "email") ||
(x === "idn-hostname" && y === "hostname") ||
(["uri", "iri"].includes(x) && y === "url") ||
(x === "iri" && y === "uri") ||
(x === "iri-reference" && y === "uri-reference");
const flatSchema = (
components: OpenApi.IComponents,
schema: OpenApi.IJsonSchema,
): OpenApi.IJsonSchema[] => {
schema = escapeReferenceOfFlatSchema(components, schema);
if (OpenApiTypeChecker.isOneOf(schema))
return schema.oneOf.map((v) => flatSchema(components, v)).flat();
return [schema];
};
const escapeReferenceOfFlatSchema = (
components: OpenApi.IComponents,
schema: OpenApi.IJsonSchema,
): Exclude<OpenApi.IJsonSchema, OpenApi.IJsonSchema.IReference> => {
if (OpenApiTypeChecker.isReference(schema) === false) return schema;
const key = schema.$ref.replace("#/components/schemas/", "");
const found: OpenApi.IJsonSchema | undefined = escapeReferenceOfFlatSchema(
components,
components.schemas?.[key] ?? {},
);
if (found === undefined)
throw new Error(
`Reference type not found: ${JSON.stringify(schema.$ref)}`,
);
return escapeReferenceOfFlatSchema(components, found);
};
/**
* @internal
*/
export const writeReferenceDescription = (props: {
components: OpenApi.IComponents;
$ref: string;
description: string | undefined;
escape: boolean;
}): string | undefined => {
const index: number = props.$ref.lastIndexOf(".");
if (index === -1) return props.description;
const accessors: string[] = props.$ref
.split("#/components/schemas/")[1]
.split(".");
const pReferences: IParentReference[] = accessors
.slice(0, props.escape ? accessors.length : accessors.length - 1)
.map((_, i, array) => array.slice(0, i + 1).join("."))
.map((key) => ({
key,
description: props.components.schemas?.[key]?.description,
}))
.filter((schema): schema is IParentReference => !!schema?.description)
.reverse();
if (pReferences.length === 0) return props.description;
return [
...(props.description?.length ? [props.description] : []),
...pReferences.map(
(pRef, i) =>
`Description of the ${i === 0 && props.escape ? "current" : "parent"} {@link ${pRef.key}} type:\n\n` +
pRef.description
.split("\n")
.map((str) => `> ${str}`)
.join("\n"),
),
].join("\n\n------------------------------\n\n");
};
}
/**
* @internal
*/
interface IParentReference {
key: string;
description: string;
}

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

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc