@samchon/openapi
Version:
OpenAPI definitions and converters for 'typia' and 'nestia'.
213 lines (202 loc) • 8.56 kB
JavaScript
import { OpenApiV3Downgrader } from "../../converters/OpenApiV3Downgrader.mjs";
import { OpenApiV3Upgrader } from "../../converters/OpenApiV3Upgrader.mjs";
import { LlmTypeCheckerV3 } from "../../utils/LlmTypeCheckerV3.mjs";
import { OpenApiConstraintShifter } from "../../utils/OpenApiConstraintShifter.mjs";
import { OpenApiTypeChecker } from "../../utils/OpenApiTypeChecker.mjs";
import { OpenApiValidator } from "../../utils/OpenApiValidator.mjs";
import { LlmDescriptionInverter } from "./LlmDescriptionInverter.mjs";
import { LlmParametersFinder } from "./LlmParametersComposer.mjs";
var LlmSchemaV3Composer;
(function(LlmSchemaV3Composer) {
LlmSchemaV3Composer.IS_DEFS = false;
LlmSchemaV3Composer.DEFAULT_CONFIG = {
recursive: 3,
constraint: true
};
LlmSchemaV3Composer.parameters = props => {
const entity = LlmParametersFinder.parameters({
...props,
method: "LlmSchemaV3Composer.parameters"
});
if (entity.success === false) return entity;
const result = LlmSchemaV3Composer.schema(props);
if (result.success === false) return result;
return {
success: true,
value: {
...result.value,
additionalProperties: false
}
};
};
LlmSchemaV3Composer.schema = props => {
const reasons = [];
OpenApiTypeChecker.visit({
closure: (next, accessor) => {
if (props.validate) reasons.push(...props.validate(next, accessor));
if (OpenApiTypeChecker.isTuple(next)) reasons.push({
accessor,
schema: next,
message: "LLM does not allow tuple type."
}); else if (OpenApiTypeChecker.isReference(next)) {
const key = next.$ref.split("#/components/schemas/")[1];
if (props.components.schemas?.[key] === undefined) {
reasons.push({
schema: next,
message: `${accessor}: unable to find reference type ${JSON.stringify(key)}.`,
accessor
});
}
}
},
components: props.components,
schema: props.schema,
accessor: props.accessor,
refAccessor: props.refAccessor
});
if (reasons.length > 0) return {
success: false,
error: {
method: "LlmSchemaV3Composer.schema",
message: "Failed to compose LLM schema of v3",
reasons
}
};
const escaped = OpenApiTypeChecker.escape({
...props,
recursive: props.config.recursive
});
if (escaped.success === false) return {
success: false,
error: {
method: "LlmSchemaV3Composer.schema",
message: "Failed to compose LLM schema of v3",
reasons: escaped.error.reasons
}
};
const downgraded = OpenApiV3Downgrader.downgradeSchema({
original: {
schemas: {}
},
downgraded: {}
})(escaped.value);
LlmTypeCheckerV3.visit({
closure: next => {
if (LlmTypeCheckerV3.isOneOf(next) && next.discriminator !== undefined) delete next.discriminator; else if (LlmTypeCheckerV3.isObject(next)) {
next.properties ?? (next.properties = {});
next.required ?? (next.required = []);
}
if (props.config.constraint === false) {
if (LlmTypeCheckerV3.isInteger(next) || LlmTypeCheckerV3.isNumber(next)) OpenApiConstraintShifter.shiftNumeric(next); else if (LlmTypeCheckerV3.isString(next)) OpenApiConstraintShifter.shiftString(next); else if (LlmTypeCheckerV3.isArray(next)) OpenApiConstraintShifter.shiftArray(next);
}
},
schema: downgraded
});
return {
success: true,
value: downgraded
};
};
LlmSchemaV3Composer.separateParameters = props => {
const [llm, human] = separateObject({
predicate: props.predicate,
schema: props.parameters
});
return {
llm: llm ?? {
type: "object",
properties: {},
additionalProperties: false,
required: []
},
human,
validate: llm ? OpenApiValidator.create({
components: {},
schema: LlmSchemaV3Composer.invert({
schema: llm
}),
required: true,
equals: props.equals
}) : undefined
};
};
const separateStation = props => {
if (props.predicate(props.schema) === true) return [ null, props.schema ]; else if (LlmTypeCheckerV3.isUnknown(props.schema) || LlmTypeCheckerV3.isOneOf(props.schema)) return [ props.schema, null ]; else if (LlmTypeCheckerV3.isObject(props.schema)) return separateObject({
predicate: props.predicate,
schema: props.schema
}); else if (LlmTypeCheckerV3.isArray(props.schema)) return separateArray({
predicate: props.predicate,
schema: props.schema
});
return [ props.schema, null ];
};
const separateArray = props => {
const [x, y] = separateStation({
predicate: props.predicate,
schema: props.schema.items
});
return [ x !== null ? {
...props.schema,
items: x
} : null, y !== null ? {
...props.schema,
items: y
} : null ];
};
const separateObject = props => {
if (Object.keys(props.schema.properties ?? {}).length === 0 && !!props.schema.additionalProperties === false) return [ props.schema, null ];
const llm = {
...props.schema,
properties: {},
additionalProperties: props.schema.additionalProperties
};
const human = {
...props.schema,
properties: {},
additionalProperties: props.schema.additionalProperties
};
for (const [key, value] of Object.entries(props.schema.properties ?? {})) {
const [x, y] = separateStation({
predicate: props.predicate,
schema: value
});
if (x !== null) llm.properties[key] = x;
if (y !== null) human.properties[key] = y;
}
if (typeof props.schema.additionalProperties === "object" && props.schema.additionalProperties !== null) {
const [dx, dy] = separateStation({
predicate: props.predicate,
schema: props.schema.additionalProperties
});
llm.additionalProperties = dx ?? false;
human.additionalProperties = dy ?? false;
}
return [ !!Object.keys(llm.properties).length || !!llm.additionalProperties ? shrinkRequired(llm) : null, !!Object.keys(human.properties).length || !!human.additionalProperties ? shrinkRequired(human) : null ];
};
const shrinkRequired = s => {
s.required = s.required.filter((key => s.properties[key] !== undefined));
return s;
};
LlmSchemaV3Composer.invert = props => {
const upgraded = OpenApiV3Upgrader.convertSchema({})(props.schema);
OpenApiTypeChecker.visit({
closure: schema => {
if (OpenApiTypeChecker.isArray(schema)) Object.assign(schema, {
...schema,
...LlmDescriptionInverter.array(schema.description)
}); else if (OpenApiTypeChecker.isInteger(schema) || OpenApiTypeChecker.isNumber(schema)) Object.assign(schema, {
...schema,
...LlmDescriptionInverter.numeric(schema.description)
}); else if (OpenApiTypeChecker.isString(schema)) Object.assign(schema, {
...schema,
...LlmDescriptionInverter.string(schema.description)
});
},
components: {},
schema: upgraded
});
return upgraded;
};
})(LlmSchemaV3Composer || (LlmSchemaV3Composer = {}));
export { LlmSchemaV3Composer };
//# sourceMappingURL=LlmSchemaV3Composer.mjs.map