Skip to content

Commit

Permalink
Merge pull request #124 from samchon/feat/length
Browse files Browse the repository at this point in the history
Limit `IHttpLlmFunction.description` length under 1,024.
  • Loading branch information
samchon authored Jan 13, 2025
2 parents 2aa6000 + a355906 commit 0d31c4f
Show file tree
Hide file tree
Showing 30 changed files with 164 additions and 66 deletions.
42 changes: 19 additions & 23 deletions examples/function-calling/arguments/claude.sale.input.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
{
"section_code": "general",
"status": null,
"opened_at": null,
"closed_at": null,
"content": {
"title": "Surface Pro 9",
"format": "md",
"body": "The Surface Pro 9 is a versatile 2-in-1 device that combines the power of a laptop with the flexibility of a tablet. It features advanced technology, making it suitable for both professional and personal use.\n\n- \"Unleash Your Creativity Anywhere\": The Surface Pro 9 is designed for those who need power and portability, making it perfect for creative professionals and students alike.\n- \"The Ultimate 2-in-1 Experience\": With its detachable keyboard and touchscreen capabilities, the Surface Pro 9 adapts to your needs, whether you're working, studying, or relaxing.\n- \"Stay Connected with 5G\": Experience lightning-fast internet speeds and seamless connectivity, no matter where you are.\n- \"Power Meets Flexibility\": The Surface Pro 9 combines the performance of a laptop with the convenience of a tablet, making it the ideal device for multitasking.\n\nIn summary, the Surface Pro 9 stands out as a powerful and flexible device, perfect for users who require both performance and portability. With its advanced features and sleek design, it is an excellent choice for anyone looking to enhance their productivity and creativity. Whether for work or play, the Surface Pro 9 is ready to meet your needs.",
"files": [],
"thumbnails": [
{
"name": "microsoft-surface-pro-9-thumbnail-1",
Expand All @@ -24,7 +22,8 @@
"extension": "jpeg",
"url": "https://serpapi.com/searches/673d3a37e45f3316ecd8ab3e/images/1be25e6e2b1fb7505946d975aac683f8826bcb8c509672de4a5f8c71f149fdef.jpeg"
}
]
],
"files": []
},
"channels": [
{
Expand All @@ -36,11 +35,18 @@
]
}
],
"tags": [
"surface",
"laptop",
"tablet",
"2-in-1",
"microsoft"
],
"units": [
{
"name": "Surface Pro 9 Entity",
"primary": true,
"required": true,
"primary": true,
"options": [
{
"type": "select",
Expand Down Expand Up @@ -93,7 +99,7 @@
],
"stocks": [
{
"name": "Surface Pro 9 (i3/8GB/128GB)",
"name": "i3/8GB/128GB",
"price": {
"nominal": 1000000,
"real": 899000
Expand All @@ -115,7 +121,7 @@
]
},
{
"name": "Surface Pro 9 (i3/16GB/256GB)",
"name": "i3/16GB/256GB",
"price": {
"nominal": 1200000,
"real": 1099000
Expand All @@ -137,7 +143,7 @@
]
},
{
"name": "Surface Pro 9 (i3/16GB/512GB)",
"name": "i3/16GB/512GB",
"price": {
"nominal": 1400000,
"real": 1299000
Expand All @@ -159,7 +165,7 @@
]
},
{
"name": "Surface Pro 9 (i5/16GB/256GB)",
"name": "i5/16GB/256GB",
"price": {
"nominal": 1500000,
"real": 1399000
Expand All @@ -181,7 +187,7 @@
]
},
{
"name": "Surface Pro 9 (i5/32GB/512GB)",
"name": "i5/32GB/512GB",
"price": {
"nominal": 1800000,
"real": 1699000
Expand All @@ -203,7 +209,7 @@
]
},
{
"name": "Surface Pro 9 (i7/16GB/512GB)",
"name": "i7/16GB/512GB",
"price": {
"nominal": 1800000,
"real": 1699000
Expand All @@ -225,7 +231,7 @@
]
},
{
"name": "Surface Pro 9 (i7/32GB/512GB)",
"name": "i7/32GB/512GB",
"price": {
"nominal": 2000000,
"real": 1899000
Expand All @@ -250,8 +256,8 @@
},
{
"name": "Warranty Program",
"primary": false,
"required": false,
"primary": false,
"options": [],
"stocks": [
{
Expand All @@ -267,8 +273,8 @@
},
{
"name": "Magnetic Keyboard",
"primary": false,
"required": false,
"primary": false,
"options": [],
"stocks": [
{
Expand All @@ -282,15 +288,5 @@
}
]
}
],
"tags": [
"Surface",
"Pro",
"9",
"Microsoft",
"2-in-1",
"Tablet",
"Laptop",
"Windows"
]
}
13 changes: 6 additions & 7 deletions examples/function-calling/schemas/claude.sale.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -327,16 +327,16 @@
},
"minItems": 1
},
"required": {
"title": "Whether the unit is required or not",
"description": "Whether the unit is required or not.\n\nWhen the unit is required, the customer must select the unit. If do not\nselect, customer can't buy it.\n\nFor example, if there's a sale \"Macbook Set\" and one of the unit is the\n\"Main Body\", is it possible to buy the \"Macbook Set\" without the\n\"Main Body\" unit? This property is for that case.",
"type": "boolean"
},
"name": {
"title": "Representative name of the unit",
"description": "Representative name of the unit.",
"type": "string"
},
"required": {
"title": "Whether the unit is required or not",
"description": "Whether the unit is required or not.\n\nWhen the unit is required, the customer must select the unit. If do not\nselect, customer can't buy it.\n\nFor example, if there's a sale \"Macbook Set\" and one of the unit is the\n\"Main Body\", is it possible to buy the \"Macbook Set\" without the\n\"Main Body\" unit? This property is for that case.",
"type": "boolean"
},
"primary": {
"title": "Whether the unit is primary or not",
"description": "Whether the unit is primary or not.\n\nJust a labeling value.",
Expand All @@ -346,8 +346,8 @@
"required": [
"options",
"stocks",
"required",
"name",
"required",
"primary"
]
},
Expand All @@ -364,7 +364,6 @@
},
"required": [
"section_code",
"status",
"opened_at",
"closed_at",
"content",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@samchon/openapi",
"version": "2.3.4",
"version": "2.4.0",
"description": "OpenAPI definitions and converters for 'typia' and 'nestia'.",
"main": "./lib/index.js",
"module": "./lib/index.mjs",
Expand Down
37 changes: 25 additions & 12 deletions src/composers/HttpLlmApplicationComposer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,28 @@ export namespace HttpLlmComposer {
: []),
];

// DESCRIPTION
const operation: OpenApi.IOperation = props.route.operation();
const description: [string | undefined, number] = (() => {
if (!operation.summary?.length || !operation.description?.length)
return [
operation.summary || operation.description,
operation.summary?.length ?? operation.description?.length ?? 0,
];
const summary: string = operation.summary.endsWith(".")
? operation.summary.slice(0, -1)
: operation.summary;
const final: string = operation.description.startsWith(summary)
? operation.description
: summary + ".\n\n" + operation.description;
return [final, final.length];
})();
if (description[1] > 1_024) {
props.errors.push(
`The description of the function is too long (must be equal or less than 1,024 characters, but ${description[1].toLocaleString()} length).`,
);
}

// FUNTION NAME
const name: string = emend(props.route.accessor.join("_"));
const isNameVariable: boolean = /^[a-zA-Z0-9_-]+$/.test(name);
Expand All @@ -186,7 +208,8 @@ export namespace HttpLlmComposer {
output === null ||
properties.some(([_k, v]) => v === null) ||
isNameVariable === false ||
isNameStartsWithNumber === true
isNameStartsWithNumber === true ||
description[1] > 1_024
)
return null;

Expand All @@ -201,7 +224,6 @@ export namespace HttpLlmComposer {
} as any as ILlmSchema.ModelParameters[Model];
if (LlmSchemaComposer.isDefs(props.model))
(parameters as any as IChatGptSchema.IParameters).$defs = $defs;
const operation: OpenApi.IOperation = props.route.operation();

// FINALIZATION
return {
Expand All @@ -217,16 +239,7 @@ export namespace HttpLlmComposer {
}) as ILlmFunction.ISeparated<Model>)
: undefined,
output: output as any,
description: (() => {
if (!operation.summary?.length || !operation.description?.length)
return operation.summary || operation.description;
const summary: string = operation.summary.endsWith(".")
? operation.summary.slice(0, -1)
: operation.summary;
return operation.description.startsWith(summary)
? operation.description
: summary + ".\n\n" + operation.description;
})(),
description: description[0],
deprecated: operation.deprecated,
tags: operation.tags,
route: () => props.route as any,
Expand Down
12 changes: 12 additions & 0 deletions test/features/issues/test_issue_104_upgrade_v20_allOf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ export const test_issue_104_upgrade_v20_allOf = async (): Promise<void> => {
TestValidator.predicate("allOf")(
() => JSON.stringify(document).indexOf("#/definitions") === -1,
);
for (const collection of Object.values(document.paths ?? {}))
for (const operation of Object.values(collection))
if (typia.is<OpenApi.IOperation>(operation)) {
const length: number =
(operation.summary?.length ? operation.summary.length + 3 : 0) +
(operation.description?.length ?? 0);
if (length <= 1_024 || operation.description === undefined) continue;
operation.description = operation.description.slice(
0,
operation.description.length - (length - 1_024),
);
}

const app: IHttpLlmApplication<"claude"> = HttpLlm.application({
model: "claude",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const test_chatgpt_function_calling_additionalProperties =
name: "enrollPerson",
description: "Enroll a person to the restaurant reservation list.",
collection: typia.json.schemas<[{ input: IPerson }]>(),
validate: typia.createValidate<[{ input: IPerson }]>(),
validate: typia.createValidate<{ input: IPerson }>(),
texts: [
{
role: "assistant",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import typia from "typia";

import { ChatGptFunctionCaller } from "../../../utils/ChatGptFunctionCaller";

export const test_chatgpt_function_calling_description_length = async () => {
await ChatGptFunctionCaller.test({
config: {
reference: true,
},
name: "testLength",
description: "가".repeat(1_024),
collection: typia.json.schemas<[{ input: IPerson }]>(),
validate: typia.createValidate<{ input: IPerson }>(),
texts: [
{
role: "assistant",
content: SYSTEM_MESSAGE,
},
{
role: "user",
content: USER_MESSAGE,
},
],
handleCompletion: async (input) => {
typia.assert<IPerson>(input);
},
});
};

interface IPerson {
name: string;
age: number;
}

const SYSTEM_MESSAGE =
"You are a helpful customer support assistant. Use the supplied tools to assist the user.";

const USER_MESSAGE =
"Just enroll a person whose name and age values 'John Doe' and 42 years old.";
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const test_chatgpt_function_calling_example = () =>
name: "enrollPerson",
description: "Enroll a person to the restaurant reservation list.",
collection: typia.json.schemas<[{ input: IPerson }]>(),
validate: typia.createValidate<[{ input: IPerson }]>(),
validate: typia.createValidate<{ input: IPerson }>(),
texts: [
{
role: "assistant",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import typia from "typia";

import { ChatGptFunctionCaller } from "../../../utils/ChatGptFunctionCaller";

export const test_chatgpt_function_calling_name_length = async () => {
await ChatGptFunctionCaller.test({
config: {
reference: true,
},
name: "A".repeat(64),
description: "Enroll a person information.",
collection: typia.json.schemas<[{ input: IPerson }]>(),
validate: typia.createValidate<{ input: IPerson }>(),
texts: [
{
role: "assistant",
content: SYSTEM_MESSAGE,
},
{
role: "user",
content: USER_MESSAGE,
},
],
handleCompletion: async (input) => {
typia.assert<IPerson>(input);
},
});
};

interface IPerson {
name: string;
age: number;
}

const SYSTEM_MESSAGE =
"You are a helpful customer support assistant. Use the supplied tools to assist the user.";

const USER_MESSAGE =
"Just enroll a person whose name and age values 'John Doe' and 42 years old.";
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const test_chatgpt_function_calling_optional = () =>
name: "registerMember",
description: "Register a membership.",
collection: typia.json.schemas<[{ input: IMember; note?: string }]>(),
validate: typia.createValidate<[{ input: IMember; note?: string }]>(),
validate: typia.createValidate<{ input: IMember; note?: string }>(),
texts: [
{
role: "assistant",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const test_chatgpt_function_calling_recursive = () =>
name: "composeCategories",
description: "Compose categories from the input.",
collection: typia.json.schemas<[{ input: IShoppingCategory[] }]>(),
validate: typia.createValidate<[{ input: IShoppingCategory[] }]>(),
validate: typia.createValidate<{ input: IShoppingCategory[] }>(),
texts: [
{
role: "assistant",
Expand Down
Loading

0 comments on commit 0d31c4f

Please sign in to comment.