Skip to content

Commit 2d480ab

Browse files
authored
Merge pull request #108 from samchon/feat/separate
Fix parameters separator for empty object case.
2 parents 590e7e7 + d4f4177 commit 2d480ab

7 files changed

+95
-2
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@samchon/openapi",
3-
"version": "2.0.3",
3+
"version": "2.0.4",
44
"description": "OpenAPI definitions and converters for 'typia' and 'nestia'.",
55
"main": "./lib/index.js",
66
"module": "./lib/index.mjs",

src/composers/llm/ChatGptSchemaComposer.ts

+8
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,13 @@ export namespace ChatGptSchemaComposer {
260260
predicate: (schema: IChatGptSchema) => boolean;
261261
schema: IChatGptSchema.IObject;
262262
}): [IChatGptSchema.IObject | null, IChatGptSchema.IObject | null] => {
263+
// EMPTY OBJECT
264+
if (
265+
Object.keys(props.schema.properties ?? {}).length === 0 &&
266+
!!props.schema.additionalProperties === false
267+
)
268+
return [props.schema, null];
269+
263270
const llm = {
264271
...props.schema,
265272
properties: {} as Record<string, IChatGptSchema>,
@@ -268,6 +275,7 @@ export namespace ChatGptSchemaComposer {
268275
...props.schema,
269276
properties: {} as Record<string, IChatGptSchema>,
270277
} satisfies IChatGptSchema.IObject;
278+
271279
for (const [key, value] of Object.entries(props.schema.properties ?? {})) {
272280
const [x, y] = separateStation({
273281
$defs: props.$defs,

src/composers/llm/LlmSchemaV3Composer.ts

+8
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,13 @@ export namespace LlmSchemaV3Composer {
219219
predicate: (schema: ILlmSchemaV3) => boolean;
220220
schema: ILlmSchemaV3.IObject;
221221
}): [ILlmSchemaV3.IObject | null, ILlmSchemaV3.IObject | null] => {
222+
// EMPTY OBJECT
223+
if (
224+
Object.keys(props.schema.properties ?? {}).length === 0 &&
225+
!!props.schema.additionalProperties === false
226+
)
227+
return [props.schema, null];
228+
222229
const llm = {
223230
...props.schema,
224231
properties: {} as Record<string, ILlmSchemaV3>,
@@ -229,6 +236,7 @@ export namespace LlmSchemaV3Composer {
229236
properties: {} as Record<string, ILlmSchemaV3>,
230237
additionalProperties: props.schema.additionalProperties,
231238
} satisfies ILlmSchemaV3.IObject;
239+
232240
for (const [key, value] of Object.entries(props.schema.properties ?? {})) {
233241
const [x, y] = separateStation({
234242
predicate: props.predicate,

src/composers/llm/LlmSchemaV3_1Composer.ts

+8
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,13 @@ export namespace LlmSchemaV3_1Composer {
424424
predicate: (schema: ILlmSchemaV3_1) => boolean;
425425
schema: ILlmSchemaV3_1.IObject;
426426
}): [ILlmSchemaV3_1.IObject | null, ILlmSchemaV3_1.IObject | null] => {
427+
// EMPTY OBJECT
428+
if (
429+
Object.keys(props.schema.properties ?? {}).length === 0 &&
430+
!!props.schema.additionalProperties === false
431+
)
432+
return [props.schema, null];
433+
427434
const llm = {
428435
...props.schema,
429436
properties: {} as Record<string, ILlmSchemaV3_1>,
@@ -433,6 +440,7 @@ export namespace LlmSchemaV3_1Composer {
433440
...props.schema,
434441
properties: {} as Record<string, ILlmSchemaV3_1>,
435442
} satisfies ILlmSchemaV3_1.IObject;
443+
436444
for (const [key, value] of Object.entries(props.schema.properties ?? {})) {
437445
const [x, y] = separateStation({
438446
$defs: props.$defs,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { TestValidator } from "@nestia/e2e";
2+
import {
3+
ILlmSchema,
4+
IOpenApiSchemaError,
5+
IResult,
6+
OpenApi,
7+
OpenApiTypeChecker,
8+
} from "@samchon/openapi";
9+
import { LlmSchemaComposer } from "@samchon/openapi/lib/composers/LlmSchemaComposer";
10+
import typia, { IJsonSchemaCollection } from "typia";
11+
12+
export const test_chatgpt_schema_separate_object_empty = (): void =>
13+
validate_llm_schema_separate_object_empty("chatgpt");
14+
15+
export const test_claude_schema_separate_object_empty = (): void =>
16+
validate_llm_schema_separate_object_empty("claude");
17+
18+
export const test_gemini_schema_separate_object_empty = (): void =>
19+
validate_llm_schema_separate_object_empty("gemini");
20+
21+
export const test_llama_schema_separate_object_empty = (): void =>
22+
validate_llm_schema_separate_object_empty("llama");
23+
24+
export const test_llm_v30_schema_separate_object_empty = (): void =>
25+
validate_llm_schema_separate_object_empty("3.0");
26+
27+
export const test_llm_v31_schema_separate_object_empty = (): void =>
28+
validate_llm_schema_separate_object_empty("3.1");
29+
30+
const validate_llm_schema_separate_object_empty = <
31+
Model extends ILlmSchema.Model,
32+
>(
33+
model: Model,
34+
): void => {
35+
TestValidator.equals("separated")(
36+
LlmSchemaComposer.separateParameters(model)({
37+
predicate: ((schema: OpenApi.IJsonSchema) =>
38+
OpenApiTypeChecker.isInteger(schema)) as any,
39+
parameters: schema(model)(typia.json.schemas<[{}]>()) as any,
40+
}),
41+
)({
42+
llm: schema(model)(typia.json.schemas<[{}]>()) as any,
43+
human: null,
44+
});
45+
};
46+
47+
const schema =
48+
<Model extends ILlmSchema.Model>(model: Model) =>
49+
(collection: IJsonSchemaCollection): ILlmSchema.IParameters<Model> => {
50+
const result: IResult<
51+
ILlmSchema.IParameters<Model>,
52+
IOpenApiSchemaError
53+
> = LlmSchemaComposer.parameters(model)({
54+
components: collection.components,
55+
schema: typia.assert<
56+
OpenApi.IJsonSchema.IObject | OpenApi.IJsonSchema.IReference
57+
>(collection.schemas[0]),
58+
config: LlmSchemaComposer.defaultConfig(
59+
model,
60+
) satisfies ILlmSchema.IConfig<Model> as any,
61+
}) as IResult<ILlmSchema.IParameters<Model>, IOpenApiSchemaError>;
62+
if (result.success === false) throw new Error("Invalid schema");
63+
return result.value;
64+
};

test/utils/ChatGptFunctionCaller.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,11 @@ export namespace ChatGptFunctionCaller {
5858
name: props.name,
5959
description: props.description,
6060
parameters: parameters.value as Record<string, any>,
61-
strict: true,
6261
},
6362
},
6463
],
64+
tool_choice: "required",
65+
parallel_tool_calls: false,
6566
});
6667

6768
const toolCalls: OpenAI.ChatCompletionMessageToolCall[] =

test/utils/ClaudeFunctionCaller.ts

+4
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ export namespace ClaudeFunctionCaller {
6363
input_schema: parameters.value as any,
6464
},
6565
],
66+
tool_choice: {
67+
type: "any",
68+
disable_parallel_tool_use: true,
69+
},
6670
});
6771

6872
const toolCalls: Anthropic.ToolUseBlock[] = completion.content.filter(

0 commit comments

Comments
 (0)