@gralkor/openclaw 4.0.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.
Files changed (115) hide show
  1. package/.env.example +32 -0
  2. package/README.md +77 -0
  3. package/config.yaml +16 -0
  4. package/dist/config.d.ts +33 -0
  5. package/dist/config.d.ts.map +1 -0
  6. package/dist/config.js +49 -0
  7. package/dist/config.js.map +1 -0
  8. package/dist/ctx-to-messages.d.ts +36 -0
  9. package/dist/ctx-to-messages.d.ts.map +1 -0
  10. package/dist/ctx-to-messages.js +120 -0
  11. package/dist/ctx-to-messages.js.map +1 -0
  12. package/dist/ctx-to-turn.d.ts +32 -0
  13. package/dist/ctx-to-turn.d.ts.map +1 -0
  14. package/dist/ctx-to-turn.js +55 -0
  15. package/dist/ctx-to-turn.js.map +1 -0
  16. package/dist/gralkor/client/http.d.ts +55 -0
  17. package/dist/gralkor/client/http.d.ts.map +1 -0
  18. package/dist/gralkor/client/http.js +150 -0
  19. package/dist/gralkor/client/http.js.map +1 -0
  20. package/dist/gralkor/client/in-memory.d.ts +38 -0
  21. package/dist/gralkor/client/in-memory.d.ts.map +1 -0
  22. package/dist/gralkor/client/in-memory.js +72 -0
  23. package/dist/gralkor/client/in-memory.js.map +1 -0
  24. package/dist/gralkor/client.d.ts +64 -0
  25. package/dist/gralkor/client.d.ts.map +1 -0
  26. package/dist/gralkor/client.js +32 -0
  27. package/dist/gralkor/client.js.map +1 -0
  28. package/dist/gralkor/config.d.ts +33 -0
  29. package/dist/gralkor/config.d.ts.map +1 -0
  30. package/dist/gralkor/config.js +58 -0
  31. package/dist/gralkor/config.js.map +1 -0
  32. package/dist/gralkor/connection.d.ts +20 -0
  33. package/dist/gralkor/connection.d.ts.map +1 -0
  34. package/dist/gralkor/connection.js +31 -0
  35. package/dist/gralkor/connection.js.map +1 -0
  36. package/dist/gralkor/index.d.ts +11 -0
  37. package/dist/gralkor/index.d.ts.map +1 -0
  38. package/dist/gralkor/index.js +6 -0
  39. package/dist/gralkor/index.js.map +1 -0
  40. package/dist/gralkor/server-env.d.ts +11 -0
  41. package/dist/gralkor/server-env.d.ts.map +1 -0
  42. package/dist/gralkor/server-env.js +26 -0
  43. package/dist/gralkor/server-env.js.map +1 -0
  44. package/dist/gralkor/server-manager.d.ts +58 -0
  45. package/dist/gralkor/server-manager.d.ts.map +1 -0
  46. package/dist/gralkor/server-manager.js +390 -0
  47. package/dist/gralkor/server-manager.js.map +1 -0
  48. package/dist/gralkor/testing.d.ts +10 -0
  49. package/dist/gralkor/testing.d.ts.map +1 -0
  50. package/dist/gralkor/testing.js +10 -0
  51. package/dist/gralkor/testing.js.map +1 -0
  52. package/dist/hooks/agent-end.d.ts +25 -0
  53. package/dist/hooks/agent-end.d.ts.map +1 -0
  54. package/dist/hooks/agent-end.js +51 -0
  55. package/dist/hooks/agent-end.js.map +1 -0
  56. package/dist/hooks/before-prompt-build.d.ts +12 -0
  57. package/dist/hooks/before-prompt-build.d.ts.map +1 -0
  58. package/dist/hooks/before-prompt-build.js +15 -0
  59. package/dist/hooks/before-prompt-build.js.map +1 -0
  60. package/dist/hooks/session-end.d.ts +18 -0
  61. package/dist/hooks/session-end.d.ts.map +1 -0
  62. package/dist/hooks/session-end.js +19 -0
  63. package/dist/hooks/session-end.js.map +1 -0
  64. package/dist/index.d.ts +130 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +133 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/native-indexer.d.ts +43 -0
  69. package/dist/native-indexer.d.ts.map +1 -0
  70. package/dist/native-indexer.js +107 -0
  71. package/dist/native-indexer.js.map +1 -0
  72. package/dist/register.d.ts +25 -0
  73. package/dist/register.d.ts.map +1 -0
  74. package/dist/register.js +184 -0
  75. package/dist/register.js.map +1 -0
  76. package/dist/session-map.d.ts +13 -0
  77. package/dist/session-map.d.ts.map +1 -0
  78. package/dist/session-map.js +32 -0
  79. package/dist/session-map.js.map +1 -0
  80. package/dist/tools/memory-add.d.ts +15 -0
  81. package/dist/tools/memory-add.d.ts.map +1 -0
  82. package/dist/tools/memory-add.js +15 -0
  83. package/dist/tools/memory-add.js.map +1 -0
  84. package/dist/tools/memory-build-communities.d.ts +19 -0
  85. package/dist/tools/memory-build-communities.d.ts.map +1 -0
  86. package/dist/tools/memory-build-communities.js +18 -0
  87. package/dist/tools/memory-build-communities.js.map +1 -0
  88. package/dist/tools/memory-build-indices.d.ts +12 -0
  89. package/dist/tools/memory-build-indices.d.ts.map +1 -0
  90. package/dist/tools/memory-build-indices.js +11 -0
  91. package/dist/tools/memory-build-indices.js.map +1 -0
  92. package/dist/tools/memory-search.d.ts +20 -0
  93. package/dist/tools/memory-search.d.ts.map +1 -0
  94. package/dist/tools/memory-search.js +18 -0
  95. package/dist/tools/memory-search.js.map +1 -0
  96. package/dist/types.d.ts +62 -0
  97. package/dist/types.d.ts.map +1 -0
  98. package/dist/types.js +8 -0
  99. package/dist/types.js.map +1 -0
  100. package/openclaw.plugin.json +130 -0
  101. package/package.json +75 -0
  102. package/server/server/.python-version +1 -0
  103. package/server/server/main.py +902 -0
  104. package/server/server/pipelines/__init__.py +0 -0
  105. package/server/server/pipelines/capture_buffer.py +170 -0
  106. package/server/server/pipelines/distill.py +122 -0
  107. package/server/server/pipelines/formatting.py +48 -0
  108. package/server/server/pipelines/interpret.py +165 -0
  109. package/server/server/pipelines/messages.py +13 -0
  110. package/server/server/pyproject.toml +19 -0
  111. package/server/server/pytest.ini +4 -0
  112. package/server/server/requirements-dev.txt +3 -0
  113. package/server/server/requirements.txt +5 -0
  114. package/server/server/uv.lock +1162 -0
  115. package/server/wheels/falkordblite-0.9.0-py3-none-manylinux_2_36_aarch64.whl +0 -0
package/.env.example ADDED
@@ -0,0 +1,32 @@
1
+ # --- Graphiti server LLM provider ---
2
+ # Set the API key for your chosen LLM provider.
3
+ # Only one provider is needed (unless noted below).
4
+ # Configured in config.yaml (llm.provider and embedder.provider).
5
+
6
+ # Google Gemini (default provider — fully self-contained: LLM + embeddings + reranking)
7
+ GOOGLE_API_KEY=
8
+
9
+ # OpenAI (handles LLM + embeddings; needed for embeddings if using Anthropic or Groq)
10
+ OPENAI_API_KEY=
11
+
12
+ # Anthropic (LLM only — still requires OPENAI_API_KEY for embeddings)
13
+ ANTHROPIC_API_KEY=
14
+
15
+ # Groq (LLM only — still requires OPENAI_API_KEY for embeddings)
16
+ GROQ_API_KEY=
17
+
18
+ # --- OpenClaw native memory embeddings ---
19
+ # OpenClaw's native memory_search needs an embedding provider to index
20
+ # MEMORY.md and memory/*.md files. Without one, files are never indexed
21
+ # and memory_search returns empty results (even in FTS-only mode — this
22
+ # is an upstream OpenClaw bug).
23
+ #
24
+ # The key must be set in the OpenClaw gateway's environment (not just here).
25
+ # Add it to ~/.openclaw/.env on the host running the gateway:
26
+ #
27
+ # echo 'GOOGLE_API_KEY=...' >> ~/.openclaw/.env
28
+ #
29
+ # OpenClaw auto-detects the provider from available keys. Any one of these
30
+ # will work: OPENAI_API_KEY, GOOGLE_API_KEY, VOYAGE_API_KEY, MISTRAL_API_KEY.
31
+ # If you already set GOOGLE_API_KEY above for Graphiti and the gateway can
32
+ # see it, native memory indexing will use it automatically.
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # @susulabs/gralkor
2
+
3
+ OpenClaw memory plugin powered by [Gralkor](https://github.com/elimydlarz/gralkor) — a temporally-aware knowledge-graph memory service (Graphiti + FalkorDB). This package is the OpenClaw harness: it supervises the Gralkor Python server (bundled inside its [`@susulabs/gralkor`](https://www.npmjs.com/package/@susulabs/gralkor) dependency), wires the HTTP API into OpenClaw hooks, and exposes `memory_search` and `memory_add` as tools.
4
+
5
+ For non-OpenClaw uses see [`@susulabs/gralkor`](https://www.npmjs.com/package/@susulabs/gralkor) (the underlying TypeScript adapter this plugin builds on) or the [Gralkor monorepo](https://github.com/elimydlarz/gralkor).
6
+
7
+ ## Compatibility
8
+
9
+ Requires OpenClaw `>= 2026.5.7`. The 2026.5.7 plugin loader gates tool registration on the manifest's `contracts.tools` field; older plugin builds (≤ 2.1.8) loaded but registered no tools and are not supported.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ openclaw plugins install @susulabs/gralkor --dangerously-force-unsafe-install
15
+ ```
16
+
17
+ (The install-time security scanner flags Gralkor as critical because the Python server that this plugin spawns lives inside `@susulabs/gralkor`. Inspect either package's source if you'd like to verify there's nothing weird going on.)
18
+
19
+ Then configure before enabling:
20
+
21
+ ```bash
22
+ openclaw config set plugins.entries.gralkor.config.dataDir /path/to/gralkor-data
23
+ openclaw config set plugins.entries.gralkor.config.googleApiKey 'your-key-here' # or OPENAI/ANTHROPIC/GROQ
24
+
25
+ openclaw config set --json plugins.allow '["gralkor"]'
26
+ openclaw config set plugins.entries.gralkor.enabled true
27
+ openclaw config set plugins.slots.memory gralkor
28
+ openclaw config set --json tools.alsoAllow '["gralkor"]'
29
+ ```
30
+
31
+ Restart OpenClaw. First boot takes 1–2 min while `uv sync` resolves Graphiti + falkordblite; subsequent starts reuse the venv.
32
+
33
+ ## What this plugin does
34
+
35
+ Three hooks + two tools, all fed by the Gralkor HTTP API:
36
+
37
+ - **`before_prompt_build`** — registers the session's group, scans workspace memory files for new content (`MEMORY.md`, `memory/*.md`), and auto-recalls relevant facts which get injected into the prompt.
38
+ - **`agent_end`** — posts the just-finished turn to `/capture` as a canonical `[{role, content}]` message list (user → behaviour(s) → assistant). The Gralkor server owns the capture buffer and flushes on idle (default 5 min) or on explicit session-end. OpenClaw-specific filtering happens here: harness-internal sub-agent runs (e.g. `sessionKey === "temp:slug-generator"`) and synthetic turns (the `/new`/`/reset` meta-prompt) are skipped, and `Conversation info` / `Sender` `(untrusted metadata)` envelope blocks are stripped from the user message before capture.
39
+ - **`session_end`** — posts `/session_end` to flush the session's buffer now instead of waiting for the idle window.
40
+ - **`memory_search` tool** — calls the same `POST /recall` path as the `before_prompt_build` hook. There is no separate slow-search endpoint: manual and auto lookups do identical server work.
41
+ - **`memory_add` tool** — `POST /tools/memory_add`. Fire-and-forget; the server queues the add for async Graphiti extraction.
42
+
43
+ Compared to previous versions of this plugin: the client-side debouncer, flush retry loop, SIGTERM handler, transcript distillation, and LLM interpretation are all **gone**. Those behaviours moved server-side — this plugin is now a thin lifecycle harness on top of `@susulabs/gralkor`.
44
+
45
+ ## Session and group identity
46
+
47
+ - `session_id` is OpenClaw's `sessionKey` — required at every boundary. Hooks and tools throw synchronously if `ctx.sessionKey` is missing or blank; there is no `"default"` bucket. (OpenClaw's argument shape for hooks and tool factories is documented in `OPENCLAW_INTEGRATION_2026-04-02.md`.)
48
+ - `group_id` is the sanitised `agentId` (hyphens replaced with underscores — a RediSearch constraint). Per-agent graph partition; agents never see each other's memory.
49
+
50
+ `before_prompt_build` is the single writer of the `sessionKey → groupId` map. Tools and later hooks look up that map — if `session_not_registered` errors appear, it means the tool fired before `before_prompt_build`, which shouldn't happen under normal OpenClaw flow.
51
+
52
+ ## Configuration
53
+
54
+ Set under `plugins.entries.gralkor.config` in `~/.openclaw/openclaw.json`. See `openclaw.plugin.json` for the full schema; the useful knobs are:
55
+
56
+ - **`dataDir`** *(required)* — writable directory for the Python venv + FalkorDB database.
57
+ - **`search.maxResults`** — cap on facts returned by the `memory_search` tool.
58
+ - **`llm` / `embedder`** — provider + model override (defaults: Gemini).
59
+ - **`googleApiKey` / `openaiApiKey` / `anthropicApiKey` / `groqApiKey`** — one is required.
60
+ - **`test`** *(default: false)* — verbose server-side logging.
61
+
62
+ ## Testing
63
+
64
+ Unit tests use `GralkorInMemoryClient` from `@susulabs/gralkor/testing` — real behaviour, no network, no Python. Full suite runs via `pnpm test`.
65
+
66
+ ## Development
67
+
68
+ ```bash
69
+ pnpm install
70
+ pnpm run build
71
+ pnpm run test
72
+ openclaw plugins install -l . # link this local checkout
73
+ ```
74
+
75
+ ## License
76
+
77
+ MIT.
package/config.yaml ADDED
@@ -0,0 +1,16 @@
1
+ # Graphiti configuration
2
+ # See: https://help.getzep.com/graphiti/configuration/llm-configuration
3
+ #
4
+ # Change the provider/model to match your API key in .env
5
+ # Supported providers: openai, anthropic, gemini, groq, azure_openai
6
+
7
+ server:
8
+ transport: "http"
9
+
10
+ llm:
11
+ provider: "gemini"
12
+ model: "gemini-3.1-flash-lite"
13
+
14
+ embedder:
15
+ provider: "gemini"
16
+ model: "gemini-embedding-2-preview"
@@ -0,0 +1,33 @@
1
+ import { type ModelConfig, type OntologyConfig, validateOntologyConfig as libValidate } from "./gralkor/index.js";
2
+ export interface GralkorPluginConfig {
3
+ agentName: string;
4
+ search: {
5
+ maxResults: number;
6
+ };
7
+ llm?: ModelConfig;
8
+ embedder?: ModelConfig;
9
+ ontology?: OntologyConfig;
10
+ dataDir?: string;
11
+ workspaceDir?: string;
12
+ test?: boolean;
13
+ googleApiKey?: string;
14
+ openaiApiKey?: string;
15
+ anthropicApiKey?: string;
16
+ groqApiKey?: string;
17
+ /**
18
+ * Output-token budget for the server's interpret pipeline on every recall.
19
+ * Unset → server applies its own default (2000). Raise for wide-recall
20
+ * workloads where the default truncates and surfaces as
21
+ * InterpretParseFailed in the server logs. Must be a positive integer.
22
+ */
23
+ interpretMaxOutputTokens?: number;
24
+ }
25
+ export declare const defaultConfig: {
26
+ readonly search: {
27
+ readonly maxResults: 20;
28
+ };
29
+ };
30
+ export declare function resolveConfig(raw?: Partial<GralkorPluginConfig>): GralkorPluginConfig;
31
+ export declare function buildSecretEnv(config: GralkorPluginConfig): Record<string, string>;
32
+ export declare const validateOntologyConfig: typeof libValidate;
33
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,sBAAsB,IAAI,WAAW,EACtC,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/B,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,eAAO,MAAM,aAAa;;;;CAEhB,CAAC;AAEX,wBAAgB,aAAa,CAC3B,GAAG,GAAE,OAAO,CAAC,mBAAmB,CAAM,GACrC,mBAAmB,CAoCrB;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOlF;AAED,eAAO,MAAM,sBAAsB,oBAAc,CAAC"}
package/dist/config.js ADDED
@@ -0,0 +1,49 @@
1
+ import { validateOntologyConfig as libValidate, } from "./gralkor/index.js";
2
+ export const defaultConfig = {
3
+ search: { maxResults: 20 },
4
+ };
5
+ export function resolveConfig(raw = {}) {
6
+ const agentName = raw.agentName;
7
+ if (typeof agentName !== "string" || agentName.trim() === "") {
8
+ throw new Error("openclaw-gralkor pluginConfig.agentName is required (non-blank string); got " +
9
+ JSON.stringify(agentName));
10
+ }
11
+ if (raw.interpretMaxOutputTokens !== undefined) {
12
+ const v = raw.interpretMaxOutputTokens;
13
+ if (typeof v !== "number" || !Number.isInteger(v) || v <= 0) {
14
+ throw new Error("openclaw-gralkor pluginConfig.interpretMaxOutputTokens must be a positive integer, got " +
15
+ JSON.stringify(v));
16
+ }
17
+ }
18
+ return {
19
+ agentName,
20
+ search: {
21
+ maxResults: raw.search?.maxResults ?? defaultConfig.search.maxResults,
22
+ },
23
+ llm: raw.llm,
24
+ embedder: raw.embedder,
25
+ ontology: raw.ontology,
26
+ dataDir: raw.dataDir,
27
+ workspaceDir: raw.workspaceDir,
28
+ test: raw.test ?? false,
29
+ googleApiKey: raw.googleApiKey,
30
+ openaiApiKey: raw.openaiApiKey,
31
+ anthropicApiKey: raw.anthropicApiKey,
32
+ groqApiKey: raw.groqApiKey,
33
+ interpretMaxOutputTokens: raw.interpretMaxOutputTokens,
34
+ };
35
+ }
36
+ export function buildSecretEnv(config) {
37
+ const env = {};
38
+ if (config.googleApiKey)
39
+ env.GOOGLE_API_KEY = config.googleApiKey.trim();
40
+ if (config.openaiApiKey)
41
+ env.OPENAI_API_KEY = config.openaiApiKey.trim();
42
+ if (config.anthropicApiKey)
43
+ env.ANTHROPIC_API_KEY = config.anthropicApiKey.trim();
44
+ if (config.groqApiKey)
45
+ env.GROQ_API_KEY = config.groqApiKey.trim();
46
+ return env;
47
+ }
48
+ export const validateOntologyConfig = libValidate;
49
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,sBAAsB,IAAI,WAAW,GACtC,MAAM,oBAAoB,CAAC;AAwB5B,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,MAAM,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;CAClB,CAAC;AAEX,MAAM,UAAU,aAAa,CAC3B,MAAoC,EAAE;IAEtC,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC;IAChC,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CACb,8EAA8E;YAC5E,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAC5B,CAAC;IACJ,CAAC;IAED,IAAI,GAAG,CAAC,wBAAwB,KAAK,SAAS,EAAE,CAAC;QAC/C,MAAM,CAAC,GAAG,GAAG,CAAC,wBAAwB,CAAC;QACvC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5D,MAAM,IAAI,KAAK,CACb,yFAAyF;gBACvF,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CACpB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO;QACL,SAAS;QACT,MAAM,EAAE;YACN,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,IAAI,aAAa,CAAC,MAAM,CAAC,UAAU;SACtE;QACD,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,KAAK;QACvB,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,eAAe,EAAE,GAAG,CAAC,eAAe;QACpC,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,wBAAwB,EAAE,GAAG,CAAC,wBAAwB;KACvD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAA2B;IACxD,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,IAAI,MAAM,CAAC,YAAY;QAAE,GAAG,CAAC,cAAc,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IACzE,IAAI,MAAM,CAAC,YAAY;QAAE,GAAG,CAAC,cAAc,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IACzE,IAAI,MAAM,CAAC,eAAe;QAAE,GAAG,CAAC,iBAAiB,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;IAClF,IAAI,MAAM,CAAC,UAAU;QAAE,GAAG,CAAC,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IACnE,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,WAAW,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type { Message } from "./gralkor/index.js";
2
+ interface ContentBlock {
3
+ type: string;
4
+ text?: string;
5
+ thinking?: string;
6
+ [key: string]: unknown;
7
+ }
8
+ export interface MessageEntry {
9
+ role: string;
10
+ content: string | ContentBlock[];
11
+ }
12
+ /**
13
+ * Reduce an OpenClaw `agent_end` message list to the canonical Gralkor
14
+ * `Message[]` shape that `/capture` accepts.
15
+ *
16
+ * Conventions:
17
+ * - The **trailing** user message becomes a `"user"` Message (its earlier
18
+ * peers belong to past turns already captured).
19
+ * - The **final** assistant message becomes a `"assistant"` Message.
20
+ * - Each intermediate message between the trailing user and final assistant
21
+ * (thinking blocks, tool calls, tool results, intermediate assistant text)
22
+ * becomes a `"behaviour"` Message rendered as a string the server's
23
+ * distillation LLM can read.
24
+ *
25
+ * Returns `null` if the ctx doesn't contain both a user message and a final
26
+ * assistant message — the hook skips capture in that case.
27
+ *
28
+ * The leading `Conversation info`/`Sender (untrusted metadata)` JSON blocks
29
+ * that OpenClaw prepends to channel-inbound user messages are stripped here
30
+ * before the user message is emitted, so harness scaffolding never reaches
31
+ * the graph.
32
+ */
33
+ export declare function ctxToMessages(messages: MessageEntry[]): Message[] | null;
34
+ export declare function textFromContent(content: string | ContentBlock[]): string;
35
+ export {};
36
+ //# sourceMappingURL=ctx-to-messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ctx-to-messages.d.ts","sourceRoot":"","sources":["../src/ctx-to-messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElD,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,OAAO,EAAE,GAAG,IAAI,CA2BxE;AASD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE,GAAG,MAAM,CAMxE"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Reduce an OpenClaw `agent_end` message list to the canonical Gralkor
3
+ * `Message[]` shape that `/capture` accepts.
4
+ *
5
+ * Conventions:
6
+ * - The **trailing** user message becomes a `"user"` Message (its earlier
7
+ * peers belong to past turns already captured).
8
+ * - The **final** assistant message becomes a `"assistant"` Message.
9
+ * - Each intermediate message between the trailing user and final assistant
10
+ * (thinking blocks, tool calls, tool results, intermediate assistant text)
11
+ * becomes a `"behaviour"` Message rendered as a string the server's
12
+ * distillation LLM can read.
13
+ *
14
+ * Returns `null` if the ctx doesn't contain both a user message and a final
15
+ * assistant message — the hook skips capture in that case.
16
+ *
17
+ * The leading `Conversation info`/`Sender (untrusted metadata)` JSON blocks
18
+ * that OpenClaw prepends to channel-inbound user messages are stripped here
19
+ * before the user message is emitted, so harness scaffolding never reaches
20
+ * the graph.
21
+ */
22
+ export function ctxToMessages(messages) {
23
+ if (messages.length === 0)
24
+ return null;
25
+ const lastUserIdx = findLastIndex(messages, (m) => m.role === "user");
26
+ if (lastUserIdx === -1)
27
+ return null;
28
+ let lastAssistantIdx = -1;
29
+ for (let i = messages.length - 1; i > lastUserIdx; i--) {
30
+ if (messages[i].role === "assistant") {
31
+ lastAssistantIdx = i;
32
+ break;
33
+ }
34
+ }
35
+ if (lastAssistantIdx === -1)
36
+ return null;
37
+ const userText = stripInboundMetadataBlocks(textFromContent(messages[lastUserIdx].content));
38
+ const assistantText = textFromContent(messages[lastAssistantIdx].content);
39
+ const out = [{ role: "user", content: userText }];
40
+ for (let i = lastUserIdx + 1; i < lastAssistantIdx; i++) {
41
+ const rendered = renderBehaviour(messages[i]);
42
+ if (rendered !== null)
43
+ out.push({ role: "behaviour", content: rendered });
44
+ }
45
+ out.push({ role: "assistant", content: assistantText });
46
+ return out;
47
+ }
48
+ function findLastIndex(arr, pred) {
49
+ for (let i = arr.length - 1; i >= 0; i--) {
50
+ if (pred(arr[i]))
51
+ return i;
52
+ }
53
+ return -1;
54
+ }
55
+ export function textFromContent(content) {
56
+ if (typeof content === "string")
57
+ return content;
58
+ return content
59
+ .filter((b) => b.type === "text" || b.type === "output_text")
60
+ .map((b) => b.text ?? "")
61
+ .join("");
62
+ }
63
+ const ANSI_RE = /\x1B\[[0-?]*[ -/]*[@-~]/g;
64
+ const MAX_BEHAVIOUR_BODY_CHARS = 500;
65
+ function cleanBody(text) {
66
+ const stripped = text.replace(ANSI_RE, "").trim();
67
+ if (stripped.length <= MAX_BEHAVIOUR_BODY_CHARS)
68
+ return stripped;
69
+ return `${stripped.slice(0, MAX_BEHAVIOUR_BODY_CHARS)}… [truncated]`;
70
+ }
71
+ /**
72
+ * Render a single intermediate ctx message as a `"behaviour"` Message body.
73
+ * Returns `null` for entries with no useful content (so the caller can drop
74
+ * them entirely rather than emit empty behaviour messages).
75
+ */
76
+ function renderBehaviour(entry) {
77
+ if (entry.role === "toolResult") {
78
+ const body = cleanBody(textFromContent(entry.content));
79
+ return body === "" ? null : `toolResult: ${body}`;
80
+ }
81
+ if (typeof entry.content === "string") {
82
+ const trimmed = entry.content.trim();
83
+ return trimmed === "" ? null : `${entry.role}: ${trimmed}`;
84
+ }
85
+ const parts = [];
86
+ for (const block of entry.content) {
87
+ const rendered = renderBlock(block);
88
+ if (rendered !== null)
89
+ parts.push(rendered);
90
+ }
91
+ if (parts.length === 0)
92
+ return null;
93
+ return parts.join("\n");
94
+ }
95
+ function renderBlock(block) {
96
+ if (block.type === "thinking" && typeof block.thinking === "string") {
97
+ const t = block.thinking.trim();
98
+ return t === "" ? null : `thought: ${t}`;
99
+ }
100
+ if ((block.type === "text" || block.type === "output_text") && typeof block.text === "string") {
101
+ const body = cleanBody(block.text);
102
+ return body === "" ? null : `text: ${body}`;
103
+ }
104
+ if (block.type === "toolCall" || block.type === "toolUse" || block.type === "tool_use") {
105
+ const name = typeof block.name === "string" ? block.name : "tool";
106
+ const argsField = "arguments" in block ? block.arguments : "input" in block ? block.input : undefined;
107
+ const argsStr = argsField === undefined ? "" : JSON.stringify(argsField);
108
+ return `tool ${name}${argsStr ? ` ← ${argsStr}` : ""}`;
109
+ }
110
+ if (block.type === "toolResult" || block.type === "tool_result") {
111
+ const text = typeof block.text === "string" ? block.text : JSON.stringify(block);
112
+ return `tool result → ${cleanBody(text)}`;
113
+ }
114
+ return null;
115
+ }
116
+ const INBOUND_METADATA_BLOCK = /^(?:(?:Conversation info|Sender) \(untrusted metadata\):[ \t]*\n```json\n[\s\S]*?\n```[ \t]*\n*)+/;
117
+ function stripInboundMetadataBlocks(text) {
118
+ return text.replace(INBOUND_METADATA_BLOCK, "");
119
+ }
120
+ //# sourceMappingURL=ctx-to-messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ctx-to-messages.js","sourceRoot":"","sources":["../src/ctx-to-messages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { Turn } from "@susu-eng/gralkor-ts";
2
+ interface ContentBlock {
3
+ type: string;
4
+ text?: string;
5
+ thinking?: string;
6
+ [key: string]: unknown;
7
+ }
8
+ export interface MessageEntry {
9
+ role: string;
10
+ content: string | ContentBlock[];
11
+ }
12
+ /**
13
+ * Reduce an OpenClaw `agent_end` message list to a single `{user_query,
14
+ * assistant_answer, events}` Turn that the Gralkor `/capture` endpoint
15
+ * accepts.
16
+ *
17
+ * Conventions:
18
+ * - The **trailing** user message is the turn's query (earlier user
19
+ * messages belong to earlier turns, already captured separately).
20
+ * - The **final** assistant message's text content is the answer.
21
+ * - Everything between the trailing user message and the final assistant
22
+ * message (thinking blocks, tool calls, tool results, intermediate
23
+ * assistant messages) is the `events` list — passed through verbatim
24
+ * so the server can distil it without the client needing to understand
25
+ * provider-specific block shapes.
26
+ *
27
+ * Returns `null` if the ctx doesn't contain both a user message and a
28
+ * final assistant message — the hook skips capture in that case.
29
+ */
30
+ export declare function ctxToTurn(messages: MessageEntry[]): Turn | null;
31
+ export {};
32
+ //# sourceMappingURL=ctx-to-turn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ctx-to-turn.d.ts","sourceRoot":"","sources":["../src/ctx-to-turn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAEjD,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI,GAAG,IAAI,CAsB/D"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Reduce an OpenClaw `agent_end` message list to a single `{user_query,
3
+ * assistant_answer, events}` Turn that the Gralkor `/capture` endpoint
4
+ * accepts.
5
+ *
6
+ * Conventions:
7
+ * - The **trailing** user message is the turn's query (earlier user
8
+ * messages belong to earlier turns, already captured separately).
9
+ * - The **final** assistant message's text content is the answer.
10
+ * - Everything between the trailing user message and the final assistant
11
+ * message (thinking blocks, tool calls, tool results, intermediate
12
+ * assistant messages) is the `events` list — passed through verbatim
13
+ * so the server can distil it without the client needing to understand
14
+ * provider-specific block shapes.
15
+ *
16
+ * Returns `null` if the ctx doesn't contain both a user message and a
17
+ * final assistant message — the hook skips capture in that case.
18
+ */
19
+ export function ctxToTurn(messages) {
20
+ if (messages.length === 0)
21
+ return null;
22
+ const lastUserIdx = findLastIndex(messages, (m) => m.role === "user");
23
+ if (lastUserIdx === -1)
24
+ return null;
25
+ // Find the last assistant message at or after lastUserIdx.
26
+ let lastAssistantIdx = -1;
27
+ for (let i = messages.length - 1; i > lastUserIdx; i--) {
28
+ if (messages[i].role === "assistant") {
29
+ lastAssistantIdx = i;
30
+ break;
31
+ }
32
+ }
33
+ if (lastAssistantIdx === -1)
34
+ return null;
35
+ const user_query = textFromContent(messages[lastUserIdx].content);
36
+ const assistant_answer = textFromContent(messages[lastAssistantIdx].content);
37
+ const events = messages.slice(lastUserIdx + 1, lastAssistantIdx);
38
+ return { user_query, assistant_answer, events };
39
+ }
40
+ function findLastIndex(arr, pred) {
41
+ for (let i = arr.length - 1; i >= 0; i--) {
42
+ if (pred(arr[i]))
43
+ return i;
44
+ }
45
+ return -1;
46
+ }
47
+ function textFromContent(content) {
48
+ if (typeof content === "string")
49
+ return content;
50
+ return content
51
+ .filter((b) => b.type === "text" || b.type === "output_text")
52
+ .map((b) => b.text ?? "")
53
+ .join("");
54
+ }
55
+ //# sourceMappingURL=ctx-to-turn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ctx-to-turn.js","sourceRoot":"","sources":["../src/ctx-to-turn.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,SAAS,CAAC,QAAwB;IAChD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvC,MAAM,WAAW,GAAG,aAAa,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;IACtE,IAAI,WAAW,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpC,2DAA2D;IAC3D,IAAI,gBAAgB,GAAG,CAAC,CAAC,CAAC;IAC1B,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;QACvD,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACrC,gBAAgB,GAAG,CAAC,CAAC;YACrB,MAAM;QACR,CAAC;IACH,CAAC;IACD,IAAI,gBAAgB,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAEzC,MAAM,UAAU,GAAG,eAAe,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC;IAClE,MAAM,gBAAgB,GAAG,eAAe,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC;IAE7E,MAAM,MAAM,GAAc,QAAQ,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,EAAE,gBAAgB,CAAC,CAAC;IAE5E,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC;AAClD,CAAC;AAED,SAAS,aAAa,CAAI,GAAQ,EAAE,IAA0B;IAC5D,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,CAAC,CAAC,CAAC;AACZ,CAAC;AAED,SAAS,eAAe,CAAC,OAAgC;IACvD,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC;IAChD,OAAO,OAAO;SACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC;SAC5D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;SACxB,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC"}
@@ -0,0 +1,55 @@
1
+ import type { GralkorClient, Message, Result } from "../client.js";
2
+ export interface GralkorHttpClientOptions {
3
+ /** Base URL of the Gralkor server (e.g. `http://127.0.0.1:4000`). No trailing slash required. */
4
+ baseUrl: string;
5
+ /** Override fetch, e.g. for tests. Defaults to global fetch. */
6
+ fetch?: typeof fetch;
7
+ /**
8
+ * Output-token budget the server passes to its interpret pipeline on every
9
+ * `/recall`. When omitted, the server applies its own default (2000). Raise
10
+ * for wide-recall workloads where the default truncates and surfaces as
11
+ * `InterpretParseFailed` server-side. Must be a positive integer.
12
+ */
13
+ interpretMaxOutputTokens?: number;
14
+ }
15
+ /**
16
+ * HTTP adapter for {@link GralkorClient}.
17
+ *
18
+ * No auth: the server binds to loopback and expects its consumer to supervise it.
19
+ * No retries at this layer: non-2xx responses and transport errors surface immediately.
20
+ * See `gralkor/TEST_TREES.md` > Retry ownership — 429 retry lives inside the
21
+ * server's `/recall` handler; no layer above it retries this class.
22
+ *
23
+ * Per-endpoint timeouts (milliseconds), calibrated to the workload:
24
+ *
25
+ * - `/health` — 2 000
26
+ * - `/recall` — 12 000 (matches the server's `/recall` deadline; tight — a server 504 may race the transport, revisit if it bites)
27
+ * - `/capture` — 5 000
28
+ * - `/session_end` — 5 000
29
+ * - `/tools/memory_add` — 60 000 (Graphiti extraction is slow)
30
+ * - `/build-indices` — none (admin; minutes-to-hours on large graphs)
31
+ * - `/build-communities` — none (admin; minutes-to-hours on large graphs)
32
+ *
33
+ * Blank session ids throw `Error` — Gralkor requires a non-blank session_id.
34
+ */
35
+ export declare class GralkorHttpClient implements GralkorClient {
36
+ private readonly baseUrl;
37
+ private readonly fetchImpl;
38
+ private readonly interpretMaxOutputTokens;
39
+ constructor(options: GralkorHttpClientOptions);
40
+ recall(groupId: string, sessionId: string | null, query: string, agentName: string, maxResults?: number): Promise<Result<string>>;
41
+ capture(sessionId: string, groupId: string, agentName: string, messages: Message[]): Promise<Result<true>>;
42
+ endSession(sessionId: string): Promise<Result<true>>;
43
+ memoryAdd(groupId: string, content: string, sourceDescription: string | null): Promise<Result<true>>;
44
+ healthCheck(): Promise<Result<true>>;
45
+ buildIndices(): Promise<Result<{
46
+ status: string;
47
+ }>>;
48
+ buildCommunities(groupId: string): Promise<Result<{
49
+ communities: number;
50
+ edges: number;
51
+ }>>;
52
+ private post;
53
+ private request;
54
+ }
55
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/gralkor/client/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEnE,MAAM,WAAW,wBAAwB;IACvC,iGAAiG;IACjG,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,iBAAkB,YAAW,aAAa;IACrD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAqB;gBAElD,OAAO,EAAE,wBAAwB;IAavC,MAAM,CACV,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAepB,OAAO,CACX,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,OAAO,EAAE,GAClB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAWlB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAMpD,SAAS,CACb,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,iBAAiB,EAAE,MAAM,GAAG,IAAI,GAC/B,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAOlB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAKpC,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAQnD,gBAAgB,CACpB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAU1D,OAAO,CAAC,IAAI;YAIE,OAAO;CAyCtB"}