@typia/vercel 12.0.0-dev.20260309 → 12.0.0-dev.20260310
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +11 -9
- package/lib/index.js +8 -6
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +8 -6
- package/lib/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +105 -103
- package/src/internal/VercelToolsRegistrar.ts +180 -180
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Tool } from "ai";
|
|
2
1
|
import { IHttpLlmController, ILlmController } from "@typia/interface";
|
|
2
|
+
import type { Tool } from "ai";
|
|
3
3
|
/**
|
|
4
4
|
* Convert typia controllers to Vercel AI SDK tools.
|
|
5
5
|
*
|
|
@@ -8,8 +8,8 @@ import { IHttpLlmController, ILlmController } from "@typia/interface";
|
|
|
8
8
|
* can be used with any LLM provider (OpenAI, Anthropic, Google, etc.).
|
|
9
9
|
*
|
|
10
10
|
* Every tool call is validated by typia. If the LLM provides invalid arguments,
|
|
11
|
-
* returns a validation error formatted by {@link LlmJson.stringify}
|
|
12
|
-
*
|
|
11
|
+
* returns a validation error formatted by {@link LlmJson.stringify} so the LLM
|
|
12
|
+
* can auto-correct in the next turn.
|
|
13
13
|
*
|
|
14
14
|
* ## Example with OpenAI
|
|
15
15
|
*
|
|
@@ -39,9 +39,9 @@ import { IHttpLlmController, ILlmController } from "@typia/interface";
|
|
|
39
39
|
* ## Example with Anthropic
|
|
40
40
|
*
|
|
41
41
|
* ```typescript
|
|
42
|
-
* import { generateText } from "ai";
|
|
43
42
|
* import { anthropic } from "@ai-sdk/anthropic";
|
|
44
43
|
* import { toVercelTools } from "@typia/vercel";
|
|
44
|
+
* import { generateText } from "ai";
|
|
45
45
|
*
|
|
46
46
|
* const result = await generateText({
|
|
47
47
|
* model: anthropic("claude-sonnet-4-20250514"),
|
|
@@ -53,14 +53,16 @@ import { IHttpLlmController, ILlmController } from "@typia/interface";
|
|
|
53
53
|
* ## Example with HTTP Controller (OpenAPI)
|
|
54
54
|
*
|
|
55
55
|
* ```typescript
|
|
56
|
-
* import { generateText } from "ai";
|
|
57
56
|
* import { openai } from "@ai-sdk/openai";
|
|
58
57
|
* import { HttpLlm } from "@typia/utils";
|
|
59
58
|
* import { toVercelTools } from "@typia/vercel";
|
|
59
|
+
* import { generateText } from "ai";
|
|
60
60
|
*
|
|
61
61
|
* const controller = HttpLlm.controller({
|
|
62
62
|
* name: "shopping",
|
|
63
|
-
* document: await fetch("https://api.example.com/swagger.json").then(
|
|
63
|
+
* document: await fetch("https://api.example.com/swagger.json").then(
|
|
64
|
+
* (r) => r.json(),
|
|
65
|
+
* ),
|
|
64
66
|
* connection: { host: "https://api.example.com" },
|
|
65
67
|
* });
|
|
66
68
|
*
|
|
@@ -71,9 +73,9 @@ import { IHttpLlmController, ILlmController } from "@typia/interface";
|
|
|
71
73
|
* });
|
|
72
74
|
* ```
|
|
73
75
|
*
|
|
76
|
+
* @author Jeongho Nam - https://github.com/samchon
|
|
74
77
|
* @param props Conversion properties
|
|
75
78
|
* @returns Record of Vercel AI SDK Tools keyed by tool name
|
|
76
|
-
* @author Jeongho Nam - https://github.com/samchon
|
|
77
79
|
*/
|
|
78
80
|
export declare function toVercelTools(props: {
|
|
79
81
|
/**
|
|
@@ -88,8 +90,8 @@ export declare function toVercelTools(props: {
|
|
|
88
90
|
/**
|
|
89
91
|
* Whether to prefix tool names with controller name.
|
|
90
92
|
*
|
|
91
|
-
* If `true`, tool names are formatted as `{controller}_{function}`.
|
|
92
|
-
*
|
|
93
|
+
* If `true`, tool names are formatted as `{controller}_{function}`. If
|
|
94
|
+
* `false`, only the function name is used (may cause conflicts).
|
|
93
95
|
*
|
|
94
96
|
* @default true
|
|
95
97
|
*/
|
package/lib/index.js
CHANGED
|
@@ -10,8 +10,8 @@ const VercelToolsRegistrar_1 = require("./internal/VercelToolsRegistrar");
|
|
|
10
10
|
* can be used with any LLM provider (OpenAI, Anthropic, Google, etc.).
|
|
11
11
|
*
|
|
12
12
|
* Every tool call is validated by typia. If the LLM provides invalid arguments,
|
|
13
|
-
* returns a validation error formatted by {@link LlmJson.stringify}
|
|
14
|
-
*
|
|
13
|
+
* returns a validation error formatted by {@link LlmJson.stringify} so the LLM
|
|
14
|
+
* can auto-correct in the next turn.
|
|
15
15
|
*
|
|
16
16
|
* ## Example with OpenAI
|
|
17
17
|
*
|
|
@@ -41,9 +41,9 @@ const VercelToolsRegistrar_1 = require("./internal/VercelToolsRegistrar");
|
|
|
41
41
|
* ## Example with Anthropic
|
|
42
42
|
*
|
|
43
43
|
* ```typescript
|
|
44
|
-
* import { generateText } from "ai";
|
|
45
44
|
* import { anthropic } from "@ai-sdk/anthropic";
|
|
46
45
|
* import { toVercelTools } from "@typia/vercel";
|
|
46
|
+
* import { generateText } from "ai";
|
|
47
47
|
*
|
|
48
48
|
* const result = await generateText({
|
|
49
49
|
* model: anthropic("claude-sonnet-4-20250514"),
|
|
@@ -55,14 +55,16 @@ const VercelToolsRegistrar_1 = require("./internal/VercelToolsRegistrar");
|
|
|
55
55
|
* ## Example with HTTP Controller (OpenAPI)
|
|
56
56
|
*
|
|
57
57
|
* ```typescript
|
|
58
|
-
* import { generateText } from "ai";
|
|
59
58
|
* import { openai } from "@ai-sdk/openai";
|
|
60
59
|
* import { HttpLlm } from "@typia/utils";
|
|
61
60
|
* import { toVercelTools } from "@typia/vercel";
|
|
61
|
+
* import { generateText } from "ai";
|
|
62
62
|
*
|
|
63
63
|
* const controller = HttpLlm.controller({
|
|
64
64
|
* name: "shopping",
|
|
65
|
-
* document: await fetch("https://api.example.com/swagger.json").then(
|
|
65
|
+
* document: await fetch("https://api.example.com/swagger.json").then(
|
|
66
|
+
* (r) => r.json(),
|
|
67
|
+
* ),
|
|
66
68
|
* connection: { host: "https://api.example.com" },
|
|
67
69
|
* });
|
|
68
70
|
*
|
|
@@ -73,9 +75,9 @@ const VercelToolsRegistrar_1 = require("./internal/VercelToolsRegistrar");
|
|
|
73
75
|
* });
|
|
74
76
|
* ```
|
|
75
77
|
*
|
|
78
|
+
* @author Jeongho Nam - https://github.com/samchon
|
|
76
79
|
* @param props Conversion properties
|
|
77
80
|
* @returns Record of Vercel AI SDK Tools keyed by tool name
|
|
78
|
-
* @author Jeongho Nam - https://github.com/samchon
|
|
79
81
|
*/
|
|
80
82
|
function toVercelTools(props) {
|
|
81
83
|
return VercelToolsRegistrar_1.VercelToolsRegistrar.convert(props);
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAkFA,sCAsBC;AArGD,0EAAuE;AAEvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4EG;AACH,SAAgB,aAAa,CAAC,KAoB7B;IACC,OAAO,2CAAoB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7C,CAAC"}
|
package/lib/index.mjs
CHANGED
|
@@ -8,8 +8,8 @@ import { VercelToolsRegistrar } from './internal/VercelToolsRegistrar.mjs';
|
|
|
8
8
|
* can be used with any LLM provider (OpenAI, Anthropic, Google, etc.).
|
|
9
9
|
*
|
|
10
10
|
* Every tool call is validated by typia. If the LLM provides invalid arguments,
|
|
11
|
-
* returns a validation error formatted by {@link LlmJson.stringify}
|
|
12
|
-
*
|
|
11
|
+
* returns a validation error formatted by {@link LlmJson.stringify} so the LLM
|
|
12
|
+
* can auto-correct in the next turn.
|
|
13
13
|
*
|
|
14
14
|
* ## Example with OpenAI
|
|
15
15
|
*
|
|
@@ -39,9 +39,9 @@ import { VercelToolsRegistrar } from './internal/VercelToolsRegistrar.mjs';
|
|
|
39
39
|
* ## Example with Anthropic
|
|
40
40
|
*
|
|
41
41
|
* ```typescript
|
|
42
|
-
* import { generateText } from "ai";
|
|
43
42
|
* import { anthropic } from "@ai-sdk/anthropic";
|
|
44
43
|
* import { toVercelTools } from "@typia/vercel";
|
|
44
|
+
* import { generateText } from "ai";
|
|
45
45
|
*
|
|
46
46
|
* const result = await generateText({
|
|
47
47
|
* model: anthropic("claude-sonnet-4-20250514"),
|
|
@@ -53,14 +53,16 @@ import { VercelToolsRegistrar } from './internal/VercelToolsRegistrar.mjs';
|
|
|
53
53
|
* ## Example with HTTP Controller (OpenAPI)
|
|
54
54
|
*
|
|
55
55
|
* ```typescript
|
|
56
|
-
* import { generateText } from "ai";
|
|
57
56
|
* import { openai } from "@ai-sdk/openai";
|
|
58
57
|
* import { HttpLlm } from "@typia/utils";
|
|
59
58
|
* import { toVercelTools } from "@typia/vercel";
|
|
59
|
+
* import { generateText } from "ai";
|
|
60
60
|
*
|
|
61
61
|
* const controller = HttpLlm.controller({
|
|
62
62
|
* name: "shopping",
|
|
63
|
-
* document: await fetch("https://api.example.com/swagger.json").then(
|
|
63
|
+
* document: await fetch("https://api.example.com/swagger.json").then(
|
|
64
|
+
* (r) => r.json(),
|
|
65
|
+
* ),
|
|
64
66
|
* connection: { host: "https://api.example.com" },
|
|
65
67
|
* });
|
|
66
68
|
*
|
|
@@ -71,9 +73,9 @@ import { VercelToolsRegistrar } from './internal/VercelToolsRegistrar.mjs';
|
|
|
71
73
|
* });
|
|
72
74
|
* ```
|
|
73
75
|
*
|
|
76
|
+
* @author Jeongho Nam - https://github.com/samchon
|
|
74
77
|
* @param props Conversion properties
|
|
75
78
|
* @returns Record of Vercel AI SDK Tools keyed by tool name
|
|
76
|
-
* @author Jeongho Nam - https://github.com/samchon
|
|
77
79
|
*/
|
|
78
80
|
function toVercelTools(props) {
|
|
79
81
|
return VercelToolsRegistrar.convert(props);
|
package/lib/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAKA
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4EG;AACG,SAAU,aAAa,CAAC,KAoB7B,EAAA;AACC,IAAA,OAAO,oBAAoB,CAAC,OAAO,CAAC,KAAK,CAAC;AAC5C;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typia/vercel",
|
|
3
|
-
"version": "12.0.0-dev.
|
|
3
|
+
"version": "12.0.0-dev.20260310",
|
|
4
4
|
"description": "Vercel AI SDK integration for typia",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
},
|
|
23
23
|
"homepage": "https://typia.io",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@typia/
|
|
26
|
-
"@typia/
|
|
25
|
+
"@typia/utils": "^12.0.0-dev.20260310",
|
|
26
|
+
"@typia/interface": "^12.0.0-dev.20260310"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
29
|
"ai": ">=4.0.0"
|
package/src/index.ts
CHANGED
|
@@ -1,103 +1,105 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { VercelToolsRegistrar } from "./internal/VercelToolsRegistrar";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Convert typia controllers to Vercel AI SDK tools.
|
|
8
|
-
*
|
|
9
|
-
* Transforms TypeScript class methods via `typia.llm.controller<Class>()` or
|
|
10
|
-
* OpenAPI operations via `HttpLlm.controller()` into Vercel AI SDK tools that
|
|
11
|
-
* can be used with any LLM provider (OpenAI, Anthropic, Google, etc.).
|
|
12
|
-
*
|
|
13
|
-
* Every tool call is validated by typia. If the LLM provides invalid arguments,
|
|
14
|
-
* returns a validation error formatted by {@link LlmJson.stringify}
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* ## Example with OpenAI
|
|
18
|
-
*
|
|
19
|
-
* ```typescript
|
|
20
|
-
* import { generateText } from "ai";
|
|
21
|
-
* import { openai } from "@ai-sdk/openai";
|
|
22
|
-
* import typia from "typia";
|
|
23
|
-
* import { toVercelTools } from "@typia/vercel";
|
|
24
|
-
*
|
|
25
|
-
* class Calculator {
|
|
26
|
-
* /** Add two numbers together. */
|
|
27
|
-
* add(props: { a: number; b: number }): number {
|
|
28
|
-
* return props.a + props.b;
|
|
29
|
-
* }
|
|
30
|
-
* }
|
|
31
|
-
*
|
|
32
|
-
* const controller = typia.llm.controller<Calculator>("calc", new Calculator());
|
|
33
|
-
* const tools = toVercelTools({ controllers: [controller] });
|
|
34
|
-
*
|
|
35
|
-
* const result = await generateText({
|
|
36
|
-
* model: openai("gpt-4o"),
|
|
37
|
-
* tools,
|
|
38
|
-
* prompt: "What is 15 + 27?",
|
|
39
|
-
* });
|
|
40
|
-
* ```
|
|
41
|
-
*
|
|
42
|
-
* ## Example with Anthropic
|
|
43
|
-
*
|
|
44
|
-
* ```typescript
|
|
45
|
-
* import {
|
|
46
|
-
* import {
|
|
47
|
-
* import {
|
|
48
|
-
*
|
|
49
|
-
* const result = await generateText({
|
|
50
|
-
* model: anthropic("claude-sonnet-4-20250514"),
|
|
51
|
-
* tools: toVercelTools({ controllers: [controller] }),
|
|
52
|
-
* prompt: "Calculate 100 * 50",
|
|
53
|
-
* });
|
|
54
|
-
* ```
|
|
55
|
-
*
|
|
56
|
-
* ## Example with HTTP Controller (OpenAPI)
|
|
57
|
-
*
|
|
58
|
-
* ```typescript
|
|
59
|
-
* import {
|
|
60
|
-
* import {
|
|
61
|
-
* import {
|
|
62
|
-
* import {
|
|
63
|
-
*
|
|
64
|
-
* const controller = HttpLlm.controller({
|
|
65
|
-
* name: "shopping",
|
|
66
|
-
* document: await fetch("https://api.example.com/swagger.json").then(
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* })
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* @author Jeongho Nam - https://github.com/samchon
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* - {@link
|
|
88
|
-
*
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
1
|
+
import { IHttpLlmController, ILlmController } from "@typia/interface";
|
|
2
|
+
import type { Tool } from "ai";
|
|
3
|
+
|
|
4
|
+
import { VercelToolsRegistrar } from "./internal/VercelToolsRegistrar";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Convert typia controllers to Vercel AI SDK tools.
|
|
8
|
+
*
|
|
9
|
+
* Transforms TypeScript class methods via `typia.llm.controller<Class>()` or
|
|
10
|
+
* OpenAPI operations via `HttpLlm.controller()` into Vercel AI SDK tools that
|
|
11
|
+
* can be used with any LLM provider (OpenAI, Anthropic, Google, etc.).
|
|
12
|
+
*
|
|
13
|
+
* Every tool call is validated by typia. If the LLM provides invalid arguments,
|
|
14
|
+
* returns a validation error formatted by {@link LlmJson.stringify} so the LLM
|
|
15
|
+
* can auto-correct in the next turn.
|
|
16
|
+
*
|
|
17
|
+
* ## Example with OpenAI
|
|
18
|
+
*
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { generateText } from "ai";
|
|
21
|
+
* import { openai } from "@ai-sdk/openai";
|
|
22
|
+
* import typia from "typia";
|
|
23
|
+
* import { toVercelTools } from "@typia/vercel";
|
|
24
|
+
*
|
|
25
|
+
* class Calculator {
|
|
26
|
+
* /** Add two numbers together. */
|
|
27
|
+
* add(props: { a: number; b: number }): number {
|
|
28
|
+
* return props.a + props.b;
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
* const controller = typia.llm.controller<Calculator>("calc", new Calculator());
|
|
33
|
+
* const tools = toVercelTools({ controllers: [controller] });
|
|
34
|
+
*
|
|
35
|
+
* const result = await generateText({
|
|
36
|
+
* model: openai("gpt-4o"),
|
|
37
|
+
* tools,
|
|
38
|
+
* prompt: "What is 15 + 27?",
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* ## Example with Anthropic
|
|
43
|
+
*
|
|
44
|
+
* ```typescript
|
|
45
|
+
* import { anthropic } from "@ai-sdk/anthropic";
|
|
46
|
+
* import { toVercelTools } from "@typia/vercel";
|
|
47
|
+
* import { generateText } from "ai";
|
|
48
|
+
*
|
|
49
|
+
* const result = await generateText({
|
|
50
|
+
* model: anthropic("claude-sonnet-4-20250514"),
|
|
51
|
+
* tools: toVercelTools({ controllers: [controller] }),
|
|
52
|
+
* prompt: "Calculate 100 * 50",
|
|
53
|
+
* });
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* ## Example with HTTP Controller (OpenAPI)
|
|
57
|
+
*
|
|
58
|
+
* ```typescript
|
|
59
|
+
* import { openai } from "@ai-sdk/openai";
|
|
60
|
+
* import { HttpLlm } from "@typia/utils";
|
|
61
|
+
* import { toVercelTools } from "@typia/vercel";
|
|
62
|
+
* import { generateText } from "ai";
|
|
63
|
+
*
|
|
64
|
+
* const controller = HttpLlm.controller({
|
|
65
|
+
* name: "shopping",
|
|
66
|
+
* document: await fetch("https://api.example.com/swagger.json").then(
|
|
67
|
+
* (r) => r.json(),
|
|
68
|
+
* ),
|
|
69
|
+
* connection: { host: "https://api.example.com" },
|
|
70
|
+
* });
|
|
71
|
+
*
|
|
72
|
+
* const result = await generateText({
|
|
73
|
+
* model: openai("gpt-4o"),
|
|
74
|
+
* tools: toVercelTools({ controllers: [controller] }),
|
|
75
|
+
* prompt: "Search for laptops under $1000",
|
|
76
|
+
* });
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* @author Jeongho Nam - https://github.com/samchon
|
|
80
|
+
* @param props Conversion properties
|
|
81
|
+
* @returns Record of Vercel AI SDK Tools keyed by tool name
|
|
82
|
+
*/
|
|
83
|
+
export function toVercelTools(props: {
|
|
84
|
+
/**
|
|
85
|
+
* List of controllers to convert to Vercel tools.
|
|
86
|
+
*
|
|
87
|
+
* - {@link ILlmController}: from `typia.llm.controller<Class>()`, converts all
|
|
88
|
+
* methods of the class to tools
|
|
89
|
+
* - {@link IHttpLlmController}: from `HttpLlm.controller()`, converts all
|
|
90
|
+
* operations from OpenAPI document to tools
|
|
91
|
+
*/
|
|
92
|
+
controllers: Array<ILlmController | IHttpLlmController>;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Whether to prefix tool names with controller name.
|
|
96
|
+
*
|
|
97
|
+
* If `true`, tool names are formatted as `{controller}_{function}`. If
|
|
98
|
+
* `false`, only the function name is used (may cause conflicts).
|
|
99
|
+
*
|
|
100
|
+
* @default true
|
|
101
|
+
*/
|
|
102
|
+
prefix?: boolean | undefined;
|
|
103
|
+
}): Record<string, Tool> {
|
|
104
|
+
return VercelToolsRegistrar.convert(props);
|
|
105
|
+
}
|
|
@@ -1,180 +1,180 @@
|
|
|
1
|
-
import {
|
|
2
|
-
IHttpLlmController,
|
|
3
|
-
IHttpLlmFunction,
|
|
4
|
-
ILlmController,
|
|
5
|
-
ILlmFunction,
|
|
6
|
-
ILlmSchema,
|
|
7
|
-
IValidation,
|
|
8
|
-
} from "@typia/interface";
|
|
9
|
-
import { HttpLlm, LlmJson } from "@typia/utils";
|
|
10
|
-
import { jsonSchema, tool } from "ai";
|
|
11
|
-
import type { Tool } from "ai";
|
|
12
|
-
import type { JSONSchema7 } from "json-schema";
|
|
13
|
-
|
|
14
|
-
export namespace VercelToolsRegistrar {
|
|
15
|
-
/**
|
|
16
|
-
* Convert typia controllers to Vercel AI SDK tools.
|
|
17
|
-
*
|
|
18
|
-
* @param props Conversion properties
|
|
19
|
-
* @returns Record of Vercel AI SDK Tools
|
|
20
|
-
*/
|
|
21
|
-
export const convert = (props: {
|
|
22
|
-
controllers: Array<ILlmController | IHttpLlmController>;
|
|
23
|
-
prefix?: boolean | undefined;
|
|
24
|
-
}): Record<string, Tool> => {
|
|
25
|
-
const tools: Record<string, Tool> = {};
|
|
26
|
-
const prefix: boolean = props.prefix ?? true;
|
|
27
|
-
|
|
28
|
-
for (const controller of props.controllers) {
|
|
29
|
-
if (controller.protocol === "class") {
|
|
30
|
-
registerClassController({
|
|
31
|
-
tools,
|
|
32
|
-
controller,
|
|
33
|
-
prefix,
|
|
34
|
-
});
|
|
35
|
-
} else {
|
|
36
|
-
registerHttpController({
|
|
37
|
-
tools,
|
|
38
|
-
controller,
|
|
39
|
-
prefix,
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return tools;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const registerClassController = (props: {
|
|
48
|
-
tools: Record<string, Tool>;
|
|
49
|
-
controller: ILlmController;
|
|
50
|
-
prefix: boolean;
|
|
51
|
-
}): void => {
|
|
52
|
-
const { tools, controller, prefix } = props;
|
|
53
|
-
const execute: Record<string, unknown> = controller.execute;
|
|
54
|
-
|
|
55
|
-
for (const func of controller.application.functions) {
|
|
56
|
-
const toolName: string = prefix
|
|
57
|
-
? `${controller.name}_${func.name}`
|
|
58
|
-
: func.name;
|
|
59
|
-
|
|
60
|
-
if (tools[toolName] !== undefined) {
|
|
61
|
-
throw new Error(
|
|
62
|
-
`Duplicate tool name "${toolName}" from controller "${controller.name}"`,
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const method: unknown = execute[func.name];
|
|
67
|
-
if (typeof method !== "function") {
|
|
68
|
-
throw new Error(
|
|
69
|
-
`Method "${func.name}" not found on controller "${controller.name}"`,
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
tools[toolName] = createTool({
|
|
74
|
-
func,
|
|
75
|
-
execute: async (args: unknown) => method.call(execute, args),
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const registerHttpController = (props: {
|
|
81
|
-
tools: Record<string, Tool>;
|
|
82
|
-
controller: IHttpLlmController;
|
|
83
|
-
prefix: boolean;
|
|
84
|
-
}): void => {
|
|
85
|
-
const { tools, controller, prefix } = props;
|
|
86
|
-
const application = controller.application;
|
|
87
|
-
const connection = controller.connection;
|
|
88
|
-
|
|
89
|
-
for (const func of application.functions) {
|
|
90
|
-
const toolName: string = prefix
|
|
91
|
-
? `${controller.name}_${func.name}`
|
|
92
|
-
: func.name;
|
|
93
|
-
|
|
94
|
-
if (tools[toolName] !== undefined) {
|
|
95
|
-
throw new Error(
|
|
96
|
-
`Duplicate tool name "${toolName}" from controller "${controller.name}"`,
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
tools[toolName] = createTool({
|
|
101
|
-
func,
|
|
102
|
-
execute: async (args: unknown) => {
|
|
103
|
-
if (controller.execute !== undefined) {
|
|
104
|
-
const response = await controller.execute({
|
|
105
|
-
connection,
|
|
106
|
-
application,
|
|
107
|
-
function: func,
|
|
108
|
-
arguments: args as object,
|
|
109
|
-
});
|
|
110
|
-
return response.body;
|
|
111
|
-
}
|
|
112
|
-
return HttpLlm.execute({
|
|
113
|
-
application,
|
|
114
|
-
function: func,
|
|
115
|
-
connection,
|
|
116
|
-
input: args as object,
|
|
117
|
-
});
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
const createTool = (props: {
|
|
124
|
-
func: ILlmFunction | IHttpLlmFunction;
|
|
125
|
-
execute: (args: unknown) => Promise<unknown>;
|
|
126
|
-
}): Tool => {
|
|
127
|
-
const { func, execute } = props;
|
|
128
|
-
|
|
129
|
-
return tool({
|
|
130
|
-
description: func.description,
|
|
131
|
-
|
|
132
|
-
// Convert ILlmSchema.IParameters to Vercel jsonSchema
|
|
133
|
-
parameters: jsonSchema<object>(
|
|
134
|
-
convertParameters(func.parameters) as JSONSchema7,
|
|
135
|
-
),
|
|
136
|
-
|
|
137
|
-
execute: async (args: object) => {
|
|
138
|
-
// Coerce and validate using typia's built-in functions
|
|
139
|
-
const coerced: unknown = LlmJson.coerce(args, func.parameters);
|
|
140
|
-
const validation: IValidation<unknown> = func.validate(coerced);
|
|
141
|
-
if (!validation.success) {
|
|
142
|
-
// Return validation error in LLM-friendly format
|
|
143
|
-
return {
|
|
144
|
-
error: true,
|
|
145
|
-
message: LlmJson.stringify(validation),
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
try {
|
|
150
|
-
const result: unknown = await execute(validation.data);
|
|
151
|
-
return result === undefined ? { success: true } : result;
|
|
152
|
-
} catch (error) {
|
|
153
|
-
return {
|
|
154
|
-
error: true,
|
|
155
|
-
message:
|
|
156
|
-
error instanceof Error
|
|
157
|
-
? `${error.name}: ${error.message}`
|
|
158
|
-
: String(error),
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
},
|
|
162
|
-
});
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
const convertParameters = (params: ILlmSchema.IParameters): JSONSchema7 => {
|
|
166
|
-
const schema: JSONSchema7 = {
|
|
167
|
-
type: "object",
|
|
168
|
-
properties: params.properties as JSONSchema7["properties"],
|
|
169
|
-
required: params.required,
|
|
170
|
-
additionalProperties: params.additionalProperties,
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
// Add $defs if present
|
|
174
|
-
if (Object.keys(params.$defs).length > 0) {
|
|
175
|
-
schema.$defs = params.$defs as JSONSchema7["$defs"];
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return schema;
|
|
179
|
-
};
|
|
180
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
IHttpLlmController,
|
|
3
|
+
IHttpLlmFunction,
|
|
4
|
+
ILlmController,
|
|
5
|
+
ILlmFunction,
|
|
6
|
+
ILlmSchema,
|
|
7
|
+
IValidation,
|
|
8
|
+
} from "@typia/interface";
|
|
9
|
+
import { HttpLlm, LlmJson } from "@typia/utils";
|
|
10
|
+
import { jsonSchema, tool } from "ai";
|
|
11
|
+
import type { Tool } from "ai";
|
|
12
|
+
import type { JSONSchema7 } from "json-schema";
|
|
13
|
+
|
|
14
|
+
export namespace VercelToolsRegistrar {
|
|
15
|
+
/**
|
|
16
|
+
* Convert typia controllers to Vercel AI SDK tools.
|
|
17
|
+
*
|
|
18
|
+
* @param props Conversion properties
|
|
19
|
+
* @returns Record of Vercel AI SDK Tools
|
|
20
|
+
*/
|
|
21
|
+
export const convert = (props: {
|
|
22
|
+
controllers: Array<ILlmController | IHttpLlmController>;
|
|
23
|
+
prefix?: boolean | undefined;
|
|
24
|
+
}): Record<string, Tool> => {
|
|
25
|
+
const tools: Record<string, Tool> = {};
|
|
26
|
+
const prefix: boolean = props.prefix ?? true;
|
|
27
|
+
|
|
28
|
+
for (const controller of props.controllers) {
|
|
29
|
+
if (controller.protocol === "class") {
|
|
30
|
+
registerClassController({
|
|
31
|
+
tools,
|
|
32
|
+
controller,
|
|
33
|
+
prefix,
|
|
34
|
+
});
|
|
35
|
+
} else {
|
|
36
|
+
registerHttpController({
|
|
37
|
+
tools,
|
|
38
|
+
controller,
|
|
39
|
+
prefix,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return tools;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const registerClassController = (props: {
|
|
48
|
+
tools: Record<string, Tool>;
|
|
49
|
+
controller: ILlmController;
|
|
50
|
+
prefix: boolean;
|
|
51
|
+
}): void => {
|
|
52
|
+
const { tools, controller, prefix } = props;
|
|
53
|
+
const execute: Record<string, unknown> = controller.execute;
|
|
54
|
+
|
|
55
|
+
for (const func of controller.application.functions) {
|
|
56
|
+
const toolName: string = prefix
|
|
57
|
+
? `${controller.name}_${func.name}`
|
|
58
|
+
: func.name;
|
|
59
|
+
|
|
60
|
+
if (tools[toolName] !== undefined) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`Duplicate tool name "${toolName}" from controller "${controller.name}"`,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const method: unknown = execute[func.name];
|
|
67
|
+
if (typeof method !== "function") {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Method "${func.name}" not found on controller "${controller.name}"`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
tools[toolName] = createTool({
|
|
74
|
+
func,
|
|
75
|
+
execute: async (args: unknown) => method.call(execute, args),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const registerHttpController = (props: {
|
|
81
|
+
tools: Record<string, Tool>;
|
|
82
|
+
controller: IHttpLlmController;
|
|
83
|
+
prefix: boolean;
|
|
84
|
+
}): void => {
|
|
85
|
+
const { tools, controller, prefix } = props;
|
|
86
|
+
const application = controller.application;
|
|
87
|
+
const connection = controller.connection;
|
|
88
|
+
|
|
89
|
+
for (const func of application.functions) {
|
|
90
|
+
const toolName: string = prefix
|
|
91
|
+
? `${controller.name}_${func.name}`
|
|
92
|
+
: func.name;
|
|
93
|
+
|
|
94
|
+
if (tools[toolName] !== undefined) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`Duplicate tool name "${toolName}" from controller "${controller.name}"`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
tools[toolName] = createTool({
|
|
101
|
+
func,
|
|
102
|
+
execute: async (args: unknown) => {
|
|
103
|
+
if (controller.execute !== undefined) {
|
|
104
|
+
const response = await controller.execute({
|
|
105
|
+
connection,
|
|
106
|
+
application,
|
|
107
|
+
function: func,
|
|
108
|
+
arguments: args as object,
|
|
109
|
+
});
|
|
110
|
+
return response.body;
|
|
111
|
+
}
|
|
112
|
+
return HttpLlm.execute({
|
|
113
|
+
application,
|
|
114
|
+
function: func,
|
|
115
|
+
connection,
|
|
116
|
+
input: args as object,
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const createTool = (props: {
|
|
124
|
+
func: ILlmFunction | IHttpLlmFunction;
|
|
125
|
+
execute: (args: unknown) => Promise<unknown>;
|
|
126
|
+
}): Tool => {
|
|
127
|
+
const { func, execute } = props;
|
|
128
|
+
|
|
129
|
+
return tool({
|
|
130
|
+
description: func.description,
|
|
131
|
+
|
|
132
|
+
// Convert ILlmSchema.IParameters to Vercel jsonSchema
|
|
133
|
+
parameters: jsonSchema<object>(
|
|
134
|
+
convertParameters(func.parameters) as JSONSchema7,
|
|
135
|
+
),
|
|
136
|
+
|
|
137
|
+
execute: async (args: object) => {
|
|
138
|
+
// Coerce and validate using typia's built-in functions
|
|
139
|
+
const coerced: unknown = LlmJson.coerce(args, func.parameters);
|
|
140
|
+
const validation: IValidation<unknown> = func.validate(coerced);
|
|
141
|
+
if (!validation.success) {
|
|
142
|
+
// Return validation error in LLM-friendly format
|
|
143
|
+
return {
|
|
144
|
+
error: true,
|
|
145
|
+
message: LlmJson.stringify(validation),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
const result: unknown = await execute(validation.data);
|
|
151
|
+
return result === undefined ? { success: true } : result;
|
|
152
|
+
} catch (error) {
|
|
153
|
+
return {
|
|
154
|
+
error: true,
|
|
155
|
+
message:
|
|
156
|
+
error instanceof Error
|
|
157
|
+
? `${error.name}: ${error.message}`
|
|
158
|
+
: String(error),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const convertParameters = (params: ILlmSchema.IParameters): JSONSchema7 => {
|
|
166
|
+
const schema: JSONSchema7 = {
|
|
167
|
+
type: "object",
|
|
168
|
+
properties: params.properties as JSONSchema7["properties"],
|
|
169
|
+
required: params.required,
|
|
170
|
+
additionalProperties: params.additionalProperties,
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// Add $defs if present
|
|
174
|
+
if (Object.keys(params.$defs).length > 0) {
|
|
175
|
+
schema.$defs = params.$defs as JSONSchema7["$defs"];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return schema;
|
|
179
|
+
};
|
|
180
|
+
}
|