@botbotgo/agent-harness 0.0.154 → 0.0.156
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/README.md +34 -8
- package/README.zh.md +41 -8
- package/dist/api.d.ts +5 -2
- package/dist/api.js +9 -0
- package/dist/config/catalogs/stores.yaml +3 -3
- package/dist/config/catalogs/vector-stores.yaml +8 -1
- package/dist/config/runtime/runtime-memory.yaml +17 -0
- package/dist/contracts/runtime.d.ts +31 -0
- package/dist/contracts/workspace.d.ts +6 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/init-project.js +18 -0
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/runtime/harness/system/mem0-ingestion-sync.d.ts +28 -2
- package/dist/runtime/harness/system/mem0-ingestion-sync.js +112 -1
- package/dist/runtime/harness/system/runtime-memory-manager.d.ts +90 -0
- package/dist/runtime/harness/system/runtime-memory-manager.js +371 -0
- package/dist/runtime/harness/system/runtime-memory-records.d.ts +4 -0
- package/dist/runtime/harness/system/runtime-memory-records.js +57 -2
- package/dist/runtime/harness/system/store.d.ts +27 -0
- package/dist/runtime/harness/system/store.js +96 -0
- package/dist/runtime/harness.d.ts +21 -1
- package/dist/runtime/harness.js +469 -45
- package/dist/runtime/support/runtime-factories.js +5 -1
- package/dist/runtime/support/vector-stores.js +97 -0
- package/dist/workspace/object-loader.js +9 -44
- package/dist/workspace/resource-compilers.js +19 -0
- package/dist/workspace/yaml-object-reader.d.ts +0 -4
- package/dist/workspace/yaml-object-reader.js +6 -32
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ import { mkdir } from "node:fs/promises";
|
|
|
3
3
|
import { Document } from "@langchain/core/documents";
|
|
4
4
|
import { createClient } from "@libsql/client";
|
|
5
5
|
import { LibSQLVectorStore } from "@langchain/community/vectorstores/libsql";
|
|
6
|
+
import { QdrantClient } from "@qdrant/js-client-rest";
|
|
6
7
|
import { compileVectorStore } from "../../workspace/resource-compilers.js";
|
|
7
8
|
import { resolveRefId } from "../../workspace/support/workspace-ref-utils.js";
|
|
8
9
|
import { resolveCompiledEmbeddingModel, resolveCompiledEmbeddingModelRef } from "./embedding-models.js";
|
|
@@ -52,6 +53,27 @@ async function ensureLibSqlSchema(db, table, column, dimensions) {
|
|
|
52
53
|
ON ${safeTable}(libsql_vector_idx(${safeColumn}))
|
|
53
54
|
`);
|
|
54
55
|
}
|
|
56
|
+
function createQdrantClientForStore(vectorStore) {
|
|
57
|
+
return new QdrantClient({
|
|
58
|
+
...(vectorStore.url ? { url: vectorStore.url } : {}),
|
|
59
|
+
...(vectorStore.host ? { host: vectorStore.host } : {}),
|
|
60
|
+
...(typeof vectorStore.port === "number" ? { port: vectorStore.port } : {}),
|
|
61
|
+
...(vectorStore.authToken ? { apiKey: vectorStore.authToken } : {}),
|
|
62
|
+
checkCompatibility: false,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async function ensureQdrantCollection(client, collection, dimensions) {
|
|
66
|
+
const collections = await client.getCollections();
|
|
67
|
+
if (collections.collections.some((entry) => entry.name === collection)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
await client.createCollection(collection, {
|
|
71
|
+
vectors: {
|
|
72
|
+
size: dimensions,
|
|
73
|
+
distance: "Cosine",
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
}
|
|
55
77
|
export function resolveCompiledVectorStoreRef(workspace, vectorStoreRef) {
|
|
56
78
|
const resolvedId = vectorStoreRef ? resolveRefId(vectorStoreRef) : "default";
|
|
57
79
|
const vectorStore = workspace.vectorStores.get(resolvedId);
|
|
@@ -75,6 +97,81 @@ export async function resolveCompiledVectorStore(workspace, vectorStore, options
|
|
|
75
97
|
const embeddings = await resolveCompiledEmbeddingModel(embeddingModel, options.embeddingModelResolver);
|
|
76
98
|
return createLlamaIndexVectorStore(workspace.workspaceRoot, vectorStore, embeddings);
|
|
77
99
|
}
|
|
100
|
+
if (vectorStore.kind === "QdrantVectorStore") {
|
|
101
|
+
const embeddingModel = resolveCompiledEmbeddingModelRef(workspace, vectorStore.embeddingModelRef);
|
|
102
|
+
const embeddings = await resolveCompiledEmbeddingModel(embeddingModel, options.embeddingModelResolver);
|
|
103
|
+
const client = createQdrantClientForStore(vectorStore);
|
|
104
|
+
const collection = vectorStore.collection ?? "vectors";
|
|
105
|
+
const ensureCollectionForTexts = async (texts) => {
|
|
106
|
+
const seedText = texts.find((text) => text.trim().length > 0) ?? "seed";
|
|
107
|
+
const sample = await embeddings.embedQuery(seedText);
|
|
108
|
+
await ensureQdrantCollection(client, collection, sample.length);
|
|
109
|
+
};
|
|
110
|
+
return {
|
|
111
|
+
kind: vectorStore.kind,
|
|
112
|
+
embeddingModelRef: vectorStore.embeddingModelRef,
|
|
113
|
+
addDocuments: async (documents) => {
|
|
114
|
+
if (documents.length === 0) {
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
await ensureCollectionForTexts(documents.map((document) => document.pageContent));
|
|
118
|
+
const vectors = await embeddings.embedDocuments(documents.map((document) => document.pageContent));
|
|
119
|
+
const ids = documents.map((_, index) => `${Date.now()}-${index}-${Math.random().toString(36).slice(2, 10)}`);
|
|
120
|
+
await client.upsert(collection, {
|
|
121
|
+
wait: true,
|
|
122
|
+
points: documents.map((document, index) => ({
|
|
123
|
+
id: ids[index] ?? index,
|
|
124
|
+
vector: vectors[index] ?? [],
|
|
125
|
+
payload: {
|
|
126
|
+
pageContent: document.pageContent,
|
|
127
|
+
...(document.metadata ? { metadata: document.metadata } : {}),
|
|
128
|
+
},
|
|
129
|
+
})),
|
|
130
|
+
});
|
|
131
|
+
return ids;
|
|
132
|
+
},
|
|
133
|
+
similaritySearch: async (query, limit) => {
|
|
134
|
+
const collections = await client.getCollections();
|
|
135
|
+
if (!collections.collections.some((entry) => entry.name === collection)) {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
const queryVector = await embeddings.embedQuery(query);
|
|
139
|
+
const rows = await client.search(collection, {
|
|
140
|
+
vector: queryVector,
|
|
141
|
+
limit,
|
|
142
|
+
with_payload: true,
|
|
143
|
+
});
|
|
144
|
+
return rows.map((row) => {
|
|
145
|
+
const payload = (row.payload ?? {});
|
|
146
|
+
return {
|
|
147
|
+
pageContent: typeof payload.pageContent === "string" ? payload.pageContent : "",
|
|
148
|
+
metadata: typeof payload.metadata === "object" && payload.metadata && !Array.isArray(payload.metadata)
|
|
149
|
+
? payload.metadata
|
|
150
|
+
: {},
|
|
151
|
+
score: typeof row.score === "number" ? row.score : undefined,
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
},
|
|
155
|
+
delete: async (params) => {
|
|
156
|
+
const collections = await client.getCollections();
|
|
157
|
+
if (!collections.collections.some((entry) => entry.name === collection)) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (params.deleteAll) {
|
|
161
|
+
await client.deleteCollection(collection);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const pointIds = (params.ids ?? []).filter((id) => typeof id === "string" || typeof id === "number");
|
|
165
|
+
if (pointIds.length === 0) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
await client.delete(collection, {
|
|
169
|
+
wait: true,
|
|
170
|
+
points: pointIds,
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
}
|
|
78
175
|
if (vectorStore.kind !== "LibSQLVectorStore") {
|
|
79
176
|
throw new Error(`Vector store kind ${vectorStore.kind} is not supported by the built-in runtime.`);
|
|
80
177
|
}
|
|
@@ -6,7 +6,7 @@ import { resolveIsolatedResourceModulePath } from "../resource/isolation.js";
|
|
|
6
6
|
import { isExternalSourceLocator, resolveResourcePackageRoot } from "../resource/sources.js";
|
|
7
7
|
import { discoverToolModuleDefinitions, isSupportedToolModulePath } from "../tool-modules.js";
|
|
8
8
|
import { fileExists } from "../utils/fs.js";
|
|
9
|
-
import {
|
|
9
|
+
import { readNamedYamlItems, readYamlItems, } from "./yaml-object-reader.js";
|
|
10
10
|
export { normalizeYamlItem, readYamlItems } from "./yaml-object-reader.js";
|
|
11
11
|
const CONVENTIONAL_OBJECT_DIRECTORIES = ["tools"];
|
|
12
12
|
const MODULE_AGENT_FILENAMES = ["agent.yaml", "agent.yml"];
|
|
@@ -39,16 +39,10 @@ function conventionalConfigRoot(root) {
|
|
|
39
39
|
}
|
|
40
40
|
function conventionalDirectoryRoots(root, relativeDir) {
|
|
41
41
|
const resourceRoot = resolveResourcePackageRoot(root);
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
path.join(root, "agents"),
|
|
47
|
-
]
|
|
48
|
-
: [
|
|
49
|
-
...(resourceRoot ? [path.join(resourceRoot, relativeDir)] : []),
|
|
50
|
-
path.join(root, relativeDir),
|
|
51
|
-
];
|
|
42
|
+
const candidates = [
|
|
43
|
+
...(resourceRoot ? [path.join(resourceRoot, relativeDir)] : []),
|
|
44
|
+
path.join(root, relativeDir),
|
|
45
|
+
];
|
|
52
46
|
return Array.from(new Set(candidates));
|
|
53
47
|
}
|
|
54
48
|
export function conventionalPackageRoots(root, relativeDir) {
|
|
@@ -569,20 +563,6 @@ function mergeAgentRecord(records, item, sourcePath) {
|
|
|
569
563
|
function mergeWorkspaceObjectRecord(records, workspaceObject, item, sourcePath) {
|
|
570
564
|
mergeRawItemRecord(records, `${workspaceObject.kind}/${workspaceObject.id}`, item, sourcePath);
|
|
571
565
|
}
|
|
572
|
-
async function loadNamedModelsForRoot(configRoot, mergedObjects) {
|
|
573
|
-
for (const { item, sourcePath } of await readNamedModelItems(configRoot)) {
|
|
574
|
-
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
575
|
-
if (!workspaceObject || workspaceObject.kind !== "model") {
|
|
576
|
-
continue;
|
|
577
|
-
}
|
|
578
|
-
mergeWorkspaceObjectRecord(mergedObjects, workspaceObject, item, sourcePath);
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
async function loadConfigAgentsForRoot(configRoot, mergedAgents) {
|
|
582
|
-
for (const { item, sourcePath } of await readConfigAgentItems(configRoot)) {
|
|
583
|
-
mergeAgentRecord(mergedAgents, item, sourcePath);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
566
|
async function loadModuleAgentsForRoot(root, mergedAgents) {
|
|
587
567
|
const modulesRoot = moduleCollectionRoot(root, "agents");
|
|
588
568
|
if (!(await fileExists(modulesRoot))) {
|
|
@@ -675,7 +655,7 @@ async function loadModuleObjectsForRoot(root, mergedObjects) {
|
|
|
675
655
|
mergeWorkspaceObjectRecord(mergedObjects, workspaceObject, item, sourcePath);
|
|
676
656
|
}
|
|
677
657
|
}
|
|
678
|
-
async function
|
|
658
|
+
async function loadConfigYamlForRoot(root, configRoot, mergedAgents, mergedObjects) {
|
|
679
659
|
if (!conventionalConfigRoot(root)) {
|
|
680
660
|
return;
|
|
681
661
|
}
|
|
@@ -684,7 +664,8 @@ async function loadConfigObjectsForRoot(root, configRoot, mergedObjects) {
|
|
|
684
664
|
if (!workspaceObject) {
|
|
685
665
|
continue;
|
|
686
666
|
}
|
|
687
|
-
if (isAgentKind(workspaceObject.kind)
|
|
667
|
+
if (isAgentKind(workspaceObject.kind)) {
|
|
668
|
+
mergeAgentRecord(mergedAgents, item, sourcePath);
|
|
688
669
|
continue;
|
|
689
670
|
}
|
|
690
671
|
mergeWorkspaceObjectRecord(mergedObjects, workspaceObject, item, sourcePath);
|
|
@@ -708,20 +689,6 @@ async function loadRootObjects(root, mergedObjects) {
|
|
|
708
689
|
function isAgentKind(kind) {
|
|
709
690
|
return kind === "agent";
|
|
710
691
|
}
|
|
711
|
-
async function readConfigAgentItems(configRoot) {
|
|
712
|
-
const records = await readYamlItems(configRoot, undefined, { recursive: true });
|
|
713
|
-
return records.filter(({ item, sourcePath }) => {
|
|
714
|
-
const kind = typeof item.kind === "string" ? item.kind : undefined;
|
|
715
|
-
if (!isAgentKind(kind)) {
|
|
716
|
-
return false;
|
|
717
|
-
}
|
|
718
|
-
const relativePath = path.relative(configRoot, sourcePath);
|
|
719
|
-
if (!relativePath || relativePath.startsWith("..")) {
|
|
720
|
-
return false;
|
|
721
|
-
}
|
|
722
|
-
return !relativePath.includes(path.sep) || relativePath.startsWith(`agents${path.sep}`);
|
|
723
|
-
});
|
|
724
|
-
}
|
|
725
692
|
export async function readToolModuleItems(root) {
|
|
726
693
|
if (!(await fileExists(root))) {
|
|
727
694
|
return [];
|
|
@@ -792,11 +759,9 @@ export async function loadWorkspaceObjects(workspaceRoot, options = {}) {
|
|
|
792
759
|
const roots = [frameworkWorkspaceRoot(), ...(options.overlayRoots ?? []), workspaceRoot];
|
|
793
760
|
for (const root of roots) {
|
|
794
761
|
const configRoot = conventionalConfigRoot(root) ?? root;
|
|
795
|
-
await
|
|
796
|
-
await loadConfigAgentsForRoot(configRoot, mergedAgents);
|
|
762
|
+
await loadConfigYamlForRoot(root, configRoot, mergedAgents, mergedObjects);
|
|
797
763
|
await loadModuleAgentsForRoot(root, mergedAgents);
|
|
798
764
|
await loadConventionalObjectsForRoot(root, mergedObjects);
|
|
799
|
-
await loadConfigObjectsForRoot(root, configRoot, mergedObjects);
|
|
800
765
|
await loadModuleObjectsForRoot(root, mergedObjects);
|
|
801
766
|
await loadRootObjects(root, mergedObjects);
|
|
802
767
|
}
|
|
@@ -89,13 +89,21 @@ export function parseEmbeddingModelObject(object) {
|
|
|
89
89
|
}
|
|
90
90
|
export function parseVectorStoreObject(object) {
|
|
91
91
|
const value = object.value;
|
|
92
|
+
const port = typeof value.port === "number" && Number.isInteger(value.port) ? value.port : undefined;
|
|
92
93
|
return {
|
|
93
94
|
id: object.id,
|
|
94
95
|
kind: String(value.storeKind ?? value.kind ?? "LibSQLVectorStore").trim(),
|
|
95
96
|
url: typeof value.url === "string" ? value.url : undefined,
|
|
97
|
+
host: typeof value.host === "string" ? value.host : undefined,
|
|
98
|
+
port,
|
|
96
99
|
authToken: typeof value.authToken === "string" ? value.authToken : undefined,
|
|
97
100
|
table: typeof value.table === "string" ? value.table : undefined,
|
|
98
101
|
column: typeof value.column === "string" ? value.column : undefined,
|
|
102
|
+
collection: typeof value.collection === "string"
|
|
103
|
+
? value.collection
|
|
104
|
+
: typeof value.collectionName === "string"
|
|
105
|
+
? value.collectionName
|
|
106
|
+
: undefined,
|
|
99
107
|
embeddingModelRef: typeof value.embeddingModelRef === "string"
|
|
100
108
|
? value.embeddingModelRef
|
|
101
109
|
: typeof asObject(value.embeddingModel)?.ref === "string"
|
|
@@ -155,6 +163,14 @@ export function validateVectorStoreObject(vectorStore) {
|
|
|
155
163
|
if ((vectorStore.kind === "LibSQLVectorStore" || vectorStore.kind === "LlamaIndexSimpleVectorStore") && !vectorStore.url) {
|
|
156
164
|
throw new Error(`Vector store ${vectorStore.id} url must not be empty for ${vectorStore.kind}`);
|
|
157
165
|
}
|
|
166
|
+
if (vectorStore.kind === "QdrantVectorStore") {
|
|
167
|
+
if (!vectorStore.url && !vectorStore.host) {
|
|
168
|
+
throw new Error(`Vector store ${vectorStore.id} must define url or host for QdrantVectorStore`);
|
|
169
|
+
}
|
|
170
|
+
if (!vectorStore.collection) {
|
|
171
|
+
throw new Error(`Vector store ${vectorStore.id} collection must not be empty for QdrantVectorStore`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
158
174
|
}
|
|
159
175
|
export function validateMcpServerObject(server) {
|
|
160
176
|
if (!server.id.trim()) {
|
|
@@ -186,9 +202,12 @@ export function compileVectorStore(vectorStore) {
|
|
|
186
202
|
id: vectorStore.id,
|
|
187
203
|
kind: vectorStore.kind,
|
|
188
204
|
url: vectorStore.url,
|
|
205
|
+
host: vectorStore.host,
|
|
206
|
+
port: vectorStore.port,
|
|
189
207
|
authToken: vectorStore.authToken,
|
|
190
208
|
table: vectorStore.table,
|
|
191
209
|
column: vectorStore.column,
|
|
210
|
+
collection: vectorStore.collection,
|
|
192
211
|
embeddingModelRef: vectorStore.embeddingModelRef,
|
|
193
212
|
runtimeValue: vectorStore.kind,
|
|
194
213
|
};
|
|
@@ -9,7 +9,3 @@ export declare function readNamedYamlItems(root: string, filenames: string[]): P
|
|
|
9
9
|
item: Record<string, unknown>;
|
|
10
10
|
sourcePath: string;
|
|
11
11
|
}>>;
|
|
12
|
-
export declare function readNamedModelItems(root: string): Promise<Array<{
|
|
13
|
-
item: Record<string, unknown>;
|
|
14
|
-
sourcePath: string;
|
|
15
|
-
}>>;
|
|
@@ -2,7 +2,6 @@ import path from "node:path";
|
|
|
2
2
|
import { readdir } from "node:fs/promises";
|
|
3
3
|
import { parseAllDocuments } from "yaml";
|
|
4
4
|
import { fileExists, listFilesRecursive, readYamlOrJson } from "../utils/fs.js";
|
|
5
|
-
const MODEL_FILENAMES = ["models.yaml", "models.yml"];
|
|
6
5
|
const ENV_PLACEHOLDER_PATTERN = /\$\{env:([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
7
6
|
function asObject(value) {
|
|
8
7
|
return typeof value === "object" && value ? value : undefined;
|
|
@@ -62,6 +61,8 @@ function normalizeKind(kind) {
|
|
|
62
61
|
return "agent";
|
|
63
62
|
case "FileStore":
|
|
64
63
|
return "file-store";
|
|
64
|
+
case "SqliteStore":
|
|
65
|
+
return "sqlite-store";
|
|
65
66
|
case "InMemoryStore":
|
|
66
67
|
return "in-memory-store";
|
|
67
68
|
case "RedisStore":
|
|
@@ -163,7 +164,10 @@ export async function readYamlItems(root, relativeDir, options = {}) {
|
|
|
163
164
|
return [];
|
|
164
165
|
}
|
|
165
166
|
const files = options.recursive
|
|
166
|
-
?
|
|
167
|
+
? Array.from(new Set([
|
|
168
|
+
...(await listFilesRecursive(targetRoot, ".yaml")),
|
|
169
|
+
...(await listFilesRecursive(targetRoot, ".yml")),
|
|
170
|
+
])).sort()
|
|
167
171
|
: (await readdir(targetRoot, { withFileTypes: true }))
|
|
168
172
|
.filter((entry) => entry.isFile() && /\.ya?ml$/i.test(entry.name))
|
|
169
173
|
.map((entry) => path.join(targetRoot, entry.name))
|
|
@@ -197,33 +201,3 @@ export async function readNamedYamlItems(root, filenames) {
|
|
|
197
201
|
}
|
|
198
202
|
return records;
|
|
199
203
|
}
|
|
200
|
-
export async function readNamedModelItems(root) {
|
|
201
|
-
const filePaths = new Set();
|
|
202
|
-
for (const filename of MODEL_FILENAMES) {
|
|
203
|
-
const directPath = path.join(root, filename);
|
|
204
|
-
if (await fileExists(directPath)) {
|
|
205
|
-
filePaths.add(directPath);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
for (const extension of [".yaml", ".yml"]) {
|
|
209
|
-
for (const filePath of await listFilesRecursive(root, extension)) {
|
|
210
|
-
if (MODEL_FILENAMES.includes(path.basename(filePath))) {
|
|
211
|
-
filePaths.add(filePath);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
const records = [];
|
|
216
|
-
for (const filePath of [...filePaths].sort()) {
|
|
217
|
-
const parsedDocuments = parseAllDocuments(await readYamlOrJson(filePath));
|
|
218
|
-
for (const parsedDocument of parsedDocuments) {
|
|
219
|
-
const resolvedDocument = interpolateEnvPlaceholders(parsedDocument.toJSON(), filePath);
|
|
220
|
-
for (const item of await objectItemsFromDocument(resolvedDocument, filePath)) {
|
|
221
|
-
const normalized = normalizeYamlItem(item);
|
|
222
|
-
if (normalized.kind === "model" && typeof normalized.id === "string" && normalized.id.trim()) {
|
|
223
|
-
records.push({ item: normalized, sourcePath: filePath });
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
return records;
|
|
229
|
-
}
|