@agentica/vector-selector 0.20.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/LICENSE +21 -0
- package/README.md +164 -0
- package/lib/embed.d.ts +0 -0
- package/lib/embed.js +2 -0
- package/lib/embed.js.map +1 -0
- package/lib/extract_query.d.ts +3 -0
- package/lib/extract_query.js +53 -0
- package/lib/extract_query.js.map +1 -0
- package/lib/index.d.ts +20 -0
- package/lib/index.js +52 -0
- package/lib/index.js.map +1 -0
- package/lib/index.mjs +312 -0
- package/lib/index.mjs.map +1 -0
- package/lib/select.d.ts +17 -0
- package/lib/select.js +197 -0
- package/lib/select.js.map +1 -0
- package/lib/strategy/index.d.ts +1 -0
- package/lib/strategy/index.js +18 -0
- package/lib/strategy/index.js.map +1 -0
- package/lib/strategy/postgres.strategy.d.ts +4 -0
- package/lib/strategy/postgres.strategy.js +87 -0
- package/lib/strategy/postgres.strategy.js.map +1 -0
- package/lib/tools.d.ts +62 -0
- package/lib/tools.js +95 -0
- package/lib/tools.js.map +1 -0
- package/lib/utils.d.ts +52 -0
- package/lib/utils.js +108 -0
- package/lib/utils.js.map +1 -0
- package/lib/utils.test.d.ts +1 -0
- package/package.json +76 -0
- package/src/embed.ts +0 -0
- package/src/extract_query.ts +47 -0
- package/src/index.ts +78 -0
- package/src/select.ts +217 -0
- package/src/strategy/index.ts +1 -0
- package/src/strategy/postgres.strategy.ts +117 -0
- package/src/tools.ts +99 -0
- package/src/utils.test.ts +185 -0
- package/src/utils.ts +105 -0
package/lib/utils.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getRetry = getRetry;
|
|
13
|
+
exports.groupByArray = groupByArray;
|
|
14
|
+
exports.uniqBy = uniqBy;
|
|
15
|
+
/**
|
|
16
|
+
* This function is used to get a retry function.
|
|
17
|
+
*
|
|
18
|
+
* It will throw an error if the count is not a number,
|
|
19
|
+
* or if the count is not a finite number,
|
|
20
|
+
* or if the count is not an integer,
|
|
21
|
+
* or if the count is less than 1.
|
|
22
|
+
*
|
|
23
|
+
* @param count - The number of times to retry the function.
|
|
24
|
+
* @returns A retry function.
|
|
25
|
+
* @throws {TypeError} If the count is not a number, or if the count is not a finite number, or if the count is not an integer, or if the count is less than 1.
|
|
26
|
+
* @throws {Error} If the function fails to return a value after the specified number of retries.
|
|
27
|
+
*/
|
|
28
|
+
function getRetry(count) {
|
|
29
|
+
if (count < 1) {
|
|
30
|
+
throw new Error("count should be greater than 0");
|
|
31
|
+
}
|
|
32
|
+
return (fn) => __awaiter(this, void 0, void 0, function* () {
|
|
33
|
+
let lastError = null;
|
|
34
|
+
for (let i = 0; i < count; i++) {
|
|
35
|
+
try {
|
|
36
|
+
return yield fn();
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
lastError = e;
|
|
40
|
+
if (i === count - 1) {
|
|
41
|
+
throw e;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// count should be greater than 0.
|
|
46
|
+
throw lastError;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* This function is used to group an array into a 2-dimensional array.
|
|
51
|
+
*
|
|
52
|
+
* It will throw an error if the count is not a number,
|
|
53
|
+
* or if the count is not a finite number,
|
|
54
|
+
* or if the count is not an integer,
|
|
55
|
+
* or if the count is less than 1.
|
|
56
|
+
*
|
|
57
|
+
* @param array - The array to group.
|
|
58
|
+
* @param count - The number of elements in each group.
|
|
59
|
+
* @returns A 2-dimensional array.
|
|
60
|
+
*/
|
|
61
|
+
function groupByArray(array, count) {
|
|
62
|
+
if (count < 1) {
|
|
63
|
+
throw new Error("count should be greater than 0");
|
|
64
|
+
}
|
|
65
|
+
if (array.length === 0) {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
if (array.length < count) {
|
|
69
|
+
return [array];
|
|
70
|
+
}
|
|
71
|
+
const grouped = [];
|
|
72
|
+
for (let i = 0; i < array.length; i += count) {
|
|
73
|
+
grouped.push(array.slice(i, i + count));
|
|
74
|
+
}
|
|
75
|
+
return grouped;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Removes duplicates from an array.
|
|
79
|
+
* You can specify which value to compare using a property selector function.
|
|
80
|
+
*
|
|
81
|
+
* @param array - Array to remove duplicates from
|
|
82
|
+
* @param selector - Function that selects the value to compare
|
|
83
|
+
* @returns New array with duplicates removed
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* const users = [
|
|
88
|
+
* { id: 1, name: 'John' },
|
|
89
|
+
* { id: 2, name: 'Jane' },
|
|
90
|
+
* { id: 1, name: 'John' }
|
|
91
|
+
* ];
|
|
92
|
+
*
|
|
93
|
+
* const uniqueUsers = uniqBy(users, user => user.id);
|
|
94
|
+
* // Result: [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }]
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
function uniqBy(array, selector) {
|
|
98
|
+
const seen = new Set();
|
|
99
|
+
return array.filter((item) => {
|
|
100
|
+
const key = selector(item);
|
|
101
|
+
if (seen.has(key)) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
seen.add(key);
|
|
105
|
+
return true;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=utils.js.map
|
package/lib/utils.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;;;;;;;;;;AAkBA,4BAsBC;AAcD,oCAkBC;AAsBD,wBAUC;AAnGD;;;;;;;;;;;;GAYG;AACH,SAAgB,QAAQ,CAAwB,KAAqC;IACnF,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,CAAU,EAAoB,EAAE,EAAE;QACvC,IAAI,SAAS,GAAY,IAAI,CAAC;QAE9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACH,OAAO,MAAM,EAAE,EAAE,CAAC;YACpB,CAAC;YACD,OAAO,CAAU,EAAE,CAAC;gBAClB,SAAS,GAAG,CAAC,CAAC;gBACd,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC,EAAE,CAAC;oBACpB,MAAM,CAAC,CAAC;gBACV,CAAC;YACH,CAAC;QACH,CAAC;QACD,kCAAkC;QAClC,MAAM,SAAS,CAAC;IAClB,CAAC,CAAA,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,YAAY,CAA2B,KAAU,EAAE,KAAqC;IACtG,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,KAAK,CAAC,CAAC;IACjB,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,SAAgB,MAAM,CAAO,KAAU,EAAE,QAAwB;IAC/D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAK,CAAC;IAC1B,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QAC3B,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAClB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentica/vector-selector",
|
|
3
|
+
"version": "0.20.0",
|
|
4
|
+
"author": "Wrtn Technologies",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://wrtnlabs.io",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/wrtnlabs/agentica"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/wrtnlabs/agent/issues"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"openai",
|
|
16
|
+
"chatgpt",
|
|
17
|
+
"anthropic",
|
|
18
|
+
"claude",
|
|
19
|
+
"ai",
|
|
20
|
+
"chatbot",
|
|
21
|
+
"nestia",
|
|
22
|
+
"swagger",
|
|
23
|
+
"openapi"
|
|
24
|
+
],
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./lib/index.d.ts",
|
|
28
|
+
"require": "./lib/index.js",
|
|
29
|
+
"default": "./lib/index.mjs"
|
|
30
|
+
},
|
|
31
|
+
"./strategy": {
|
|
32
|
+
"types": "./lib/strategy/index.d.ts",
|
|
33
|
+
"require": "./lib/strategy/index.js",
|
|
34
|
+
"default": "./lib/strategy/index.mjs"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"main": "lib/index.js",
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"LICENSE",
|
|
43
|
+
"README.md",
|
|
44
|
+
"lib",
|
|
45
|
+
"package.json",
|
|
46
|
+
"prompts",
|
|
47
|
+
"src"
|
|
48
|
+
],
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@agentica/core": "^0.20.0"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@wrtnlabs/connector-hive-api": "^1.5.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
57
|
+
"@rollup/plugin-typescript": "^12.1.1",
|
|
58
|
+
"@samchon/openapi": "^4.2.0",
|
|
59
|
+
"@types/node": "^22.10.5",
|
|
60
|
+
"json-schema-to-ts": "^3.1.1",
|
|
61
|
+
"rimraf": "^6.0.1",
|
|
62
|
+
"rollup": "^4.29.1",
|
|
63
|
+
"type-fest": "^4.37.0",
|
|
64
|
+
"typescript": "~5.8.3",
|
|
65
|
+
"vitest": "^3.0.9",
|
|
66
|
+
"@agentica/core": "^0.20.0"
|
|
67
|
+
},
|
|
68
|
+
"scripts": {
|
|
69
|
+
"build": "tsc -p ./tsconfig.build.json && rollup -c",
|
|
70
|
+
"lint": "eslint .",
|
|
71
|
+
"format": "eslint --fix .",
|
|
72
|
+
"test": "vitest"
|
|
73
|
+
},
|
|
74
|
+
"module": "lib/index.mjs",
|
|
75
|
+
"typings": "lib/index.d.ts"
|
|
76
|
+
}
|
package/src/embed.ts
ADDED
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { AgenticaContext } from "@agentica/core";
|
|
2
|
+
import type { ILlmSchema } from "@samchon/openapi";
|
|
3
|
+
import type { FromSchema } from "json-schema-to-ts";
|
|
4
|
+
|
|
5
|
+
import { factory, utils } from "@agentica/core";
|
|
6
|
+
|
|
7
|
+
import { Tools } from "./tools";
|
|
8
|
+
|
|
9
|
+
export async function extractQuery<SchemaModel extends ILlmSchema.Model>(ctx: AgenticaContext<SchemaModel>) {
|
|
10
|
+
const completionStream = await ctx.request("select", {
|
|
11
|
+
messages: [
|
|
12
|
+
{
|
|
13
|
+
role: "system",
|
|
14
|
+
content: [
|
|
15
|
+
"You are a function searcher. You will extract search queries from the user's message, and the query results will be function names.",
|
|
16
|
+
"A query is a 2–3 sentence description of the action the user needs to perform.",
|
|
17
|
+
"Therefore, the extracted queries must be suitable for function search.",
|
|
18
|
+
"You need to identify the actions required to achieve what the user wants and extract queries that can be used to search for those actions.",
|
|
19
|
+
"Extract only one query per task.",
|
|
20
|
+
].join("\n"),
|
|
21
|
+
},
|
|
22
|
+
...ctx.histories
|
|
23
|
+
.map(factory.decodeHistory<SchemaModel>)
|
|
24
|
+
.flat(),
|
|
25
|
+
{
|
|
26
|
+
role: "user",
|
|
27
|
+
content: ctx.prompt.text,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
tool_choice: "required",
|
|
31
|
+
|
|
32
|
+
tools: [Tools.extract_query],
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const chunks = await utils.StreamUtil.readAll(completionStream);
|
|
36
|
+
const completion = utils.ChatGptCompletionMessageUtil.merge(chunks);
|
|
37
|
+
const queries = completion.choices[0]?.message.tool_calls?.flatMap((v) => {
|
|
38
|
+
const arg = JSON.parse(v.function.arguments) as Partial<FromSchema<typeof Tools.extract_query.function.parameters>>;
|
|
39
|
+
if (!Array.isArray(arg.query_list)) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return arg.query_list.map(v => v.query);
|
|
44
|
+
}) ?? [];
|
|
45
|
+
|
|
46
|
+
return queries;
|
|
47
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { AgenticaContext, AgenticaHistory } from "@agentica/core";
|
|
2
|
+
import type { ILlmSchema } from "@samchon/openapi";
|
|
3
|
+
|
|
4
|
+
import { extractQuery } from "./extract_query";
|
|
5
|
+
import { selectFunction } from "./select";
|
|
6
|
+
import { uniqBy } from "./utils";
|
|
7
|
+
|
|
8
|
+
export interface IAgenticaVectorSelectorBootProps<SchemaModel extends ILlmSchema.Model> {
|
|
9
|
+
strategy: IAgenticaVectorSelectorStrategy<SchemaModel>;
|
|
10
|
+
}
|
|
11
|
+
export interface IAgenticaVectorSelectorStrategy<SchemaModel extends ILlmSchema.Model> {
|
|
12
|
+
searchTool: (ctx: AgenticaContext<SchemaModel>, query: string) => Promise<{
|
|
13
|
+
name: string;
|
|
14
|
+
description: string | undefined;
|
|
15
|
+
}[]>;
|
|
16
|
+
embedContext: (
|
|
17
|
+
props: {
|
|
18
|
+
ctx: AgenticaContext<SchemaModel>;
|
|
19
|
+
setEmbedded: () => void;
|
|
20
|
+
}
|
|
21
|
+
) => Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function BootAgenticaVectorSelector<SchemaModel extends ILlmSchema.Model>(props: IAgenticaVectorSelectorBootProps<SchemaModel>) {
|
|
25
|
+
const { isEmbedded, setEmbedded } = useEmbeddedContext<SchemaModel>();
|
|
26
|
+
const { searchTool, embedContext } = props.strategy;
|
|
27
|
+
const selectorExecute = async (
|
|
28
|
+
ctx: AgenticaContext<SchemaModel>,
|
|
29
|
+
): Promise<AgenticaHistory<SchemaModel>[]> => {
|
|
30
|
+
if (!isEmbedded(ctx)) {
|
|
31
|
+
await embedContext({ ctx, setEmbedded: () => setEmbedded(ctx) });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const queries = await extractQuery(ctx);
|
|
35
|
+
const toolList = await Promise.all(
|
|
36
|
+
queries.map(async query => searchTool(ctx, query)),
|
|
37
|
+
).then(res =>
|
|
38
|
+
res.flatMap(output =>
|
|
39
|
+
output.map(v => ({
|
|
40
|
+
name: v.name,
|
|
41
|
+
description: v.description,
|
|
42
|
+
})),
|
|
43
|
+
).map((v) => {
|
|
44
|
+
const op = ctx.operations.flat.get(v.name);
|
|
45
|
+
if (op === undefined || op.protocol !== "http") {
|
|
46
|
+
return v;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
...v,
|
|
51
|
+
method: op.function.method,
|
|
52
|
+
path: op.function.path,
|
|
53
|
+
tags: op.function.tags,
|
|
54
|
+
};
|
|
55
|
+
}),
|
|
56
|
+
).then(arr => uniqBy(arr, v => v.name));
|
|
57
|
+
|
|
58
|
+
if (toolList.length === 0) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const prompts = await selectFunction({ ctx, toolList });
|
|
63
|
+
return prompts;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return selectorExecute;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function useEmbeddedContext<SchemaModel extends ILlmSchema.Model>() {
|
|
70
|
+
const set = new Set<string>();
|
|
71
|
+
return {
|
|
72
|
+
isEmbedded: (ctx: AgenticaContext<SchemaModel>) =>
|
|
73
|
+
set.has(JSON.stringify(ctx.operations.array)),
|
|
74
|
+
setEmbedded: (ctx: AgenticaContext<SchemaModel>) => {
|
|
75
|
+
set.add(JSON.stringify(ctx.operations.array));
|
|
76
|
+
},
|
|
77
|
+
} as const;
|
|
78
|
+
}
|
package/src/select.ts
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import type { AgenticaContext, AgenticaOperationSelection, AgenticaSelectHistory } from "@agentica/core";
|
|
2
|
+
import type { ILlmSchema } from "@samchon/openapi";
|
|
3
|
+
|
|
4
|
+
import { factory, utils } from "@agentica/core";
|
|
5
|
+
import { AgenticaDefaultPrompt } from "@agentica/core/src/constants/AgenticaDefaultPrompt";
|
|
6
|
+
import { AgenticaSystemPrompt } from "@agentica/core/src/constants/AgenticaSystemPrompt";
|
|
7
|
+
|
|
8
|
+
import { Tools } from "./tools";
|
|
9
|
+
|
|
10
|
+
interface IFailure {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
validation: {
|
|
14
|
+
data: string;
|
|
15
|
+
errors: string[];
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function selectFunction<SchemaModel extends ILlmSchema.Model>(props: {
|
|
20
|
+
ctx: AgenticaContext<SchemaModel>;
|
|
21
|
+
toolList: object[];
|
|
22
|
+
prevFailures?: IFailure[];
|
|
23
|
+
restRetry?: number;
|
|
24
|
+
}) {
|
|
25
|
+
const { ctx, toolList, prevFailures = [], restRetry = 5 } = props;
|
|
26
|
+
const selectCompletion = await ctx.request("select", {
|
|
27
|
+
messages: [
|
|
28
|
+
{
|
|
29
|
+
role: "system",
|
|
30
|
+
content: AgenticaDefaultPrompt.write(ctx.config),
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
role: "assistant",
|
|
34
|
+
tool_calls: [
|
|
35
|
+
{
|
|
36
|
+
type: "function",
|
|
37
|
+
id: "getApiFunctions",
|
|
38
|
+
function: {
|
|
39
|
+
name: "getApiFunctions",
|
|
40
|
+
arguments: JSON.stringify({}),
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
role: "tool",
|
|
47
|
+
tool_call_id: "getApiFunctions",
|
|
48
|
+
content: JSON.stringify(toolList),
|
|
49
|
+
},
|
|
50
|
+
...ctx.histories.flatMap(factory.decodeHistory<SchemaModel>),
|
|
51
|
+
{
|
|
52
|
+
role: "user",
|
|
53
|
+
content: ctx.prompt.text,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
role: "system",
|
|
57
|
+
content: `${ctx.config?.systemPrompt?.select?.(ctx.histories)
|
|
58
|
+
?? AgenticaSystemPrompt.SELECT}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
When selecting functions, consider what the user can call from their perspective, and choose all the functions necessary to accomplish the task.
|
|
62
|
+
Select them in a logical sequence, taking into account the relationships between each function.
|
|
63
|
+
`,
|
|
64
|
+
},
|
|
65
|
+
...emendMessages(prevFailures),
|
|
66
|
+
],
|
|
67
|
+
tool_choice: {
|
|
68
|
+
type: "function",
|
|
69
|
+
function: {
|
|
70
|
+
name: "select_functions",
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
parallel_tool_calls: false,
|
|
74
|
+
tools: [Tools.select_functions],
|
|
75
|
+
})
|
|
76
|
+
.then(async v => utils.StreamUtil.readAll(v))
|
|
77
|
+
.then(utils.ChatGptCompletionMessageUtil.merge);
|
|
78
|
+
|
|
79
|
+
const toolCalls = selectCompletion.choices
|
|
80
|
+
.filter(v => v.message.tool_calls != null);
|
|
81
|
+
|
|
82
|
+
if (toolCalls.length === 0) {
|
|
83
|
+
return selectCompletion.choices.flatMap((v) => {
|
|
84
|
+
if (v.message.content != null && v.message.content !== "") {
|
|
85
|
+
return [factory.createTextHistory({ role: "assistant", text: v.message.content })];
|
|
86
|
+
}
|
|
87
|
+
return [];
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const failures = toolCalls.reduce<IFailure[]>((acc, cur) => {
|
|
92
|
+
cur.message.tool_calls?.forEach((tc) => {
|
|
93
|
+
const errors: string[] = [];
|
|
94
|
+
const arg = JSON.parse(tc.function.arguments) as Partial<{ reason: string; function_name: string }>[];
|
|
95
|
+
if (!Array.isArray(arg)) {
|
|
96
|
+
errors.push(JSON.stringify({
|
|
97
|
+
path: "$input",
|
|
98
|
+
expected: "array",
|
|
99
|
+
value: arg,
|
|
100
|
+
}));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
arg.forEach((v, idx) => {
|
|
104
|
+
if (v.reason == null || typeof v.reason !== "string") {
|
|
105
|
+
errors.push(JSON.stringify({
|
|
106
|
+
path: `$$input[${idx}].reason`,
|
|
107
|
+
expected: "string",
|
|
108
|
+
value: v.reason,
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (v.function_name == null || typeof v.function_name !== "string") {
|
|
113
|
+
errors.push(JSON.stringify({
|
|
114
|
+
path: `$$input[${idx}].function_name`,
|
|
115
|
+
expected: "string",
|
|
116
|
+
value: v.function_name,
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
if (errors.length !== 0) {
|
|
122
|
+
acc.push({
|
|
123
|
+
id: tc.id,
|
|
124
|
+
name: tc.function.name,
|
|
125
|
+
validation: { data: tc.function.arguments, errors },
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
return acc;
|
|
130
|
+
}, []);
|
|
131
|
+
|
|
132
|
+
if (failures.length !== 0) {
|
|
133
|
+
const feedback = [...prevFailures, ...failures];
|
|
134
|
+
if (restRetry === 0) {
|
|
135
|
+
throw new Error(`Failed to select function after ${restRetry} retries\n${JSON.stringify(feedback)}`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return selectFunction({
|
|
139
|
+
ctx,
|
|
140
|
+
toolList,
|
|
141
|
+
prevFailures: feedback,
|
|
142
|
+
restRetry: restRetry - 1,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const prompts: AgenticaSelectHistory<SchemaModel>[] = [];
|
|
147
|
+
toolCalls.forEach((v) => {
|
|
148
|
+
v.message.tool_calls!.forEach((tc) => {
|
|
149
|
+
const collection: AgenticaSelectHistory<SchemaModel> = {
|
|
150
|
+
type: "select",
|
|
151
|
+
id: tc.id,
|
|
152
|
+
selections: [],
|
|
153
|
+
toJSON: () => ({
|
|
154
|
+
type: "select",
|
|
155
|
+
id: tc.id,
|
|
156
|
+
selections: collection.selections.map(s => s.toJSON()),
|
|
157
|
+
}),
|
|
158
|
+
};
|
|
159
|
+
const arg = JSON.parse(tc.function.arguments) as {
|
|
160
|
+
function_list: {
|
|
161
|
+
reason: string;
|
|
162
|
+
function_name: string;
|
|
163
|
+
}[];
|
|
164
|
+
};
|
|
165
|
+
arg.function_list.forEach((v) => {
|
|
166
|
+
const operation = ctx.operations.flat.get(v.function_name);
|
|
167
|
+
|
|
168
|
+
if (operation === undefined) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const selection: AgenticaOperationSelection<SchemaModel>
|
|
172
|
+
= factory.createOperationSelection({
|
|
173
|
+
reason: v.reason,
|
|
174
|
+
operation,
|
|
175
|
+
});
|
|
176
|
+
ctx.stack.push(selection);
|
|
177
|
+
ctx.dispatch(factory.createSelectEvent({ selection })).catch(() => {});
|
|
178
|
+
collection.selections.push(selection);
|
|
179
|
+
});
|
|
180
|
+
prompts.push(collection);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
return prompts;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function emendMessages<SchemaModel extends ILlmSchema.Model>(failures: IFailure[]): ReturnType<typeof factory.decodeHistory<SchemaModel>> {
|
|
188
|
+
return failures
|
|
189
|
+
.flatMap(f => [
|
|
190
|
+
{
|
|
191
|
+
role: "assistant",
|
|
192
|
+
tool_calls: [
|
|
193
|
+
{
|
|
194
|
+
type: "function",
|
|
195
|
+
id: f.id,
|
|
196
|
+
function: {
|
|
197
|
+
name: f.name,
|
|
198
|
+
arguments: JSON.stringify(f.validation.data),
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
role: "tool",
|
|
205
|
+
content: JSON.stringify(f.validation.errors),
|
|
206
|
+
tool_call_id: f.id,
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
role: "system",
|
|
210
|
+
content: [
|
|
211
|
+
"You A.I. assistant has composed wrong typed arguments.",
|
|
212
|
+
"",
|
|
213
|
+
"Correct it at the next function calling.",
|
|
214
|
+
].join("\n"),
|
|
215
|
+
},
|
|
216
|
+
]) satisfies ReturnType<typeof factory.decodeHistory<SchemaModel>>;
|
|
217
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./postgres.strategy";
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { AgenticaContext, AgenticaOperation } from "@agentica/core";
|
|
2
|
+
import type { ILlmSchema } from "@samchon/openapi";
|
|
3
|
+
import type { IConnection } from "@wrtnlabs/connector-hive-api";
|
|
4
|
+
import type { IApplicationConnectorRetrieval } from "@wrtnlabs/connector-hive-api/lib/structures/connector/IApplicationConnectorRetrieval";
|
|
5
|
+
|
|
6
|
+
import { functional, HttpError } from "@wrtnlabs/connector-hive-api";
|
|
7
|
+
|
|
8
|
+
import type { IAgenticaVectorSelectorStrategy } from "..";
|
|
9
|
+
|
|
10
|
+
import { getRetry, groupByArray } from "../utils";
|
|
11
|
+
|
|
12
|
+
const retry = getRetry(3);
|
|
13
|
+
|
|
14
|
+
const filterMap = new Map<string, IApplicationConnectorRetrieval.IFilter>();
|
|
15
|
+
function searchTool<SchemaModel extends ILlmSchema.Model>(connection: IConnection<object | undefined>): IAgenticaVectorSelectorStrategy<SchemaModel>["searchTool"] {
|
|
16
|
+
return async (ctx: AgenticaContext<SchemaModel>, query: string) => {
|
|
17
|
+
const filter = filterMap.get(JSON.stringify(ctx.operations.array));
|
|
18
|
+
return retry(async () =>
|
|
19
|
+
functional.connector_retrievals.createRetrievalRequest(connection, {
|
|
20
|
+
query,
|
|
21
|
+
limit: 10,
|
|
22
|
+
filter,
|
|
23
|
+
}),
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function embedOperation(connection: IConnection<object | undefined>) {
|
|
29
|
+
return async <SchemaModel extends ILlmSchema.Model>(
|
|
30
|
+
controllerName: string,
|
|
31
|
+
opList: AgenticaOperation<SchemaModel>[],
|
|
32
|
+
) => {
|
|
33
|
+
const application = await retry(async () =>
|
|
34
|
+
functional.applications.create(connection, {
|
|
35
|
+
name: controllerName,
|
|
36
|
+
description: undefined,
|
|
37
|
+
}),
|
|
38
|
+
).catch(async (e) => {
|
|
39
|
+
if (!(e instanceof HttpError)) {
|
|
40
|
+
throw e;
|
|
41
|
+
}
|
|
42
|
+
if (e.status !== 409) {
|
|
43
|
+
throw e;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return retry(async () =>
|
|
47
|
+
functional.applications.by_names.getByName(
|
|
48
|
+
connection,
|
|
49
|
+
controllerName,
|
|
50
|
+
),
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const version = await retry(async () =>
|
|
55
|
+
functional.applications.by_ids.versions.create(
|
|
56
|
+
connection,
|
|
57
|
+
application.id,
|
|
58
|
+
{},
|
|
59
|
+
),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
// concurrency request count
|
|
63
|
+
await groupByArray(opList, 10).reduce(async (accPromise, cur) => {
|
|
64
|
+
await accPromise;
|
|
65
|
+
await Promise.all(
|
|
66
|
+
cur.map(async v =>
|
|
67
|
+
retry(async () =>
|
|
68
|
+
functional.application_versions.by_ids.connectors.create(
|
|
69
|
+
connection,
|
|
70
|
+
version.id,
|
|
71
|
+
{ name: v.name, description: v.function.description ?? "" },
|
|
72
|
+
),
|
|
73
|
+
),
|
|
74
|
+
),
|
|
75
|
+
);
|
|
76
|
+
return Promise.resolve();
|
|
77
|
+
}, Promise.resolve());
|
|
78
|
+
|
|
79
|
+
return { version, applicationId: application.id };
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function embedContext<SchemaModel extends ILlmSchema.Model>(connection: IConnection<object | undefined>): IAgenticaVectorSelectorStrategy<SchemaModel>["embedContext"] {
|
|
84
|
+
return async (props: { ctx: AgenticaContext<SchemaModel>; setEmbedded: () => void }) => {
|
|
85
|
+
const { ctx, setEmbedded } = props;
|
|
86
|
+
const filter = await Promise.all(
|
|
87
|
+
Array.from(ctx.operations.group.entries()).map(
|
|
88
|
+
async ([key, value]: [
|
|
89
|
+
string,
|
|
90
|
+
Map<string, AgenticaOperation<SchemaModel>>,
|
|
91
|
+
]) => {
|
|
92
|
+
const result = await embedOperation(connection)(
|
|
93
|
+
key,
|
|
94
|
+
Array.from(value.values()),
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
id: result.applicationId,
|
|
99
|
+
version: result.version.version,
|
|
100
|
+
type: "byId",
|
|
101
|
+
} satisfies IApplicationConnectorRetrieval.IFilterApplicationById;
|
|
102
|
+
},
|
|
103
|
+
),
|
|
104
|
+
);
|
|
105
|
+
filterMap.set(JSON.stringify(ctx.operations.array), {
|
|
106
|
+
applications: filter,
|
|
107
|
+
});
|
|
108
|
+
setEmbedded();
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function configurePostgresStrategy<SchemaModel extends ILlmSchema.Model>(connection: IConnection<object | undefined>): IAgenticaVectorSelectorStrategy<SchemaModel> {
|
|
113
|
+
return {
|
|
114
|
+
searchTool: searchTool(connection),
|
|
115
|
+
embedContext: embedContext(connection),
|
|
116
|
+
};
|
|
117
|
+
}
|