@simbimbo/memory-ocmemog 0.1.20 → 0.1.21
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/CHANGELOG.md +9 -0
- package/index.ts +169 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.1.21 — 2026-03-30
|
|
6
|
+
|
|
7
|
+
OpenClaw memory-runtime compatibility release.
|
|
8
|
+
|
|
9
|
+
### Highlights
|
|
10
|
+
- fixed `memory-ocmemog` so it registers the primary OpenClaw memory runtime instead of exposing only tool surfaces
|
|
11
|
+
- restored compatibility with current OpenClaw host status/runtime expectations, resolving the `Memory ... unavailable` state while keeping the ocmemog sidecar healthy on `127.0.0.1:17891`
|
|
12
|
+
- kept the release intentionally minimal and scoped to the real host/plugin integration fix
|
|
13
|
+
|
|
5
14
|
## 0.1.20 — 2026-03-29
|
|
6
15
|
|
|
7
16
|
Operational-artifact canonicalization, dead-lane retrieval hardening, and rehydratable-memory recall fixes.
|
package/index.ts
CHANGED
|
@@ -12,6 +12,41 @@ type PluginConfig = {
|
|
|
12
12
|
token?: string;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
type MemoryManagerStatus = {
|
|
16
|
+
backend: string;
|
|
17
|
+
provider: string;
|
|
18
|
+
model?: string;
|
|
19
|
+
requestedProvider?: string;
|
|
20
|
+
files?: number;
|
|
21
|
+
chunks?: number;
|
|
22
|
+
dirty?: boolean;
|
|
23
|
+
workspaceDir?: string;
|
|
24
|
+
dbPath?: string;
|
|
25
|
+
vector?: { enabled?: boolean; available?: boolean; error?: string };
|
|
26
|
+
fts?: { enabled?: boolean; available?: boolean; error?: string };
|
|
27
|
+
custom?: Record<string, unknown>;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type MemorySearchManager = {
|
|
31
|
+
search(query: string, opts?: Record<string, unknown>): Promise<unknown>;
|
|
32
|
+
readFile(params: { relPath?: string; path?: string; from?: number; lines?: number }): Promise<{ text: string; path: string }>;
|
|
33
|
+
status(): MemoryManagerStatus;
|
|
34
|
+
sync?(params?: Record<string, unknown>): Promise<void>;
|
|
35
|
+
probeEmbeddingAvailability?(): Promise<{ ok: boolean; error?: string }>;
|
|
36
|
+
probeVectorAvailability?(): Promise<boolean>;
|
|
37
|
+
close?(): Promise<void>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
type MemoryRuntime = {
|
|
41
|
+
getMemorySearchManager(params: Record<string, unknown>): Promise<{ manager: MemorySearchManager | null; error?: string }>;
|
|
42
|
+
resolveMemoryBackendConfig(params: Record<string, unknown>): Record<string, unknown>;
|
|
43
|
+
closeAllMemorySearchManagers(): Promise<void>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
type OpenClawPluginApiCompat = OpenClawPluginApi & {
|
|
47
|
+
registerMemoryRuntime?: (runtime: MemoryRuntime) => void;
|
|
48
|
+
};
|
|
49
|
+
|
|
15
50
|
const DURABLE_OUTBOX_ENABLED = !["0", "false", "no"].includes(
|
|
16
51
|
String(process.env.OCMEMOG_DURABLE_OUTBOX ?? "true").trim().toLowerCase(),
|
|
17
52
|
);
|
|
@@ -56,6 +91,16 @@ type RecentResponse = {
|
|
|
56
91
|
error?: string;
|
|
57
92
|
};
|
|
58
93
|
|
|
94
|
+
type SidecarHealthResponse = {
|
|
95
|
+
ok?: boolean;
|
|
96
|
+
version?: string;
|
|
97
|
+
service?: string;
|
|
98
|
+
vector_provider?: string;
|
|
99
|
+
vector_available?: boolean;
|
|
100
|
+
database_path?: string;
|
|
101
|
+
[key: string]: unknown;
|
|
102
|
+
};
|
|
103
|
+
|
|
59
104
|
type ConversationHydrateResponse = {
|
|
60
105
|
ok: boolean;
|
|
61
106
|
recent_turns?: Array<Record<string, unknown>>;
|
|
@@ -719,6 +764,122 @@ function registerAutomaticContinuityHooks(api: OpenClawPluginApi, config: Plugin
|
|
|
719
764
|
});
|
|
720
765
|
}
|
|
721
766
|
|
|
767
|
+
async function getSidecarHealth(config: PluginConfig): Promise<SidecarHealthResponse> {
|
|
768
|
+
return await getJson<SidecarHealthResponse>(config, "/healthz");
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
function normalizeReadPath(params: { relPath?: string; path?: string }): string {
|
|
772
|
+
const value = String(params.relPath ?? params.path ?? "").trim();
|
|
773
|
+
return value;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
function createOcmemogSearchManager(api: OpenClawPluginApi, config: PluginConfig): MemorySearchManager {
|
|
777
|
+
let closed = false;
|
|
778
|
+
|
|
779
|
+
return {
|
|
780
|
+
async search(query: string, opts?: Record<string, unknown>): Promise<unknown> {
|
|
781
|
+
if (closed) throw new Error("memory manager closed");
|
|
782
|
+
const payload = await postJson<SearchResponse>(config, "/memory/search", {
|
|
783
|
+
query,
|
|
784
|
+
limit: opts?.limit,
|
|
785
|
+
categories: opts?.categories,
|
|
786
|
+
metadata_filters: opts?.metadataFilters,
|
|
787
|
+
lane: opts?.lane,
|
|
788
|
+
});
|
|
789
|
+
return payload;
|
|
790
|
+
},
|
|
791
|
+
async readFile(params: { relPath?: string; path?: string; from?: number; lines?: number }): Promise<{ text: string; path: string }> {
|
|
792
|
+
if (closed) throw new Error("memory manager closed");
|
|
793
|
+
const relPath = normalizeReadPath(params);
|
|
794
|
+
if (!relPath) throw new Error("path required");
|
|
795
|
+
if (!relPath.endsWith('.md')) throw new Error('path required');
|
|
796
|
+
const absPath = path.resolve(api.workspaceDir ?? process.cwd(), relPath);
|
|
797
|
+
let text = "";
|
|
798
|
+
try {
|
|
799
|
+
text = await fs.readFile(absPath, "utf8");
|
|
800
|
+
} catch (error) {
|
|
801
|
+
const code = (error as NodeJS.ErrnoException)?.code;
|
|
802
|
+
if (code === "ENOENT") return { text: "", path: relPath };
|
|
803
|
+
throw error;
|
|
804
|
+
}
|
|
805
|
+
if (params.from !== undefined || params.lines !== undefined) {
|
|
806
|
+
const lines = text.split("\n");
|
|
807
|
+
const start = Math.max(1, Number(params.from ?? 1));
|
|
808
|
+
const count = Math.max(1, Number(params.lines ?? lines.length));
|
|
809
|
+
text = lines.slice(start - 1, start - 1 + count).join("\n");
|
|
810
|
+
}
|
|
811
|
+
return { text, path: relPath };
|
|
812
|
+
},
|
|
813
|
+
status(): MemoryManagerStatus {
|
|
814
|
+
return {
|
|
815
|
+
backend: "ocmemog",
|
|
816
|
+
provider: "ocmemog",
|
|
817
|
+
model: "ocmemog",
|
|
818
|
+
requestedProvider: "ocmemog",
|
|
819
|
+
dirty: false,
|
|
820
|
+
workspaceDir: api.workspaceDir,
|
|
821
|
+
vector: {
|
|
822
|
+
enabled: true,
|
|
823
|
+
available: true,
|
|
824
|
+
},
|
|
825
|
+
fts: {
|
|
826
|
+
enabled: true,
|
|
827
|
+
available: true,
|
|
828
|
+
},
|
|
829
|
+
custom: {
|
|
830
|
+
endpoint: config.endpoint,
|
|
831
|
+
runtime: "ocmemog-sidecar-adapter",
|
|
832
|
+
sidecar: "ocmemog",
|
|
833
|
+
},
|
|
834
|
+
};
|
|
835
|
+
},
|
|
836
|
+
async probeEmbeddingAvailability(): Promise<{ ok: boolean; error?: string }> {
|
|
837
|
+
try {
|
|
838
|
+
const health = await getSidecarHealth(config);
|
|
839
|
+
return { ok: Boolean(health.ok ?? true) };
|
|
840
|
+
} catch (error) {
|
|
841
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
842
|
+
}
|
|
843
|
+
},
|
|
844
|
+
async probeVectorAvailability(): Promise<boolean> {
|
|
845
|
+
try {
|
|
846
|
+
const health = await getSidecarHealth(config);
|
|
847
|
+
return Boolean(health.vector_available ?? true);
|
|
848
|
+
} catch {
|
|
849
|
+
return false;
|
|
850
|
+
}
|
|
851
|
+
},
|
|
852
|
+
async close(): Promise<void> {
|
|
853
|
+
closed = true;
|
|
854
|
+
},
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
function createOcmemogMemoryRuntime(api: OpenClawPluginApi, config: PluginConfig): MemoryRuntime {
|
|
859
|
+
let manager: MemorySearchManager | null = null;
|
|
860
|
+
return {
|
|
861
|
+
async getMemorySearchManager(_params: Record<string, unknown>): Promise<{ manager: MemorySearchManager | null; error?: string }> {
|
|
862
|
+
try {
|
|
863
|
+
manager ??= createOcmemogSearchManager(api, config);
|
|
864
|
+
return { manager };
|
|
865
|
+
} catch (error) {
|
|
866
|
+
return { manager: null, error: error instanceof Error ? error.message : String(error) };
|
|
867
|
+
}
|
|
868
|
+
},
|
|
869
|
+
resolveMemoryBackendConfig(_params: Record<string, unknown>): Record<string, unknown> {
|
|
870
|
+
return {
|
|
871
|
+
backend: "ocmemog",
|
|
872
|
+
endpoint: config.endpoint,
|
|
873
|
+
timeoutMs: config.timeoutMs,
|
|
874
|
+
};
|
|
875
|
+
},
|
|
876
|
+
async closeAllMemorySearchManagers(): Promise<void> {
|
|
877
|
+
await manager?.close?.();
|
|
878
|
+
manager = null;
|
|
879
|
+
},
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
|
|
722
883
|
const ocmemogPlugin = {
|
|
723
884
|
id: "memory-ocmemog",
|
|
724
885
|
name: "Memory (OCMemog)",
|
|
@@ -726,6 +887,14 @@ const ocmemogPlugin = {
|
|
|
726
887
|
kind: "memory",
|
|
727
888
|
register(api: OpenClawPluginApi) {
|
|
728
889
|
const config = readConfig(api.pluginConfig);
|
|
890
|
+
const apiCompat = api as OpenClawPluginApiCompat;
|
|
891
|
+
|
|
892
|
+
if (typeof apiCompat.registerMemoryRuntime === "function") {
|
|
893
|
+
apiCompat.registerMemoryRuntime(createOcmemogMemoryRuntime(api, config));
|
|
894
|
+
api.logger.info(`ocmemog registered primary memory runtime via sidecar adapter (${config.endpoint})`);
|
|
895
|
+
} else {
|
|
896
|
+
api.logger.info("ocmemog host API does not expose registerMemoryRuntime; continuing in legacy tool-only compatibility mode");
|
|
897
|
+
}
|
|
729
898
|
|
|
730
899
|
registerAutomaticContinuityHooks(api, config);
|
|
731
900
|
|
package/package.json
CHANGED