Skip to content

Commit 6219f08

Browse files
authored
fix(core): LLM custom validation was not working. (#1793)
* fix(core): LLM custom validation was not working. * refactoring * add test case
1 parent 136719c commit 6219f08

File tree

10 files changed

+244
-227
lines changed

10 files changed

+244
-227
lines changed

packages/core/src/programmers/llm/LlmApplicationProgrammer.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export namespace LlmApplicationProgrammer {
5252
}
5353
>;
5454
name?: string;
55+
configArgument?: ts.Expression;
5556
}
5657

5758
export const write = (props: IWriteProps): ts.CallExpression => {
@@ -82,17 +83,7 @@ export namespace LlmApplicationProgrammer {
8283
),
8384
typeNode,
8485
),
85-
ts.factory.createObjectLiteralExpression(
86-
[
87-
ts.factory.createPropertyAssignment(
88-
"equals",
89-
props.config?.equals === true
90-
? ts.factory.createTrue()
91-
: ts.factory.createFalse(),
92-
),
93-
],
94-
false,
95-
),
86+
...(props.configArgument ? [props.configArgument] : []),
9687
],
9788
);
9889
};
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { ILlmSchema } from "@typia/interface";
2+
import ts from "typescript";
3+
4+
import { ITypiaContext } from "../../context/ITypiaContext";
5+
import { MetadataSchema } from "../../schemas/metadata/MetadataSchema";
6+
import { LlmApplicationProgrammer } from "./LlmApplicationProgrammer";
7+
8+
export namespace LlmControllerProgrammer {
9+
export interface IWriteProps {
10+
context: ITypiaContext;
11+
modulo: ts.LeftHandSideExpression;
12+
metadata: MetadataSchema;
13+
config?: Partial<
14+
ILlmSchema.IConfig & {
15+
equals: boolean;
16+
}
17+
>;
18+
className?: string;
19+
node: ts.TypeNode;
20+
nameArgument: ts.Expression;
21+
executeArgument: ts.Expression;
22+
configArgument?: ts.Expression;
23+
}
24+
25+
export const write = (props: IWriteProps): ts.Expression => {
26+
const typeNode: ts.ImportTypeNode = props.context.importer.type({
27+
file: "typia",
28+
name: "ILlmController",
29+
arguments: [props.node],
30+
});
31+
const value: ts.ObjectLiteralExpression =
32+
ts.factory.createObjectLiteralExpression(
33+
[
34+
ts.factory.createPropertyAssignment(
35+
"protocol",
36+
ts.factory.createStringLiteral("class"),
37+
),
38+
ts.factory.createPropertyAssignment("name", props.nameArgument),
39+
ts.factory.createPropertyAssignment("execute", props.executeArgument),
40+
ts.factory.createPropertyAssignment(
41+
"application",
42+
LlmApplicationProgrammer.write({
43+
context: props.context,
44+
modulo: props.modulo,
45+
metadata: props.metadata,
46+
config: props.config,
47+
name: props.className,
48+
configArgument: props.configArgument,
49+
}),
50+
),
51+
],
52+
true,
53+
);
54+
return ts.factory.createAsExpression(
55+
ts.factory.createSatisfiesExpression(value, typeNode),
56+
typeNode,
57+
);
58+
};
59+
}

packages/core/src/programmers/llm/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from "./LlmApplicationProgrammer";
2+
export * from "./LlmControllerProgrammer";
23
export * from "./LlmCoerceProgrammer";
34
export * from "./LlmMetadataFactory";
45
export * from "./LlmParametersProgrammer";
Lines changed: 5 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import {
2-
ITypiaContext,
32
LlmApplicationProgrammer,
43
LlmMetadataFactory,
54
MetadataCollection,
65
MetadataFactory,
76
MetadataSchema,
87
} from "@typia/core";
9-
import { ILlmApplication, ILlmSchema, ValidationPipe } from "@typia/interface";
8+
import { ILlmSchema, ValidationPipe } from "@typia/interface";
109
import ts from "typescript";
1110

1211
import { ITransformProps } from "../../ITransformProps";
@@ -80,147 +79,11 @@ export namespace LlmApplicationTransformer {
8079
metadata: analyze(false),
8180
name: top.getFullText().trim(),
8281
config,
82+
configArgument:
83+
props.expression.arguments?.[0] !== undefined
84+
? props.expression.arguments[0]
85+
: undefined,
8386
});
8487
};
8588

86-
/** @internal */
87-
export const decompose = (
88-
method: string,
89-
props: ITransformProps,
90-
): {
91-
application: ILlmApplication.__IPrimitive;
92-
type: ts.Type;
93-
node: ts.TypeNode;
94-
config:
95-
| Partial<
96-
ILlmSchema.IConfig & {
97-
equals: boolean;
98-
}
99-
>
100-
| undefined;
101-
} | null => {
102-
// GET GENERIC ARGUMENT
103-
if (!props.expression.typeArguments?.length)
104-
throw new TransformerError({
105-
code: `typia.llm.${method}`,
106-
message: "no generic argument.",
107-
});
108-
const top: ts.Node = props.expression.typeArguments[0]!;
109-
if (ts.isTypeNode(top) === false) return null;
110-
111-
// GET TYPE
112-
const config:
113-
| Partial<
114-
ILlmSchema.IConfig & {
115-
equals: boolean;
116-
}
117-
>
118-
| undefined = LlmMetadataFactory.getConfig({
119-
context: props.context,
120-
method,
121-
node: props.expression.typeArguments[1],
122-
});
123-
const type: ts.Type = props.context.checker.getTypeFromTypeNode(top);
124-
125-
// VALIDATE TYPE
126-
const analyze = (validate: boolean): MetadataSchema => {
127-
const result: ValidationPipe<MetadataSchema, MetadataFactory.IError> =
128-
MetadataFactory.analyze({
129-
checker: props.context.checker,
130-
transformer: props.context.transformer,
131-
options: {
132-
absorb: validate,
133-
escape: true,
134-
constant: true,
135-
functional: true,
136-
validate:
137-
validate === true
138-
? (next) =>
139-
LlmApplicationProgrammer.validate({
140-
config,
141-
metadata: next.metadata,
142-
explore: next.explore,
143-
top: next.top,
144-
})
145-
: undefined,
146-
},
147-
components: new MetadataCollection({
148-
replace: MetadataCollection.replace,
149-
}),
150-
type,
151-
});
152-
if (result.success === false)
153-
throw TransformerError.from({
154-
code: `typia.llm.${method}`,
155-
errors: result.errors,
156-
});
157-
return result.data;
158-
};
159-
analyze(true);
160-
161-
// GENERATE LLM APPLICATION
162-
return {
163-
application: LlmApplicationProgrammer.writeApplication({
164-
context: props.context,
165-
modulo: props.modulo,
166-
metadata: analyze(false),
167-
config,
168-
name: top.getFullText().trim(),
169-
}),
170-
node: top,
171-
type,
172-
config,
173-
};
174-
};
175-
176-
export const getConfigArgument = (props: {
177-
context: ITypiaContext;
178-
argument: ts.Expression;
179-
equals?: boolean | undefined;
180-
}) => {
181-
const satisfiesTypeNode: ts.TypeNode = ts.factory.createTypeReferenceNode(
182-
ts.factory.createIdentifier("Partial"),
183-
[
184-
ts.factory.createTypeReferenceNode(
185-
ts.factory.createIdentifier("Pick"),
186-
[
187-
ts.factory.createImportTypeNode(
188-
ts.factory.createLiteralTypeNode(
189-
ts.factory.createStringLiteral("typia"),
190-
),
191-
undefined,
192-
ts.factory.createQualifiedName(
193-
ts.factory.createIdentifier("ILlmApplication"),
194-
ts.factory.createIdentifier("IConfig"),
195-
),
196-
undefined,
197-
false,
198-
),
199-
ts.factory.createUnionTypeNode([
200-
ts.factory.createLiteralTypeNode(
201-
ts.factory.createStringLiteral("validate"),
202-
),
203-
]),
204-
],
205-
),
206-
],
207-
);
208-
return ts.factory.createObjectLiteralExpression(
209-
[
210-
ts.factory.createSpreadAssignment(
211-
ts.factory.createSatisfiesExpression(
212-
props.argument,
213-
satisfiesTypeNode,
214-
),
215-
),
216-
ts.factory.createPropertyAssignment(
217-
"equals",
218-
props.equals === true
219-
? ts.factory.createTrue()
220-
: ts.factory.createFalse(),
221-
),
222-
],
223-
true,
224-
);
225-
};
22689
}

0 commit comments

Comments
 (0)