@cortexmem/bridge-openclaw 0.1.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.
- package/README.md +59 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +103 -0
- package/package.json +24 -0
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# @cortexmem/bridge-openclaw
|
|
2
|
+
|
|
3
|
+
Bridge plugin that connects [OpenClaw](https://github.com/openclaw) agents to [Cortex](https://github.com/rikouu/cortex) memory service.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @cortexmem/bridge-openclaw
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import cortexBridge from '@cortexmem/bridge-openclaw';
|
|
15
|
+
|
|
16
|
+
const agent = new Agent({
|
|
17
|
+
plugins: [cortexBridge],
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Environment Variables
|
|
22
|
+
|
|
23
|
+
| Variable | Default | Description |
|
|
24
|
+
|----------|---------|-------------|
|
|
25
|
+
| `CORTEX_URL` | `http://localhost:21100` | Cortex server URL |
|
|
26
|
+
| `CORTEX_DEBUG` | — | Enable debug logging |
|
|
27
|
+
|
|
28
|
+
## Hooks
|
|
29
|
+
|
|
30
|
+
The plugin provides three automatic hooks:
|
|
31
|
+
|
|
32
|
+
- **`onBeforeResponse`** — Recalls relevant memories and injects them as context before the agent responds.
|
|
33
|
+
- **`onAfterResponse`** — Extracts memories from conversations after the agent responds (fire-and-forget).
|
|
34
|
+
- **`onBeforeCompaction`** — Emergency flush of key information before context window compression.
|
|
35
|
+
|
|
36
|
+
## API
|
|
37
|
+
|
|
38
|
+
### `healthCheck()`
|
|
39
|
+
|
|
40
|
+
Verify the Cortex server is reachable.
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { healthCheck } from '@cortexmem/bridge-openclaw';
|
|
44
|
+
|
|
45
|
+
const status = await healthCheck();
|
|
46
|
+
// { ok: true, latency_ms: 12 }
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Individual Hooks
|
|
50
|
+
|
|
51
|
+
You can also import hooks individually:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { onBeforeResponse, onAfterResponse, onBeforeCompaction } from '@cortexmem/bridge-openclaw';
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## License
|
|
58
|
+
|
|
59
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cortex Bridge Plugin for OpenClaw
|
|
3
|
+
*
|
|
4
|
+
* Thin bridge (~200 lines) that forwards OpenClaw hooks to Cortex Sidecar REST API.
|
|
5
|
+
* Key design: NEVER block the Agent. All calls have hard timeouts + graceful fallback.
|
|
6
|
+
*/
|
|
7
|
+
interface AgentContext {
|
|
8
|
+
agentId?: string;
|
|
9
|
+
sessionId?: string;
|
|
10
|
+
lastUserMessage?: string;
|
|
11
|
+
lastAssistantMessage?: string;
|
|
12
|
+
messages?: {
|
|
13
|
+
role: string;
|
|
14
|
+
content: string;
|
|
15
|
+
}[];
|
|
16
|
+
metadata?: Record<string, any>;
|
|
17
|
+
}
|
|
18
|
+
interface PluginResult {
|
|
19
|
+
prependContext?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Called before Agent generates a response.
|
|
23
|
+
* Searches Cortex for relevant memories and injects them as context.
|
|
24
|
+
*/
|
|
25
|
+
declare function onBeforeResponse(context: AgentContext): Promise<PluginResult | null>;
|
|
26
|
+
/**
|
|
27
|
+
* Called after Agent generates a response.
|
|
28
|
+
* Sends the conversation exchange to Cortex for memory extraction.
|
|
29
|
+
* Fire-and-forget — does NOT wait for result.
|
|
30
|
+
*/
|
|
31
|
+
declare function onAfterResponse(context: AgentContext): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Called before context window compaction.
|
|
34
|
+
* Emergency flush — extract key info before it's lost.
|
|
35
|
+
*/
|
|
36
|
+
declare function onBeforeCompaction(context: AgentContext): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Health check — verify Cortex Sidecar is reachable.
|
|
39
|
+
*/
|
|
40
|
+
declare function healthCheck(): Promise<{
|
|
41
|
+
ok: boolean;
|
|
42
|
+
latency_ms: number;
|
|
43
|
+
error?: string;
|
|
44
|
+
}>;
|
|
45
|
+
declare const pluginInfo: {
|
|
46
|
+
name: string;
|
|
47
|
+
version: string;
|
|
48
|
+
description: string;
|
|
49
|
+
cortexUrl: string;
|
|
50
|
+
};
|
|
51
|
+
declare const _default: {
|
|
52
|
+
name: string;
|
|
53
|
+
onBeforeResponse: typeof onBeforeResponse;
|
|
54
|
+
onAfterResponse: typeof onAfterResponse;
|
|
55
|
+
onBeforeCompaction: typeof onBeforeCompaction;
|
|
56
|
+
healthCheck: typeof healthCheck;
|
|
57
|
+
pluginInfo: {
|
|
58
|
+
name: string;
|
|
59
|
+
version: string;
|
|
60
|
+
description: string;
|
|
61
|
+
cortexUrl: string;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export { _default as default, healthCheck, onAfterResponse, onBeforeCompaction, onBeforeResponse, pluginInfo };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var CORTEX_URL = process.env.CORTEX_URL || "http://localhost:21100";
|
|
3
|
+
var RECALL_TIMEOUT = 3e3;
|
|
4
|
+
var INGEST_TIMEOUT = 5e3;
|
|
5
|
+
var FLUSH_TIMEOUT = 5e3;
|
|
6
|
+
async function onBeforeResponse(context) {
|
|
7
|
+
if (!context.lastUserMessage) return null;
|
|
8
|
+
try {
|
|
9
|
+
const res = await fetch(`${CORTEX_URL}/api/v1/recall`, {
|
|
10
|
+
method: "POST",
|
|
11
|
+
headers: { "Content-Type": "application/json" },
|
|
12
|
+
body: JSON.stringify({
|
|
13
|
+
query: context.lastUserMessage,
|
|
14
|
+
agent_id: context.agentId || "openclaw",
|
|
15
|
+
max_tokens: 2e3
|
|
16
|
+
}),
|
|
17
|
+
signal: AbortSignal.timeout(RECALL_TIMEOUT)
|
|
18
|
+
});
|
|
19
|
+
if (res.ok) {
|
|
20
|
+
const data = await res.json();
|
|
21
|
+
if (data.context && data.meta.injected_count > 0) {
|
|
22
|
+
return { prependContext: data.context };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
} catch (e) {
|
|
26
|
+
if (process.env.CORTEX_DEBUG) {
|
|
27
|
+
console.warn("[cortex-bridge] Sidecar unreachable for recall:", e.message);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
async function onAfterResponse(context) {
|
|
33
|
+
if (!context.lastUserMessage || !context.lastAssistantMessage) return;
|
|
34
|
+
try {
|
|
35
|
+
fetch(`${CORTEX_URL}/api/v1/ingest`, {
|
|
36
|
+
method: "POST",
|
|
37
|
+
headers: { "Content-Type": "application/json" },
|
|
38
|
+
body: JSON.stringify({
|
|
39
|
+
user_message: context.lastUserMessage,
|
|
40
|
+
assistant_message: context.lastAssistantMessage,
|
|
41
|
+
agent_id: context.agentId || "openclaw",
|
|
42
|
+
session_id: context.sessionId
|
|
43
|
+
}),
|
|
44
|
+
signal: AbortSignal.timeout(INGEST_TIMEOUT)
|
|
45
|
+
}).catch(() => {
|
|
46
|
+
});
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function onBeforeCompaction(context) {
|
|
51
|
+
if (!context.messages || context.messages.length === 0) return;
|
|
52
|
+
try {
|
|
53
|
+
await fetch(`${CORTEX_URL}/api/v1/flush`, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: { "Content-Type": "application/json" },
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
messages: context.messages,
|
|
58
|
+
agent_id: context.agentId || "openclaw",
|
|
59
|
+
session_id: context.sessionId,
|
|
60
|
+
reason: "compaction"
|
|
61
|
+
}),
|
|
62
|
+
signal: AbortSignal.timeout(FLUSH_TIMEOUT)
|
|
63
|
+
});
|
|
64
|
+
} catch (e) {
|
|
65
|
+
if (process.env.CORTEX_DEBUG) {
|
|
66
|
+
console.warn("[cortex-bridge] Flush failed:", e.message);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function healthCheck() {
|
|
71
|
+
const start = Date.now();
|
|
72
|
+
try {
|
|
73
|
+
const res = await fetch(`${CORTEX_URL}/api/v1/health`, {
|
|
74
|
+
signal: AbortSignal.timeout(2e3)
|
|
75
|
+
});
|
|
76
|
+
const data = await res.json();
|
|
77
|
+
return { ok: data.status === "ok", latency_ms: Date.now() - start };
|
|
78
|
+
} catch (e) {
|
|
79
|
+
return { ok: false, latency_ms: Date.now() - start, error: e.message };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
var pluginInfo = {
|
|
83
|
+
name: "cortex-bridge",
|
|
84
|
+
version: "0.1.0",
|
|
85
|
+
description: "Bridge plugin for Cortex AI Agent Memory Service",
|
|
86
|
+
cortexUrl: CORTEX_URL
|
|
87
|
+
};
|
|
88
|
+
var index_default = {
|
|
89
|
+
name: "cortex-bridge",
|
|
90
|
+
onBeforeResponse,
|
|
91
|
+
onAfterResponse,
|
|
92
|
+
onBeforeCompaction,
|
|
93
|
+
healthCheck,
|
|
94
|
+
pluginInfo
|
|
95
|
+
};
|
|
96
|
+
export {
|
|
97
|
+
index_default as default,
|
|
98
|
+
healthCheck,
|
|
99
|
+
onAfterResponse,
|
|
100
|
+
onBeforeCompaction,
|
|
101
|
+
onBeforeResponse,
|
|
102
|
+
pluginInfo
|
|
103
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cortexmem/bridge-openclaw",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsup src/index.ts --format esm --dts",
|
|
16
|
+
"dev": "tsx src/index.ts"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/node": "^22.19.11",
|
|
20
|
+
"tsup": "^8.4.0",
|
|
21
|
+
"tsx": "^4.19.3",
|
|
22
|
+
"typescript": "^5.7.3"
|
|
23
|
+
}
|
|
24
|
+
}
|