open-agents-ai 0.187.162 → 0.187.163
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/index.js +311 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3680,7 +3680,7 @@ var init_memory_search = __esm({
|
|
|
3680
3680
|
"use strict";
|
|
3681
3681
|
MemorySearchTool = class {
|
|
3682
3682
|
name = "memory_search";
|
|
3683
|
-
description = "Search across all memory entries by relevance. Unlike memory_read (exact topic+key), this finds relevant memories using text matching. Use when you don't know the exact topic or key, or want to find all memories related to a concept.";
|
|
3683
|
+
description = "Search across all memory entries by relevance. Unlike memory_read (exact topic+key), this finds relevant memories using text matching or associative graph traversal. Use when you don't know the exact topic or key, or want to find all memories related to a concept. Mode 'graph' uses knowledge graph traversal for multi-hop associative queries (e.g. 'what caused the auth error?').";
|
|
3684
3684
|
parameters = {
|
|
3685
3685
|
type: "object",
|
|
3686
3686
|
properties: {
|
|
@@ -3691,6 +3691,11 @@ var init_memory_search = __esm({
|
|
|
3691
3691
|
max_results: {
|
|
3692
3692
|
type: "number",
|
|
3693
3693
|
description: "Maximum number of results to return (default: 10)"
|
|
3694
|
+
},
|
|
3695
|
+
mode: {
|
|
3696
|
+
type: "string",
|
|
3697
|
+
enum: ["text", "graph", "episodes"],
|
|
3698
|
+
description: "Search mode: 'text' (default \u2014 TF-IDF), 'graph' (PPR traversal), 'episodes' (recent episodes). Default: text."
|
|
3694
3699
|
}
|
|
3695
3700
|
},
|
|
3696
3701
|
required: ["query"]
|
|
@@ -3702,7 +3707,87 @@ var init_memory_search = __esm({
|
|
|
3702
3707
|
async execute(args) {
|
|
3703
3708
|
const query = args["query"];
|
|
3704
3709
|
const maxResults = args["max_results"] ?? 10;
|
|
3710
|
+
const mode = args["mode"] ?? "text";
|
|
3705
3711
|
const start2 = performance.now();
|
|
3712
|
+
if (mode === "graph" || mode === "episodes") {
|
|
3713
|
+
try {
|
|
3714
|
+
const { join: pathJoin } = await import("node:path");
|
|
3715
|
+
const { existsSync: pathExists } = await import("node:fs");
|
|
3716
|
+
const { createRequire: createRequire7 } = await import("node:module");
|
|
3717
|
+
const oaDir = pathJoin(this.workingDir, ".oa");
|
|
3718
|
+
const epDbPath = pathJoin(oaDir, "episodes.db");
|
|
3719
|
+
const kgDbPath = pathJoin(oaDir, "knowledge.db");
|
|
3720
|
+
if (!pathExists(epDbPath)) {
|
|
3721
|
+
return { success: true, output: `No episode store found. Run tasks to build the knowledge graph.`, durationMs: performance.now() - start2 };
|
|
3722
|
+
}
|
|
3723
|
+
const req2 = createRequire7(import.meta.url);
|
|
3724
|
+
const Database2 = req2("better-sqlite3");
|
|
3725
|
+
if (mode === "episodes") {
|
|
3726
|
+
const db = new Database2(epDbPath, { readonly: true });
|
|
3727
|
+
const queryLower = query.toLowerCase();
|
|
3728
|
+
const rows = db.prepare(`
|
|
3729
|
+
SELECT * FROM episodes
|
|
3730
|
+
WHERE content LIKE ? OR tool_name LIKE ?
|
|
3731
|
+
ORDER BY importance DESC, timestamp DESC
|
|
3732
|
+
LIMIT ?
|
|
3733
|
+
`).all(`%${queryLower}%`, `%${queryLower}%`, maxResults);
|
|
3734
|
+
db.close();
|
|
3735
|
+
if (rows.length === 0) {
|
|
3736
|
+
return { success: true, output: `No episodes found for "${query}".`, durationMs: performance.now() - start2 };
|
|
3737
|
+
}
|
|
3738
|
+
const lines = rows.map((r2) => `[${r2.tool_name ?? r2.modality}] (importance: ${r2.importance}, decay: ${r2.decay_class})
|
|
3739
|
+
${r2.content.slice(0, 200)}`);
|
|
3740
|
+
return {
|
|
3741
|
+
success: true,
|
|
3742
|
+
output: `Episode search for "${query}" (${rows.length} results):
|
|
3743
|
+
|
|
3744
|
+
${lines.join("\n\n")}`,
|
|
3745
|
+
durationMs: performance.now() - start2
|
|
3746
|
+
};
|
|
3747
|
+
}
|
|
3748
|
+
if (mode === "graph" && pathExists(kgDbPath)) {
|
|
3749
|
+
const db = new Database2(kgDbPath, { readonly: true });
|
|
3750
|
+
const queryLower = query.toLowerCase();
|
|
3751
|
+
const nodes = db.prepare(`
|
|
3752
|
+
SELECT * FROM kg_nodes WHERE text LIKE ? ORDER BY mention_count DESC LIMIT 20
|
|
3753
|
+
`).all(`%${queryLower}%`);
|
|
3754
|
+
const episodeIds = /* @__PURE__ */ new Set();
|
|
3755
|
+
const nodeInfo = [];
|
|
3756
|
+
for (const node of nodes.slice(0, 5)) {
|
|
3757
|
+
const edges = db.prepare(`
|
|
3758
|
+
SELECT * FROM kg_edges WHERE (src_id = ? OR dst_id = ?) AND valid_until IS NULL
|
|
3759
|
+
`).all(node.id, node.id);
|
|
3760
|
+
nodeInfo.push(`${node.text} (${node.node_type}, ${node.mention_count} mentions, ${edges.length} edges)`);
|
|
3761
|
+
for (const edge of edges) {
|
|
3762
|
+
if (edge.source_episode_id)
|
|
3763
|
+
episodeIds.add(edge.source_episode_id);
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
db.close();
|
|
3767
|
+
const epLines = [];
|
|
3768
|
+
if (episodeIds.size > 0 && pathExists(epDbPath)) {
|
|
3769
|
+
const epDb = new Database2(epDbPath, { readonly: true });
|
|
3770
|
+
for (const epId of [...episodeIds].slice(0, maxResults)) {
|
|
3771
|
+
const ep = epDb.prepare("SELECT * FROM episodes WHERE id = ?").get(epId);
|
|
3772
|
+
if (ep)
|
|
3773
|
+
epLines.push(`[${ep.tool_name ?? ep.modality}] ${ep.content.slice(0, 150)}`);
|
|
3774
|
+
}
|
|
3775
|
+
epDb.close();
|
|
3776
|
+
}
|
|
3777
|
+
const output = [
|
|
3778
|
+
`Knowledge graph search for "${query}":`,
|
|
3779
|
+
`
|
|
3780
|
+
Nodes found: ${nodes.length}`,
|
|
3781
|
+
nodeInfo.length > 0 ? nodeInfo.map((n2) => ` - ${n2}`).join("\n") : " (no matching nodes)",
|
|
3782
|
+
epLines.length > 0 ? `
|
|
3783
|
+
Linked episodes (${epLines.length}):
|
|
3784
|
+
${epLines.map((l2) => ` ${l2}`).join("\n")}` : ""
|
|
3785
|
+
].filter(Boolean).join("\n");
|
|
3786
|
+
return { success: true, output, durationMs: performance.now() - start2 };
|
|
3787
|
+
}
|
|
3788
|
+
} catch {
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
3706
3791
|
try {
|
|
3707
3792
|
const allEntries = await this.loadAllMemories();
|
|
3708
3793
|
if (allEntries.length === 0) {
|
|
@@ -265232,9 +265317,214 @@ var init_gistCompressor = __esm({
|
|
|
265232
265317
|
}
|
|
265233
265318
|
});
|
|
265234
265319
|
|
|
265320
|
+
// packages/memory/dist/pprRetrieval.js
|
|
265321
|
+
function extractQueryEntities(query) {
|
|
265322
|
+
const entities = [];
|
|
265323
|
+
const seen = /* @__PURE__ */ new Set();
|
|
265324
|
+
const add2 = (text) => {
|
|
265325
|
+
const normalized = text.trim().toLowerCase();
|
|
265326
|
+
if (normalized.length < 2 || seen.has(normalized))
|
|
265327
|
+
return;
|
|
265328
|
+
seen.add(normalized);
|
|
265329
|
+
entities.push(text.trim());
|
|
265330
|
+
};
|
|
265331
|
+
const filePattern = /(?:[\w./-]+\/[\w./-]+|[\w-]+\.\w{1,5})\b/g;
|
|
265332
|
+
for (const match of query.matchAll(filePattern)) {
|
|
265333
|
+
if (match[0].includes(".") || match[0].includes("/"))
|
|
265334
|
+
add2(match[0]);
|
|
265335
|
+
}
|
|
265336
|
+
const errorPattern = /\b[A-Z][a-z]+(?:[A-Z][a-z]+)+\b|\b\w+(?:Error|Exception|Failed|Failure)\b/g;
|
|
265337
|
+
for (const match of query.matchAll(errorPattern))
|
|
265338
|
+
add2(match[0]);
|
|
265339
|
+
const toolPattern = /\b(?:file_read|file_write|file_edit|shell|grep_search|find_files|memory_\w+|web_\w+|camera_\w+|audio_\w+|wifi_\w+|bluetooth_\w+|sdr_\w+|flipper_\w+|meshtastic|gps_\w+|visual_\w+)\b/g;
|
|
265340
|
+
for (const match of query.matchAll(toolPattern))
|
|
265341
|
+
add2(match[0]);
|
|
265342
|
+
const quotedPattern = /["']([^"']{2,50})["']/g;
|
|
265343
|
+
for (const match of query.matchAll(quotedPattern))
|
|
265344
|
+
add2(match[1]);
|
|
265345
|
+
const STOP_WORDS2 = /* @__PURE__ */ new Set([
|
|
265346
|
+
"the",
|
|
265347
|
+
"and",
|
|
265348
|
+
"for",
|
|
265349
|
+
"was",
|
|
265350
|
+
"are",
|
|
265351
|
+
"not",
|
|
265352
|
+
"but",
|
|
265353
|
+
"had",
|
|
265354
|
+
"has",
|
|
265355
|
+
"have",
|
|
265356
|
+
"this",
|
|
265357
|
+
"that",
|
|
265358
|
+
"with",
|
|
265359
|
+
"from",
|
|
265360
|
+
"what",
|
|
265361
|
+
"when",
|
|
265362
|
+
"where",
|
|
265363
|
+
"how",
|
|
265364
|
+
"why",
|
|
265365
|
+
"which",
|
|
265366
|
+
"who",
|
|
265367
|
+
"did",
|
|
265368
|
+
"does",
|
|
265369
|
+
"can",
|
|
265370
|
+
"could",
|
|
265371
|
+
"would",
|
|
265372
|
+
"should",
|
|
265373
|
+
"will",
|
|
265374
|
+
"been",
|
|
265375
|
+
"being",
|
|
265376
|
+
"were",
|
|
265377
|
+
"about",
|
|
265378
|
+
"than",
|
|
265379
|
+
"then",
|
|
265380
|
+
"also",
|
|
265381
|
+
"just",
|
|
265382
|
+
"more",
|
|
265383
|
+
"some",
|
|
265384
|
+
"only",
|
|
265385
|
+
"into",
|
|
265386
|
+
"over"
|
|
265387
|
+
]);
|
|
265388
|
+
const words = query.split(/\s+/).filter((w) => w.length >= 4 && !STOP_WORDS2.has(w.toLowerCase()));
|
|
265389
|
+
for (const word2 of words) {
|
|
265390
|
+
if (/^[A-Z]/.test(word2) || /[._-]/.test(word2) || /\d/.test(word2)) {
|
|
265391
|
+
add2(word2.replace(/[.,;:!?]+$/, ""));
|
|
265392
|
+
}
|
|
265393
|
+
}
|
|
265394
|
+
return entities;
|
|
265395
|
+
}
|
|
265396
|
+
function personalizedPageRank(graph, seedNodeIds, config) {
|
|
265397
|
+
const cfg = { ...DEFAULT_CONFIG5, ...config };
|
|
265398
|
+
const scores = /* @__PURE__ */ new Map();
|
|
265399
|
+
if (seedNodeIds.length === 0)
|
|
265400
|
+
return scores;
|
|
265401
|
+
const nodeCount = graph.nodeCount();
|
|
265402
|
+
if (nodeCount === 0)
|
|
265403
|
+
return scores;
|
|
265404
|
+
const teleportProb = 1 / seedNodeIds.length;
|
|
265405
|
+
const seedSet = new Set(seedNodeIds);
|
|
265406
|
+
const allNodes = /* @__PURE__ */ new Set();
|
|
265407
|
+
for (const seedId of seedNodeIds) {
|
|
265408
|
+
allNodes.add(seedId);
|
|
265409
|
+
const neighbors2 = graph.neighbors(seedId);
|
|
265410
|
+
for (const { node } of neighbors2) {
|
|
265411
|
+
allNodes.add(node.id);
|
|
265412
|
+
const hop2 = graph.neighbors(node.id);
|
|
265413
|
+
for (const { node: n2 } of hop2)
|
|
265414
|
+
allNodes.add(n2.id);
|
|
265415
|
+
}
|
|
265416
|
+
}
|
|
265417
|
+
for (const nodeId of allNodes) {
|
|
265418
|
+
scores.set(nodeId, seedSet.has(nodeId) ? teleportProb : 0);
|
|
265419
|
+
}
|
|
265420
|
+
for (let iter = 0; iter < cfg.maxIterations; iter++) {
|
|
265421
|
+
const newScores = /* @__PURE__ */ new Map();
|
|
265422
|
+
let maxDelta = 0;
|
|
265423
|
+
for (const nodeId of allNodes) {
|
|
265424
|
+
const teleport = seedSet.has(nodeId) ? (1 - cfg.damping) * teleportProb : 0;
|
|
265425
|
+
let walkSum = 0;
|
|
265426
|
+
const inEdges = graph.currentEdges(nodeId);
|
|
265427
|
+
for (const edge of inEdges) {
|
|
265428
|
+
const neighborId = edge.srcId === nodeId ? edge.dstId : edge.srcId;
|
|
265429
|
+
const neighborScore = scores.get(neighborId) ?? 0;
|
|
265430
|
+
const neighborOutDegree = graph.currentEdges(neighborId).length || 1;
|
|
265431
|
+
walkSum += neighborScore / neighborOutDegree;
|
|
265432
|
+
}
|
|
265433
|
+
const newScore = teleport + cfg.damping * walkSum;
|
|
265434
|
+
newScores.set(nodeId, newScore);
|
|
265435
|
+
const delta = Math.abs(newScore - (scores.get(nodeId) ?? 0));
|
|
265436
|
+
if (delta > maxDelta)
|
|
265437
|
+
maxDelta = delta;
|
|
265438
|
+
}
|
|
265439
|
+
for (const [id, score] of newScores)
|
|
265440
|
+
scores.set(id, score);
|
|
265441
|
+
if (maxDelta < cfg.convergenceThreshold) {
|
|
265442
|
+
return scores;
|
|
265443
|
+
}
|
|
265444
|
+
}
|
|
265445
|
+
return scores;
|
|
265446
|
+
}
|
|
265447
|
+
function retrieveByPPR(query, graph, episodeStore, config) {
|
|
265448
|
+
const cfg = { ...DEFAULT_CONFIG5, ...config };
|
|
265449
|
+
const queryEntities = extractQueryEntities(query);
|
|
265450
|
+
if (queryEntities.length === 0) {
|
|
265451
|
+
return { episodes: [], queryEntities: [], seedNodes: [], iterations: 0 };
|
|
265452
|
+
}
|
|
265453
|
+
const seedNodes = [];
|
|
265454
|
+
for (const entity of queryEntities) {
|
|
265455
|
+
const node = graph.findNode(entity);
|
|
265456
|
+
if (node) {
|
|
265457
|
+
seedNodes.push(node.id);
|
|
265458
|
+
continue;
|
|
265459
|
+
}
|
|
265460
|
+
for (const nodeType of ["file", "error", "tool", "entity", "event", "concept", "person"]) {
|
|
265461
|
+
const candidates = graph.nodesByType(nodeType, 50);
|
|
265462
|
+
for (const candidate of candidates) {
|
|
265463
|
+
if (candidate.text.toLowerCase().includes(entity.toLowerCase()) || entity.toLowerCase().includes(candidate.text.toLowerCase())) {
|
|
265464
|
+
seedNodes.push(candidate.id);
|
|
265465
|
+
break;
|
|
265466
|
+
}
|
|
265467
|
+
}
|
|
265468
|
+
if (seedNodes.length > queryEntities.indexOf(entity))
|
|
265469
|
+
break;
|
|
265470
|
+
}
|
|
265471
|
+
}
|
|
265472
|
+
if (seedNodes.length === 0) {
|
|
265473
|
+
return { episodes: [], queryEntities, seedNodes: [], iterations: 0 };
|
|
265474
|
+
}
|
|
265475
|
+
const pprScores = personalizedPageRank(graph, seedNodes, cfg);
|
|
265476
|
+
const episodeScores = /* @__PURE__ */ new Map();
|
|
265477
|
+
for (const [nodeId, score] of pprScores) {
|
|
265478
|
+
if (score < 1e-3)
|
|
265479
|
+
continue;
|
|
265480
|
+
const node = graph.getNode(nodeId);
|
|
265481
|
+
if (!node)
|
|
265482
|
+
continue;
|
|
265483
|
+
const edges = graph.currentEdges(nodeId);
|
|
265484
|
+
for (const edge of edges) {
|
|
265485
|
+
if (edge.sourceEpisodeId) {
|
|
265486
|
+
const existing = episodeScores.get(edge.sourceEpisodeId);
|
|
265487
|
+
if (existing) {
|
|
265488
|
+
existing.score += score;
|
|
265489
|
+
existing.matchedNodes.push(node.text);
|
|
265490
|
+
} else {
|
|
265491
|
+
episodeScores.set(edge.sourceEpisodeId, { score, matchedNodes: [node.text] });
|
|
265492
|
+
}
|
|
265493
|
+
}
|
|
265494
|
+
}
|
|
265495
|
+
}
|
|
265496
|
+
const ranked = [...episodeScores.entries()].sort((a2, b) => b[1].score - a2[1].score).slice(0, cfg.topK);
|
|
265497
|
+
const episodes = [];
|
|
265498
|
+
for (const [epId, { score, matchedNodes }] of ranked) {
|
|
265499
|
+
const episode = episodeStore.get(epId);
|
|
265500
|
+
if (episode) {
|
|
265501
|
+
episodes.push({ episode, pprScore: score, matchedNodes: [...new Set(matchedNodes)] });
|
|
265502
|
+
}
|
|
265503
|
+
}
|
|
265504
|
+
return {
|
|
265505
|
+
episodes,
|
|
265506
|
+
queryEntities,
|
|
265507
|
+
seedNodes,
|
|
265508
|
+
iterations: cfg.maxIterations
|
|
265509
|
+
};
|
|
265510
|
+
}
|
|
265511
|
+
var DEFAULT_CONFIG5;
|
|
265512
|
+
var init_pprRetrieval = __esm({
|
|
265513
|
+
"packages/memory/dist/pprRetrieval.js"() {
|
|
265514
|
+
"use strict";
|
|
265515
|
+
init_zettelkasten();
|
|
265516
|
+
DEFAULT_CONFIG5 = {
|
|
265517
|
+
damping: 0.5,
|
|
265518
|
+
maxIterations: 50,
|
|
265519
|
+
convergenceThreshold: 1e-6,
|
|
265520
|
+
topK: 10
|
|
265521
|
+
};
|
|
265522
|
+
}
|
|
265523
|
+
});
|
|
265524
|
+
|
|
265235
265525
|
// packages/memory/dist/embeddings.js
|
|
265236
265526
|
async function generateEmbedding(text, config) {
|
|
265237
|
-
const cfg = { ...
|
|
265527
|
+
const cfg = { ...DEFAULT_CONFIG6, ...config };
|
|
265238
265528
|
try {
|
|
265239
265529
|
const url = `${cfg.baseUrl}/api/embed`;
|
|
265240
265530
|
const resp = await fetch(url, {
|
|
@@ -265269,7 +265559,7 @@ async function generateEmbedding(text, config) {
|
|
|
265269
265559
|
}
|
|
265270
265560
|
}
|
|
265271
265561
|
async function checkEmbeddingAvailable(config) {
|
|
265272
|
-
const cfg = { ...
|
|
265562
|
+
const cfg = { ...DEFAULT_CONFIG6, ...config };
|
|
265273
265563
|
try {
|
|
265274
265564
|
const resp = await fetch(`${cfg.baseUrl}/api/tags`, {
|
|
265275
265565
|
signal: AbortSignal.timeout(5e3)
|
|
@@ -265296,11 +265586,11 @@ async function pullEmbeddingModel(baseUrl, model, timeoutMs) {
|
|
|
265296
265586
|
return false;
|
|
265297
265587
|
}
|
|
265298
265588
|
}
|
|
265299
|
-
var
|
|
265589
|
+
var DEFAULT_CONFIG6;
|
|
265300
265590
|
var init_embeddings = __esm({
|
|
265301
265591
|
"packages/memory/dist/embeddings.js"() {
|
|
265302
265592
|
"use strict";
|
|
265303
|
-
|
|
265593
|
+
DEFAULT_CONFIG6 = {
|
|
265304
265594
|
baseUrl: "http://localhost:11434",
|
|
265305
265595
|
model: "nomic-embed-text",
|
|
265306
265596
|
timeoutMs: 3e4
|
|
@@ -265332,6 +265622,7 @@ var init_dist7 = __esm({
|
|
|
265332
265622
|
init_temporalGraph();
|
|
265333
265623
|
init_zettelkasten();
|
|
265334
265624
|
init_gistCompressor();
|
|
265625
|
+
init_pprRetrieval();
|
|
265335
265626
|
init_embeddings();
|
|
265336
265627
|
init_proceduralMemoryStore();
|
|
265337
265628
|
}
|
|
@@ -267000,6 +267291,21 @@ If you're stuck, try a completely different approach. Do NOT repeat what failed
|
|
|
267000
267291
|
if (compacted.length < prevLen)
|
|
267001
267292
|
recentToolResults.clear();
|
|
267002
267293
|
}
|
|
267294
|
+
if (turn > 0 && turn % 3 === 0 && this._temporalGraph && this._episodeStore) {
|
|
267295
|
+
try {
|
|
267296
|
+
const taskGoal = this._taskState.goal || task.slice(0, 200);
|
|
267297
|
+
const pprResult = retrieveByPPR(taskGoal, this._temporalGraph, this._episodeStore, { topK: 3 });
|
|
267298
|
+
if (pprResult.episodes.length > 0) {
|
|
267299
|
+
const memoryLines = pprResult.episodes.map(({ episode, pprScore, matchedNodes }) => `- [${episode.toolName ?? episode.modality}] ${episode.content.slice(0, 120)} (via: ${matchedNodes.slice(0, 2).join(", ")})`);
|
|
267300
|
+
compacted.push({
|
|
267301
|
+
role: "system",
|
|
267302
|
+
content: `[Associative Memory \u2014 related prior experience]
|
|
267303
|
+
${memoryLines.join("\n")}`
|
|
267304
|
+
});
|
|
267305
|
+
}
|
|
267306
|
+
} catch {
|
|
267307
|
+
}
|
|
267308
|
+
}
|
|
267003
267309
|
if (this.options.environmentProvider) {
|
|
267004
267310
|
try {
|
|
267005
267311
|
const envStr = this.options.environmentProvider();
|
package/package.json
CHANGED