@typia/langchain 12.0.0-dev.20260309 → 12.0.0-dev.20260311

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 CHANGED
@@ -7,43 +7,43 @@ import { IHttpLlmController, ILlmController } from "@typia/interface";
7
7
  * OpenAPI operations via `HttpLlm.controller()` to LangChain tools.
8
8
  *
9
9
  * Every tool call is validated by typia. If LLM provides invalid arguments,
10
- * returns validation error formatted by {@link LlmJson.stringify}
11
- * so that LLM can correct them automatically.
12
- *
13
- * @param props Conversion properties
14
- * @returns Array of LangChain DynamicStructuredTool
10
+ * returns validation error formatted by {@link LlmJson.stringify} so that LLM
11
+ * can correct them automatically.
15
12
  *
16
13
  * @example
17
- * ```typescript
18
- * import { ChatOpenAI } from "@langchain/openai";
19
- * import { AgentExecutor, createToolCallingAgent } from "langchain/agents";
20
- * import typia from "typia";
21
- * import { toLangChainTools } from "@typia/langchain";
14
+ * ```typescript
15
+ * import { ChatOpenAI } from "@langchain/openai";
16
+ * import { AgentExecutor, createToolCallingAgent } from "langchain/agents";
17
+ * import typia from "typia";
18
+ * import { toLangChainTools } from "@typia/langchain";
22
19
  *
23
- * class Calculator {
24
- * add(input: { a: number; b: number }): number {
25
- * return input.a + input.b;
20
+ * class Calculator {
21
+ * add(input: { a: number; b: number }): number {
22
+ * return input.a + input.b;
23
+ * }
26
24
  * }
27
- * }
28
25
  *
29
- * const tools = toLangChainTools({
30
- * controllers: [
31
- * typia.llm.controller<Calculator>("calculator", new Calculator()),
32
- * ],
33
- * });
26
+ * const tools = toLangChainTools({
27
+ * controllers: [
28
+ * typia.llm.controller<Calculator>("calculator", new Calculator()),
29
+ * ],
30
+ * });
34
31
  *
35
- * const llm = new ChatOpenAI({ model: "gpt-4" });
36
- * const agent = createToolCallingAgent({ llm, tools, prompt });
37
- * const executor = new AgentExecutor({ agent, tools });
38
- * await executor.invoke({ input: "What is 10 + 5?" });
39
- * ```
32
+ * const llm = new ChatOpenAI({ model: "gpt-4" });
33
+ * const agent = createToolCallingAgent({ llm, tools, prompt });
34
+ * const executor = new AgentExecutor({ agent, tools });
35
+ * await executor.invoke({ input: "What is 10 + 5?" });
36
+ * ```;
37
+ *
38
+ * @param props Conversion properties
39
+ * @returns Array of LangChain DynamicStructuredTool
40
40
  */
41
41
  export declare function toLangChainTools(props: {
42
42
  /**
43
43
  * List of controllers to convert to LangChain tools.
44
44
  *
45
- * - {@link ILlmController}: from `typia.llm.controller<Class>()`, converts
46
- * all methods of the class to tools
45
+ * - {@link ILlmController}: from `typia.llm.controller<Class>()`, converts all
46
+ * methods of the class to tools
47
47
  * - {@link IHttpLlmController}: from `HttpLlm.controller()`, converts all
48
48
  * operations from OpenAPI document to tools
49
49
  */
@@ -51,8 +51,8 @@ export declare function toLangChainTools(props: {
51
51
  /**
52
52
  * Whether to add controller name as prefix to tool names.
53
53
  *
54
- * If `true`, tool names become `{controllerName}_{methodName}`.
55
- * If `false`, tool names are just `{methodName}`.
54
+ * If `true`, tool names become `{controllerName}_{methodName}`. If `false`,
55
+ * tool names are just `{methodName}`.
56
56
  *
57
57
  * @default true
58
58
  */
package/lib/index.js CHANGED
@@ -9,36 +9,36 @@ const LangChainToolsRegistrar_1 = require("./internal/LangChainToolsRegistrar");
9
9
  * OpenAPI operations via `HttpLlm.controller()` to LangChain tools.
10
10
  *
11
11
  * Every tool call is validated by typia. If LLM provides invalid arguments,
12
- * returns validation error formatted by {@link LlmJson.stringify}
13
- * so that LLM can correct them automatically.
14
- *
15
- * @param props Conversion properties
16
- * @returns Array of LangChain DynamicStructuredTool
12
+ * returns validation error formatted by {@link LlmJson.stringify} so that LLM
13
+ * can correct them automatically.
17
14
  *
18
15
  * @example
19
- * ```typescript
20
- * import { ChatOpenAI } from "@langchain/openai";
21
- * import { AgentExecutor, createToolCallingAgent } from "langchain/agents";
22
- * import typia from "typia";
23
- * import { toLangChainTools } from "@typia/langchain";
16
+ * ```typescript
17
+ * import { ChatOpenAI } from "@langchain/openai";
18
+ * import { AgentExecutor, createToolCallingAgent } from "langchain/agents";
19
+ * import typia from "typia";
20
+ * import { toLangChainTools } from "@typia/langchain";
24
21
  *
25
- * class Calculator {
26
- * add(input: { a: number; b: number }): number {
27
- * return input.a + input.b;
22
+ * class Calculator {
23
+ * add(input: { a: number; b: number }): number {
24
+ * return input.a + input.b;
25
+ * }
28
26
  * }
29
- * }
30
27
  *
31
- * const tools = toLangChainTools({
32
- * controllers: [
33
- * typia.llm.controller<Calculator>("calculator", new Calculator()),
34
- * ],
35
- * });
28
+ * const tools = toLangChainTools({
29
+ * controllers: [
30
+ * typia.llm.controller<Calculator>("calculator", new Calculator()),
31
+ * ],
32
+ * });
36
33
  *
37
- * const llm = new ChatOpenAI({ model: "gpt-4" });
38
- * const agent = createToolCallingAgent({ llm, tools, prompt });
39
- * const executor = new AgentExecutor({ agent, tools });
40
- * await executor.invoke({ input: "What is 10 + 5?" });
41
- * ```
34
+ * const llm = new ChatOpenAI({ model: "gpt-4" });
35
+ * const agent = createToolCallingAgent({ llm, tools, prompt });
36
+ * const executor = new AgentExecutor({ agent, tools });
37
+ * await executor.invoke({ input: "What is 10 + 5?" });
38
+ * ```;
39
+ *
40
+ * @param props Conversion properties
41
+ * @returns Array of LangChain DynamicStructuredTool
42
42
  */
43
43
  function toLangChainTools(props) {
44
44
  return LangChainToolsRegistrar_1.LangChainToolsRegistrar.convert(props);
package/lib/index.mjs CHANGED
@@ -7,36 +7,36 @@ import { LangChainToolsRegistrar } from './internal/LangChainToolsRegistrar.mjs'
7
7
  * OpenAPI operations via `HttpLlm.controller()` to LangChain tools.
8
8
  *
9
9
  * Every tool call is validated by typia. If LLM provides invalid arguments,
10
- * returns validation error formatted by {@link LlmJson.stringify}
11
- * so that LLM can correct them automatically.
12
- *
13
- * @param props Conversion properties
14
- * @returns Array of LangChain DynamicStructuredTool
10
+ * returns validation error formatted by {@link LlmJson.stringify} so that LLM
11
+ * can correct them automatically.
15
12
  *
16
13
  * @example
17
- * ```typescript
18
- * import { ChatOpenAI } from "@langchain/openai";
19
- * import { AgentExecutor, createToolCallingAgent } from "langchain/agents";
20
- * import typia from "typia";
21
- * import { toLangChainTools } from "@typia/langchain";
14
+ * ```typescript
15
+ * import { ChatOpenAI } from "@langchain/openai";
16
+ * import { AgentExecutor, createToolCallingAgent } from "langchain/agents";
17
+ * import typia from "typia";
18
+ * import { toLangChainTools } from "@typia/langchain";
22
19
  *
23
- * class Calculator {
24
- * add(input: { a: number; b: number }): number {
25
- * return input.a + input.b;
20
+ * class Calculator {
21
+ * add(input: { a: number; b: number }): number {
22
+ * return input.a + input.b;
23
+ * }
26
24
  * }
27
- * }
28
25
  *
29
- * const tools = toLangChainTools({
30
- * controllers: [
31
- * typia.llm.controller<Calculator>("calculator", new Calculator()),
32
- * ],
33
- * });
26
+ * const tools = toLangChainTools({
27
+ * controllers: [
28
+ * typia.llm.controller<Calculator>("calculator", new Calculator()),
29
+ * ],
30
+ * });
34
31
  *
35
- * const llm = new ChatOpenAI({ model: "gpt-4" });
36
- * const agent = createToolCallingAgent({ llm, tools, prompt });
37
- * const executor = new AgentExecutor({ agent, tools });
38
- * await executor.invoke({ input: "What is 10 + 5?" });
39
- * ```
32
+ * const llm = new ChatOpenAI({ model: "gpt-4" });
33
+ * const agent = createToolCallingAgent({ llm, tools, prompt });
34
+ * const executor = new AgentExecutor({ agent, tools });
35
+ * await executor.invoke({ input: "What is 10 + 5?" });
36
+ * ```;
37
+ *
38
+ * @param props Conversion properties
39
+ * @returns Array of LangChain DynamicStructuredTool
40
40
  */
41
41
  function toLangChainTools(props) {
42
42
  return LangChainToolsRegistrar.convert(props);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typia/langchain",
3
- "version": "12.0.0-dev.20260309",
3
+ "version": "12.0.0-dev.20260311",
4
4
  "description": "LangChain.js integration for typia",
5
5
  "main": "lib/index.js",
6
6
  "exports": {
@@ -23,8 +23,8 @@
23
23
  "homepage": "https://typia.io",
24
24
  "dependencies": {
25
25
  "zod": "^3.25.0",
26
- "@typia/interface": "^12.0.0-dev.20260309",
27
- "@typia/utils": "^12.0.0-dev.20260309"
26
+ "@typia/interface": "^12.0.0-dev.20260311",
27
+ "@typia/utils": "^12.0.0-dev.20260311"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "@langchain/core": ">=0.3.0"
package/src/index.ts CHANGED
@@ -1,66 +1,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}
14
- * so that LLM can correct them automatically.
15
- *
16
- * @param props Conversion properties
17
- * @returns Array of LangChain DynamicStructuredTool
18
- *
19
- * @example
20
- * ```typescript
21
- * import { ChatOpenAI } from "@langchain/openai";
22
- * import { AgentExecutor, createToolCallingAgent } from "langchain/agents";
23
- * import typia from "typia";
24
- * import { toLangChainTools } from "@typia/langchain";
25
- *
26
- * class Calculator {
27
- * add(input: { a: number; b: number }): number {
28
- * return input.a + input.b;
29
- * }
30
- * }
31
- *
32
- * const tools = toLangChainTools({
33
- * controllers: [
34
- * typia.llm.controller<Calculator>("calculator", new Calculator()),
35
- * ],
36
- * });
37
- *
38
- * const llm = new ChatOpenAI({ model: "gpt-4" });
39
- * const agent = createToolCallingAgent({ llm, tools, prompt });
40
- * const executor = new AgentExecutor({ agent, tools });
41
- * await executor.invoke({ input: "What is 10 + 5?" });
42
- * ```
43
- */
44
- export function toLangChainTools(props: {
45
- /**
46
- * List of controllers to convert to LangChain tools.
47
- *
48
- * - {@link ILlmController}: from `typia.llm.controller<Class>()`, converts
49
- * all methods of the class to tools
50
- * - {@link IHttpLlmController}: from `HttpLlm.controller()`, converts all
51
- * operations from OpenAPI document to tools
52
- */
53
- controllers: Array<ILlmController | IHttpLlmController>;
54
-
55
- /**
56
- * Whether to add controller name as prefix to tool names.
57
- *
58
- * If `true`, tool names become `{controllerName}_{methodName}`.
59
- * If `false`, tool names are just `{methodName}`.
60
- *
61
- * @default true
62
- */
63
- prefix?: boolean | undefined;
64
- }): DynamicStructuredTool[] {
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 { ChatOpenAI } from "@langchain/openai";
19
+ * import { AgentExecutor, createToolCallingAgent } from "langchain/agents";
20
+ * import typia from "typia";
21
+ * import { toLangChainTools } from "@typia/langchain";
22
+ *
23
+ * class Calculator {
24
+ * add(input: { a: number; b: number }): number {
25
+ * return input.a + input.b;
26
+ * }
27
+ * }
28
+ *
29
+ * const tools = toLangChainTools({
30
+ * controllers: [
31
+ * typia.llm.controller<Calculator>("calculator", new Calculator()),
32
+ * ],
33
+ * });
34
+ *
35
+ * const llm = new ChatOpenAI({ model: "gpt-4" });
36
+ * const agent = createToolCallingAgent({ llm, tools, prompt });
37
+ * const executor = new AgentExecutor({ agent, tools });
38
+ * await executor.invoke({ input: "What is 10 + 5?" });
39
+ * ```;
40
+ *
41
+ * @param props Conversion properties
42
+ * @returns Array of LangChain DynamicStructuredTool
43
+ */
44
+ export function toLangChainTools(props: {
45
+ /**
46
+ * List of controllers to convert to LangChain tools.
47
+ *
48
+ * - {@link ILlmController}: from `typia.llm.controller<Class>()`, converts all
49
+ * methods of the class to tools
50
+ * - {@link IHttpLlmController}: from `HttpLlm.controller()`, converts all
51
+ * operations from OpenAPI document to tools
52
+ */
53
+ controllers: Array<ILlmController | IHttpLlmController>;
54
+
55
+ /**
56
+ * Whether to add controller name as prefix to tool names.
57
+ *
58
+ * If `true`, tool names become `{controllerName}_{methodName}`. If `false`,
59
+ * tool names are just `{methodName}`.
60
+ *
61
+ * @default true
62
+ */
63
+ prefix?: boolean | undefined;
64
+ }): DynamicStructuredTool[] {
65
+ return LangChainToolsRegistrar.convert(props);
66
+ }
@@ -1,139 +1,139 @@
1
- import { DynamicStructuredTool } from "@langchain/core/tools";
2
- import {
3
- IHttpLlmController,
4
- IHttpLlmFunction,
5
- ILlmController,
6
- ILlmFunction,
7
- IValidation,
8
- } from "@typia/interface";
9
- import { HttpLlm, LlmJson } from "@typia/utils";
10
- import { z } from "zod";
11
-
12
- export namespace LangChainToolsRegistrar {
13
- export const convert = (props: {
14
- controllers: Array<ILlmController | IHttpLlmController>;
15
- prefix?: boolean | undefined;
16
- }): DynamicStructuredTool[] => {
17
- const prefix: boolean = props.prefix ?? true;
18
- const tools: DynamicStructuredTool[] = [];
19
-
20
- for (const controller of props.controllers) {
21
- if (controller.protocol === "class") {
22
- convertClassController(tools, controller, prefix);
23
- } else {
24
- convertHttpController(tools, controller, prefix);
25
- }
26
- }
27
-
28
- return tools;
29
- };
30
-
31
- const convertClassController = (
32
- tools: DynamicStructuredTool[],
33
- controller: ILlmController,
34
- prefix: boolean,
35
- ): void => {
36
- const execute: Record<string, unknown> = controller.execute;
37
-
38
- for (const func of controller.application.functions) {
39
- const method: unknown = execute[func.name];
40
- if (typeof method !== "function") {
41
- throw new Error(
42
- `Method "${func.name}" not found on controller "${controller.name}"`,
43
- );
44
- }
45
-
46
- const toolName: string = prefix
47
- ? `${controller.name}_${func.name}`
48
- : func.name;
49
-
50
- tools.push(
51
- createTool({
52
- name: toolName,
53
- function: func,
54
- execute: async (args: unknown) => method.call(execute, args),
55
- }),
56
- );
57
- }
58
- };
59
-
60
- const convertHttpController = (
61
- tools: DynamicStructuredTool[],
62
- controller: IHttpLlmController,
63
- prefix: boolean,
64
- ): void => {
65
- const application = controller.application;
66
- const connection = controller.connection;
67
-
68
- for (const func of application.functions) {
69
- const toolName: string = prefix
70
- ? `${controller.name}_${func.name}`
71
- : func.name;
72
-
73
- tools.push(
74
- createTool({
75
- name: toolName,
76
- function: func,
77
- execute: async (args: unknown) => {
78
- if (controller.execute !== undefined) {
79
- const response = await controller.execute({
80
- connection,
81
- application,
82
- function: func,
83
- arguments: args as object,
84
- });
85
- return response.body;
86
- }
87
- return HttpLlm.execute({
88
- application,
89
- function: func,
90
- connection,
91
- input: args as object,
92
- });
93
- },
94
- }),
95
- );
96
- }
97
- };
98
-
99
- // Schema that accepts any object - bypasses LangChain's validation
100
- // so typia can handle all validation with proper error messages.
101
- // LangChain validates JSON Schema using @cfworker/json-schema which
102
- // throws ToolInputParsingException before reaching our func.
103
- const passthroughSchema = z.record(z.unknown());
104
-
105
- const createTool = (entry: {
106
- name: string;
107
- function: ILlmFunction | IHttpLlmFunction;
108
- execute: (args: unknown) => Promise<unknown>;
109
- }): DynamicStructuredTool => {
110
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
111
- return new DynamicStructuredTool<any>({
112
- name: entry.name,
113
- description: entry.function.description ?? "",
114
- schema: passthroughSchema,
115
- func: async (args: unknown): Promise<string> => {
116
- const coerced: unknown = LlmJson.coerce(
117
- args,
118
- entry.function.parameters,
119
- );
120
- const validation: IValidation<unknown> =
121
- entry.function.validate(coerced);
122
- if (!validation.success) {
123
- return LlmJson.stringify(validation);
124
- }
125
-
126
- try {
127
- const result: unknown = await entry.execute(validation.data);
128
- return result === undefined
129
- ? "Success"
130
- : JSON.stringify(result, null, 2);
131
- } catch (error) {
132
- return error instanceof Error
133
- ? `${error.name}: ${error.message}`
134
- : String(error);
135
- }
136
- },
137
- });
138
- };
139
- }
1
+ import { DynamicStructuredTool } from "@langchain/core/tools";
2
+ import {
3
+ IHttpLlmController,
4
+ IHttpLlmFunction,
5
+ ILlmController,
6
+ ILlmFunction,
7
+ IValidation,
8
+ } from "@typia/interface";
9
+ import { HttpLlm, LlmJson } from "@typia/utils";
10
+ import { z } from "zod";
11
+
12
+ export namespace LangChainToolsRegistrar {
13
+ export const convert = (props: {
14
+ controllers: Array<ILlmController | IHttpLlmController>;
15
+ prefix?: boolean | undefined;
16
+ }): DynamicStructuredTool[] => {
17
+ const prefix: boolean = props.prefix ?? true;
18
+ const tools: DynamicStructuredTool[] = [];
19
+
20
+ for (const controller of props.controllers) {
21
+ if (controller.protocol === "class") {
22
+ convertClassController(tools, controller, prefix);
23
+ } else {
24
+ convertHttpController(tools, controller, prefix);
25
+ }
26
+ }
27
+
28
+ return tools;
29
+ };
30
+
31
+ const convertClassController = (
32
+ tools: DynamicStructuredTool[],
33
+ controller: ILlmController,
34
+ prefix: boolean,
35
+ ): void => {
36
+ const execute: Record<string, unknown> = controller.execute;
37
+
38
+ for (const func of controller.application.functions) {
39
+ const method: unknown = execute[func.name];
40
+ if (typeof method !== "function") {
41
+ throw new Error(
42
+ `Method "${func.name}" not found on controller "${controller.name}"`,
43
+ );
44
+ }
45
+
46
+ const toolName: string = prefix
47
+ ? `${controller.name}_${func.name}`
48
+ : func.name;
49
+
50
+ tools.push(
51
+ createTool({
52
+ name: toolName,
53
+ function: func,
54
+ execute: async (args: unknown) => method.call(execute, args),
55
+ }),
56
+ );
57
+ }
58
+ };
59
+
60
+ const convertHttpController = (
61
+ tools: DynamicStructuredTool[],
62
+ controller: IHttpLlmController,
63
+ prefix: boolean,
64
+ ): void => {
65
+ const application = controller.application;
66
+ const connection = controller.connection;
67
+
68
+ for (const func of application.functions) {
69
+ const toolName: string = prefix
70
+ ? `${controller.name}_${func.name}`
71
+ : func.name;
72
+
73
+ tools.push(
74
+ createTool({
75
+ name: toolName,
76
+ function: func,
77
+ execute: async (args: unknown) => {
78
+ if (controller.execute !== undefined) {
79
+ const response = await controller.execute({
80
+ connection,
81
+ application,
82
+ function: func,
83
+ arguments: args as object,
84
+ });
85
+ return response.body;
86
+ }
87
+ return HttpLlm.execute({
88
+ application,
89
+ function: func,
90
+ connection,
91
+ input: args as object,
92
+ });
93
+ },
94
+ }),
95
+ );
96
+ }
97
+ };
98
+
99
+ // Schema that accepts any object - bypasses LangChain's validation
100
+ // so typia can handle all validation with proper error messages.
101
+ // LangChain validates JSON Schema using @cfworker/json-schema which
102
+ // throws ToolInputParsingException before reaching our func.
103
+ const passthroughSchema = z.record(z.unknown());
104
+
105
+ const createTool = (entry: {
106
+ name: string;
107
+ function: ILlmFunction | IHttpLlmFunction;
108
+ execute: (args: unknown) => Promise<unknown>;
109
+ }): DynamicStructuredTool => {
110
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
111
+ return new DynamicStructuredTool<any>({
112
+ name: entry.name,
113
+ description: entry.function.description ?? "",
114
+ schema: passthroughSchema,
115
+ func: async (args: unknown): Promise<string> => {
116
+ const coerced: unknown = LlmJson.coerce(
117
+ args,
118
+ entry.function.parameters,
119
+ );
120
+ const validation: IValidation<unknown> =
121
+ entry.function.validate(coerced);
122
+ if (!validation.success) {
123
+ return LlmJson.stringify(validation);
124
+ }
125
+
126
+ try {
127
+ const result: unknown = await entry.execute(validation.data);
128
+ return result === undefined
129
+ ? "Success"
130
+ : JSON.stringify(result, null, 2);
131
+ } catch (error) {
132
+ return error instanceof Error
133
+ ? `${error.name}: ${error.message}`
134
+ : String(error);
135
+ }
136
+ },
137
+ });
138
+ };
139
+ }