UNPKG

@samchon/openapi

Version:

OpenAPI definitions and converters for 'typia' and 'nestia'.

1 lines 17.2 kB
{"version":3,"file":"HttpLlmApplicationComposer.mjs","sources":["../../src/composers/HttpLlmApplicationComposer.ts"],"sourcesContent":["import { OpenApi } from \"../OpenApi\";\nimport { IHttpLlmApplication } from \"../structures/IHttpLlmApplication\";\nimport { IHttpLlmFunction } from \"../structures/IHttpLlmFunction\";\nimport { IHttpMigrateApplication } from \"../structures/IHttpMigrateApplication\";\nimport { IHttpMigrateRoute } from \"../structures/IHttpMigrateRoute\";\nimport { ILlmFunction } from \"../structures/ILlmFunction\";\nimport { ILlmSchema } from \"../structures/ILlmSchema\";\nimport { IOpenApiSchemaError } from \"../structures/IOpenApiSchemaError\";\nimport { IResult } from \"../structures/IResult\";\nimport { OpenApiValidator } from \"../utils/OpenApiValidator\";\nimport { LlmSchemaComposer } from \"./LlmSchemaComposer\";\n\nexport namespace HttpLlmComposer {\n export const application = <Model extends ILlmSchema.Model>(props: {\n model: Model;\n migrate: IHttpMigrateApplication;\n options: IHttpLlmApplication.IOptions<Model>;\n }): IHttpLlmApplication<Model> => {\n // COMPOSE FUNCTIONS\n const errors: IHttpLlmApplication.IError[] = props.migrate.errors\n .filter((e) => e.operation()[\"x-samchon-human\"] !== true)\n .map((e) => ({\n method: e.method,\n path: e.path,\n messages: e.messages,\n operation: () => e.operation(),\n route: () => undefined,\n }));\n const functions: IHttpLlmFunction<Model>[] = props.migrate.routes\n .filter((e) => e.operation()[\"x-samchon-human\"] !== true)\n .map((route, i) => {\n if (route.method === \"head\") {\n errors.push({\n method: route.method,\n path: route.path,\n messages: [\"HEAD method is not supported in the LLM application.\"],\n operation: () => route.operation(),\n route: () => route as any as IHttpMigrateRoute,\n });\n return null;\n } else if (\n route.body?.type === \"multipart/form-data\" ||\n route.success?.type === \"multipart/form-data\"\n ) {\n errors.push({\n method: route.method,\n path: route.path,\n messages: [\n `The \"multipart/form-data\" content type is not supported in the LLM application.`,\n ],\n operation: () => route.operation(),\n route: () => route as any as IHttpMigrateRoute,\n });\n return null;\n }\n const localErrors: string[] = [];\n const func: IHttpLlmFunction<Model> | null = composeFunction<Model>({\n model: props.model,\n config: props.options,\n components: props.migrate.document().components,\n route: route,\n errors: localErrors,\n index: i,\n });\n if (func === null)\n errors.push({\n method: route.method,\n path: route.path,\n messages: localErrors,\n operation: () => route.operation(),\n route: () => route as any as IHttpMigrateRoute,\n });\n return func;\n })\n .filter((v): v is IHttpLlmFunction<Model> => v !== null);\n\n const app: IHttpLlmApplication<Model> = {\n model: props.model,\n options: props.options,\n functions,\n errors,\n };\n shorten(app, props.options?.maxLength ?? 64);\n return app;\n };\n\n const composeFunction = <Model extends ILlmSchema.Model>(props: {\n model: Model;\n components: OpenApi.IComponents;\n route: IHttpMigrateRoute;\n config: IHttpLlmApplication.IOptions<Model>;\n errors: string[];\n index: number;\n }): IHttpLlmFunction<Model> | null => {\n // METADATA\n const endpoint: string = `$input.paths[${JSON.stringify(props.route.path)}][${JSON.stringify(props.route.method)}]`;\n const operation: OpenApi.IOperation = props.route.operation();\n const description: [string | undefined, number] = (() => {\n if (!operation.summary?.length || !operation.description?.length)\n return [\n operation.summary || operation.description,\n operation.summary?.length ?? operation.description?.length ?? 0,\n ];\n const summary: string = operation.summary.endsWith(\".\")\n ? operation.summary.slice(0, -1)\n : operation.summary;\n const final: string = operation.description.startsWith(summary)\n ? operation.description\n : summary + \".\\n\\n\" + operation.description;\n return [final, final.length];\n })();\n if (description[1] > 1_024) {\n props.errors.push(\n `The description of the function is too long (must be equal or less than 1,024 characters, but ${description[1].toLocaleString()} length).`,\n );\n }\n\n // FUNCTION NAME\n const name: string = emend(props.route.accessor.join(\"_\"));\n const isNameVariable: boolean = /^[a-zA-Z0-9_-]+$/.test(name);\n const isNameStartsWithNumber: boolean = /^[0-9]/.test(name[0] ?? \"\");\n if (isNameVariable === false)\n props.errors.push(\n `Elements of path (separated by '/') must be composed with alphabets, numbers, underscores, and hyphens`,\n );\n\n //----\n // CONSTRUCT SCHEMAS\n //----\n // PARAMETERS\n const parameters: OpenApi.IJsonSchema.IObject = {\n type: \"object\",\n properties: Object.fromEntries([\n ...props.route.parameters.map(\n (s) =>\n [\n s.key,\n {\n ...s.schema,\n title: s.parameter().title ?? s.schema.title,\n description: s.parameter().description ?? s.schema.description,\n },\n ] as const,\n ),\n ...(props.route.query\n ? [\n [\n props.route.query.key,\n {\n ...props.route.query.schema,\n title:\n props.route.query.title() ?? props.route.query.schema.title,\n description:\n props.route.query.description() ??\n props.route.query.schema.description,\n },\n ] as const,\n ]\n : []),\n ...(props.route.body\n ? [\n [\n props.route.body.key,\n {\n ...props.route.body.schema,\n description:\n props.route.body.description() ??\n props.route.body.schema.description,\n },\n ] as const,\n ]\n : []),\n ]),\n };\n parameters.required = Object.keys(parameters.properties ?? {});\n\n const llmParameters: IResult<\n ILlmSchema.IParameters<Model>,\n IOpenApiSchemaError\n > = LlmSchemaComposer.parameters(props.model)({\n config: props.config as any,\n components: props.components,\n schema: parameters,\n accessor: `${endpoint}.parameters`,\n }) as IResult<ILlmSchema.IParameters<Model>, IOpenApiSchemaError>;\n\n // RETURN VALUE\n const output: IResult<ILlmSchema<Model>, IOpenApiSchemaError> | undefined =\n props.route.success\n ? (LlmSchemaComposer.schema(props.model)({\n config: props.config as any,\n components: props.components,\n schema: props.route.success.schema,\n accessor: `${endpoint}.responses[${JSON.stringify(props.route.success.status)}][${JSON.stringify(props.route.success.type)}].schema`,\n $defs: llmParameters.success\n ? (llmParameters.value as any).$defs!\n : {},\n }) as IResult<ILlmSchema<Model>, IOpenApiSchemaError>)\n : undefined;\n\n //----\n // CONVERSION\n //----\n if (\n output?.success === false ||\n llmParameters.success === false ||\n isNameVariable === false ||\n isNameStartsWithNumber === true ||\n description[1] > 1_024\n ) {\n if (output?.success === false)\n props.errors.push(\n ...output.error.reasons.map((r) => `${r.accessor}: ${r.message}`),\n );\n if (llmParameters.success === false)\n props.errors.push(\n ...llmParameters.error.reasons.map((r) => {\n const accessor: string = r.accessor.replace(\n `parameters.properties[\"body\"]`,\n `requestBody.content[${JSON.stringify(props.route.body?.type ?? \"application/json\")}].schema`,\n );\n return `${accessor}: ${r.message}`;\n }),\n );\n return null;\n }\n return {\n method: props.route.method as \"get\",\n path: props.route.path,\n name,\n parameters: llmParameters.value,\n separated: props.config.separate\n ? (LlmSchemaComposer.separateParameters(props.model)({\n predicate: props.config.separate as any,\n parameters:\n llmParameters.value satisfies ILlmSchema.ModelParameters[Model] as any,\n }) as ILlmFunction.ISeparated<Model>)\n : undefined,\n output: output?.value,\n description: description[0],\n deprecated: operation.deprecated,\n tags: operation.tags,\n validate: OpenApiValidator.create({\n components: props.components,\n schema: parameters,\n required: true,\n }),\n route: () => props.route as any,\n operation: () => props.route.operation(),\n };\n };\n\n export const shorten = <Model extends ILlmSchema.Model>(\n app: IHttpLlmApplication<Model>,\n limit: number = 64,\n ): void => {\n const dictionary: Set<string> = new Set();\n const longFunctions: IHttpLlmFunction<Model>[] = [];\n for (const func of app.functions) {\n dictionary.add(func.name);\n if (func.name.length > limit) {\n longFunctions.push(func);\n }\n }\n if (longFunctions.length === 0) return;\n\n let index: number = 0;\n for (const func of longFunctions) {\n let success: boolean = false;\n let rename = (str: string) => {\n dictionary.delete(func.name);\n dictionary.add(str);\n func.name = str;\n success = true;\n };\n for (let i: number = 1; i < func.route().accessor.length; ++i) {\n const shortName: string = func.route().accessor.slice(i).join(\"_\");\n if (shortName.length > limit - 8) continue;\n else if (dictionary.has(shortName) === false) rename(shortName);\n else {\n const newName: string = `_${index}_${shortName}`;\n if (dictionary.has(newName) === true) continue;\n rename(newName);\n ++index;\n }\n break;\n }\n if (success === false) rename(randomFormatUuid());\n }\n };\n}\n\nconst randomFormatUuid = (): string =>\n \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n\nconst emend = (str: string): string => {\n for (const ch of FORBIDDEN) str = str.split(ch).join(\"_\");\n return str;\n};\n\nconst FORBIDDEN = [\"$\", \"%\", \".\"];\n"],"names":["HttpLlmComposer","application","props","errors","migrate","filter","e","operation","map","method","path","messages","route","undefined","functions","routes","i","push","body","type","success","localErrors","func","composeFunction","model","config","options","components","document","v","app","shorten","maxLength","endpoint","JSON","stringify","description","summary","length","endsWith","slice","final","startsWith","toLocaleString","name","emend","accessor","join","isNameVariable","test","isNameStartsWithNumber","parameters","properties","Object","fromEntries","s","key","schema","title","parameter","query","required","keys","llmParameters","LlmSchemaComposer","output","status","$defs","value","error","reasons","r","message","replace","separated","separate","separateParameters","predicate","deprecated","tags","validate","OpenApiValidator","create","limit","dictionary","Set","longFunctions","add","index","rename","str","delete","shortName","has","newName","randomFormatUuid","c","Math","random","toString","ch","FORBIDDEN","split"],"mappings":"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"}