@agentica/core 0.16.8 → 0.16.9
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/context/AgenticaOperation.d.ts +4 -2
- package/lib/context/internal/AgenticaOperationComposer.d.ts +0 -9
- package/lib/context/internal/AgenticaOperationComposer.js +105 -35
- package/lib/context/internal/AgenticaOperationComposer.js.map +1 -1
- package/lib/context/internal/AgenticaOperationComposer.spec.d.ts +1 -0
- package/lib/context/internal/AgenticaOperationComposer.spec.js +266 -0
- package/lib/context/internal/AgenticaOperationComposer.spec.js.map +1 -0
- package/lib/functional/assertHttpLlmApplication.js +31 -31
- package/lib/functional/assertMcpLlmApplication.d.ts +15 -0
- package/lib/functional/assertMcpLlmApplication.js +59 -0
- package/lib/functional/assertMcpLlmApplication.js.map +1 -0
- package/lib/functional/validateHttpLlmApplication.js +27 -27
- package/lib/index.d.ts +1 -0
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +406 -204
- package/lib/index.mjs.map +1 -1
- package/lib/json/IAgenticaOperationJson.d.ts +1 -1
- package/lib/orchestrate/call.js +204 -94
- package/lib/orchestrate/call.js.map +1 -1
- package/lib/orchestrate/initialize.js +60 -60
- package/lib/structures/IAgenticaController.d.ts +9 -2
- package/lib/structures/mcp/IMcpLlmApplication.d.ts +15 -0
- package/lib/structures/mcp/IMcpLlmApplication.js +3 -0
- package/lib/structures/mcp/IMcpLlmApplication.js.map +1 -0
- package/lib/structures/mcp/IMcpLlmFunction.d.ts +17 -0
- package/lib/structures/mcp/IMcpLlmFunction.js +3 -0
- package/lib/structures/mcp/IMcpLlmFunction.js.map +1 -0
- package/lib/structures/mcp/IMcpLlmTransportProps.d.ts +11 -0
- package/lib/structures/mcp/IMcpLlmTransportProps.js +3 -0
- package/lib/structures/mcp/IMcpLlmTransportProps.js.map +1 -0
- package/lib/structures/mcp/index.d.ts +3 -0
- package/lib/structures/mcp/index.js +20 -0
- package/lib/structures/mcp/index.js.map +1 -0
- package/package.json +11 -6
- package/src/context/AgenticaOperation.ts +9 -2
- package/src/context/internal/AgenticaOperationComposer.spec.ts +314 -0
- package/src/context/internal/AgenticaOperationComposer.ts +119 -49
- package/src/functional/assertMcpLlmApplication.ts +48 -0
- package/src/index.ts +6 -2
- package/src/json/IAgenticaOperationJson.ts +1 -1
- package/src/orchestrate/call.ts +237 -135
- package/src/structures/IAgenticaController.ts +12 -2
- package/src/structures/mcp/IMcpLlmApplication.ts +17 -0
- package/src/structures/mcp/IMcpLlmFunction.ts +19 -0
- package/src/structures/mcp/IMcpLlmTransportProps.ts +13 -0
- package/src/structures/mcp/index.ts +3 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP LLM function.
|
|
3
|
+
*/
|
|
4
|
+
export interface IMcpLlmFunction {
|
|
5
|
+
/**
|
|
6
|
+
* Name of the function.
|
|
7
|
+
*/
|
|
8
|
+
name: string;
|
|
9
|
+
/**
|
|
10
|
+
* Description of the function.
|
|
11
|
+
*/
|
|
12
|
+
description?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Parameters of the function.
|
|
15
|
+
*/
|
|
16
|
+
parameters: object;
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IMcpLlmFunction.js","sourceRoot":"","sources":["../../../src/structures/mcp/IMcpLlmFunction.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SSEClientTransportOptions } from "@modelcontextprotocol/sdk/client/sse.d.ts";
|
|
2
|
+
import type { StdioServerParameters } from "@modelcontextprotocol/sdk/client/stdio.d.ts";
|
|
3
|
+
export type IMcpLlmTransportProps = IMcpLlmTransportPropsHttp | IMcpLlmTransportPropsStdio;
|
|
4
|
+
export interface IMcpLlmTransportPropsHttp extends IMcpLlmTransportPropsBase<"sse">, SSEClientTransportOptions {
|
|
5
|
+
url: URL;
|
|
6
|
+
}
|
|
7
|
+
export interface IMcpLlmTransportPropsStdio extends IMcpLlmTransportPropsBase<"stdio">, StdioServerParameters {
|
|
8
|
+
}
|
|
9
|
+
export interface IMcpLlmTransportPropsBase<T extends string> {
|
|
10
|
+
type: T;
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IMcpLlmTransportProps.js","sourceRoot":"","sources":["../../../src/structures/mcp/IMcpLlmTransportProps.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./IMcpLlmApplication"), exports);
|
|
18
|
+
__exportStar(require("./IMcpLlmFunction"), exports);
|
|
19
|
+
__exportStar(require("./IMcpLlmTransportProps"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/structures/mcp/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAqC;AACrC,oDAAkC;AAClC,0DAAwC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentica/core",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.9",
|
|
4
4
|
"description": "Agentic AI Library specialized in LLM Function Calling",
|
|
5
5
|
"author": "Wrtn Technologies",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,9 +36,10 @@
|
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@
|
|
40
|
-
"
|
|
41
|
-
"
|
|
39
|
+
"@modelcontextprotocol/sdk": "^1.9.0",
|
|
40
|
+
"@samchon/openapi": "^4.0.0",
|
|
41
|
+
"openai": "^4.80.0",
|
|
42
|
+
"typia": "^9.0.1"
|
|
42
43
|
},
|
|
43
44
|
"dependencies": {
|
|
44
45
|
"@samchon/openapi": "^4.0.0",
|
|
@@ -46,9 +47,11 @@
|
|
|
46
47
|
"uuid": "^11.0.4"
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|
|
50
|
+
"@modelcontextprotocol/sdk": "^1.9.0",
|
|
49
51
|
"@nestia/e2e": "^6.0.1",
|
|
50
52
|
"@rollup/plugin-terser": "^0.4.4",
|
|
51
53
|
"@rollup/plugin-typescript": "^12.1.2",
|
|
54
|
+
"@ryoppippi/unplugin-typia": "^2.1.4",
|
|
52
55
|
"@types/node": "^22.13.4",
|
|
53
56
|
"@types/uuid": "^10.0.0",
|
|
54
57
|
"openai": "^4.80.0",
|
|
@@ -57,14 +60,16 @@
|
|
|
57
60
|
"ts-node": "^10.9.2",
|
|
58
61
|
"ts-patch": "^3.3.0",
|
|
59
62
|
"typedoc": "^0.27.7",
|
|
60
|
-
"typescript": "~5.8.3"
|
|
63
|
+
"typescript": "~5.8.3",
|
|
64
|
+
"vitest": "^3.0.9"
|
|
61
65
|
},
|
|
62
66
|
"scripts": {
|
|
63
67
|
"build": "rimraf lib && pnpm build:prompt && tsc && rollup -c",
|
|
64
68
|
"build:prompt": "node build/prompt.js",
|
|
65
69
|
"dev": "rimraf lib && tsc --watch",
|
|
66
70
|
"lint": "eslint .",
|
|
67
|
-
"format": "eslint --fix ."
|
|
71
|
+
"format": "eslint --fix .",
|
|
72
|
+
"test": "vitest"
|
|
68
73
|
},
|
|
69
74
|
"module": "lib/index.mjs",
|
|
70
75
|
"typings": "lib/index.d.ts"
|
|
@@ -2,6 +2,7 @@ import type { IHttpLlmFunction, ILlmFunction, ILlmSchema } from "@samchon/openap
|
|
|
2
2
|
|
|
3
3
|
import type { IAgenticaOperationJson } from "../json/IAgenticaOperationJson";
|
|
4
4
|
import type { IAgenticaController } from "../structures/IAgenticaController";
|
|
5
|
+
import type { IMcpLlmFunction } from "../structures/mcp/IMcpLlmFunction";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Operation information in the Agentica Agent.
|
|
@@ -20,7 +21,8 @@ import type { IAgenticaController } from "../structures/IAgenticaController";
|
|
|
20
21
|
*/
|
|
21
22
|
export type AgenticaOperation<Model extends ILlmSchema.Model> =
|
|
22
23
|
| AgenticaOperation.Class<Model>
|
|
23
|
-
| AgenticaOperation.Http<Model
|
|
24
|
+
| AgenticaOperation.Http<Model>
|
|
25
|
+
| AgenticaOperation.Mcp;
|
|
24
26
|
export namespace AgenticaOperation {
|
|
25
27
|
export type Class<Model extends ILlmSchema.Model> = Base<
|
|
26
28
|
"class",
|
|
@@ -32,9 +34,14 @@ export namespace AgenticaOperation {
|
|
|
32
34
|
IAgenticaController.IHttp<Model>,
|
|
33
35
|
IHttpLlmFunction<Model>
|
|
34
36
|
>;
|
|
37
|
+
export type Mcp = Base<
|
|
38
|
+
"mcp",
|
|
39
|
+
IAgenticaController.IMcp,
|
|
40
|
+
IMcpLlmFunction
|
|
41
|
+
>;
|
|
35
42
|
|
|
36
43
|
interface Base<
|
|
37
|
-
Protocol extends "http" | "class",
|
|
44
|
+
Protocol extends "http" | "class" | "mcp",
|
|
38
45
|
Controller extends object,
|
|
39
46
|
Function extends object,
|
|
40
47
|
> {
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import type { IHttpLlmFunction, ILlmFunction, IValidation } from "@samchon/openapi";
|
|
2
|
+
|
|
3
|
+
import type { IAgenticaConfig } from "../../structures/IAgenticaConfig";
|
|
4
|
+
import type { IAgenticaController } from "../../structures/IAgenticaController";
|
|
5
|
+
import type { IMcpLlmFunction } from "../../structures/mcp/IMcpLlmFunction";
|
|
6
|
+
|
|
7
|
+
import { compose, divide, getOperations, toClassOperations, toHttpOperations, toMcpOperations } from "./AgenticaOperationComposer";
|
|
8
|
+
|
|
9
|
+
// test helper functions
|
|
10
|
+
function createMockHttpFunction(name: string, method: "get" | "post" | "patch" | "put" | "delete", path: string): IHttpLlmFunction<any> {
|
|
11
|
+
return {
|
|
12
|
+
name,
|
|
13
|
+
method,
|
|
14
|
+
path,
|
|
15
|
+
validate: () => ({ success: true, data: {} } as IValidation<unknown>),
|
|
16
|
+
operation: () => ({}),
|
|
17
|
+
route: () => ({
|
|
18
|
+
method,
|
|
19
|
+
path,
|
|
20
|
+
emendedPath: path,
|
|
21
|
+
accessor: [name],
|
|
22
|
+
body: null,
|
|
23
|
+
query: null,
|
|
24
|
+
parameters: [],
|
|
25
|
+
headers: null,
|
|
26
|
+
success: null,
|
|
27
|
+
exceptions: {},
|
|
28
|
+
comment: () => "OK",
|
|
29
|
+
operation: () => ({}),
|
|
30
|
+
}),
|
|
31
|
+
parameters: {},
|
|
32
|
+
output: {},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function createMockHttpController(name: string, functions: IHttpLlmFunction<any>[]): IAgenticaController.IHttp<any> {
|
|
37
|
+
return {
|
|
38
|
+
name,
|
|
39
|
+
protocol: "http",
|
|
40
|
+
connection: { host: "https://example.com" },
|
|
41
|
+
application: {
|
|
42
|
+
model: "chatgpt",
|
|
43
|
+
options: {},
|
|
44
|
+
functions,
|
|
45
|
+
errors: [],
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function createMockClassController(name: string, functions: ILlmFunction<any>[]): IAgenticaController.IClass<any> {
|
|
51
|
+
return {
|
|
52
|
+
name,
|
|
53
|
+
protocol: "class",
|
|
54
|
+
application: {
|
|
55
|
+
model: "chatgpt",
|
|
56
|
+
options: {},
|
|
57
|
+
functions,
|
|
58
|
+
},
|
|
59
|
+
execute: {},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function createMockMcpController(name: string, functions: IMcpLlmFunction[]): IAgenticaController.IMcp {
|
|
64
|
+
return {
|
|
65
|
+
name,
|
|
66
|
+
protocol: "mcp",
|
|
67
|
+
application: {
|
|
68
|
+
transport: {
|
|
69
|
+
type: "sse",
|
|
70
|
+
url: new URL("https://example.com"),
|
|
71
|
+
},
|
|
72
|
+
functions,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
describe("a AgenticaOperationComposer", () => {
|
|
78
|
+
describe("compose", () => {
|
|
79
|
+
it("should compose operations from controllers", () => {
|
|
80
|
+
// Mock controllers
|
|
81
|
+
const mockHttpController = createMockHttpController("httpController", [
|
|
82
|
+
createMockHttpFunction("function1", "get", "/api/function1"),
|
|
83
|
+
createMockHttpFunction("function2", "post", "/api/function2"),
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
const mockClassController = createMockClassController("classController", [
|
|
87
|
+
{
|
|
88
|
+
name: "function3",
|
|
89
|
+
validate: () => ({ success: true, data: {} } as IValidation<unknown>),
|
|
90
|
+
parameters: {},
|
|
91
|
+
output: {},
|
|
92
|
+
},
|
|
93
|
+
]);
|
|
94
|
+
|
|
95
|
+
const mockMcpController = createMockMcpController("mcpController", [
|
|
96
|
+
{
|
|
97
|
+
name: "function4",
|
|
98
|
+
parameters: {},
|
|
99
|
+
},
|
|
100
|
+
]);
|
|
101
|
+
|
|
102
|
+
const controllers = [mockHttpController, mockClassController, mockMcpController];
|
|
103
|
+
|
|
104
|
+
const result = compose({ controllers });
|
|
105
|
+
|
|
106
|
+
expect(result.array).toHaveLength(4);
|
|
107
|
+
expect(result.flat).toBeInstanceOf(Map);
|
|
108
|
+
expect(result.group).toBeInstanceOf(Map);
|
|
109
|
+
expect(result.divided).toBeUndefined();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("should divide operations when capacity is provided", () => {
|
|
113
|
+
// Mock controllers
|
|
114
|
+
const mockController = createMockHttpController("httpController", [
|
|
115
|
+
createMockHttpFunction("function1", "get", "/api/function1"),
|
|
116
|
+
createMockHttpFunction("function2", "post", "/api/function2"),
|
|
117
|
+
createMockHttpFunction("function3", "put", "/api/function3"),
|
|
118
|
+
createMockHttpFunction("function4", "delete", "/api/function4"),
|
|
119
|
+
createMockHttpFunction("function5", "patch", "/api/function5"),
|
|
120
|
+
]);
|
|
121
|
+
|
|
122
|
+
const config: IAgenticaConfig<any> = {
|
|
123
|
+
capacity: 2,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const result = compose({ controllers: [mockController], config });
|
|
127
|
+
|
|
128
|
+
expect(result.array).toHaveLength(5);
|
|
129
|
+
expect(result.divided).toBeDefined();
|
|
130
|
+
expect(result.divided).toHaveLength(3); // 5 items with capacity 2 should be divided into 3 groups
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe("getOperations", () => {
|
|
135
|
+
it("should get operations from http controllers", () => {
|
|
136
|
+
const mockController = createMockHttpController("httpController", [
|
|
137
|
+
createMockHttpFunction("function1", "get", "/api/function1"),
|
|
138
|
+
createMockHttpFunction("function2", "post", "/api/function2"),
|
|
139
|
+
]);
|
|
140
|
+
|
|
141
|
+
const result = getOperations({ controllers: [mockController], naming: (func, idx) => `_${idx}_${func}` });
|
|
142
|
+
|
|
143
|
+
expect(result).toHaveLength(2);
|
|
144
|
+
expect(result[0]?.protocol).toBe("http");
|
|
145
|
+
expect(result[0]?.name).toBe("_0_function1");
|
|
146
|
+
expect(result[1]?.name).toBe("_0_function2");
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("should get operations from class controllers", () => {
|
|
150
|
+
const mockController = createMockClassController("classController", [
|
|
151
|
+
{
|
|
152
|
+
name: "function1",
|
|
153
|
+
validate: () => ({ success: true, data: {} } as IValidation<unknown>),
|
|
154
|
+
parameters: {},
|
|
155
|
+
output: {},
|
|
156
|
+
},
|
|
157
|
+
]);
|
|
158
|
+
|
|
159
|
+
const result = getOperations({ controllers: [mockController], naming: (func, idx) => `_${idx}_${func}` });
|
|
160
|
+
|
|
161
|
+
expect(result).toHaveLength(1);
|
|
162
|
+
expect(result[0]?.protocol).toBe("class");
|
|
163
|
+
expect(result[0]?.name).toBe("_0_function1");
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("should get operations from mcp controllers", () => {
|
|
167
|
+
const mockController = createMockMcpController("mcpController", [
|
|
168
|
+
{
|
|
169
|
+
name: "function1",
|
|
170
|
+
parameters: {},
|
|
171
|
+
},
|
|
172
|
+
]);
|
|
173
|
+
|
|
174
|
+
const result = getOperations({ controllers: [mockController], naming: (func, idx) => `_${idx}_${func}` });
|
|
175
|
+
|
|
176
|
+
expect(result).toHaveLength(1);
|
|
177
|
+
expect(result[0]?.protocol).toBe("mcp");
|
|
178
|
+
expect(result[0]?.name).toBe("_0_function1");
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("should throw error for unsupported protocol", () => {
|
|
182
|
+
const mockController: IAgenticaController.IHttp<any> = {
|
|
183
|
+
name: "unsupportedController",
|
|
184
|
+
protocol: "unsupported" as unknown as "http",
|
|
185
|
+
connection: { host: "https://example.com" },
|
|
186
|
+
application: { } as unknown as IAgenticaController.IHttp<any>["application"],
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
expect(() => getOperations({ controllers: [mockController], naming: (func, idx) => `_${idx}_${func}` })).toThrow("Unsupported protocol: unsupported");
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
describe("toHttpOperations", () => {
|
|
194
|
+
it("should convert http controller to operations", () => {
|
|
195
|
+
const mockController = createMockHttpController("httpController", [
|
|
196
|
+
createMockHttpFunction("function1", "get", "/api/function1"),
|
|
197
|
+
createMockHttpFunction("function2", "post", "/api/function2"),
|
|
198
|
+
]);
|
|
199
|
+
|
|
200
|
+
const result = toHttpOperations({ controller: mockController, index: 0, naming: (func, idx) => `_${idx}_${func}` });
|
|
201
|
+
|
|
202
|
+
expect(result).toHaveLength(2);
|
|
203
|
+
expect(result[0]?.protocol).toBe("http");
|
|
204
|
+
expect(result[0]?.name).toBe("_0_function1");
|
|
205
|
+
expect(result[1]?.name).toBe("_0_function2");
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
describe("toClassOperations", () => {
|
|
210
|
+
it("should convert class controller to operations", () => {
|
|
211
|
+
const mockController = createMockClassController("classController", [
|
|
212
|
+
{
|
|
213
|
+
name: "function1",
|
|
214
|
+
validate: () => ({ success: true, data: {} } as IValidation<unknown>),
|
|
215
|
+
parameters: {},
|
|
216
|
+
output: {},
|
|
217
|
+
},
|
|
218
|
+
]);
|
|
219
|
+
|
|
220
|
+
const result = toClassOperations({ controller: mockController, index: 0, naming: (func, idx) => `_${idx}_${func}` });
|
|
221
|
+
|
|
222
|
+
expect(result).toHaveLength(1);
|
|
223
|
+
expect(result[0]?.protocol).toBe("class");
|
|
224
|
+
expect(result[0]?.name).toBe("_0_function1");
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
describe("toMcpOperations", () => {
|
|
229
|
+
it("should convert mcp controller to operations", () => {
|
|
230
|
+
const mockController = createMockMcpController("mcpController", [
|
|
231
|
+
{
|
|
232
|
+
name: "function1",
|
|
233
|
+
parameters: {},
|
|
234
|
+
},
|
|
235
|
+
]);
|
|
236
|
+
|
|
237
|
+
const result = toMcpOperations({ controller: mockController, index: 0, naming: (func, idx) => `_${idx}_${func}` });
|
|
238
|
+
|
|
239
|
+
expect(result).toHaveLength(1);
|
|
240
|
+
expect(result[0]?.protocol).toBe("mcp");
|
|
241
|
+
expect(result[0]?.name).toBe("_0_function1");
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
describe("divide with invalid capacity", () => {
|
|
245
|
+
it("should throw error when capacity is 0", () => {
|
|
246
|
+
const array = [1, 2, 3, 4, 5];
|
|
247
|
+
const capacity = 0;
|
|
248
|
+
|
|
249
|
+
expect(() => divide({ array, capacity })).toThrow("Capacity must be a positive integer");
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it("should throw error when capacity is negative", () => {
|
|
253
|
+
const array = [1, 2, 3, 4, 5];
|
|
254
|
+
const capacity = -3;
|
|
255
|
+
|
|
256
|
+
expect(() => divide({ array, capacity })).toThrow("Capacity must be a positive integer");
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it("should throw error when capacity is decimal", () => {
|
|
260
|
+
const array = [1, 2, 3, 4, 5];
|
|
261
|
+
const capacity = 2.5;
|
|
262
|
+
const result = divide({ array, capacity });
|
|
263
|
+
expect(result).toEqual([[1, 2, 3], [4, 5]]);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it("should throw error when capacity is Infinity", () => {
|
|
267
|
+
const array = [1, 2, 3, 4, 5];
|
|
268
|
+
const capacity = Infinity;
|
|
269
|
+
|
|
270
|
+
expect(() => divide({ array, capacity })).toThrow("Capacity must be a positive integer");
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("should throw error when capacity is NaN", () => {
|
|
274
|
+
const array = [1, 2, 3, 4, 5];
|
|
275
|
+
const capacity = Number.NaN;
|
|
276
|
+
|
|
277
|
+
expect(() => divide({ array, capacity })).toThrow("Capacity must be a positive integer");
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
describe("divide", () => {
|
|
282
|
+
it("should divide array into chunks based on capacity", () => {
|
|
283
|
+
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
284
|
+
const capacity = 3;
|
|
285
|
+
|
|
286
|
+
const result = divide({ array, capacity });
|
|
287
|
+
|
|
288
|
+
expect(result).toHaveLength(4); // 10 items with capacity 3 should be divided into 4 groups
|
|
289
|
+
expect(result[0]).toEqual([1, 2, 3]);
|
|
290
|
+
expect(result[1]).toEqual([4, 5, 6]);
|
|
291
|
+
expect(result[2]).toEqual([7, 8, 9]);
|
|
292
|
+
expect(result[3]).toEqual([10]);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it("should handle empty array", () => {
|
|
296
|
+
const array: number[] = [];
|
|
297
|
+
const capacity = 3;
|
|
298
|
+
|
|
299
|
+
const result = divide({ array, capacity });
|
|
300
|
+
|
|
301
|
+
expect(result).toHaveLength(0);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it("should handle array smaller than capacity", () => {
|
|
305
|
+
const array = [1, 2];
|
|
306
|
+
const capacity = 3;
|
|
307
|
+
|
|
308
|
+
const result = divide({ array, capacity });
|
|
309
|
+
|
|
310
|
+
expect(result).toHaveLength(1);
|
|
311
|
+
expect(result[0]).toEqual([1, 2]);
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
});
|
|
@@ -8,59 +8,27 @@ import type { AgenticaOperationCollection } from "../AgenticaOperationCollection
|
|
|
8
8
|
|
|
9
9
|
import { __map_take } from "../../utils/__map_take";
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Compose the agentica operation collection.
|
|
13
|
+
*
|
|
14
|
+
* Compose the {@link AgenticaOperationCollection} from the given
|
|
15
|
+
* controllers and config.
|
|
16
|
+
*
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
11
19
|
export function compose<Model extends ILlmSchema.Model>(props: {
|
|
12
20
|
controllers: IAgenticaController<Model>[];
|
|
13
21
|
config?: IAgenticaConfig<Model> | IMicroAgenticaConfig<Model> | undefined;
|
|
14
22
|
}): AgenticaOperationCollection<Model> {
|
|
15
|
-
const unique: boolean
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
.map(controller =>
|
|
20
|
-
controller.application.functions.map(func => func.name),
|
|
21
|
-
)
|
|
22
|
-
.flat();
|
|
23
|
-
return new Set(names).size === names.length;
|
|
24
|
-
})();
|
|
25
|
-
const naming = (func: string, ci: number) =>
|
|
26
|
-
unique ? func : `_${ci}_${func}`;
|
|
27
|
-
|
|
28
|
-
const array: AgenticaOperation<Model>[] = props.controllers
|
|
29
|
-
.map((controller, ci) =>
|
|
30
|
-
controller.protocol === "http"
|
|
31
|
-
? controller.application.functions.map(
|
|
32
|
-
func =>
|
|
33
|
-
({
|
|
34
|
-
protocol: "http",
|
|
35
|
-
controller,
|
|
36
|
-
function: func,
|
|
37
|
-
name: naming(func.name, ci),
|
|
38
|
-
toJSON: () => ({
|
|
39
|
-
protocol: "http",
|
|
40
|
-
controller: controller.name,
|
|
41
|
-
function: func.name,
|
|
42
|
-
name: naming(func.name, ci),
|
|
43
|
-
}),
|
|
44
|
-
}) satisfies AgenticaOperation.Http<Model>,
|
|
45
|
-
)
|
|
46
|
-
: controller.application.functions.map(
|
|
47
|
-
func =>
|
|
48
|
-
({
|
|
49
|
-
protocol: "class",
|
|
50
|
-
controller,
|
|
51
|
-
function: func,
|
|
52
|
-
name: naming(func.name, ci),
|
|
53
|
-
toJSON: () => ({
|
|
54
|
-
protocol: "class",
|
|
55
|
-
controller: controller.name,
|
|
56
|
-
function: func.name,
|
|
57
|
-
name: naming(func.name, ci),
|
|
58
|
-
}),
|
|
59
|
-
}) satisfies AgenticaOperation.Class<Model>,
|
|
60
|
-
),
|
|
61
|
-
)
|
|
62
|
-
.flat();
|
|
23
|
+
const unique: boolean = (props.controllers.length === 1 || (() => {
|
|
24
|
+
const names = props.controllers.map(controllers => controllers.application.functions.map(func => func.name)).flat();
|
|
25
|
+
return new Set(names).size === names.length;
|
|
26
|
+
})());
|
|
63
27
|
|
|
28
|
+
const array: AgenticaOperation<Model>[] = getOperations({
|
|
29
|
+
controllers: props.controllers,
|
|
30
|
+
naming: (func: string, controllerIndex: number) => unique ? func : `_${controllerIndex}_${func}`,
|
|
31
|
+
});
|
|
64
32
|
const capacity: number | undefined = (props.config as IAgenticaConfig<Model>)?.capacity;
|
|
65
33
|
const divided: AgenticaOperation<Model>[][] | undefined
|
|
66
34
|
= capacity !== undefined && array.length > capacity
|
|
@@ -87,10 +55,112 @@ export function compose<Model extends ILlmSchema.Model>(props: {
|
|
|
87
55
|
};
|
|
88
56
|
}
|
|
89
57
|
|
|
90
|
-
|
|
58
|
+
/**
|
|
59
|
+
* @internal
|
|
60
|
+
*/
|
|
61
|
+
export function getOperations<Model extends ILlmSchema.Model>(props: {
|
|
62
|
+
controllers: IAgenticaController<Model>[];
|
|
63
|
+
naming: (func: string, controllerIndex: number) => string;
|
|
64
|
+
}): AgenticaOperation<Model>[] {
|
|
65
|
+
return props.controllers.flatMap((controller, idx) => {
|
|
66
|
+
switch (controller.protocol) {
|
|
67
|
+
case "http":{
|
|
68
|
+
return toHttpOperations({ controller, index: idx, naming: props.naming }); }
|
|
69
|
+
case "class":{
|
|
70
|
+
return toClassOperations({ controller, index: idx, naming: props.naming }); }
|
|
71
|
+
case "mcp": {
|
|
72
|
+
return toMcpOperations({ controller, index: idx, naming: props.naming });
|
|
73
|
+
}
|
|
74
|
+
default:
|
|
75
|
+
controller satisfies never;
|
|
76
|
+
throw new Error(`Unsupported protocol: ${(controller as { protocol: string }).protocol}`);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @internal
|
|
83
|
+
*/
|
|
84
|
+
export function toHttpOperations<Model extends ILlmSchema.Model>(props: {
|
|
85
|
+
controller: IAgenticaController.IHttp<Model>;
|
|
86
|
+
index: number;
|
|
87
|
+
naming: (func: string, controllerIndex: number) => string;
|
|
88
|
+
}): AgenticaOperation<Model>[] {
|
|
89
|
+
return props.controller.application.functions.map(func => ({
|
|
90
|
+
protocol: "http",
|
|
91
|
+
controller: props.controller,
|
|
92
|
+
function: func,
|
|
93
|
+
name: props.naming(func.name, props.index),
|
|
94
|
+
toJSON: () => ({
|
|
95
|
+
protocol: "http",
|
|
96
|
+
controller: props.controller.name,
|
|
97
|
+
function: func.name,
|
|
98
|
+
name: props.naming(func.name, props.index),
|
|
99
|
+
}),
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @internal
|
|
105
|
+
*/
|
|
106
|
+
export function toClassOperations<Model extends ILlmSchema.Model>(props: {
|
|
107
|
+
controller: IAgenticaController.IClass<Model>;
|
|
108
|
+
index: number;
|
|
109
|
+
naming: (func: string, controllerIndex: number) => string;
|
|
110
|
+
}): AgenticaOperation<Model>[] {
|
|
111
|
+
return props.controller.application.functions.map(func => ({
|
|
112
|
+
protocol: "class",
|
|
113
|
+
controller: props.controller,
|
|
114
|
+
function: func,
|
|
115
|
+
name: props.naming(func.name, props.index),
|
|
116
|
+
toJSON: () => ({
|
|
117
|
+
protocol: "class",
|
|
118
|
+
controller: props.controller.name,
|
|
119
|
+
function: func.name,
|
|
120
|
+
name: props.naming(func.name, props.index),
|
|
121
|
+
}),
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @internal
|
|
127
|
+
*/
|
|
128
|
+
export function toMcpOperations<Model extends ILlmSchema.Model>(props: {
|
|
129
|
+
controller: IAgenticaController.IMcp;
|
|
130
|
+
index: number;
|
|
131
|
+
naming: (func: string, controllerIndex: number) => string;
|
|
132
|
+
}): AgenticaOperation<Model>[] {
|
|
133
|
+
return props.controller.application.functions.map(func => ({
|
|
134
|
+
protocol: "mcp",
|
|
135
|
+
controller: props.controller,
|
|
136
|
+
function: func,
|
|
137
|
+
name: props.naming(func.name, props.index),
|
|
138
|
+
toJSON: () => ({
|
|
139
|
+
protocol: "mcp",
|
|
140
|
+
controller: props.controller.name,
|
|
141
|
+
function: func.name,
|
|
142
|
+
name: props.naming(func.name, props.index),
|
|
143
|
+
}),
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* @internal
|
|
149
|
+
*/
|
|
150
|
+
export function divide<T>(props: {
|
|
91
151
|
array: T[];
|
|
92
152
|
capacity: number;
|
|
93
153
|
}): T[][] {
|
|
154
|
+
if (props.capacity <= 0) {
|
|
155
|
+
throw new Error("Capacity must be a positive integer");
|
|
156
|
+
}
|
|
157
|
+
if (Number.isNaN(props.capacity)) {
|
|
158
|
+
throw new TypeError("Capacity must be a positive integer");
|
|
159
|
+
}
|
|
160
|
+
if (props.capacity === Infinity) {
|
|
161
|
+
throw new Error("Capacity must be a positive integer");
|
|
162
|
+
}
|
|
163
|
+
|
|
94
164
|
const size: number = Math.ceil(props.array.length / props.capacity);
|
|
95
165
|
const capacity: number = Math.ceil(props.array.length / size);
|
|
96
166
|
const replica: T[] = props.array.slice();
|