@botbotgo/agent-harness 0.0.328 → 0.0.330
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/dist/package-version.d.ts +2 -2
- package/dist/package-version.js +2 -2
- package/dist/runtime/adapter/model/model-providers.js +1 -1
- package/dist/runtime/harness/system/mem0-ingestion-sync.d.ts +18 -1
- package/dist/runtime/harness/system/mem0-ingestion-sync.js +57 -13
- package/dist/runtime/support/embedding-models.js +1 -1
- package/dist/runtime/support/vector-stores.js +68 -25
- package/package.json +4 -5
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
2
|
-
export declare const AGENT_HARNESS_RELEASE_DATE = "2026-04-
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.329";
|
|
2
|
+
export declare const AGENT_HARNESS_RELEASE_DATE = "2026-04-23";
|
package/dist/package-version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
2
|
-
export const AGENT_HARNESS_RELEASE_DATE = "2026-04-
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.329";
|
|
2
|
+
export const AGENT_HARNESS_RELEASE_DATE = "2026-04-23";
|
|
@@ -415,7 +415,7 @@ async function createNodeLlamaCppModel(model) {
|
|
|
415
415
|
}));
|
|
416
416
|
}
|
|
417
417
|
catch (error) {
|
|
418
|
-
throw new Error(`Failed to initialize ${model.provider} model ${model.id}. Install node-llama-cpp in the application workspace and ensure the GGUF file exists at ${modelPath}.`, { cause: error });
|
|
418
|
+
throw new Error(`Failed to initialize ${model.provider} model ${model.id}. Install @langchain/community and node-llama-cpp in the application workspace and ensure the GGUF file exists at ${modelPath}.`, { cause: error });
|
|
419
419
|
}
|
|
420
420
|
}
|
|
421
421
|
export async function createResolvedModel(model, modelResolver) {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type Memory as Mem0Memory, type Message as Mem0Message } from "mem0ai";
|
|
2
1
|
import type { HarnessEvent, HarnessEventProjection } from "../../../contracts/types.js";
|
|
3
2
|
import type { RuntimePersistence } from "../../../persistence/types.js";
|
|
4
3
|
import { type StoreLike } from "./store.js";
|
|
@@ -17,6 +16,24 @@ export type ResolvedMem0Config = {
|
|
|
17
16
|
writeOnApprovalResolution: boolean;
|
|
18
17
|
writeOnRequestCompletion: boolean;
|
|
19
18
|
};
|
|
19
|
+
type Mem0Message = {
|
|
20
|
+
role: string;
|
|
21
|
+
content: string;
|
|
22
|
+
};
|
|
23
|
+
type Mem0Memory = {
|
|
24
|
+
id?: string;
|
|
25
|
+
memory?: string;
|
|
26
|
+
data?: {
|
|
27
|
+
memory?: string;
|
|
28
|
+
};
|
|
29
|
+
score?: number;
|
|
30
|
+
categories?: string[];
|
|
31
|
+
metadata?: Record<string, unknown>;
|
|
32
|
+
agent_id?: string;
|
|
33
|
+
request_id?: string;
|
|
34
|
+
created_at?: string | Date;
|
|
35
|
+
updated_at?: string | Date;
|
|
36
|
+
};
|
|
20
37
|
type Mem0ClientLike = {
|
|
21
38
|
add(messages: Mem0Message[], options?: Record<string, unknown>): Promise<unknown>;
|
|
22
39
|
search(query: string, options?: Record<string, unknown>): Promise<Mem0Memory[]>;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { MemoryClient } from "mem0ai";
|
|
4
3
|
import { extractMessageText } from "../../../utils/message-content.js";
|
|
5
4
|
import { FileBackedStore } from "./store.js";
|
|
6
5
|
const MEM0_EVENT_TYPES = new Set([
|
|
@@ -79,27 +78,24 @@ async function createDefaultMem0Client(config) {
|
|
|
79
78
|
if (!apiKey) {
|
|
80
79
|
throw new Error(`runtimeMemory.mem0 is enabled but environment variable ${config.apiKeyEnv} is not set`);
|
|
81
80
|
}
|
|
82
|
-
return
|
|
83
|
-
apiKey,
|
|
84
|
-
...(config.host ? { host: config.host } : {}),
|
|
85
|
-
...(config.organizationName ? { organizationName: config.organizationName } : {}),
|
|
86
|
-
...(config.projectName ? { projectName: config.projectName } : {}),
|
|
87
|
-
...(config.organizationId ? { organizationId: config.organizationId } : {}),
|
|
88
|
-
...(config.projectId ? { projectId: config.projectId } : {}),
|
|
89
|
-
});
|
|
81
|
+
return createCloudMem0Client(config, apiKey);
|
|
90
82
|
}
|
|
91
83
|
function normalizeMem0Host(host) {
|
|
92
84
|
return host.replace(/\/+$/, "");
|
|
93
85
|
}
|
|
86
|
+
function buildMem0Headers(apiKey) {
|
|
87
|
+
return {
|
|
88
|
+
"Content-Type": "application/json",
|
|
89
|
+
...(apiKey ? { Authorization: `Token ${apiKey}` } : {}),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
94
92
|
async function selfHostedMem0Request(config, pathname, options = {}) {
|
|
95
93
|
if (!config.host) {
|
|
96
94
|
throw new Error("Self-hosted mem0 client requires runtimeMemory.mem0.host.");
|
|
97
95
|
}
|
|
98
96
|
const response = await fetch(`${normalizeMem0Host(config.host)}${pathname}`, {
|
|
99
97
|
method: options.method ?? "GET",
|
|
100
|
-
headers:
|
|
101
|
-
"Content-Type": "application/json",
|
|
102
|
-
},
|
|
98
|
+
headers: buildMem0Headers(),
|
|
103
99
|
...(options.body ? { body: JSON.stringify(options.body) } : {}),
|
|
104
100
|
});
|
|
105
101
|
if (!response.ok) {
|
|
@@ -107,6 +103,54 @@ async function selfHostedMem0Request(config, pathname, options = {}) {
|
|
|
107
103
|
}
|
|
108
104
|
return response.json();
|
|
109
105
|
}
|
|
106
|
+
function applyMem0Scope(payload, config) {
|
|
107
|
+
const scoped = { ...payload };
|
|
108
|
+
if (config.organizationName && config.projectName) {
|
|
109
|
+
scoped.org_name = config.organizationName;
|
|
110
|
+
scoped.project_name = config.projectName;
|
|
111
|
+
}
|
|
112
|
+
if (config.organizationId && config.projectId) {
|
|
113
|
+
scoped.org_id = config.organizationId;
|
|
114
|
+
scoped.project_id = config.projectId;
|
|
115
|
+
delete scoped.org_name;
|
|
116
|
+
delete scoped.project_name;
|
|
117
|
+
}
|
|
118
|
+
return scoped;
|
|
119
|
+
}
|
|
120
|
+
async function cloudMem0Request(config, apiKey, pathname, options = {}) {
|
|
121
|
+
const host = normalizeMem0Host(config.host ?? "https://api.mem0.ai");
|
|
122
|
+
const response = await fetch(`${host}${pathname}`, {
|
|
123
|
+
method: options.method ?? "GET",
|
|
124
|
+
headers: buildMem0Headers(apiKey),
|
|
125
|
+
...(options.body ? { body: JSON.stringify(applyMem0Scope(options.body, config)) } : {}),
|
|
126
|
+
});
|
|
127
|
+
if (!response.ok) {
|
|
128
|
+
throw new Error(`Mem0 request failed: ${response.status} ${response.statusText}`);
|
|
129
|
+
}
|
|
130
|
+
return response.json();
|
|
131
|
+
}
|
|
132
|
+
function createCloudMem0Client(config, apiKey) {
|
|
133
|
+
return {
|
|
134
|
+
async add(messages, options = {}) {
|
|
135
|
+
return cloudMem0Request(config, apiKey, "/v1/memories/", {
|
|
136
|
+
method: "POST",
|
|
137
|
+
body: {
|
|
138
|
+
messages,
|
|
139
|
+
...options,
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
},
|
|
143
|
+
async search(query, options = {}) {
|
|
144
|
+
return cloudMem0Request(config, apiKey, "/v1/memories/search/", {
|
|
145
|
+
method: "POST",
|
|
146
|
+
body: {
|
|
147
|
+
query,
|
|
148
|
+
...options,
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
110
154
|
function createSelfHostedMem0Client(config) {
|
|
111
155
|
return {
|
|
112
156
|
async add(messages, options = {}) {
|
|
@@ -275,7 +319,7 @@ export class Mem0SemanticRecall {
|
|
|
275
319
|
const createdAt = toIsoString(record.created_at) ?? new Date(0).toISOString();
|
|
276
320
|
const updatedAt = toIsoString(record.updated_at) ?? createdAt;
|
|
277
321
|
return {
|
|
278
|
-
id: record.id,
|
|
322
|
+
id: typeof record.id === "string" && record.id.trim().length > 0 ? record.id : memory,
|
|
279
323
|
memory,
|
|
280
324
|
score: typeof record.score === "number" && Number.isFinite(record.score) ? record.score : 0,
|
|
281
325
|
categories: Array.isArray(record.categories)
|
|
@@ -65,7 +65,7 @@ async function createNodeLlamaCppEmbeddings(embeddingModel) {
|
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
67
|
catch (error) {
|
|
68
|
-
throw new Error(`Failed to initialize ${embeddingModel.provider} embedding model ${embeddingModel.id}. Install node-llama-cpp in the application workspace and ensure the GGUF file exists at ${modelPath}.`, { cause: error });
|
|
68
|
+
throw new Error(`Failed to initialize ${embeddingModel.provider} embedding model ${embeddingModel.id}. Install @langchain/community and node-llama-cpp in the application workspace and ensure the GGUF file exists at ${modelPath}.`, { cause: error });
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
async function createLazyLlamaIndexEmbeddingModel(embeddingModel) {
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { mkdir } from "node:fs/promises";
|
|
3
|
-
import { Document } from "@langchain/core/documents";
|
|
4
3
|
import { createClient } from "@libsql/client";
|
|
5
|
-
import { LibSQLVectorStore } from "@langchain/community/vectorstores/libsql";
|
|
6
4
|
import { QdrantClient } from "@qdrant/js-client-rest";
|
|
7
5
|
import { compileVectorStore } from "../../workspace/resource-compilers.js";
|
|
8
6
|
import { getRuntimeStorageRoots, resolveRefId } from "../../workspace/support/workspace-ref-utils.js";
|
|
@@ -52,6 +50,69 @@ async function ensureLibSqlSchema(db, table, column, dimensions) {
|
|
|
52
50
|
ON ${safeTable}(libsql_vector_idx(${safeColumn}))
|
|
53
51
|
`);
|
|
54
52
|
}
|
|
53
|
+
function serializeVector(vector) {
|
|
54
|
+
if (!vector.every((value) => typeof value === "number" && Number.isFinite(value))) {
|
|
55
|
+
throw new Error("Invalid vector: all elements must be finite numbers.");
|
|
56
|
+
}
|
|
57
|
+
return `[${vector.join(",")}]`;
|
|
58
|
+
}
|
|
59
|
+
async function addLibSqlDocuments(db, table, column, documents, vectors) {
|
|
60
|
+
const safeTable = assertIdentifier(table, "table name");
|
|
61
|
+
const safeColumn = assertIdentifier(column, "column name");
|
|
62
|
+
const statements = documents.map((document, index) => ({
|
|
63
|
+
sql: `INSERT INTO ${safeTable} (content, metadata, ${safeColumn}) VALUES (:content, :metadata, vector(:embedding)) RETURNING ${safeTable}.rowid AS id`,
|
|
64
|
+
args: {
|
|
65
|
+
content: document.pageContent,
|
|
66
|
+
metadata: JSON.stringify(document.metadata ?? {}),
|
|
67
|
+
embedding: serializeVector(vectors[index] ?? []),
|
|
68
|
+
},
|
|
69
|
+
}));
|
|
70
|
+
if (statements.length === 0) {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
const results = await db.batch(statements);
|
|
74
|
+
return results.flatMap((result) => result.rows.map((row) => String(row.id)));
|
|
75
|
+
}
|
|
76
|
+
async function similaritySearchLibSql(db, table, column, queryVector, limit) {
|
|
77
|
+
const safeTable = assertIdentifier(table, "table name");
|
|
78
|
+
const safeColumn = assertIdentifier(column, "column name");
|
|
79
|
+
const safeIndex = assertIdentifier(`idx_${safeTable}_${safeColumn}`, "index name");
|
|
80
|
+
const rows = await db.execute({
|
|
81
|
+
sql: `SELECT ${safeTable}.rowid AS id, ${safeTable}.content, ${safeTable}.metadata, vector_distance_cos(${safeTable}.${safeColumn}, vector(:queryVector)) AS distance
|
|
82
|
+
FROM vector_top_k('${safeIndex}', vector(:queryVector), CAST(:limit AS INTEGER)) AS top_k
|
|
83
|
+
JOIN ${safeTable} ON top_k.rowid = ${safeTable}.rowid`,
|
|
84
|
+
args: {
|
|
85
|
+
queryVector: serializeVector(queryVector),
|
|
86
|
+
limit,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
return rows.rows.map((row) => {
|
|
90
|
+
const parsedMetadata = typeof row.metadata === "string" ? JSON.parse(row.metadata) : {};
|
|
91
|
+
const metadata = typeof parsedMetadata === "object" && parsedMetadata && !Array.isArray(parsedMetadata)
|
|
92
|
+
? parsedMetadata
|
|
93
|
+
: {};
|
|
94
|
+
return {
|
|
95
|
+
pageContent: typeof row.content === "string" ? row.content : "",
|
|
96
|
+
metadata,
|
|
97
|
+
score: typeof row.distance === "number" ? 1 - row.distance : undefined,
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
async function deleteLibSqlVectors(db, table, params) {
|
|
102
|
+
const safeTable = assertIdentifier(table, "table name");
|
|
103
|
+
if (params.deleteAll) {
|
|
104
|
+
await db.execute(`DELETE FROM ${safeTable}`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const ids = params.ids ?? [];
|
|
108
|
+
if (ids.length === 0) {
|
|
109
|
+
throw new Error('You must provide an "ids" parameter or a "deleteAll" parameter.');
|
|
110
|
+
}
|
|
111
|
+
await db.batch(ids.map((id) => ({
|
|
112
|
+
sql: `DELETE FROM ${safeTable} WHERE rowid = :id`,
|
|
113
|
+
args: { id },
|
|
114
|
+
})));
|
|
115
|
+
}
|
|
55
116
|
function createQdrantClientForStore(vectorStore) {
|
|
56
117
|
return new QdrantClient({
|
|
57
118
|
...(vectorStore.url ? { url: vectorStore.url } : {}),
|
|
@@ -197,35 +258,17 @@ export async function resolveCompiledVectorStore(workspace, vectorStore, options
|
|
|
197
258
|
embeddingModelRef: vectorStore.embeddingModelRef,
|
|
198
259
|
addDocuments: async (documents) => {
|
|
199
260
|
await ensureSchemaForTexts(documents.map((document) => document.pageContent));
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
table,
|
|
203
|
-
column,
|
|
204
|
-
});
|
|
205
|
-
return store.addDocuments(documents.map((document) => new Document(document)));
|
|
261
|
+
const vectors = await embeddings.embedDocuments(documents.map((document) => document.pageContent));
|
|
262
|
+
return addLibSqlDocuments(db, table, column, documents, vectors);
|
|
206
263
|
},
|
|
207
264
|
similaritySearch: async (query, limit) => {
|
|
208
265
|
await ensureSchemaForTexts([query]);
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
table,
|
|
212
|
-
column,
|
|
213
|
-
});
|
|
214
|
-
const rows = (await store.similaritySearchWithScore(query, limit));
|
|
215
|
-
return rows.map(([document, score]) => ({
|
|
216
|
-
pageContent: document.pageContent,
|
|
217
|
-
metadata: document.metadata,
|
|
218
|
-
score: typeof score === "number" ? 1 - score : score,
|
|
219
|
-
}));
|
|
266
|
+
const queryVector = await embeddings.embedQuery(query);
|
|
267
|
+
return similaritySearchLibSql(db, table, column, queryVector, limit);
|
|
220
268
|
},
|
|
221
269
|
delete: async (params) => {
|
|
222
270
|
await ensureSchemaForTexts(["seed"]);
|
|
223
|
-
|
|
224
|
-
db,
|
|
225
|
-
table,
|
|
226
|
-
column,
|
|
227
|
-
});
|
|
228
|
-
await store.delete(params);
|
|
271
|
+
await deleteLibSqlVectors(db, table, params);
|
|
229
272
|
},
|
|
230
273
|
};
|
|
231
274
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botbotgo/agent-harness",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.330",
|
|
4
4
|
"description": "Workspace runtime for multi-agent applications",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -48,7 +48,6 @@
|
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@langchain/anthropic": "^1.3.27",
|
|
51
|
-
"@langchain/community": "^1.1.27",
|
|
52
51
|
"@langchain/core": "^1.1.41",
|
|
53
52
|
"@langchain/google": "^0.1.10",
|
|
54
53
|
"@langchain/langgraph": "^1.2.9",
|
|
@@ -57,11 +56,10 @@
|
|
|
57
56
|
"@libsql/client": "^0.17.0",
|
|
58
57
|
"@llamaindex/ollama": "^0.1.23",
|
|
59
58
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
60
|
-
"@qdrant/js-client-rest": "
|
|
59
|
+
"@qdrant/js-client-rest": "1.13.0",
|
|
61
60
|
"deepagents": "^1.9.0",
|
|
62
61
|
"langchain": "^1.3.4",
|
|
63
62
|
"llamaindex": "^0.12.1",
|
|
64
|
-
"mem0ai": "^2.4.6",
|
|
65
63
|
"mustache": "^4.2.0",
|
|
66
64
|
"yaml": "^2.8.1",
|
|
67
65
|
"zod": "^3.25.76"
|
|
@@ -89,6 +87,7 @@
|
|
|
89
87
|
"release:publish": "npm publish --access public --registry https://registry.npmjs.org/"
|
|
90
88
|
},
|
|
91
89
|
"devDependencies": {
|
|
90
|
+
"@langchain/community": "^1.1.27",
|
|
92
91
|
"@types/node": "^25.5.2",
|
|
93
92
|
"typescript": "^6.0.2",
|
|
94
93
|
"vite": "^7.3.2",
|
|
@@ -100,7 +99,7 @@
|
|
|
100
99
|
"hono": "^4.12.14",
|
|
101
100
|
"langsmith": "^0.5.20",
|
|
102
101
|
"undici": "^6.24.0",
|
|
103
|
-
"@qdrant/js-client-rest": "
|
|
102
|
+
"@qdrant/js-client-rest": "1.13.0",
|
|
104
103
|
"vite": "^7.3.2",
|
|
105
104
|
"openai": "6.33.0",
|
|
106
105
|
"protobufjs": "^7.5.5"
|