From 12a2b4c351b5981284be0ec8972d276bc062db54 Mon Sep 17 00:00:00 2001 From: Jeongho Nam Date: Fri, 13 Dec 2024 01:02:42 +0900 Subject: [PATCH] Block LLM function schema composition by `@human` tag. Follows the samchon/openapi#106 concept. --- package.json | 2 +- packages/typescript-json/README.md | 27 ++++++++++- packages/typescript-json/package.json | 4 +- .../json/JsonApplicationProgrammer.ts | 5 +- .../llm/LlmApplicationProgrammer.ts | 2 + test/{debug.js => debug.ts} | 2 +- test/generate/output/generate_http.ts | 16 ++++--- test/generate/output/generate_index.ts | 32 ++++++++----- test/generate/output/generate_json.ts | 32 ++++++++----- test/generate/output/generate_misc.ts | 32 ++++++++----- test/generate/output/generate_notations.ts | 48 ++++++++++++------- test/generate/output/generate_plain.ts | 32 ++++++++----- test/generate/output/generate_protobuf.ts | 32 ++++++++----- test/issue.ts | 21 ++++++++ test/package.json | 3 +- test/src/debug/llm.application.ts | 17 +++++++ .../issues/test_issue_openapi_106_human.ts | 21 ++++++++ website/pages/docs/llm/application.mdx | 24 ++++++++-- 18 files changed, 257 insertions(+), 95 deletions(-) rename test/{debug.js => debug.ts} (73%) create mode 100644 test/issue.ts create mode 100644 test/src/debug/llm.application.ts create mode 100644 test/src/features/issues/test_issue_openapi_106_human.ts diff --git a/package.json b/package.json index d6ed64d53d..a552ca7333 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "typia", - "version": "7.2.0", + "version": "7.2.1", "description": "Superfast runtime validators with only one line", "main": "lib/index.js", "typings": "lib/index.d.ts", diff --git a/packages/typescript-json/README.md b/packages/typescript-json/README.md index 7a6e17fd13..c32cd565d4 100644 --- a/packages/typescript-json/README.md +++ b/packages/typescript-json/README.md @@ -46,7 +46,7 @@ export namespace protobuf { export function random(g?: Partial): T; ``` -Typia is a transformer library supporting below features: +`typia` is a transformer library supporting below features: - Super-fast Runtime Validators - Enhanced JSON schema and serde functions @@ -63,6 +63,31 @@ Typia is a transformer library supporting below features: +## Transformation +If you call `typia` function, it would be compiled like below. + +This is the key concept of `typia`, transforming TypeScript type to a runtime function. The `typia.is()` function is transformed to a dedicated type checker by analyzing the target type `T` in the compilation level. + +This feature enables developers to ensure type safety in their applications, leveraging TypeScript's static typing while also providing runtime validation. Instead of defining additional schemas, you can simply utilize the pure TypeScript type itself. + +```typescript +//---- +// examples/checkString.ts +//---- +import typia, { tags } from "typia"; +export const checkString = typia.createIs(); + +//---- +// examples/checkUUID.js +//---- +import typia from "typia"; +export const checkString = (() => { + return (input) => "string" === typeof input; +})(); +``` + + + ## Sponsors Thanks for your support. diff --git a/packages/typescript-json/package.json b/packages/typescript-json/package.json index 2cc2baee6f..2439da5365 100644 --- a/packages/typescript-json/package.json +++ b/packages/typescript-json/package.json @@ -1,6 +1,6 @@ { "name": "typescript-json", - "version": "7.1.0-dev.20241209", + "version": "7.2.1-dev.20241212", "description": "Superfast runtime validators with only one line", "main": "lib/index.js", "typings": "lib/index.d.ts", @@ -37,7 +37,7 @@ }, "homepage": "https://typia.io", "dependencies": { - "typia": "7.1.0-dev.20241209" + "typia": "7.2.1-dev.20241212" }, "peerDependencies": { "typescript": ">=4.8.0 <5.8.0", diff --git a/src/programmers/json/JsonApplicationProgrammer.ts b/src/programmers/json/JsonApplicationProgrammer.ts index 54990489bf..3921708bac 100644 --- a/src/programmers/json/JsonApplicationProgrammer.ts +++ b/src/programmers/json/JsonApplicationProgrammer.ts @@ -5,6 +5,7 @@ import { IJsDocTagInfo } from "../../schemas/metadata/IJsDocTagInfo"; import { Metadata } from "../../schemas/metadata/Metadata"; import { MetadataFunction } from "../../schemas/metadata/MetadataFunction"; import { MetadataObjectType } from "../../schemas/metadata/MetadataObjectType"; +import { MetadataProperty } from "../../schemas/metadata/MetadataProperty"; import { JsonSchemasProgrammer } from "./JsonSchemasProgrammer"; @@ -60,6 +61,7 @@ export namespace JsonApplicationProgrammer { export const write = (props: { version: Version; metadata: Metadata; + filter?: (prop: MetadataProperty) => boolean; }): __IJsonApplication => { const errors: string[] = validate(props.metadata, { top: true, @@ -101,7 +103,8 @@ export namespace JsonApplicationProgrammer { (p) => p.jsDocTags.find( (tag) => tag.name === "hidden" || tag.name === "internal", - ) === undefined, + ) === undefined && + (props.filter === undefined || props.filter(p) === true), ) .map((r) => collectFunction({ diff --git a/src/programmers/llm/LlmApplicationProgrammer.ts b/src/programmers/llm/LlmApplicationProgrammer.ts index 182a1afb0e..e647a7cc00 100644 --- a/src/programmers/llm/LlmApplicationProgrammer.ts +++ b/src/programmers/llm/LlmApplicationProgrammer.ts @@ -139,6 +139,8 @@ export namespace LlmApplicationProgrammer { JsonApplicationProgrammer.write({ version: "3.1", metadata: props.metadata, + filter: (p) => + p.jsDocTags.some((tag) => tag.name === "human") === false, }); const functions: Array | null> = application.functions.map((func) => diff --git a/test/debug.js b/test/debug.ts similarity index 73% rename from test/debug.js rename to test/debug.ts index d2144e6584..b507abaf20 100644 --- a/test/debug.js +++ b/test/debug.ts @@ -1,4 +1,4 @@ -const cp = require("child_process"); +import cp from "child_process"; cp.execSync(`npx ts-node src/debug/${process.argv[2]}.ts`, { cwd: __dirname, diff --git a/test/generate/output/generate_http.ts b/test/generate/output/generate_http.ts index 162c1bf3db..03f2855491 100644 --- a/test/generate/output/generate_http.ts +++ b/test/generate/output/generate_http.ts @@ -302,15 +302,19 @@ export const validateQuery = (() => { value: input, }))(input, "$input", true); const success = 0 === errors.length; - return { - success, - errors, - data: input, - } as any; + return success + ? { + success, + data: input, + } + : ({ + success, + errors, + data: input, + } as any); } return { success: true, - errors: [], data: input, } as any; }; diff --git a/test/generate/output/generate_index.ts b/test/generate/output/generate_index.ts index f5ded4524e..5654cd1a5b 100644 --- a/test/generate/output/generate_index.ts +++ b/test/generate/output/generate_index.ts @@ -758,15 +758,19 @@ export const validate = (() => { value: input, }))(input, "$input", true); const success = 0 === errors.length; - return { - success, - errors, - data: input, - } as any; + return success + ? { + success, + data: input, + } + : ({ + success, + errors, + data: input, + } as any); } return { success: true, - errors: [], data: input, } as any; }; @@ -1704,15 +1708,19 @@ export const validateEquals = (() => { value: input, }))(input, "$input", true); const success = 0 === errors.length; - return { - success, - errors, - data: input, - } as any; + return success + ? { + success, + data: input, + } + : ({ + success, + errors, + data: input, + } as any); } return { success: true, - errors: [], data: input, } as any; }; diff --git a/test/generate/output/generate_json.ts b/test/generate/output/generate_json.ts index 3d6e0a491e..7dbbfea8f0 100644 --- a/test/generate/output/generate_json.ts +++ b/test/generate/output/generate_json.ts @@ -605,15 +605,19 @@ export const createValidateStringify = (() => { value: input, }))(input, "$input", true); const success = 0 === errors.length; - return { - success, - errors, - data: input, - } as any; + return success + ? { + success, + data: input, + } + : ({ + success, + errors, + data: input, + } as any); } return { success: true, - errors: [], data: input, } as any; }; @@ -1098,15 +1102,19 @@ export const createValidateParse = (() => { value: input, }))(input, "$input", true); const success = 0 === errors.length; - return { - success, - errors, - data: input, - } as any; + return success + ? { + success, + data: input, + } + : ({ + success, + errors, + data: input, + } as any); } return { success: true, - errors: [], data: input, } as any; }; diff --git a/test/generate/output/generate_misc.ts b/test/generate/output/generate_misc.ts index ae698957f7..c24ab9557b 100644 --- a/test/generate/output/generate_misc.ts +++ b/test/generate/output/generate_misc.ts @@ -567,15 +567,19 @@ export const createValidateClone = (() => { value: input, }))(input, "$input", true); const success = 0 === errors.length; - return { - success, - errors, - data: input, - } as any; + return success + ? { + success, + data: input, + } + : ({ + success, + errors, + data: input, + } as any); } return { success: true, - errors: [], data: input, } as any; }; @@ -1195,15 +1199,19 @@ export const createValidatePrune = (() => { value: input, }))(input, "$input", true); const success = 0 === errors.length; - return { - success, - errors, - data: input, - } as any; + return success + ? { + success, + data: input, + } + : ({ + success, + errors, + data: input, + } as any); } return { success: true, - errors: [], data: input, } as any; }; diff --git a/test/generate/output/generate_notations.ts b/test/generate/output/generate_notations.ts index 0e3e386cb6..33a009bfc4 100644 --- a/test/generate/output/generate_notations.ts +++ b/test/generate/output/generate_notations.ts @@ -546,15 +546,19 @@ export const createValidateCamel = (() => { value: input, }))(input, "$input", true); const success = 0 === errors.length; - return { - success, - errors, - data: input, - } as any; + return success + ? { + success, + data: input, + } + : ({ + success, + errors, + data: input, + } as any); } return { success: true, - errors: [], data: input, } as any; }; @@ -1098,15 +1102,19 @@ export const createValidatePascal = (() => { value: input, }))(input, "$input", true); const success = 0 === errors.length; - return { - success, - errors, - data: input, - } as any; + return success + ? { + success, + data: input, + } + : ({ + success, + errors, + data: input, + } as any); } return { success: true, - errors: [], data: input, } as any; }; @@ -1650,15 +1658,19 @@ export const createValidateSnake = (() => { value: input, }))(input, "$input", true); const success = 0 === errors.length; - return { - success, - errors, - data: input, - } as any; + return success + ? { + success, + data: input, + } + : ({ + success, + errors, + data: input, + } as any); } return { success: true, - errors: [], data: input, } as any; }; diff --git a/test/generate/output/generate_plain.ts b/test/generate/output/generate_plain.ts index 817371b18f..e9434a0641 100644 --- a/test/generate/output/generate_plain.ts +++ b/test/generate/output/generate_plain.ts @@ -1463,15 +1463,19 @@ export const createValidate = (() => { value: input, }))(input, "$input", true); const success = 0 === errors.length; - return { - success, - errors, - data: input, - } as any; + return success + ? { + success, + data: input, + } + : ({ + success, + errors, + data: input, + } as any); } return { success: true, - errors: [], data: input, } as any; }; @@ -1704,15 +1708,19 @@ export const createValidateEquals = (() => { value: input, }))(input, "$input", true); const success = 0 === errors.length; - return { - success, - errors, - data: input, - } as any; + return success + ? { + success, + data: input, + } + : ({ + success, + errors, + data: input, + } as any); } return { success: true, - errors: [], data: input, } as any; }; diff --git a/test/generate/output/generate_protobuf.ts b/test/generate/output/generate_protobuf.ts index 77a2583fa3..b48aa46dee 100644 --- a/test/generate/output/generate_protobuf.ts +++ b/test/generate/output/generate_protobuf.ts @@ -433,15 +433,19 @@ export const createValidateEncode = (() => { value: input, }))(input, "$input", true); const success = 0 === errors.length; - return { - success, - errors, - data: input, - } as any; + return success + ? { + success, + data: input, + } + : ({ + success, + errors, + data: input, + } as any); } return { success: true, - errors: [], data: input, } as any; }; @@ -867,15 +871,19 @@ export const createValidateDecode = (() => { value: input, }))(input, "$input", true); const success = 0 === errors.length; - return { - success, - errors, - data: input, - } as any; + return success + ? { + success, + data: input, + } + : ({ + success, + errors, + data: input, + } as any); } return { success: true, - errors: [], data: input, } as any; }; diff --git a/test/issue.ts b/test/issue.ts new file mode 100644 index 0000000000..5fe7b3f33d --- /dev/null +++ b/test/issue.ts @@ -0,0 +1,21 @@ +import fs from "fs"; + +const main = async () => { + const issue: string | undefined = process.argv[2]; + if (issue === undefined) throw new Error("Target issue not provided."); + + const directory: string[] = await fs.promises.readdir( + `${__dirname}/src/features/issues`, + ); + const targets: string[] = directory.filter((f) => f.includes(issue)); + for (const file of targets) { + console.log(file); + const modulo = await import(`./src/features/issues/${file}`); + for (const value of Object.values(modulo)) + if (typeof value === "function") await value(); + } +}; +main().catch((exp) => { + console.error(exp); + process.exit(-1); +}); diff --git a/test/package.json b/test/package.json index d961ec116c..cd7d180415 100644 --- a/test/package.json +++ b/test/package.json @@ -17,7 +17,8 @@ "prettier": "prettier ./src/**/*.ts --write", "setup": "node build/setup.js", "start": "node bin", - "debug": "node debug", + "debug": "ts-node debug", + "issue": "ts-node issue", "template": "ts-node --project build/tsconfig.json build/template.ts" }, "repository": { diff --git a/test/src/debug/llm.application.ts b/test/src/debug/llm.application.ts new file mode 100644 index 0000000000..bab3cd8894 --- /dev/null +++ b/test/src/debug/llm.application.ts @@ -0,0 +1,17 @@ +import { ILlmApplication } from "@samchon/openapi"; +import typia from "typia"; + +interface SomeApplication { + plus(props: { x: number; y: number }): number; + + /** + * @human + */ + minus(props: { x: number; y: number }): number; +} + +const app: ILlmApplication<"chatgpt"> = typia.llm.application< + SomeApplication, + "chatgpt" +>(); +console.log(app); diff --git a/test/src/features/issues/test_issue_openapi_106_human.ts b/test/src/features/issues/test_issue_openapi_106_human.ts new file mode 100644 index 0000000000..1b25bad814 --- /dev/null +++ b/test/src/features/issues/test_issue_openapi_106_human.ts @@ -0,0 +1,21 @@ +import { ILlmApplication } from "@samchon/openapi"; +import typia from "typia"; + +import { TestValidator } from "../../helpers/TestValidator"; + +interface SomeApplication { + plus(props: { x: number; y: number }): number; + + /** + * @human + */ + minus(props: { x: number; y: number }): number; +} + +export const test_issue_openapi_106_human = (): void => { + const app: ILlmApplication<"chatgpt"> = typia.llm.application< + SomeApplication, + "chatgpt" + >(); + TestValidator.equals("functions")(app.functions.map((f) => f.name))(["plus"]); +}; diff --git a/website/pages/docs/llm/application.mdx b/website/pages/docs/llm/application.mdx index 7bff9ffeec..0ced2addd7 100644 --- a/website/pages/docs/llm/application.mdx +++ b/website/pages/docs/llm/application.mdx @@ -1119,7 +1119,7 @@ interface BbsArticleController { ## Function Hiding Hiding some functions by comment tag. -If you write `@hidden` or `@internal` tag onto a function description comment, the function would not participate in the LLM (Large Language Model) function calling application composition. `ILlmFunction` schema does not be genrated in the `ILlmApplication.functions` collection. +If you write `@hidden`, `@human` or `@internal` tag onto a function description comment, the function would not participate in the LLM (Large Language Model) function calling application composition. `ILlmFunction` schema does not be genrated in the `ILlmApplication.functions` collection. It's a good feature to hide some internal functions, so that avoiding the LLM function calling. @@ -1128,7 +1128,7 @@ It's a good feature to hide some internal functions, so that avoiding the LLM fu "Compiled JavaScript File", ]}> -```typescript filename="example/src/llm.application.hideden.ts" showLineNumbers {25, 38} +```typescript filename="example/src/llm.application.hideden.ts" showLineNumbers {38, 54, 74} import { ClaudeTypeChecker, ILlmApplication, @@ -1159,6 +1159,22 @@ interface BbsArticleController { input: IBbsArticle.ICreate; }): Promise; + /** + * Read an article. + * + * Reads an article from the DB. + * + * @param props Properties of read function + * @returns The article + * @hidden + */ + at(props: { + /** + * Target article's {@link IBbsArticle.id}. + */ + id: string & tags.Format<"uuid">; + }): Promise; + /** * Update an article. * @@ -1166,7 +1182,7 @@ interface BbsArticleController { * * @param props Properties of update function * @param input New content to update - * @hidden + * @internal */ update(props: { /** @@ -1186,7 +1202,7 @@ interface BbsArticleController { * Erases an article from the DB. * * @param props Properties of erase function - * @internal + * @human */ erase(props: { /**