@typia/langchain 12.0.0-dev.20260310 → 12.0.0-dev.20260312
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 +7 -9
- package/lib/index.js +6 -8
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +6 -8
- package/lib/index.mjs.map +1 -1
- package/lib/internal/LangChainToolsRegistrar.js +30 -27
- package/lib/internal/LangChainToolsRegistrar.js.map +1 -1
- package/lib/internal/LangChainToolsRegistrar.mjs +38 -37
- package/lib/internal/LangChainToolsRegistrar.mjs.map +1 -1
- package/package.json +5 -6
- package/src/index.ts +64 -66
- package/src/internal/LangChainToolsRegistrar.ts +149 -139
package/lib/index.d.ts
CHANGED
|
@@ -12,14 +12,13 @@ import { IHttpLlmController, ILlmController } from "@typia/interface";
|
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* ```typescript
|
|
15
|
-
* import {
|
|
16
|
-
* import { AgentExecutor, createToolCallingAgent } from "langchain/agents";
|
|
15
|
+
* import { initChatModel } from "langchain/chat_models/universal";
|
|
17
16
|
* import typia from "typia";
|
|
18
17
|
* import { toLangChainTools } from "@typia/langchain";
|
|
19
18
|
*
|
|
20
19
|
* class Calculator {
|
|
21
|
-
* add(input: { a: number; b: number }): number {
|
|
22
|
-
* return input.a + input.b;
|
|
20
|
+
* add(input: { a: number; b: number }): { value: number } {
|
|
21
|
+
* return { value: input.a + input.b };
|
|
23
22
|
* }
|
|
24
23
|
* }
|
|
25
24
|
*
|
|
@@ -29,10 +28,9 @@ import { IHttpLlmController, ILlmController } from "@typia/interface";
|
|
|
29
28
|
* ],
|
|
30
29
|
* });
|
|
31
30
|
*
|
|
32
|
-
* const llm =
|
|
33
|
-
* const
|
|
34
|
-
* const
|
|
35
|
-
* await executor.invoke({ input: "What is 10 + 5?" });
|
|
31
|
+
* const llm = await initChatModel();
|
|
32
|
+
* const modelWithTools = llm.bindTools(tools);
|
|
33
|
+
* const result = await modelWithTools.invoke("What is 10 + 5?");
|
|
36
34
|
* ```;
|
|
37
35
|
*
|
|
38
36
|
* @param props Conversion properties
|
|
@@ -54,7 +52,7 @@ export declare function toLangChainTools(props: {
|
|
|
54
52
|
* If `true`, tool names become `{controllerName}_{methodName}`. If `false`,
|
|
55
53
|
* tool names are just `{methodName}`.
|
|
56
54
|
*
|
|
57
|
-
* @default
|
|
55
|
+
* @default false
|
|
58
56
|
*/
|
|
59
57
|
prefix?: boolean | undefined;
|
|
60
58
|
}): DynamicStructuredTool[];
|
package/lib/index.js
CHANGED
|
@@ -14,14 +14,13 @@ const LangChainToolsRegistrar_1 = require("./internal/LangChainToolsRegistrar");
|
|
|
14
14
|
*
|
|
15
15
|
* @example
|
|
16
16
|
* ```typescript
|
|
17
|
-
* import {
|
|
18
|
-
* import { AgentExecutor, createToolCallingAgent } from "langchain/agents";
|
|
17
|
+
* import { initChatModel } from "langchain/chat_models/universal";
|
|
19
18
|
* import typia from "typia";
|
|
20
19
|
* import { toLangChainTools } from "@typia/langchain";
|
|
21
20
|
*
|
|
22
21
|
* class Calculator {
|
|
23
|
-
* add(input: { a: number; b: number }): number {
|
|
24
|
-
* return input.a + input.b;
|
|
22
|
+
* add(input: { a: number; b: number }): { value: number } {
|
|
23
|
+
* return { value: input.a + input.b };
|
|
25
24
|
* }
|
|
26
25
|
* }
|
|
27
26
|
*
|
|
@@ -31,10 +30,9 @@ const LangChainToolsRegistrar_1 = require("./internal/LangChainToolsRegistrar");
|
|
|
31
30
|
* ],
|
|
32
31
|
* });
|
|
33
32
|
*
|
|
34
|
-
* const llm =
|
|
35
|
-
* const
|
|
36
|
-
* const
|
|
37
|
-
* await executor.invoke({ input: "What is 10 + 5?" });
|
|
33
|
+
* const llm = await initChatModel();
|
|
34
|
+
* const modelWithTools = llm.bindTools(tools);
|
|
35
|
+
* const result = await modelWithTools.invoke("What is 10 + 5?");
|
|
38
36
|
* ```;
|
|
39
37
|
*
|
|
40
38
|
* @param props Conversion properties
|
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":";;AAyCA,4CAsBC;AA5DD,gFAA6E;AAE7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,SAAgB,gBAAgB,CAAC,KAoBhC;IACC,OAAO,iDAAuB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAChD,CAAC"}
|
package/lib/index.mjs
CHANGED
|
@@ -12,14 +12,13 @@ import { LangChainToolsRegistrar } from './internal/LangChainToolsRegistrar.mjs'
|
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* ```typescript
|
|
15
|
-
* import {
|
|
16
|
-
* import { AgentExecutor, createToolCallingAgent } from "langchain/agents";
|
|
15
|
+
* import { initChatModel } from "langchain/chat_models/universal";
|
|
17
16
|
* import typia from "typia";
|
|
18
17
|
* import { toLangChainTools } from "@typia/langchain";
|
|
19
18
|
*
|
|
20
19
|
* class Calculator {
|
|
21
|
-
* add(input: { a: number; b: number }): number {
|
|
22
|
-
* return input.a + input.b;
|
|
20
|
+
* add(input: { a: number; b: number }): { value: number } {
|
|
21
|
+
* return { value: input.a + input.b };
|
|
23
22
|
* }
|
|
24
23
|
* }
|
|
25
24
|
*
|
|
@@ -29,10 +28,9 @@ import { LangChainToolsRegistrar } from './internal/LangChainToolsRegistrar.mjs'
|
|
|
29
28
|
* ],
|
|
30
29
|
* });
|
|
31
30
|
*
|
|
32
|
-
* const llm =
|
|
33
|
-
* const
|
|
34
|
-
* const
|
|
35
|
-
* await executor.invoke({ input: "What is 10 + 5?" });
|
|
31
|
+
* const llm = await initChatModel();
|
|
32
|
+
* const modelWithTools = llm.bindTools(tools);
|
|
33
|
+
* const result = await modelWithTools.invoke("What is 10 + 5?");
|
|
36
34
|
* ```;
|
|
37
35
|
*
|
|
38
36
|
* @param props Conversion properties
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCG;AACG,SAAU,gBAAgB,CAAC,KAoBhC,EAAA;AACC,IAAA,OAAO,uBAAuB,CAAC,OAAO,CAAC,KAAK,CAAC;AAC/C;;;;"}
|
|
@@ -12,13 +12,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.LangChainToolsRegistrar = void 0;
|
|
13
13
|
const tools_1 = require("@langchain/core/tools");
|
|
14
14
|
const utils_1 = require("@typia/utils");
|
|
15
|
-
const zod_1 = require("zod");
|
|
16
15
|
var LangChainToolsRegistrar;
|
|
17
16
|
(function (LangChainToolsRegistrar) {
|
|
18
17
|
LangChainToolsRegistrar.convert = (props) => {
|
|
19
18
|
var _a;
|
|
20
|
-
const prefix = (_a = props.prefix) !== null && _a !== void 0 ? _a :
|
|
19
|
+
const prefix = (_a = props.prefix) !== null && _a !== void 0 ? _a : false;
|
|
21
20
|
const tools = [];
|
|
21
|
+
// check duplicate tool names
|
|
22
|
+
if (prefix === false && props.controllers.length >= 2) {
|
|
23
|
+
const names = new Map();
|
|
24
|
+
const duplicates = [];
|
|
25
|
+
for (const controller of props.controllers) {
|
|
26
|
+
for (const func of controller.application.functions) {
|
|
27
|
+
const existing = names.get(func.name);
|
|
28
|
+
if (existing !== undefined)
|
|
29
|
+
duplicates.push(`"${func.name}" in "${controller.name}" (conflicts with "${existing}")`);
|
|
30
|
+
else
|
|
31
|
+
names.set(func.name, controller.name);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (duplicates.length > 0)
|
|
35
|
+
throw new Error(`Duplicate tool names found:\n - ${duplicates.join("\n - ")}`);
|
|
36
|
+
}
|
|
37
|
+
// convert controllers to tools
|
|
22
38
|
for (const controller of props.controllers) {
|
|
23
39
|
if (controller.protocol === "class") {
|
|
24
40
|
convertClassController(tools, controller, prefix);
|
|
@@ -32,13 +48,13 @@ var LangChainToolsRegistrar;
|
|
|
32
48
|
const convertClassController = (tools, controller, prefix) => {
|
|
33
49
|
const execute = controller.execute;
|
|
34
50
|
for (const func of controller.application.functions) {
|
|
51
|
+
const toolName = prefix
|
|
52
|
+
? `${controller.name}_${func.name}`
|
|
53
|
+
: func.name;
|
|
35
54
|
const method = execute[func.name];
|
|
36
55
|
if (typeof method !== "function") {
|
|
37
56
|
throw new Error(`Method "${func.name}" not found on controller "${controller.name}"`);
|
|
38
57
|
}
|
|
39
|
-
const toolName = prefix
|
|
40
|
-
? `${controller.name}_${func.name}`
|
|
41
|
-
: func.name;
|
|
42
58
|
tools.push(createTool({
|
|
43
59
|
name: toolName,
|
|
44
60
|
function: func,
|
|
@@ -76,35 +92,22 @@ var LangChainToolsRegistrar;
|
|
|
76
92
|
}));
|
|
77
93
|
}
|
|
78
94
|
};
|
|
79
|
-
// Schema that accepts any object - bypasses LangChain's validation
|
|
80
|
-
// so typia can handle all validation with proper error messages.
|
|
81
|
-
// LangChain validates JSON Schema using @cfworker/json-schema which
|
|
82
|
-
// throws ToolInputParsingException before reaching our func.
|
|
83
|
-
const passthroughSchema = zod_1.z.record(zod_1.z.unknown());
|
|
84
95
|
const createTool = (entry) => {
|
|
85
96
|
var _a;
|
|
86
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
87
97
|
return new tools_1.DynamicStructuredTool({
|
|
88
98
|
name: entry.name,
|
|
89
99
|
description: (_a = entry.function.description) !== null && _a !== void 0 ? _a : "",
|
|
90
|
-
schema:
|
|
100
|
+
schema: entry.function.parameters,
|
|
91
101
|
func: (args) => __awaiter(this, void 0, void 0, function* () {
|
|
92
102
|
const coerced = utils_1.LlmJson.coerce(args, entry.function.parameters);
|
|
93
|
-
const
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
: JSON.stringify(result, null, 2);
|
|
102
|
-
}
|
|
103
|
-
catch (error) {
|
|
104
|
-
return error instanceof Error
|
|
105
|
-
? `${error.name}: ${error.message}`
|
|
106
|
-
: String(error);
|
|
107
|
-
}
|
|
103
|
+
const valid = entry.function.validate(coerced);
|
|
104
|
+
if (valid.success === false)
|
|
105
|
+
throw new tools_1.ToolInputParsingException(`Type errors in "${entry.name}" arguments:\n\n` +
|
|
106
|
+
`\`\`\`json\n${utils_1.LlmJson.stringify(valid)}\n\`\`\``, JSON.stringify(coerced));
|
|
107
|
+
const result = yield entry.execute(valid.data);
|
|
108
|
+
return result === undefined
|
|
109
|
+
? { success: true }
|
|
110
|
+
: { success: true, data: result };
|
|
108
111
|
}),
|
|
109
112
|
});
|
|
110
113
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LangChainToolsRegistrar.js","sourceRoot":"","sources":["../../src/internal/LangChainToolsRegistrar.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"LangChainToolsRegistrar.js","sourceRoot":"","sources":["../../src/internal/LangChainToolsRegistrar.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,28 @@
|
|
|
1
|
-
import { DynamicStructuredTool } from '@langchain/core/tools';
|
|
1
|
+
import { DynamicStructuredTool, ToolInputParsingException } from '@langchain/core/tools';
|
|
2
2
|
import { LlmJson, HttpLlm } from '@typia/utils';
|
|
3
|
-
import { z } from 'zod';
|
|
4
3
|
|
|
5
4
|
var LangChainToolsRegistrar;
|
|
6
5
|
(function (LangChainToolsRegistrar) {
|
|
7
6
|
LangChainToolsRegistrar.convert = (props) => {
|
|
8
|
-
const prefix = props.prefix ??
|
|
7
|
+
const prefix = props.prefix ?? false;
|
|
9
8
|
const tools = [];
|
|
9
|
+
// check duplicate tool names
|
|
10
|
+
if (prefix === false && props.controllers.length >= 2) {
|
|
11
|
+
const names = new Map();
|
|
12
|
+
const duplicates = [];
|
|
13
|
+
for (const controller of props.controllers) {
|
|
14
|
+
for (const func of controller.application.functions) {
|
|
15
|
+
const existing = names.get(func.name);
|
|
16
|
+
if (existing !== undefined)
|
|
17
|
+
duplicates.push(`"${func.name}" in "${controller.name}" (conflicts with "${existing}")`);
|
|
18
|
+
else
|
|
19
|
+
names.set(func.name, controller.name);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (duplicates.length > 0)
|
|
23
|
+
throw new Error(`Duplicate tool names found:\n - ${duplicates.join("\n - ")}`);
|
|
24
|
+
}
|
|
25
|
+
// convert controllers to tools
|
|
10
26
|
for (const controller of props.controllers) {
|
|
11
27
|
if (controller.protocol === "class") {
|
|
12
28
|
convertClassController(tools, controller, prefix);
|
|
@@ -20,13 +36,13 @@ var LangChainToolsRegistrar;
|
|
|
20
36
|
const convertClassController = (tools, controller, prefix) => {
|
|
21
37
|
const execute = controller.execute;
|
|
22
38
|
for (const func of controller.application.functions) {
|
|
39
|
+
const toolName = prefix
|
|
40
|
+
? `${controller.name}_${func.name}`
|
|
41
|
+
: func.name;
|
|
23
42
|
const method = execute[func.name];
|
|
24
43
|
if (typeof method !== "function") {
|
|
25
44
|
throw new Error(`Method "${func.name}" not found on controller "${controller.name}"`);
|
|
26
45
|
}
|
|
27
|
-
const toolName = prefix
|
|
28
|
-
? `${controller.name}_${func.name}`
|
|
29
|
-
: func.name;
|
|
30
46
|
tools.push(createTool({
|
|
31
47
|
name: toolName,
|
|
32
48
|
function: func,
|
|
@@ -64,37 +80,22 @@ var LangChainToolsRegistrar;
|
|
|
64
80
|
}));
|
|
65
81
|
}
|
|
66
82
|
};
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
try {
|
|
85
|
-
const result = await entry.execute(validation.data);
|
|
86
|
-
return result === undefined
|
|
87
|
-
? "Success"
|
|
88
|
-
: JSON.stringify(result, null, 2);
|
|
89
|
-
}
|
|
90
|
-
catch (error) {
|
|
91
|
-
return error instanceof Error
|
|
92
|
-
? `${error.name}: ${error.message}`
|
|
93
|
-
: String(error);
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
});
|
|
97
|
-
};
|
|
83
|
+
const createTool = (entry) => new DynamicStructuredTool({
|
|
84
|
+
name: entry.name,
|
|
85
|
+
description: entry.function.description ?? "",
|
|
86
|
+
schema: entry.function.parameters,
|
|
87
|
+
func: async (args) => {
|
|
88
|
+
const coerced = LlmJson.coerce(args, entry.function.parameters);
|
|
89
|
+
const valid = entry.function.validate(coerced);
|
|
90
|
+
if (valid.success === false)
|
|
91
|
+
throw new ToolInputParsingException(`Type errors in "${entry.name}" arguments:\n\n` +
|
|
92
|
+
`\`\`\`json\n${LlmJson.stringify(valid)}\n\`\`\``, JSON.stringify(coerced));
|
|
93
|
+
const result = await entry.execute(valid.data);
|
|
94
|
+
return result === undefined
|
|
95
|
+
? { success: true }
|
|
96
|
+
: { success: true, data: result };
|
|
97
|
+
},
|
|
98
|
+
});
|
|
98
99
|
})(LangChainToolsRegistrar || (LangChainToolsRegistrar = {}));
|
|
99
100
|
|
|
100
101
|
export { LangChainToolsRegistrar };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LangChainToolsRegistrar.mjs","sources":["../../src/internal/LangChainToolsRegistrar.ts"],"sourcesContent":[null],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"LangChainToolsRegistrar.mjs","sources":["../../src/internal/LangChainToolsRegistrar.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typia/langchain",
|
|
3
|
-
"version": "12.0.0-dev.
|
|
3
|
+
"version": "12.0.0-dev.20260312",
|
|
4
4
|
"description": "LangChain.js integration for typia",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -22,15 +22,14 @@
|
|
|
22
22
|
},
|
|
23
23
|
"homepage": "https://typia.io",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"
|
|
26
|
-
"@typia/
|
|
27
|
-
"@typia/utils": "^12.0.0-dev.20260310"
|
|
25
|
+
"@typia/interface": "^12.0.0-dev.20260312",
|
|
26
|
+
"@typia/utils": "^12.0.0-dev.20260312"
|
|
28
27
|
},
|
|
29
28
|
"peerDependencies": {
|
|
30
|
-
"@langchain/core": ">=0.
|
|
29
|
+
"@langchain/core": ">=1.0.0"
|
|
31
30
|
},
|
|
32
31
|
"devDependencies": {
|
|
33
|
-
"@langchain/core": "^
|
|
32
|
+
"@langchain/core": "^1.1.31",
|
|
34
33
|
"@rollup/plugin-commonjs": "^29.0.0",
|
|
35
34
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
36
35
|
"@rollup/plugin-typescript": "^12.3.0",
|
package/src/index.ts
CHANGED
|
@@ -1,66 +1,64 @@
|
|
|
1
|
-
import type { DynamicStructuredTool } from "@langchain/core/tools";
|
|
2
|
-
import { IHttpLlmController, ILlmController } from "@typia/interface";
|
|
3
|
-
|
|
4
|
-
import { LangChainToolsRegistrar } from "./internal/LangChainToolsRegistrar";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Convert typia controllers to LangChain tools.
|
|
8
|
-
*
|
|
9
|
-
* Converts TypeScript class methods via `typia.llm.controller<Class>()` or
|
|
10
|
-
* OpenAPI operations via `HttpLlm.controller()` to LangChain tools.
|
|
11
|
-
*
|
|
12
|
-
* Every tool call is validated by typia. If LLM provides invalid arguments,
|
|
13
|
-
* returns validation error formatted by {@link LlmJson.stringify} so that LLM
|
|
14
|
-
* can correct them automatically.
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* ```typescript
|
|
18
|
-
* import {
|
|
19
|
-
* import
|
|
20
|
-
* import
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* const
|
|
36
|
-
* const
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* - {@link
|
|
49
|
-
*
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
return LangChainToolsRegistrar.convert(props);
|
|
66
|
-
}
|
|
1
|
+
import type { DynamicStructuredTool } from "@langchain/core/tools";
|
|
2
|
+
import { IHttpLlmController, ILlmController } from "@typia/interface";
|
|
3
|
+
|
|
4
|
+
import { LangChainToolsRegistrar } from "./internal/LangChainToolsRegistrar";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Convert typia controllers to LangChain tools.
|
|
8
|
+
*
|
|
9
|
+
* Converts TypeScript class methods via `typia.llm.controller<Class>()` or
|
|
10
|
+
* OpenAPI operations via `HttpLlm.controller()` to LangChain tools.
|
|
11
|
+
*
|
|
12
|
+
* Every tool call is validated by typia. If LLM provides invalid arguments,
|
|
13
|
+
* returns validation error formatted by {@link LlmJson.stringify} so that LLM
|
|
14
|
+
* can correct them automatically.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { initChatModel } from "langchain/chat_models/universal";
|
|
19
|
+
* import typia from "typia";
|
|
20
|
+
* import { toLangChainTools } from "@typia/langchain";
|
|
21
|
+
*
|
|
22
|
+
* class Calculator {
|
|
23
|
+
* add(input: { a: number; b: number }): { value: number } {
|
|
24
|
+
* return { value: input.a + input.b };
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* const tools = toLangChainTools({
|
|
29
|
+
* controllers: [
|
|
30
|
+
* typia.llm.controller<Calculator>("calculator", new Calculator()),
|
|
31
|
+
* ],
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* const llm = await initChatModel();
|
|
35
|
+
* const modelWithTools = llm.bindTools(tools);
|
|
36
|
+
* const result = await modelWithTools.invoke("What is 10 + 5?");
|
|
37
|
+
* ```;
|
|
38
|
+
*
|
|
39
|
+
* @param props Conversion properties
|
|
40
|
+
* @returns Array of LangChain DynamicStructuredTool
|
|
41
|
+
*/
|
|
42
|
+
export function toLangChainTools(props: {
|
|
43
|
+
/**
|
|
44
|
+
* List of controllers to convert to LangChain tools.
|
|
45
|
+
*
|
|
46
|
+
* - {@link ILlmController}: from `typia.llm.controller<Class>()`, converts all
|
|
47
|
+
* methods of the class to tools
|
|
48
|
+
* - {@link IHttpLlmController}: from `HttpLlm.controller()`, converts all
|
|
49
|
+
* operations from OpenAPI document to tools
|
|
50
|
+
*/
|
|
51
|
+
controllers: Array<ILlmController | IHttpLlmController>;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Whether to add controller name as prefix to tool names.
|
|
55
|
+
*
|
|
56
|
+
* If `true`, tool names become `{controllerName}_{methodName}`. If `false`,
|
|
57
|
+
* tool names are just `{methodName}`.
|
|
58
|
+
*
|
|
59
|
+
* @default false
|
|
60
|
+
*/
|
|
61
|
+
prefix?: boolean | undefined;
|
|
62
|
+
}): DynamicStructuredTool[] {
|
|
63
|
+
return LangChainToolsRegistrar.convert(props);
|
|
64
|
+
}
|
|
@@ -1,139 +1,149 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
tools.push(
|
|
74
|
-
createTool({
|
|
75
|
-
name: toolName,
|
|
76
|
-
function: func,
|
|
77
|
-
execute: async (args: unknown) =>
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
DynamicStructuredTool,
|
|
3
|
+
ToolInputParsingException,
|
|
4
|
+
} from "@langchain/core/tools";
|
|
5
|
+
import {
|
|
6
|
+
IHttpLlmController,
|
|
7
|
+
IHttpLlmFunction,
|
|
8
|
+
ILlmController,
|
|
9
|
+
ILlmFunction,
|
|
10
|
+
IValidation,
|
|
11
|
+
} from "@typia/interface";
|
|
12
|
+
import { HttpLlm, LlmJson } from "@typia/utils";
|
|
13
|
+
|
|
14
|
+
export namespace LangChainToolsRegistrar {
|
|
15
|
+
export const convert = (props: {
|
|
16
|
+
controllers: Array<ILlmController | IHttpLlmController>;
|
|
17
|
+
prefix?: boolean | undefined;
|
|
18
|
+
}): DynamicStructuredTool[] => {
|
|
19
|
+
const prefix: boolean = props.prefix ?? false;
|
|
20
|
+
const tools: DynamicStructuredTool[] = [];
|
|
21
|
+
|
|
22
|
+
// check duplicate tool names
|
|
23
|
+
if (prefix === false && props.controllers.length >= 2) {
|
|
24
|
+
const names: Map<string, string> = new Map();
|
|
25
|
+
const duplicates: string[] = [];
|
|
26
|
+
for (const controller of props.controllers) {
|
|
27
|
+
for (const func of controller.application.functions) {
|
|
28
|
+
const existing: string | undefined = names.get(func.name);
|
|
29
|
+
if (existing !== undefined)
|
|
30
|
+
duplicates.push(
|
|
31
|
+
`"${func.name}" in "${controller.name}" (conflicts with "${existing}")`,
|
|
32
|
+
);
|
|
33
|
+
else names.set(func.name, controller.name);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (duplicates.length > 0)
|
|
37
|
+
throw new Error(
|
|
38
|
+
`Duplicate tool names found:\n - ${duplicates.join("\n - ")}`,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// convert controllers to tools
|
|
43
|
+
for (const controller of props.controllers) {
|
|
44
|
+
if (controller.protocol === "class") {
|
|
45
|
+
convertClassController(tools, controller, prefix);
|
|
46
|
+
} else {
|
|
47
|
+
convertHttpController(tools, controller, prefix);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return tools;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const convertClassController = (
|
|
55
|
+
tools: DynamicStructuredTool[],
|
|
56
|
+
controller: ILlmController,
|
|
57
|
+
prefix: boolean,
|
|
58
|
+
): void => {
|
|
59
|
+
const execute: Record<string, unknown> = controller.execute;
|
|
60
|
+
|
|
61
|
+
for (const func of controller.application.functions) {
|
|
62
|
+
const toolName: string = prefix
|
|
63
|
+
? `${controller.name}_${func.name}`
|
|
64
|
+
: func.name;
|
|
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.push(
|
|
74
|
+
createTool({
|
|
75
|
+
name: toolName,
|
|
76
|
+
function: func,
|
|
77
|
+
execute: async (args: unknown) => method.call(execute, args),
|
|
78
|
+
}),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const convertHttpController = (
|
|
84
|
+
tools: DynamicStructuredTool[],
|
|
85
|
+
controller: IHttpLlmController,
|
|
86
|
+
prefix: boolean,
|
|
87
|
+
): void => {
|
|
88
|
+
const application = controller.application;
|
|
89
|
+
const connection = controller.connection;
|
|
90
|
+
|
|
91
|
+
for (const func of application.functions) {
|
|
92
|
+
const toolName: string = prefix
|
|
93
|
+
? `${controller.name}_${func.name}`
|
|
94
|
+
: func.name;
|
|
95
|
+
|
|
96
|
+
tools.push(
|
|
97
|
+
createTool({
|
|
98
|
+
name: toolName,
|
|
99
|
+
function: func,
|
|
100
|
+
execute: async (args: unknown) => {
|
|
101
|
+
if (controller.execute !== undefined) {
|
|
102
|
+
const response = await controller.execute({
|
|
103
|
+
connection,
|
|
104
|
+
application,
|
|
105
|
+
function: func,
|
|
106
|
+
arguments: args as object,
|
|
107
|
+
});
|
|
108
|
+
return response.body;
|
|
109
|
+
}
|
|
110
|
+
return HttpLlm.execute({
|
|
111
|
+
application,
|
|
112
|
+
function: func,
|
|
113
|
+
connection,
|
|
114
|
+
input: args as object,
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
}),
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const createTool = (entry: {
|
|
123
|
+
name: string;
|
|
124
|
+
function: ILlmFunction | IHttpLlmFunction;
|
|
125
|
+
execute: (args: unknown) => Promise<unknown>;
|
|
126
|
+
}): DynamicStructuredTool =>
|
|
127
|
+
new DynamicStructuredTool<any>({
|
|
128
|
+
name: entry.name,
|
|
129
|
+
description: entry.function.description ?? "",
|
|
130
|
+
schema: entry.function.parameters,
|
|
131
|
+
func: async (args: unknown): Promise<unknown> => {
|
|
132
|
+
const coerced: unknown = LlmJson.coerce(
|
|
133
|
+
args,
|
|
134
|
+
entry.function.parameters,
|
|
135
|
+
);
|
|
136
|
+
const valid: IValidation<unknown> = entry.function.validate(coerced);
|
|
137
|
+
if (valid.success === false)
|
|
138
|
+
throw new ToolInputParsingException(
|
|
139
|
+
`Type errors in "${entry.name}" arguments:\n\n` +
|
|
140
|
+
`\`\`\`json\n${LlmJson.stringify(valid)}\n\`\`\``,
|
|
141
|
+
JSON.stringify(coerced),
|
|
142
|
+
);
|
|
143
|
+
const result: unknown = await entry.execute(valid.data);
|
|
144
|
+
return result === undefined
|
|
145
|
+
? { success: true }
|
|
146
|
+
: { success: true, data: result };
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
}
|