@susu-eng/gralkor 26.0.19 → 27.0.1
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 +70 -51
- package/dist/client.d.ts +9 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -1
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/hooks.d.ts +0 -3
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +7 -39
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -90
- package/dist/index.js.map +1 -1
- package/dist/native-indexer.d.ts +36 -0
- package/dist/native-indexer.d.ts.map +1 -0
- package/dist/native-indexer.js +134 -0
- package/dist/native-indexer.js.map +1 -0
- package/dist/register.d.ts +1 -1
- package/dist/register.d.ts.map +1 -1
- package/dist/register.js +7 -2
- package/dist/register.js.map +1 -1
- package/dist/server-manager.d.ts.map +1 -1
- package/dist/server-manager.js +19 -23
- package/dist/server-manager.js.map +1 -1
- package/dist/tools.d.ts +22 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +41 -1
- package/dist/tools.js.map +1 -1
- package/openclaw.plugin.json +1 -2
- package/package.json +7 -6
- package/server/main.py +40 -11
- package/server/wheels/falkordblite-0.9.0-py3-none-manylinux_2_36_aarch64.whl +0 -0
package/dist/tools.js
CHANGED
|
@@ -11,7 +11,10 @@ export function formatFacts(facts) {
|
|
|
11
11
|
if (facts.length === 0)
|
|
12
12
|
return "No graph facts found.";
|
|
13
13
|
const lines = facts.map(formatFact).join("\n");
|
|
14
|
-
return `
|
|
14
|
+
return `Memories:\n${lines}`;
|
|
15
|
+
}
|
|
16
|
+
export function formatNode(n) {
|
|
17
|
+
return `- ${n.name}: ${n.summary ?? "(no summary)"}`;
|
|
15
18
|
}
|
|
16
19
|
export function createMemoryStoreTool(client, config, opts = {}) {
|
|
17
20
|
const { getGroupId, serverReady } = opts;
|
|
@@ -53,6 +56,43 @@ export function createMemoryStoreTool(client, config, opts = {}) {
|
|
|
53
56
|
},
|
|
54
57
|
};
|
|
55
58
|
}
|
|
59
|
+
export function createMemorySearchTool(client, config, opts = {}) {
|
|
60
|
+
const { getGroupId, serverReady } = opts;
|
|
61
|
+
return {
|
|
62
|
+
name: "memory_search",
|
|
63
|
+
description: "Search memory for relevant context. Use specific, focused queries.",
|
|
64
|
+
parameters: {
|
|
65
|
+
type: "object",
|
|
66
|
+
properties: {
|
|
67
|
+
query: { type: "string" },
|
|
68
|
+
limit: { type: "number" },
|
|
69
|
+
},
|
|
70
|
+
required: ["query"],
|
|
71
|
+
},
|
|
72
|
+
async execute(_toolCallId, args) {
|
|
73
|
+
if (serverReady && !serverReady.isReady()) {
|
|
74
|
+
throw new Error("[gralkor] memory_search failed: server is not ready");
|
|
75
|
+
}
|
|
76
|
+
const groupId = getGroupId?.() ?? "default";
|
|
77
|
+
const limit = args.limit ?? 10;
|
|
78
|
+
const results = await client.search(args.query, [groupId], limit, "slow");
|
|
79
|
+
const factCount = results.facts.length;
|
|
80
|
+
const nodeCount = results.nodes.length;
|
|
81
|
+
console.log(`[gralkor] memory_search result — graph: ${factCount} facts ${nodeCount} nodes — groupId:${groupId}`);
|
|
82
|
+
if (factCount === 0 && nodeCount === 0)
|
|
83
|
+
return "No memories found.";
|
|
84
|
+
const nodeSection = nodeCount > 0
|
|
85
|
+
? "\n\nEntities:\n" + results.nodes.map(formatNode).join("\n")
|
|
86
|
+
: "";
|
|
87
|
+
const output = formatFacts(results.facts) + nodeSection + "\n\n" + INTERPRETATION_INSTRUCTION;
|
|
88
|
+
if (config.test) {
|
|
89
|
+
console.log(`[gralkor] [test] memory_search query: ${args.query}`);
|
|
90
|
+
console.log(`[gralkor] [test] memory_search result:\n${output}`);
|
|
91
|
+
}
|
|
92
|
+
return output;
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
56
96
|
export function createBuildIndicesTool(client, opts = {}) {
|
|
57
97
|
const { serverReady } = opts;
|
|
58
98
|
return {
|
package/dist/tools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,0BAA0B,GACrC,8EAA8E;IAC9E,uEAAuE,CAAC;AAE1E,MAAM,UAAU,UAAU,CAAC,CAAO;IAChC,MAAM,SAAS,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,MAAM,OAAO,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAChE,MAAM,SAAS,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,MAAM,SAAS,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,OAAO,KAAK,CAAC,CAAC,IAAI,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,EAAE,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,uBAAuB,CAAC;IACvD,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/C,OAAO,
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@susu-eng/gralkor",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "27.0.1",
|
|
4
4
|
"description": "OpenClaw memory plugin powered by Graphiti knowledge graphs and FalkorDB",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -47,10 +47,11 @@
|
|
|
47
47
|
"node": ">=18"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"openclaw": ">= 2026.
|
|
50
|
+
"openclaw": ">= 2026.4.2"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/node": "^25.0.0",
|
|
54
|
+
"memfs": "^4.57.1",
|
|
54
55
|
"typescript": "^5.7.0",
|
|
55
56
|
"vitest": "^4.1.2"
|
|
56
57
|
},
|
|
@@ -61,6 +62,10 @@
|
|
|
61
62
|
"test": "pnpm run typecheck && pnpm run test:plugin && pnpm run test:integration && pnpm run test:server",
|
|
62
63
|
"test:plugin": "vitest run",
|
|
63
64
|
"test:integration": "vitest run --config test/integration/vitest.config.ts",
|
|
65
|
+
"test:functional": "bash test/harness/functional-env.sh test",
|
|
66
|
+
"test:functional:up": "bash test/harness/functional-env.sh up",
|
|
67
|
+
"test:functional:run": "bash test/harness/functional-env.sh run",
|
|
68
|
+
"test:functional:down": "bash test/harness/functional-env.sh down",
|
|
64
69
|
"test:server": "cd server && uv run pytest tests/",
|
|
65
70
|
"test:server:changed": "cd server && files=$(git diff --name-only --diff-filter=d HEAD -- 'tests/*.py') && [ -n \"$files\" ] && uv run pytest $files || echo 'No changed server test files'",
|
|
66
71
|
"test:mutate": "stryker run",
|
|
@@ -70,10 +75,6 @@
|
|
|
70
75
|
"docker:up": "pnpm run docker:build && docker compose up -d",
|
|
71
76
|
"docker:down": "docker compose down",
|
|
72
77
|
"docker:logs": "docker compose logs graphiti",
|
|
73
|
-
"harness": "bash test/harness/build.sh",
|
|
74
|
-
"harness:npm": "bash test/harness/build.sh --npm",
|
|
75
|
-
"harness:run": "docker run --rm -it --platform linux/amd64 gralkor-harness:latest",
|
|
76
|
-
"harness:shell": "docker run --rm -it --platform linux/amd64 gralkor-harness:latest bash",
|
|
77
78
|
"publish:npm": "bash scripts/publish.sh"
|
|
78
79
|
}
|
|
79
80
|
}
|
package/server/main.py
CHANGED
|
@@ -7,6 +7,7 @@ import logging
|
|
|
7
7
|
import os
|
|
8
8
|
import time
|
|
9
9
|
from contextlib import asynccontextmanager
|
|
10
|
+
from copy import deepcopy
|
|
10
11
|
from dataclasses import dataclass, field
|
|
11
12
|
from datetime import datetime, timezone
|
|
12
13
|
from typing import Any, Literal
|
|
@@ -23,6 +24,7 @@ from graphiti_core.driver.falkordb_driver import FalkorDriver
|
|
|
23
24
|
from graphiti_core.edges import EntityEdge
|
|
24
25
|
from graphiti_core.nodes import EpisodicNode, EpisodeType
|
|
25
26
|
from graphiti_core.llm_client import LLMConfig
|
|
27
|
+
from graphiti_core.search.search_config_recipes import COMBINED_HYBRID_SEARCH_CROSS_ENCODER
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
# ── Config ────────────────────────────────────────────────────
|
|
@@ -386,6 +388,7 @@ class SearchRequest(BaseModel):
|
|
|
386
388
|
query: str
|
|
387
389
|
group_ids: list[str]
|
|
388
390
|
num_results: int = 10
|
|
391
|
+
mode: Literal["fast", "slow"] = "fast"
|
|
389
392
|
|
|
390
393
|
|
|
391
394
|
class GroupIdRequest(BaseModel):
|
|
@@ -399,6 +402,15 @@ def _ts(dt: datetime | None) -> str | None:
|
|
|
399
402
|
return dt.isoformat() if dt else None
|
|
400
403
|
|
|
401
404
|
|
|
405
|
+
def _serialize_node(node) -> dict[str, Any]:
|
|
406
|
+
return {
|
|
407
|
+
"uuid": node.uuid,
|
|
408
|
+
"name": node.name,
|
|
409
|
+
"summary": node.summary,
|
|
410
|
+
"group_id": node.group_id,
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
|
|
402
414
|
def _serialize_fact(edge: EntityEdge) -> dict[str, Any]:
|
|
403
415
|
return {
|
|
404
416
|
"uuid": edge.uuid,
|
|
@@ -698,8 +710,8 @@ def _prioritize_facts(
|
|
|
698
710
|
|
|
699
711
|
@app.post("/search")
|
|
700
712
|
async def search(req: SearchRequest):
|
|
701
|
-
logger.info("[gralkor] search — query:%d chars group_ids:%s num_results:%d",
|
|
702
|
-
len(req.query), req.group_ids, req.num_results)
|
|
713
|
+
logger.info("[gralkor] search — mode:%s query:%d chars group_ids:%s num_results:%d",
|
|
714
|
+
req.mode, len(req.query), req.group_ids, req.num_results)
|
|
703
715
|
# graphiti.add_episode() clones the driver to target the correct FalkorDB
|
|
704
716
|
# named graph (database=group_id), but graphiti.search() does not — it just
|
|
705
717
|
# uses whatever graph the driver currently points at. Before the first
|
|
@@ -710,23 +722,40 @@ async def search(req: SearchRequest):
|
|
|
710
722
|
# Over-fetch to compensate for expired facts that will be deprioritized.
|
|
711
723
|
fetch_limit = req.num_results * 2
|
|
712
724
|
try:
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
725
|
+
if req.mode == "slow":
|
|
726
|
+
# Cross-encoder + BFS: higher quality, also returns entity node summaries.
|
|
727
|
+
# deepcopy required — COMBINED_HYBRID_SEARCH_CROSS_ENCODER is a module-level
|
|
728
|
+
# constant; mutating .limit directly would corrupt it across requests.
|
|
729
|
+
config = deepcopy(COMBINED_HYBRID_SEARCH_CROSS_ENCODER)
|
|
730
|
+
config.limit = fetch_limit
|
|
731
|
+
search_result = await graphiti.search_(
|
|
732
|
+
query=_sanitize_query(req.query),
|
|
733
|
+
group_ids=req.group_ids,
|
|
734
|
+
config=config,
|
|
735
|
+
)
|
|
736
|
+
edges = search_result.edges
|
|
737
|
+
nodes = search_result.nodes
|
|
738
|
+
else:
|
|
739
|
+
edges = await graphiti.search(
|
|
740
|
+
query=_sanitize_query(req.query),
|
|
741
|
+
group_ids=req.group_ids,
|
|
742
|
+
num_results=fetch_limit,
|
|
743
|
+
)
|
|
744
|
+
nodes = []
|
|
718
745
|
except Exception as e:
|
|
719
746
|
duration_ms = (time.monotonic() - t0) * 1000
|
|
720
|
-
logger.error("[gralkor] search failed — %.0fms: %s", duration_ms, e)
|
|
747
|
+
logger.error("[gralkor] search failed — mode:%s %.0fms: %s", req.mode, duration_ms, e)
|
|
721
748
|
raise
|
|
722
749
|
duration_ms = (time.monotonic() - t0) * 1000
|
|
723
750
|
prioritized = _prioritize_facts(edges, req.num_results)
|
|
724
751
|
valid_count = sum(1 for e in prioritized if e.invalid_at is None)
|
|
725
752
|
result = [_serialize_fact(e) for e in prioritized]
|
|
726
|
-
|
|
727
|
-
|
|
753
|
+
serialized_nodes = [_serialize_node(n) for n in nodes]
|
|
754
|
+
logger.info("[gralkor] search result — mode:%s %d facts (%d valid, %d non-valid) %d nodes from %d fetched %.0fms",
|
|
755
|
+
req.mode, len(prioritized), valid_count, len(prioritized) - valid_count,
|
|
756
|
+
len(serialized_nodes), len(edges), duration_ms)
|
|
728
757
|
logger.debug("[gralkor] search facts: %s", result)
|
|
729
|
-
return {"facts": result}
|
|
758
|
+
return {"facts": result, "nodes": serialized_nodes}
|
|
730
759
|
|
|
731
760
|
|
|
732
761
|
|
|
Binary file
|