@typia/langchain 13.1.19 → 13.3.0
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.cts +66 -0
- package/lib/index.d.mts +66 -0
- package/lib/internal/LangChainParameterConverter.d.ts +20 -18
- package/lib/internal/LangChainParameterConverter.js +20 -18
- package/lib/internal/LangChainParameterConverter.js.map +1 -1
- package/lib/internal/LangChainParameterConverter.mjs.map +1 -1
- package/lib/internal/LangChainToolsRegistrar.js +63 -35
- package/lib/internal/LangChainToolsRegistrar.js.map +1 -1
- package/lib/internal/LangChainToolsRegistrar.mjs +42 -24
- package/lib/internal/LangChainToolsRegistrar.mjs.map +1 -1
- package/package.json +12 -5
- package/src/internal/LangChainParameterConverter.ts +20 -18
- package/src/internal/LangChainToolsRegistrar.ts +35 -3
package/lib/index.d.cts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { DynamicStructuredTool } from "@langchain/core/tools";
|
|
2
|
+
import { IHttpLlmController, ILlmController } from "@typia/interface";
|
|
3
|
+
type ILangChainController = ILlmController | IHttpLlmController;
|
|
4
|
+
interface ILangChainToolsOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Whether to add controller name as prefix to tool names.
|
|
7
|
+
*
|
|
8
|
+
* If `true`, tool names become `{controllerName}_{methodName}`. If `false`,
|
|
9
|
+
* tool names are just `{methodName}`.
|
|
10
|
+
*
|
|
11
|
+
* @default false
|
|
12
|
+
*/
|
|
13
|
+
prefix?: boolean | undefined;
|
|
14
|
+
}
|
|
15
|
+
interface ILangChainToolsProps extends ILangChainToolsOptions {
|
|
16
|
+
/**
|
|
17
|
+
* List of controllers to convert to LangChain tools.
|
|
18
|
+
*
|
|
19
|
+
* - {@link ILlmController}: from `typia.llm.controller<Class>()`, converts all
|
|
20
|
+
* methods of the class to tools
|
|
21
|
+
* - {@link IHttpLlmController}: from `HttpLlm.controller()`, converts all
|
|
22
|
+
* operations from OpenAPI document to tools
|
|
23
|
+
*/
|
|
24
|
+
controllers: ILangChainController[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Convert typia controllers to LangChain tools.
|
|
28
|
+
*
|
|
29
|
+
* Converts TypeScript class methods via `typia.llm.controller<Class>()` or
|
|
30
|
+
* OpenAPI operations via `HttpLlm.controller()` to LangChain tools.
|
|
31
|
+
*
|
|
32
|
+
* Every tool call is validated by typia. If LLM provides invalid arguments,
|
|
33
|
+
* returns validation error formatted by {@link LlmJson.stringify} so that LLM
|
|
34
|
+
* can correct them automatically.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* import { initChatModel } from "langchain/chat_models/universal";
|
|
39
|
+
* import typia from "typia";
|
|
40
|
+
* import { toLangChainTools } from "@typia/langchain";
|
|
41
|
+
*
|
|
42
|
+
* class Calculator {
|
|
43
|
+
* add(input: { a: number; b: number }): { value: number } {
|
|
44
|
+
* return { value: input.a + input.b };
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
*
|
|
48
|
+
* const controller = typia.llm.controller<Calculator>(
|
|
49
|
+
* "calculator",
|
|
50
|
+
* new Calculator(),
|
|
51
|
+
* );
|
|
52
|
+
* const tools = toLangChainTools(controller);
|
|
53
|
+
*
|
|
54
|
+
* const llm = await initChatModel();
|
|
55
|
+
* const modelWithTools = llm.bindTools(tools);
|
|
56
|
+
* const result = await modelWithTools.invoke("What is 10 + 5?");
|
|
57
|
+
* ```;
|
|
58
|
+
*
|
|
59
|
+
* @param input Controller, controller list, or conversion properties
|
|
60
|
+
* @param options Conversion options when `input` is not a properties object
|
|
61
|
+
* @returns Array of LangChain DynamicStructuredTool
|
|
62
|
+
*/
|
|
63
|
+
export declare function toLangChainTools(controller: ILangChainController, options?: ILangChainToolsOptions | undefined): DynamicStructuredTool[];
|
|
64
|
+
export declare function toLangChainTools(controllers: ILangChainController[], options?: ILangChainToolsOptions | undefined): DynamicStructuredTool[];
|
|
65
|
+
export declare function toLangChainTools(props: ILangChainToolsProps): DynamicStructuredTool[];
|
|
66
|
+
export {};
|
package/lib/index.d.mts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { DynamicStructuredTool } from "@langchain/core/tools";
|
|
2
|
+
import { IHttpLlmController, ILlmController } from "@typia/interface";
|
|
3
|
+
type ILangChainController = ILlmController | IHttpLlmController;
|
|
4
|
+
interface ILangChainToolsOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Whether to add controller name as prefix to tool names.
|
|
7
|
+
*
|
|
8
|
+
* If `true`, tool names become `{controllerName}_{methodName}`. If `false`,
|
|
9
|
+
* tool names are just `{methodName}`.
|
|
10
|
+
*
|
|
11
|
+
* @default false
|
|
12
|
+
*/
|
|
13
|
+
prefix?: boolean | undefined;
|
|
14
|
+
}
|
|
15
|
+
interface ILangChainToolsProps extends ILangChainToolsOptions {
|
|
16
|
+
/**
|
|
17
|
+
* List of controllers to convert to LangChain tools.
|
|
18
|
+
*
|
|
19
|
+
* - {@link ILlmController}: from `typia.llm.controller<Class>()`, converts all
|
|
20
|
+
* methods of the class to tools
|
|
21
|
+
* - {@link IHttpLlmController}: from `HttpLlm.controller()`, converts all
|
|
22
|
+
* operations from OpenAPI document to tools
|
|
23
|
+
*/
|
|
24
|
+
controllers: ILangChainController[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Convert typia controllers to LangChain tools.
|
|
28
|
+
*
|
|
29
|
+
* Converts TypeScript class methods via `typia.llm.controller<Class>()` or
|
|
30
|
+
* OpenAPI operations via `HttpLlm.controller()` to LangChain tools.
|
|
31
|
+
*
|
|
32
|
+
* Every tool call is validated by typia. If LLM provides invalid arguments,
|
|
33
|
+
* returns validation error formatted by {@link LlmJson.stringify} so that LLM
|
|
34
|
+
* can correct them automatically.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* import { initChatModel } from "langchain/chat_models/universal";
|
|
39
|
+
* import typia from "typia";
|
|
40
|
+
* import { toLangChainTools } from "@typia/langchain";
|
|
41
|
+
*
|
|
42
|
+
* class Calculator {
|
|
43
|
+
* add(input: { a: number; b: number }): { value: number } {
|
|
44
|
+
* return { value: input.a + input.b };
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
*
|
|
48
|
+
* const controller = typia.llm.controller<Calculator>(
|
|
49
|
+
* "calculator",
|
|
50
|
+
* new Calculator(),
|
|
51
|
+
* );
|
|
52
|
+
* const tools = toLangChainTools(controller);
|
|
53
|
+
*
|
|
54
|
+
* const llm = await initChatModel();
|
|
55
|
+
* const modelWithTools = llm.bindTools(tools);
|
|
56
|
+
* const result = await modelWithTools.invoke("What is 10 + 5?");
|
|
57
|
+
* ```;
|
|
58
|
+
*
|
|
59
|
+
* @param input Controller, controller list, or conversion properties
|
|
60
|
+
* @param options Conversion options when `input` is not a properties object
|
|
61
|
+
* @returns Array of LangChain DynamicStructuredTool
|
|
62
|
+
*/
|
|
63
|
+
export declare function toLangChainTools(controller: ILangChainController, options?: ILangChainToolsOptions | undefined): DynamicStructuredTool[];
|
|
64
|
+
export declare function toLangChainTools(controllers: ILangChainController[], options?: ILangChainToolsOptions | undefined): DynamicStructuredTool[];
|
|
65
|
+
export declare function toLangChainTools(props: ILangChainToolsProps): DynamicStructuredTool[];
|
|
66
|
+
export {};
|
|
@@ -3,29 +3,31 @@ import { IHttpLlmFunction, ILlmFunction } from "@typia/interface";
|
|
|
3
3
|
/**
|
|
4
4
|
* A Standard JSON Schema view of one typia function's parameters.
|
|
5
5
|
*
|
|
6
|
-
* LangChain's tool `schema` fills two roles at once:
|
|
7
|
-
* turns it into the parameters the model is shown,
|
|
8
|
-
* validates incoming arguments against it before the
|
|
9
|
-
* over a bare `ILlmSchema.IParameters` fills the first
|
|
10
|
-
* second — LangChain validates it with
|
|
11
|
-
* what typia would have coerced and
|
|
12
|
-
* typia's coercion and its correctable
|
|
6
|
+
* LangChain's tool `schema` fills two roles at once:
|
|
7
|
+
* `toJsonSchema(tool.schema)` turns it into the parameters the model is shown,
|
|
8
|
+
* and `StructuredTool.call` validates incoming arguments against it before the
|
|
9
|
+
* tool body runs. Handing over a bare `ILlmSchema.IParameters` fills the first
|
|
10
|
+
* role but forfeits the second — LangChain validates it with
|
|
11
|
+
* `@cfworker/json-schema`, which rejects what typia would have coerced and
|
|
12
|
+
* reports the failure in its own words, so typia's coercion and its correctable
|
|
13
|
+
* feedback both become unreachable.
|
|
13
14
|
*
|
|
14
|
-
* Standard JSON Schema separates the two roles. It carries a model-facing
|
|
15
|
-
* under `~standard.jsonSchema` and, by declaring no
|
|
16
|
-
* validator — which is exactly typia's position: show
|
|
17
|
-
* leave validation to `LlmJson.validateArguments` in
|
|
18
|
-
* reads the schema back through its own
|
|
19
|
-
* same parameters document as before,
|
|
15
|
+
* Standard JSON Schema separates the two roles. It carries a model-facing
|
|
16
|
+
* schema under `~standard.jsonSchema` and, by declaring no
|
|
17
|
+
* `~standard.validate`, no validator — which is exactly typia's position: show
|
|
18
|
+
* the model this schema, and leave validation to `LlmJson.validateArguments` in
|
|
19
|
+
* the tool body. LangChain reads the schema back through its own
|
|
20
|
+
* `toJsonSchema`, so the model sees the same parameters document as before,
|
|
21
|
+
* byte for byte.
|
|
20
22
|
*
|
|
21
|
-
* `@typia/vercel` states the same contract to the AI SDK through
|
|
22
|
-
* whose `validate` is likewise left undefined so that
|
|
23
|
-
* short-circuits its own validation.
|
|
23
|
+
* `@typia/vercel` states the same contract to the AI SDK through
|
|
24
|
+
* `jsonSchema()`, whose `validate` is likewise left undefined so that
|
|
25
|
+
* `safeValidateTypes` short-circuits its own validation.
|
|
24
26
|
*
|
|
25
27
|
* Two version floors hold this together, and both are pinned in the package
|
|
26
28
|
* manifest. `toJsonSchema` only reads `~standard.jsonSchema` from
|
|
27
|
-
* `@langchain/core@1.1.30` onwards — older versions return the wrapper itself
|
|
28
|
-
* would advertise
|
|
29
|
+
* `@langchain/core@1.1.30` onwards — older versions return the wrapper itself
|
|
30
|
+
* and would advertise _that_ to the model in place of the parameters — and
|
|
29
31
|
* `StandardJSONSchemaV1` only exists from `@standard-schema/spec@1.1.0`.
|
|
30
32
|
*
|
|
31
33
|
* @see https://github.com/standard-schema/standard-schema
|
|
@@ -4,29 +4,31 @@ exports.LangChainParameterConverter = void 0;
|
|
|
4
4
|
/**
|
|
5
5
|
* A Standard JSON Schema view of one typia function's parameters.
|
|
6
6
|
*
|
|
7
|
-
* LangChain's tool `schema` fills two roles at once:
|
|
8
|
-
* turns it into the parameters the model is shown,
|
|
9
|
-
* validates incoming arguments against it before the
|
|
10
|
-
* over a bare `ILlmSchema.IParameters` fills the first
|
|
11
|
-
* second — LangChain validates it with
|
|
12
|
-
* what typia would have coerced and
|
|
13
|
-
* typia's coercion and its correctable
|
|
7
|
+
* LangChain's tool `schema` fills two roles at once:
|
|
8
|
+
* `toJsonSchema(tool.schema)` turns it into the parameters the model is shown,
|
|
9
|
+
* and `StructuredTool.call` validates incoming arguments against it before the
|
|
10
|
+
* tool body runs. Handing over a bare `ILlmSchema.IParameters` fills the first
|
|
11
|
+
* role but forfeits the second — LangChain validates it with
|
|
12
|
+
* `@cfworker/json-schema`, which rejects what typia would have coerced and
|
|
13
|
+
* reports the failure in its own words, so typia's coercion and its correctable
|
|
14
|
+
* feedback both become unreachable.
|
|
14
15
|
*
|
|
15
|
-
* Standard JSON Schema separates the two roles. It carries a model-facing
|
|
16
|
-
* under `~standard.jsonSchema` and, by declaring no
|
|
17
|
-
* validator — which is exactly typia's position: show
|
|
18
|
-
* leave validation to `LlmJson.validateArguments` in
|
|
19
|
-
* reads the schema back through its own
|
|
20
|
-
* same parameters document as before,
|
|
16
|
+
* Standard JSON Schema separates the two roles. It carries a model-facing
|
|
17
|
+
* schema under `~standard.jsonSchema` and, by declaring no
|
|
18
|
+
* `~standard.validate`, no validator — which is exactly typia's position: show
|
|
19
|
+
* the model this schema, and leave validation to `LlmJson.validateArguments` in
|
|
20
|
+
* the tool body. LangChain reads the schema back through its own
|
|
21
|
+
* `toJsonSchema`, so the model sees the same parameters document as before,
|
|
22
|
+
* byte for byte.
|
|
21
23
|
*
|
|
22
|
-
* `@typia/vercel` states the same contract to the AI SDK through
|
|
23
|
-
* whose `validate` is likewise left undefined so that
|
|
24
|
-
* short-circuits its own validation.
|
|
24
|
+
* `@typia/vercel` states the same contract to the AI SDK through
|
|
25
|
+
* `jsonSchema()`, whose `validate` is likewise left undefined so that
|
|
26
|
+
* `safeValidateTypes` short-circuits its own validation.
|
|
25
27
|
*
|
|
26
28
|
* Two version floors hold this together, and both are pinned in the package
|
|
27
29
|
* manifest. `toJsonSchema` only reads `~standard.jsonSchema` from
|
|
28
|
-
* `@langchain/core@1.1.30` onwards — older versions return the wrapper itself
|
|
29
|
-
* would advertise
|
|
30
|
+
* `@langchain/core@1.1.30` onwards — older versions return the wrapper itself
|
|
31
|
+
* and would advertise _that_ to the model in place of the parameters — and
|
|
30
32
|
* `StandardJSONSchemaV1` only exists from `@standard-schema/spec@1.1.0`.
|
|
31
33
|
*
|
|
32
34
|
* @see https://github.com/standard-schema/standard-schema
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LangChainParameterConverter.js","sourceRoot":"","sources":["../../src/internal/LangChainParameterConverter.ts"],"names":[],"mappings":";;;AAGA
|
|
1
|
+
{"version":3,"file":"LangChainParameterConverter.js","sourceRoot":"","sources":["../../src/internal/LangChainParameterConverter.ts"],"names":[],"mappings":";;;AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,IAAiB,2BAA2B,CAmB3C;AAnBD,WAAiB,2BAA2B;IAC7B,mCAAO,GAAG,CACrB,IAAqC,EACf,EAAE;QACxB,4EAA4E;QAC5E,wCAAwC;QACxC,MAAM,UAAU,GAAG,GAA4B,EAAE,CAC/C,IAAI,CAAC,UAAgD,CAAC;QACxD,OAAO;YACL,WAAW,EAAE;gBACX,OAAO,EAAE,CAAC;gBACV,MAAM,EAAE,OAAO;gBACf,UAAU,EAAE;oBACV,KAAK,EAAE,UAAU;oBACjB,MAAM,EAAE,UAAU;iBACnB;aACF;SACF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC,EAnBgB,2BAA2B,aAA3B,2BAA2B,GAA3B,2BAA2B,QAmB3C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LangChainParameterConverter.mjs","names":[],"sources":["../../src/internal/LangChainParameterConverter.ts"],"sourcesContent":["import { StandardJSONSchemaV1 } from \"@standard-schema/spec\";\nimport { IHttpLlmFunction, ILlmFunction } from \"@typia/interface\";\n\n/**\n * A Standard JSON Schema view of one typia function's parameters.\n *\n * LangChain's tool `schema` fills two roles at once
|
|
1
|
+
{"version":3,"file":"LangChainParameterConverter.mjs","names":[],"sources":["../../src/internal/LangChainParameterConverter.ts"],"sourcesContent":["import { StandardJSONSchemaV1 } from \"@standard-schema/spec\";\nimport { IHttpLlmFunction, ILlmFunction } from \"@typia/interface\";\n\n/**\n * A Standard JSON Schema view of one typia function's parameters.\n *\n * LangChain's tool `schema` fills two roles at once:\n * `toJsonSchema(tool.schema)` turns it into the parameters the model is shown,\n * and `StructuredTool.call` validates incoming arguments against it before the\n * tool body runs. Handing over a bare `ILlmSchema.IParameters` fills the first\n * role but forfeits the second — LangChain validates it with\n * `@cfworker/json-schema`, which rejects what typia would have coerced and\n * reports the failure in its own words, so typia's coercion and its correctable\n * feedback both become unreachable.\n *\n * Standard JSON Schema separates the two roles. It carries a model-facing\n * schema under `~standard.jsonSchema` and, by declaring no\n * `~standard.validate`, no validator — which is exactly typia's position: show\n * the model this schema, and leave validation to `LlmJson.validateArguments` in\n * the tool body. LangChain reads the schema back through its own\n * `toJsonSchema`, so the model sees the same parameters document as before,\n * byte for byte.\n *\n * `@typia/vercel` states the same contract to the AI SDK through\n * `jsonSchema()`, whose `validate` is likewise left undefined so that\n * `safeValidateTypes` short-circuits its own validation.\n *\n * Two version floors hold this together, and both are pinned in the package\n * manifest. `toJsonSchema` only reads `~standard.jsonSchema` from\n * `@langchain/core@1.1.30` onwards — older versions return the wrapper itself\n * and would advertise _that_ to the model in place of the parameters — and\n * `StandardJSONSchemaV1` only exists from `@standard-schema/spec@1.1.0`.\n *\n * @see https://github.com/standard-schema/standard-schema\n */\nexport namespace LangChainParameterConverter {\n export const convert = (\n func: ILlmFunction | IHttpLlmFunction,\n ): StandardJSONSchemaV1 => {\n // Coercion never changes the shape a value must end up in, so the input and\n // output schemas are the same document.\n const jsonSchema = (): Record<string, unknown> =>\n func.parameters as unknown as Record<string, unknown>;\n return {\n \"~standard\": {\n version: 1,\n vendor: \"typia\",\n jsonSchema: {\n input: jsonSchema,\n output: jsonSchema,\n },\n },\n };\n };\n}\n"],"mappings":";AAmCO,IAAA;;yCAEH,SACyB;EAGzB,MAAM,mBACJ,KAAK;EACP,OAAO,EACL,aAAa;GACX,SAAS;GACT,QAAQ;GACR,YAAY;IACV,OAAO;IACP,QAAQ;GACV;EACF,EACF;CACF;GACD,gCAAA,8BAAA,CAAA,EAAD"}
|
|
@@ -59,6 +59,7 @@ var LangChainToolsRegistrar;
|
|
|
59
59
|
tools.push(createTool({
|
|
60
60
|
name: toolName,
|
|
61
61
|
function: func,
|
|
62
|
+
config: controller.application.config,
|
|
62
63
|
execute: (args) => __awaiter(this, void 0, void 0, function* () { return method.call(execute, args); }),
|
|
63
64
|
}));
|
|
64
65
|
}
|
|
@@ -71,6 +72,7 @@ var LangChainToolsRegistrar;
|
|
|
71
72
|
tools.push(createTool({
|
|
72
73
|
name: toolName,
|
|
73
74
|
function: func,
|
|
75
|
+
config: application.config,
|
|
74
76
|
execute: (args) => __awaiter(this, void 0, void 0, function* () {
|
|
75
77
|
if (controller.execute !== undefined) {
|
|
76
78
|
const response = yield controller.execute({
|
|
@@ -91,42 +93,68 @@ var LangChainToolsRegistrar;
|
|
|
91
93
|
}));
|
|
92
94
|
}
|
|
93
95
|
};
|
|
94
|
-
const createTool = (entry) => {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
96
|
+
const createTool = (entry) => {
|
|
97
|
+
var _a;
|
|
98
|
+
// A declared return type is a promise to the model, so a result that breaks
|
|
99
|
+
// it is reported rather than delivered. `@typia/mcp` and `@typia/vercel`
|
|
100
|
+
// already refuse one; this tool consulted `output` for its existence alone,
|
|
101
|
+
// so a method returning nothing was reported while a method returning the
|
|
102
|
+
// wrong shape was not (#2302).
|
|
103
|
+
//
|
|
104
|
+
// The application's own config decides how the schema is read back: a
|
|
105
|
+
// strict application carries its constraints as description tags instead of
|
|
106
|
+
// keywords, and only that config tells the inverter to read them.
|
|
107
|
+
const validateOutput = entry.function.output === undefined
|
|
108
|
+
? undefined
|
|
109
|
+
: utils_1.LlmJson.validate(entry.function.output, true, entry.config);
|
|
110
|
+
return (0, tools_1.tool)((args) => __awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
const valid = utils_1.LlmJson.validateArguments(entry.function, args !== null && args !== void 0 ? args : {});
|
|
112
|
+
if (valid.success === false)
|
|
113
|
+
throw new tools_1.ToolInputParsingException(`Type errors in "${entry.name}" arguments:\n\n` +
|
|
114
|
+
utils_1.LlmJson.stringify(valid), JSON.stringify(args !== null && args !== void 0 ? args : {}));
|
|
115
|
+
try {
|
|
116
|
+
const result = yield entry.execute(valid.data);
|
|
117
|
+
if (result === undefined) {
|
|
118
|
+
return validateOutput === undefined
|
|
119
|
+
? { success: true }
|
|
120
|
+
: {
|
|
121
|
+
success: false,
|
|
122
|
+
error: `Function "${entry.name}" returned undefined despite declaring an output schema`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if (validateOutput !== undefined) {
|
|
126
|
+
const output = validateOutput(result);
|
|
127
|
+
if (output.success === false)
|
|
128
|
+
return {
|
|
129
|
+
success: false,
|
|
130
|
+
error: `Type errors in "${entry.name}" output:
|
|
131
|
+
|
|
132
|
+
` + utils_1.LlmJson.stringify(output),
|
|
133
|
+
};
|
|
134
|
+
return { success: true, data: output.data };
|
|
135
|
+
}
|
|
136
|
+
return { success: true, data: result };
|
|
108
137
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}); };
|
|
138
|
+
catch (error) {
|
|
139
|
+
return {
|
|
140
|
+
success: false,
|
|
141
|
+
error: error instanceof Error
|
|
142
|
+
? `${error.name}: ${error.message}`
|
|
143
|
+
: String(error),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}), {
|
|
147
|
+
name: entry.name,
|
|
148
|
+
description: (_a = entry.function.description) !== null && _a !== void 0 ? _a : "",
|
|
149
|
+
// Declares the model-facing schema without a validator, so the
|
|
150
|
+
// coerce-and-validate step above is the only one that runs; see
|
|
151
|
+
// `LangChainParameterConverter`. The cast is needed because `tool()`
|
|
152
|
+
// still types `schema` as Zod-or-JSON-Schema, even though the
|
|
153
|
+
// `toJsonSchema` it reads that schema back with accepts Standard JSON
|
|
154
|
+
// Schema by its own public signature.
|
|
155
|
+
schema: LangChainParameterConverter_1.LangChainParameterConverter.convert(entry.function),
|
|
156
|
+
});
|
|
157
|
+
};
|
|
130
158
|
const getToolName = (controllerName, functionName, prefix) => (prefix ? `${controllerName}_${functionName}` : functionName);
|
|
131
159
|
})(LangChainToolsRegistrar || (exports.LangChainToolsRegistrar = LangChainToolsRegistrar = {}));
|
|
132
160
|
//# sourceMappingURL=LangChainToolsRegistrar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LangChainToolsRegistrar.js","sourceRoot":"","sources":["../../src/internal/LangChainToolsRegistrar.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,iDAI+B;
|
|
1
|
+
{"version":3,"file":"LangChainToolsRegistrar.js","sourceRoot":"","sources":["../../src/internal/LangChainToolsRegistrar.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,6 +32,7 @@ let LangChainToolsRegistrar;
|
|
|
32
32
|
tools.push(createTool({
|
|
33
33
|
name: toolName,
|
|
34
34
|
function: func,
|
|
35
|
+
config: controller.application.config,
|
|
35
36
|
execute: async (args) => method.call(execute, args)
|
|
36
37
|
}));
|
|
37
38
|
}
|
|
@@ -44,6 +45,7 @@ let LangChainToolsRegistrar;
|
|
|
44
45
|
tools.push(createTool({
|
|
45
46
|
name: toolName,
|
|
46
47
|
function: func,
|
|
48
|
+
config: application.config,
|
|
47
49
|
execute: async (args) => {
|
|
48
50
|
if (controller.execute !== void 0) return (await controller.execute({
|
|
49
51
|
connection,
|
|
@@ -61,30 +63,46 @@ let LangChainToolsRegistrar;
|
|
|
61
63
|
}));
|
|
62
64
|
}
|
|
63
65
|
};
|
|
64
|
-
const createTool = (entry) =>
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
66
|
+
const createTool = (entry) => {
|
|
67
|
+
const validateOutput = entry.function.output === void 0 ? void 0 : LlmJson.validate(entry.function.output, true, entry.config);
|
|
68
|
+
return tool(async (args) => {
|
|
69
|
+
const valid = LlmJson.validateArguments(entry.function, args ?? {});
|
|
70
|
+
if (valid.success === false) throw new ToolInputParsingException(`Type errors in "${entry.name}" arguments:\n\n` + LlmJson.stringify(valid), JSON.stringify(args ?? {}));
|
|
71
|
+
try {
|
|
72
|
+
const result = await entry.execute(valid.data);
|
|
73
|
+
if (result === void 0) return validateOutput === void 0 ? { success: true } : {
|
|
74
|
+
success: false,
|
|
75
|
+
error: `Function "${entry.name}" returned undefined despite declaring an output schema`
|
|
76
|
+
};
|
|
77
|
+
if (validateOutput !== void 0) {
|
|
78
|
+
const output = validateOutput(result);
|
|
79
|
+
if (output.success === false) return {
|
|
80
|
+
success: false,
|
|
81
|
+
error: `Type errors in "${entry.name}" output:
|
|
82
|
+
|
|
83
|
+
` + LlmJson.stringify(output)
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
success: true,
|
|
87
|
+
data: output.data
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
success: true,
|
|
92
|
+
data: result
|
|
93
|
+
};
|
|
94
|
+
} catch (error) {
|
|
95
|
+
return {
|
|
96
|
+
success: false,
|
|
97
|
+
error: error instanceof Error ? `${error.name}: ${error.message}` : String(error)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}, {
|
|
101
|
+
name: entry.name,
|
|
102
|
+
description: entry.function.description ?? "",
|
|
103
|
+
schema: LangChainParameterConverter.convert(entry.function)
|
|
104
|
+
});
|
|
105
|
+
};
|
|
88
106
|
const getToolName = (controllerName, functionName, prefix) => prefix ? `${controllerName}_${functionName}` : functionName;
|
|
89
107
|
})(LangChainToolsRegistrar || (LangChainToolsRegistrar = {}));
|
|
90
108
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LangChainToolsRegistrar.mjs","names":[],"sources":["../../src/internal/LangChainToolsRegistrar.ts"],"sourcesContent":["import {\n DynamicStructuredTool,\n ToolInputParsingException,\n tool,\n} from \"@langchain/core/tools\";\nimport type { JSONSchema } from \"@langchain/core/utils/json_schema\";\nimport {\n IHttpLlmController,\n IHttpLlmFunction,\n ILlmController,\n ILlmFunction,\n IValidation,\n} from \"@typia/interface\";\nimport { HttpLlm, LlmJson } from \"@typia/utils\";\n\nimport { LangChainParameterConverter } from \"./LangChainParameterConverter\";\n\nexport namespace LangChainToolsRegistrar {\n export const convert = (props: {\n controllers: Array<ILlmController | IHttpLlmController>;\n prefix?: boolean | undefined;\n }): DynamicStructuredTool[] => {\n const prefix: boolean = props.prefix ?? false;\n const tools: DynamicStructuredTool[] = [];\n\n // check duplicate tool names\n if (props.controllers.length >= 2) {\n const names: Map<string, string> = new Map();\n const duplicates: string[] = [];\n for (const controller of props.controllers) {\n for (const func of controller.application.functions) {\n const toolName: string = getToolName(\n controller.name,\n func.name,\n prefix,\n );\n const existing: string | undefined = names.get(toolName);\n const origin: string = `${controller.protocol} controller \"${controller.name}\" function \"${func.name}\"`;\n if (existing !== undefined)\n duplicates.push(\n `\"${toolName}\" from ${origin} (conflicts with ${existing})`,\n );\n else names.set(toolName, origin);\n }\n }\n if (duplicates.length > 0)\n throw new Error(\n `Duplicate tool names found:\\n - ${duplicates.join(\"\\n - \")}`,\n );\n }\n\n // convert controllers to tools\n for (const controller of props.controllers) {\n if (controller.protocol === \"class\") {\n convertClassController(tools, controller, prefix);\n } else {\n convertHttpController(tools, controller, prefix);\n }\n }\n\n return tools;\n };\n\n const convertClassController = (\n tools: DynamicStructuredTool[],\n controller: ILlmController,\n prefix: boolean,\n ): void => {\n const execute: Record<string, unknown> = controller.execute;\n\n for (const func of controller.application.functions) {\n const toolName: string = getToolName(controller.name, func.name, prefix);\n\n const method: unknown = execute[func.name];\n if (typeof method !== \"function\") {\n throw new Error(\n `Method \"${func.name}\" not found on controller \"${controller.name}\"`,\n );\n }\n\n tools.push(\n createTool({\n name: toolName,\n function: func,\n execute: async (args: unknown) => method.call(execute, args),\n }),\n );\n }\n };\n\n const convertHttpController = (\n tools: DynamicStructuredTool[],\n controller: IHttpLlmController,\n prefix: boolean,\n ): void => {\n const application = controller.application;\n const connection = controller.connection;\n\n for (const func of application.functions) {\n const toolName: string = getToolName(controller.name, func.name, prefix);\n\n tools.push(\n createTool({\n name: toolName,\n function: func,\n execute: async (args: unknown) => {\n if (controller.execute !== undefined) {\n const response = await controller.execute({\n connection,\n application,\n function: func,\n arguments: args as object,\n });\n return response.body;\n }\n return HttpLlm.execute({\n application,\n function: func,\n connection,\n input: args as object,\n });\n },\n }),\n );\n }\n };\n\n const createTool = (entry: {\n name: string;\n function: ILlmFunction | IHttpLlmFunction;\n execute: (args: unknown) => Promise<unknown>;\n }): DynamicStructuredTool =>\n tool(\n async (args: unknown): Promise<unknown> => {\n const valid: IValidation<unknown> = LlmJson.validateArguments(\n entry.function,\n args ?? {},\n );\n if (valid.success === false)\n throw new ToolInputParsingException(\n `Type errors in \"${entry.name}\" arguments:\\n\\n` +\n LlmJson.stringify(valid),\n JSON.stringify(args ?? {}),\n );\n try {\n const result: unknown = await entry.execute(valid.data);\n if (result === undefined) {\n return entry.function.output === undefined\n ? ({ success: true } satisfies ITryResult)\n : ({\n success: false,\n error: `Function \"${entry.name}\" returned undefined despite declaring an output schema`,\n } satisfies ITryResult);\n }\n return { success: true, data: result } satisfies ITryResult;\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? `${error.name}: ${error.message}`\n : String(error),\n } satisfies ITryResult;\n }\n },\n {\n name: entry.name,\n description: entry.function.description ?? \"\",\n // Declares the model-facing schema without a validator, so the\n // coerce-and-validate step above is the only one that runs; see\n // `LangChainParameterConverter`. The cast is needed because `tool()`\n // still types `schema` as Zod-or-JSON-Schema, even though the\n // `toJsonSchema` it reads that schema back with accepts Standard JSON\n // Schema by its own public signature.\n schema: LangChainParameterConverter.convert(\n entry.function,\n ) as JSONSchema,\n },\n );\n\n const getToolName = (\n controllerName: string,\n functionName: string,\n prefix: boolean,\n ): string => (prefix ? `${controllerName}_${functionName}` : functionName);\n}\n\ntype ITryResult =\n | { success: true; data?: unknown | undefined }\n | { success: false; error: string };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"LangChainToolsRegistrar.mjs","names":[],"sources":["../../src/internal/LangChainToolsRegistrar.ts"],"sourcesContent":["import {\n DynamicStructuredTool,\n ToolInputParsingException,\n tool,\n} from \"@langchain/core/tools\";\nimport type { JSONSchema } from \"@langchain/core/utils/json_schema\";\nimport {\n IHttpLlmController,\n IHttpLlmFunction,\n ILlmController,\n ILlmFunction,\n ILlmSchema,\n IValidation,\n} from \"@typia/interface\";\nimport { HttpLlm, LlmJson } from \"@typia/utils\";\n\nimport { LangChainParameterConverter } from \"./LangChainParameterConverter\";\n\nexport namespace LangChainToolsRegistrar {\n export const convert = (props: {\n controllers: Array<ILlmController | IHttpLlmController>;\n prefix?: boolean | undefined;\n }): DynamicStructuredTool[] => {\n const prefix: boolean = props.prefix ?? false;\n const tools: DynamicStructuredTool[] = [];\n\n // check duplicate tool names\n if (props.controllers.length >= 2) {\n const names: Map<string, string> = new Map();\n const duplicates: string[] = [];\n for (const controller of props.controllers) {\n for (const func of controller.application.functions) {\n const toolName: string = getToolName(\n controller.name,\n func.name,\n prefix,\n );\n const existing: string | undefined = names.get(toolName);\n const origin: string = `${controller.protocol} controller \"${controller.name}\" function \"${func.name}\"`;\n if (existing !== undefined)\n duplicates.push(\n `\"${toolName}\" from ${origin} (conflicts with ${existing})`,\n );\n else names.set(toolName, origin);\n }\n }\n if (duplicates.length > 0)\n throw new Error(\n `Duplicate tool names found:\\n - ${duplicates.join(\"\\n - \")}`,\n );\n }\n\n // convert controllers to tools\n for (const controller of props.controllers) {\n if (controller.protocol === \"class\") {\n convertClassController(tools, controller, prefix);\n } else {\n convertHttpController(tools, controller, prefix);\n }\n }\n\n return tools;\n };\n\n const convertClassController = (\n tools: DynamicStructuredTool[],\n controller: ILlmController,\n prefix: boolean,\n ): void => {\n const execute: Record<string, unknown> = controller.execute;\n\n for (const func of controller.application.functions) {\n const toolName: string = getToolName(controller.name, func.name, prefix);\n\n const method: unknown = execute[func.name];\n if (typeof method !== \"function\") {\n throw new Error(\n `Method \"${func.name}\" not found on controller \"${controller.name}\"`,\n );\n }\n\n tools.push(\n createTool({\n name: toolName,\n function: func,\n config: controller.application.config,\n execute: async (args: unknown) => method.call(execute, args),\n }),\n );\n }\n };\n\n const convertHttpController = (\n tools: DynamicStructuredTool[],\n controller: IHttpLlmController,\n prefix: boolean,\n ): void => {\n const application = controller.application;\n const connection = controller.connection;\n\n for (const func of application.functions) {\n const toolName: string = getToolName(controller.name, func.name, prefix);\n\n tools.push(\n createTool({\n name: toolName,\n function: func,\n config: application.config,\n execute: async (args: unknown) => {\n if (controller.execute !== undefined) {\n const response = await controller.execute({\n connection,\n application,\n function: func,\n arguments: args as object,\n });\n return response.body;\n }\n return HttpLlm.execute({\n application,\n function: func,\n connection,\n input: args as object,\n });\n },\n }),\n );\n }\n };\n\n const createTool = (entry: {\n name: string;\n function: ILlmFunction | IHttpLlmFunction;\n config: ILlmSchema.IConfig;\n execute: (args: unknown) => Promise<unknown>;\n }): DynamicStructuredTool => {\n // A declared return type is a promise to the model, so a result that breaks\n // it is reported rather than delivered. `@typia/mcp` and `@typia/vercel`\n // already refuse one; this tool consulted `output` for its existence alone,\n // so a method returning nothing was reported while a method returning the\n // wrong shape was not (#2302).\n //\n // The application's own config decides how the schema is read back: a\n // strict application carries its constraints as description tags instead of\n // keywords, and only that config tells the inverter to read them.\n const validateOutput:\n | ((output: unknown) => IValidation<unknown>)\n | undefined =\n entry.function.output === undefined\n ? undefined\n : LlmJson.validate(entry.function.output, true, entry.config);\n return tool(\n async (args: unknown): Promise<unknown> => {\n const valid: IValidation<unknown> = LlmJson.validateArguments(\n entry.function,\n args ?? {},\n );\n if (valid.success === false)\n throw new ToolInputParsingException(\n `Type errors in \"${entry.name}\" arguments:\\n\\n` +\n LlmJson.stringify(valid),\n JSON.stringify(args ?? {}),\n );\n try {\n const result: unknown = await entry.execute(valid.data);\n if (result === undefined) {\n return validateOutput === undefined\n ? ({ success: true } satisfies ITryResult)\n : ({\n success: false,\n error: `Function \"${entry.name}\" returned undefined despite declaring an output schema`,\n } satisfies ITryResult);\n }\n if (validateOutput !== undefined) {\n const output: IValidation<unknown> = validateOutput(result);\n if (output.success === false)\n return {\n success: false,\n error:\n `Type errors in \"${entry.name}\" output:\n\n` + LlmJson.stringify(output),\n } satisfies ITryResult;\n return { success: true, data: output.data } satisfies ITryResult;\n }\n return { success: true, data: result } satisfies ITryResult;\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? `${error.name}: ${error.message}`\n : String(error),\n } satisfies ITryResult;\n }\n },\n {\n name: entry.name,\n description: entry.function.description ?? \"\",\n // Declares the model-facing schema without a validator, so the\n // coerce-and-validate step above is the only one that runs; see\n // `LangChainParameterConverter`. The cast is needed because `tool()`\n // still types `schema` as Zod-or-JSON-Schema, even though the\n // `toJsonSchema` it reads that schema back with accepts Standard JSON\n // Schema by its own public signature.\n schema: LangChainParameterConverter.convert(\n entry.function,\n ) as JSONSchema,\n },\n );\n };\n\n const getToolName = (\n controllerName: string,\n functionName: string,\n prefix: boolean,\n ): string => (prefix ? `${controllerName}_${functionName}` : functionName);\n}\n\ntype ITryResult =\n | { success: true; data?: unknown | undefined }\n | { success: false; error: string };\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typia/langchain",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.3.0",
|
|
4
4
|
"description": "LangChain.js integration for typia",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
|
+
"import": {
|
|
9
|
+
"types": "./lib/index.d.mts",
|
|
10
|
+
"default": "./lib/index.mjs"
|
|
11
|
+
},
|
|
12
|
+
"require": {
|
|
13
|
+
"types": "./lib/index.d.cts",
|
|
14
|
+
"default": "./lib/index.js"
|
|
15
|
+
},
|
|
8
16
|
"types": "./lib/index.d.ts",
|
|
9
|
-
"import": "./lib/index.mjs",
|
|
10
17
|
"default": "./lib/index.js"
|
|
11
18
|
},
|
|
12
19
|
"./package.json": "./package.json"
|
|
@@ -23,8 +30,8 @@
|
|
|
23
30
|
"homepage": "https://typia.io",
|
|
24
31
|
"dependencies": {
|
|
25
32
|
"@standard-schema/spec": "^1.1.0",
|
|
26
|
-
"@typia/interface": "^13.
|
|
27
|
-
"@typia/utils": "^13.
|
|
33
|
+
"@typia/interface": "^13.3.0",
|
|
34
|
+
"@typia/utils": "^13.3.0"
|
|
28
35
|
},
|
|
29
36
|
"peerDependencies": {
|
|
30
37
|
"@langchain/core": ">=1.1.30"
|
|
@@ -61,7 +68,7 @@
|
|
|
61
68
|
"access": "public"
|
|
62
69
|
},
|
|
63
70
|
"scripts": {
|
|
64
|
-
"build": "rimraf lib && ttsc && rolldown -c",
|
|
71
|
+
"build": "rimraf lib && ttsc && node ../../scripts/create-conditional-declarations.cjs lib/index.d.ts && rolldown -c",
|
|
65
72
|
"dev": "ttsc --watch"
|
|
66
73
|
},
|
|
67
74
|
"module": "lib/index.mjs",
|
|
@@ -4,29 +4,31 @@ import { IHttpLlmFunction, ILlmFunction } from "@typia/interface";
|
|
|
4
4
|
/**
|
|
5
5
|
* A Standard JSON Schema view of one typia function's parameters.
|
|
6
6
|
*
|
|
7
|
-
* LangChain's tool `schema` fills two roles at once:
|
|
8
|
-
* turns it into the parameters the model is shown,
|
|
9
|
-
* validates incoming arguments against it before the
|
|
10
|
-
* over a bare `ILlmSchema.IParameters` fills the first
|
|
11
|
-
* second — LangChain validates it with
|
|
12
|
-
* what typia would have coerced and
|
|
13
|
-
* typia's coercion and its correctable
|
|
7
|
+
* LangChain's tool `schema` fills two roles at once:
|
|
8
|
+
* `toJsonSchema(tool.schema)` turns it into the parameters the model is shown,
|
|
9
|
+
* and `StructuredTool.call` validates incoming arguments against it before the
|
|
10
|
+
* tool body runs. Handing over a bare `ILlmSchema.IParameters` fills the first
|
|
11
|
+
* role but forfeits the second — LangChain validates it with
|
|
12
|
+
* `@cfworker/json-schema`, which rejects what typia would have coerced and
|
|
13
|
+
* reports the failure in its own words, so typia's coercion and its correctable
|
|
14
|
+
* feedback both become unreachable.
|
|
14
15
|
*
|
|
15
|
-
* Standard JSON Schema separates the two roles. It carries a model-facing
|
|
16
|
-
* under `~standard.jsonSchema` and, by declaring no
|
|
17
|
-
* validator — which is exactly typia's position: show
|
|
18
|
-
* leave validation to `LlmJson.validateArguments` in
|
|
19
|
-
* reads the schema back through its own
|
|
20
|
-
* same parameters document as before,
|
|
16
|
+
* Standard JSON Schema separates the two roles. It carries a model-facing
|
|
17
|
+
* schema under `~standard.jsonSchema` and, by declaring no
|
|
18
|
+
* `~standard.validate`, no validator — which is exactly typia's position: show
|
|
19
|
+
* the model this schema, and leave validation to `LlmJson.validateArguments` in
|
|
20
|
+
* the tool body. LangChain reads the schema back through its own
|
|
21
|
+
* `toJsonSchema`, so the model sees the same parameters document as before,
|
|
22
|
+
* byte for byte.
|
|
21
23
|
*
|
|
22
|
-
* `@typia/vercel` states the same contract to the AI SDK through
|
|
23
|
-
* whose `validate` is likewise left undefined so that
|
|
24
|
-
* short-circuits its own validation.
|
|
24
|
+
* `@typia/vercel` states the same contract to the AI SDK through
|
|
25
|
+
* `jsonSchema()`, whose `validate` is likewise left undefined so that
|
|
26
|
+
* `safeValidateTypes` short-circuits its own validation.
|
|
25
27
|
*
|
|
26
28
|
* Two version floors hold this together, and both are pinned in the package
|
|
27
29
|
* manifest. `toJsonSchema` only reads `~standard.jsonSchema` from
|
|
28
|
-
* `@langchain/core@1.1.30` onwards — older versions return the wrapper itself
|
|
29
|
-
* would advertise
|
|
30
|
+
* `@langchain/core@1.1.30` onwards — older versions return the wrapper itself
|
|
31
|
+
* and would advertise _that_ to the model in place of the parameters — and
|
|
30
32
|
* `StandardJSONSchemaV1` only exists from `@standard-schema/spec@1.1.0`.
|
|
31
33
|
*
|
|
32
34
|
* @see https://github.com/standard-schema/standard-schema
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
IHttpLlmFunction,
|
|
10
10
|
ILlmController,
|
|
11
11
|
ILlmFunction,
|
|
12
|
+
ILlmSchema,
|
|
12
13
|
IValidation,
|
|
13
14
|
} from "@typia/interface";
|
|
14
15
|
import { HttpLlm, LlmJson } from "@typia/utils";
|
|
@@ -82,6 +83,7 @@ export namespace LangChainToolsRegistrar {
|
|
|
82
83
|
createTool({
|
|
83
84
|
name: toolName,
|
|
84
85
|
function: func,
|
|
86
|
+
config: controller.application.config,
|
|
85
87
|
execute: async (args: unknown) => method.call(execute, args),
|
|
86
88
|
}),
|
|
87
89
|
);
|
|
@@ -103,6 +105,7 @@ export namespace LangChainToolsRegistrar {
|
|
|
103
105
|
createTool({
|
|
104
106
|
name: toolName,
|
|
105
107
|
function: func,
|
|
108
|
+
config: application.config,
|
|
106
109
|
execute: async (args: unknown) => {
|
|
107
110
|
if (controller.execute !== undefined) {
|
|
108
111
|
const response = await controller.execute({
|
|
@@ -128,9 +131,25 @@ export namespace LangChainToolsRegistrar {
|
|
|
128
131
|
const createTool = (entry: {
|
|
129
132
|
name: string;
|
|
130
133
|
function: ILlmFunction | IHttpLlmFunction;
|
|
134
|
+
config: ILlmSchema.IConfig;
|
|
131
135
|
execute: (args: unknown) => Promise<unknown>;
|
|
132
|
-
}): DynamicStructuredTool =>
|
|
133
|
-
|
|
136
|
+
}): DynamicStructuredTool => {
|
|
137
|
+
// A declared return type is a promise to the model, so a result that breaks
|
|
138
|
+
// it is reported rather than delivered. `@typia/mcp` and `@typia/vercel`
|
|
139
|
+
// already refuse one; this tool consulted `output` for its existence alone,
|
|
140
|
+
// so a method returning nothing was reported while a method returning the
|
|
141
|
+
// wrong shape was not (#2302).
|
|
142
|
+
//
|
|
143
|
+
// The application's own config decides how the schema is read back: a
|
|
144
|
+
// strict application carries its constraints as description tags instead of
|
|
145
|
+
// keywords, and only that config tells the inverter to read them.
|
|
146
|
+
const validateOutput:
|
|
147
|
+
| ((output: unknown) => IValidation<unknown>)
|
|
148
|
+
| undefined =
|
|
149
|
+
entry.function.output === undefined
|
|
150
|
+
? undefined
|
|
151
|
+
: LlmJson.validate(entry.function.output, true, entry.config);
|
|
152
|
+
return tool(
|
|
134
153
|
async (args: unknown): Promise<unknown> => {
|
|
135
154
|
const valid: IValidation<unknown> = LlmJson.validateArguments(
|
|
136
155
|
entry.function,
|
|
@@ -145,13 +164,25 @@ export namespace LangChainToolsRegistrar {
|
|
|
145
164
|
try {
|
|
146
165
|
const result: unknown = await entry.execute(valid.data);
|
|
147
166
|
if (result === undefined) {
|
|
148
|
-
return
|
|
167
|
+
return validateOutput === undefined
|
|
149
168
|
? ({ success: true } satisfies ITryResult)
|
|
150
169
|
: ({
|
|
151
170
|
success: false,
|
|
152
171
|
error: `Function "${entry.name}" returned undefined despite declaring an output schema`,
|
|
153
172
|
} satisfies ITryResult);
|
|
154
173
|
}
|
|
174
|
+
if (validateOutput !== undefined) {
|
|
175
|
+
const output: IValidation<unknown> = validateOutput(result);
|
|
176
|
+
if (output.success === false)
|
|
177
|
+
return {
|
|
178
|
+
success: false,
|
|
179
|
+
error:
|
|
180
|
+
`Type errors in "${entry.name}" output:
|
|
181
|
+
|
|
182
|
+
` + LlmJson.stringify(output),
|
|
183
|
+
} satisfies ITryResult;
|
|
184
|
+
return { success: true, data: output.data } satisfies ITryResult;
|
|
185
|
+
}
|
|
155
186
|
return { success: true, data: result } satisfies ITryResult;
|
|
156
187
|
} catch (error) {
|
|
157
188
|
return {
|
|
@@ -177,6 +208,7 @@ export namespace LangChainToolsRegistrar {
|
|
|
177
208
|
) as JSONSchema,
|
|
178
209
|
},
|
|
179
210
|
);
|
|
211
|
+
};
|
|
180
212
|
|
|
181
213
|
const getToolName = (
|
|
182
214
|
controllerName: string,
|