@ubundi/openclaw-cortex 0.2.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 (59) hide show
  1. package/README.md +157 -0
  2. package/dist/client.d.ts +48 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/dist/client.js +73 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/config.d.ts +68 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +27 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/hooks/capture.d.ts +24 -0
  11. package/dist/hooks/capture.d.ts.map +1 -0
  12. package/dist/hooks/capture.js +66 -0
  13. package/dist/hooks/capture.js.map +1 -0
  14. package/dist/hooks/recall.d.ts +28 -0
  15. package/dist/hooks/recall.d.ts.map +1 -0
  16. package/dist/hooks/recall.js +68 -0
  17. package/dist/hooks/recall.js.map +1 -0
  18. package/dist/index.d.ts +66 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +94 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/services/reflect.d.ts +19 -0
  23. package/dist/services/reflect.d.ts.map +1 -0
  24. package/dist/services/reflect.js +38 -0
  25. package/dist/services/reflect.js.map +1 -0
  26. package/dist/sync/daily-logs.d.ts +21 -0
  27. package/dist/sync/daily-logs.d.ts.map +1 -0
  28. package/dist/sync/daily-logs.js +43 -0
  29. package/dist/sync/daily-logs.js.map +1 -0
  30. package/dist/sync/memory-md.d.ts +25 -0
  31. package/dist/sync/memory-md.d.ts.map +1 -0
  32. package/dist/sync/memory-md.js +67 -0
  33. package/dist/sync/memory-md.js.map +1 -0
  34. package/dist/sync/transcripts.d.ts +21 -0
  35. package/dist/sync/transcripts.d.ts.map +1 -0
  36. package/dist/sync/transcripts.js +51 -0
  37. package/dist/sync/transcripts.js.map +1 -0
  38. package/dist/sync/watcher.d.ts +28 -0
  39. package/dist/sync/watcher.d.ts.map +1 -0
  40. package/dist/sync/watcher.js +85 -0
  41. package/dist/sync/watcher.js.map +1 -0
  42. package/dist/utils/format.d.ts +3 -0
  43. package/dist/utils/format.d.ts.map +1 -0
  44. package/dist/utils/format.js +7 -0
  45. package/dist/utils/format.js.map +1 -0
  46. package/dist/utils/metrics.d.ts +19 -0
  47. package/dist/utils/metrics.d.ts.map +1 -0
  48. package/dist/utils/metrics.js +45 -0
  49. package/dist/utils/metrics.js.map +1 -0
  50. package/dist/utils/retry-queue.d.ts +27 -0
  51. package/dist/utils/retry-queue.d.ts.map +1 -0
  52. package/dist/utils/retry-queue.js +67 -0
  53. package/dist/utils/retry-queue.js.map +1 -0
  54. package/dist/utils/transcript-cleaner.d.ts +24 -0
  55. package/dist/utils/transcript-cleaner.d.ts.map +1 -0
  56. package/dist/utils/transcript-cleaner.js +96 -0
  57. package/dist/utils/transcript-cleaner.js.map +1 -0
  58. package/openclaw.plugin.json +95 -0
  59. package/package.json +41 -0
package/README.md ADDED
@@ -0,0 +1,157 @@
1
+ # @ubundi/openclaw-cortex
2
+
3
+ ![OpenClaw Cortex Logo](assets/logo.png)
4
+
5
+ OpenClaw plugin for [Cortex](https://github.com/ubundi/cortex) long-term memory. Gives your agent persistent memory that survives across sessions — who you are, what your project does, decisions you made weeks ago, and how things changed over time.
6
+
7
+ - **Auto-Recall** — injects relevant memories before every agent turn via `before_agent_start` hook
8
+ - **Auto-Capture** — extracts facts from conversations via `agent_end` hook
9
+ - **File Sync** — watches `MEMORY.md`, daily logs, and session transcripts for background ingestion
10
+ - **Periodic Reflect** — consolidates memories, resolves SUPERSEDES chains, detects contradictions
11
+ - **Resilience** — retry queue with exponential backoff, cold-start detection, latency metrics
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ openclaw plugins install @ubundi/openclaw-cortex
17
+ ```
18
+
19
+ Or link locally for development:
20
+
21
+ ```bash
22
+ openclaw plugins install -l ./path/to/openclaw-cortex
23
+ ```
24
+
25
+ ## Configuration
26
+
27
+ Add to your `openclaw.json`:
28
+
29
+ ```json5
30
+ {
31
+ plugins: {
32
+ entries: {
33
+ "@ubundi/openclaw-cortex": {
34
+ enabled: true,
35
+ config: {
36
+ apiKey: "sk-cortex-...",
37
+ baseUrl: "https://q5p64iw9c9.execute-api.us-east-1.amazonaws.com/prod",
38
+ autoRecall: true,
39
+ autoCapture: true,
40
+ recallTopK: 5,
41
+ recallTimeoutMs: 500,
42
+ recallMode: "fast",
43
+ fileSync: true,
44
+ transcriptSync: true,
45
+ reflectIntervalMs: 3600000
46
+ }
47
+ }
48
+ },
49
+ slots: {
50
+ memory: "@ubundi/openclaw-cortex"
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ Environment variables are supported via `${VAR_NAME}` syntax:
57
+
58
+ ```json
59
+ {
60
+ "apiKey": "${CORTEX_API_KEY}",
61
+ "baseUrl": "${CORTEX_BASE_URL}"
62
+ }
63
+ ```
64
+
65
+ ### Config Options
66
+
67
+ | Option | Type | Default | Description |
68
+ |---|---|---|---|
69
+ | `apiKey` | string | _required_ | Cortex API key |
70
+ | `baseUrl` | string | `https://q5p64iw9c9...` | Cortex API base URL |
71
+ | `autoRecall` | boolean | `true` | Inject memories before each agent turn |
72
+ | `autoCapture` | boolean | `true` | Extract facts after agent responses |
73
+ | `recallTopK` | number | `5` | Number of memories to retrieve per turn |
74
+ | `recallTimeoutMs` | number | `500` | Max time to wait for recall (ms) |
75
+ | `recallMode` | string | `"fast"` | Retrieval depth: `fast`, `balanced`, or `full` |
76
+ | `fileSync` | boolean | `true` | Watch MEMORY.md and daily logs |
77
+ | `transcriptSync` | boolean | `true` | Watch and ingest session transcripts |
78
+ | `reflectIntervalMs` | number | `3600000` | Memory consolidation interval (ms). `0` to disable |
79
+
80
+ ### Recall Modes
81
+
82
+ | Mode | What it does | Server-side latency |
83
+ |---|---|---|
84
+ | `fast` | BM25 + semantic search only | ~80-150ms |
85
+ | `balanced` | Adds light reranking | ~150-300ms |
86
+ | `full` | Adds graph traversal + full reranker | ~300-600ms |
87
+
88
+ Use `fast` (default) for auto-recall where latency matters. Use `full` for explicit recall via SKILL.md where depth matters more than speed.
89
+
90
+ ## How It Works
91
+
92
+ ### Auto-Recall
93
+
94
+ Before every agent turn, the plugin queries Cortex's `/v1/retrieve` endpoint and prepends results to the agent's context:
95
+
96
+ ```xml
97
+ <cortex_memories>
98
+ - [0.95] User prefers TypeScript over JavaScript
99
+ - [0.87] Project uses PostgreSQL with pgvector
100
+ </cortex_memories>
101
+ ```
102
+
103
+ If the request exceeds `recallTimeoutMs`, the agent proceeds without memories (silent degradation). After 3 consecutive failures, recall is disabled for 30 seconds (cold-start detection) to avoid hammering a cold ECS task.
104
+
105
+ ### Auto-Capture
106
+
107
+ After each successful agent turn, the plugin extracts the last 20 messages and sends them to Cortex's `/v1/ingest/conversation` endpoint. A heuristic skips trivial exchanges (short messages, system-only turns).
108
+
109
+ Capture is fire-and-forget — it never blocks the agent. Failed ingestions are queued for retry with exponential backoff (up to 5 retries).
110
+
111
+ ### File Sync
112
+
113
+ The plugin watches OpenClaw's memory files and ingests changes into Cortex:
114
+
115
+ - **MEMORY.md** — Line-level diff with 2-second debounce. Only added lines are ingested.
116
+ - **memory/\*.md** (daily logs) — Offset-based append detection. New content is ingested as it's written.
117
+ - **sessions/\*.jsonl** (transcripts) — Strips system prompts, tool JSON, and base64 images. Cleans dialogue into conversation format and batch ingests with session-scoped IDs.
118
+
119
+ Failed file sync operations are queued for retry, so transient network failures don't cause data loss.
120
+
121
+ ### Periodic Reflect
122
+
123
+ Every `reflectIntervalMs` (default: 1 hour), the plugin calls Cortex's `/v1/reflect` endpoint to consolidate memories:
124
+
125
+ - Merges duplicate facts ingested across sessions
126
+ - Marks stale facts as superseded (SUPERSEDES chains)
127
+ - Detects contradictions between facts
128
+ - Tracks belief drift over time
129
+
130
+ Set `reflectIntervalMs: 0` to disable.
131
+
132
+ ### Observability
133
+
134
+ On shutdown, the plugin logs recall latency percentiles:
135
+
136
+ ```
137
+ Cortex recall latency (847 samples): p50=120ms p95=340ms p99=480ms
138
+ ```
139
+
140
+ Use this to tune `recallTimeoutMs` and `recallMode` for your deployment.
141
+
142
+ ## Compatibility with SKILL.md
143
+
144
+ If both this plugin and the Cortex SKILL.md are active, the `<cortex_memories>` tag in the prepended context signals to the skill that recall has already happened — the agent can skip manual `curl` calls.
145
+
146
+ ## Development
147
+
148
+ ```bash
149
+ npm install
150
+ npm run build # TypeScript → dist/
151
+ npm test # Run vitest (52 tests)
152
+ npm run test:watch # Watch mode
153
+ ```
154
+
155
+ ## License
156
+
157
+ MIT
@@ -0,0 +1,48 @@
1
+ export interface RetrieveResult {
2
+ node_id: string;
3
+ type: string;
4
+ content: string;
5
+ score: number;
6
+ source?: string;
7
+ confidence?: number;
8
+ metadata?: Record<string, unknown>;
9
+ }
10
+ export interface RetrieveResponse {
11
+ results: RetrieveResult[];
12
+ }
13
+ export interface IngestFact {
14
+ core: string;
15
+ fact_type: string;
16
+ occurred_at: string | null;
17
+ entity_refs: string[];
18
+ speaker: string;
19
+ }
20
+ export interface IngestEntity {
21
+ name: string;
22
+ type: string;
23
+ aliases: string[];
24
+ }
25
+ export interface IngestResponse {
26
+ nodes_created: number;
27
+ edges_created: number;
28
+ facts: IngestFact[];
29
+ entities: IngestEntity[];
30
+ }
31
+ export interface ReflectResponse {
32
+ synthesized_count: number;
33
+ superseded_count: number;
34
+ }
35
+ export interface ConversationMessage {
36
+ role: string;
37
+ content: string;
38
+ }
39
+ export declare class CortexClient {
40
+ private baseUrl;
41
+ private apiKey;
42
+ constructor(baseUrl: string, apiKey: string);
43
+ retrieve(query: string, topK: number, mode: "fast" | "full", timeoutMs: number): Promise<RetrieveResponse>;
44
+ ingest(text: string, sessionId?: string): Promise<IngestResponse>;
45
+ ingestConversation(messages: ConversationMessage[], sessionId?: string): Promise<IngestResponse>;
46
+ reflect(sessionId?: string): Promise<ReflectResponse>;
47
+ }
48
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,YAAY;IAErB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,MAAM;gBADN,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM;IAGlB,QAAQ,CACZ,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,CAAC;IAyBtB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAiBjE,kBAAkB,CACtB,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,cAAc,CAAC;IAiBpB,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;CAgB5D"}
package/dist/client.js ADDED
@@ -0,0 +1,73 @@
1
+ export class CortexClient {
2
+ baseUrl;
3
+ apiKey;
4
+ constructor(baseUrl, apiKey) {
5
+ this.baseUrl = baseUrl;
6
+ this.apiKey = apiKey;
7
+ }
8
+ async retrieve(query, topK, mode, timeoutMs) {
9
+ const controller = new AbortController();
10
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
11
+ try {
12
+ const res = await fetch(`${this.baseUrl}/v1/retrieve`, {
13
+ method: "POST",
14
+ headers: {
15
+ "x-api-key": this.apiKey,
16
+ "Content-Type": "application/json",
17
+ },
18
+ body: JSON.stringify({ query, top_k: topK, mode }),
19
+ signal: controller.signal,
20
+ });
21
+ if (!res.ok) {
22
+ throw new Error(`Cortex retrieve failed: ${res.status}`);
23
+ }
24
+ return (await res.json());
25
+ }
26
+ finally {
27
+ clearTimeout(timeout);
28
+ }
29
+ }
30
+ async ingest(text, sessionId) {
31
+ const res = await fetch(`${this.baseUrl}/v1/ingest`, {
32
+ method: "POST",
33
+ headers: {
34
+ "x-api-key": this.apiKey,
35
+ "Content-Type": "application/json",
36
+ },
37
+ body: JSON.stringify({ text, session_id: sessionId }),
38
+ });
39
+ if (!res.ok) {
40
+ throw new Error(`Cortex ingest failed: ${res.status}`);
41
+ }
42
+ return (await res.json());
43
+ }
44
+ async ingestConversation(messages, sessionId) {
45
+ const res = await fetch(`${this.baseUrl}/v1/ingest/conversation`, {
46
+ method: "POST",
47
+ headers: {
48
+ "x-api-key": this.apiKey,
49
+ "Content-Type": "application/json",
50
+ },
51
+ body: JSON.stringify({ messages, session_id: sessionId }),
52
+ });
53
+ if (!res.ok) {
54
+ throw new Error(`Cortex ingest/conversation failed: ${res.status}`);
55
+ }
56
+ return (await res.json());
57
+ }
58
+ async reflect(sessionId) {
59
+ const res = await fetch(`${this.baseUrl}/v1/reflect`, {
60
+ method: "POST",
61
+ headers: {
62
+ "x-api-key": this.apiKey,
63
+ "Content-Type": "application/json",
64
+ },
65
+ body: JSON.stringify({ session_id: sessionId }),
66
+ });
67
+ if (!res.ok) {
68
+ throw new Error(`Cortex reflect failed: ${res.status}`);
69
+ }
70
+ return (await res.json());
71
+ }
72
+ }
73
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AA6CA,MAAM,OAAO,YAAY;IAEb;IACA;IAFV,YACU,OAAe,EACf,MAAc;QADd,YAAO,GAAP,OAAO,CAAQ;QACf,WAAM,GAAN,MAAM,CAAQ;IACrB,CAAC;IAEJ,KAAK,CAAC,QAAQ,CACZ,KAAa,EACb,IAAY,EACZ,IAAqB,EACrB,SAAiB;QAEjB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;QAEhE,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,cAAc,EAAE;gBACrD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,WAAW,EAAE,IAAI,CAAC,MAAM;oBACxB,cAAc,EAAE,kBAAkB;iBACnC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;gBAClD,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;YAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YAC3D,CAAC;YAED,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAqB,CAAC;QAChD,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY,EAAE,SAAkB;QAC3C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,YAAY,EAAE;YACnD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,WAAW,EAAE,IAAI,CAAC,MAAM;gBACxB,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;SACtD,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QACzD,CAAC;QAED,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAmB,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,kBAAkB,CACtB,QAA+B,EAC/B,SAAkB;QAElB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,yBAAyB,EAAE;YAChE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,WAAW,EAAE,IAAI,CAAC,MAAM;gBACxB,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;SAC1D,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,sCAAsC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QACtE,CAAC;QAED,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAmB,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,SAAkB;QAC9B,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,aAAa,EAAE;YACpD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,WAAW,EAAE,IAAI,CAAC,MAAM;gBACxB,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;SAChD,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAC1D,CAAC;QAED,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAoB,CAAC;IAC/C,CAAC;CACF"}
@@ -0,0 +1,68 @@
1
+ import { z } from "zod";
2
+ export declare const RecallMode: z.ZodEnum<["fast", "balanced", "full"]>;
3
+ export type RecallMode = z.infer<typeof RecallMode>;
4
+ export declare const CortexConfigSchema: z.ZodObject<{
5
+ apiKey: z.ZodString;
6
+ baseUrl: z.ZodDefault<z.ZodString>;
7
+ autoRecall: z.ZodDefault<z.ZodBoolean>;
8
+ autoCapture: z.ZodDefault<z.ZodBoolean>;
9
+ recallTopK: z.ZodDefault<z.ZodNumber>;
10
+ recallTimeoutMs: z.ZodDefault<z.ZodNumber>;
11
+ recallMode: z.ZodDefault<z.ZodEnum<["fast", "balanced", "full"]>>;
12
+ fileSync: z.ZodDefault<z.ZodBoolean>;
13
+ transcriptSync: z.ZodDefault<z.ZodBoolean>;
14
+ reflectIntervalMs: z.ZodDefault<z.ZodNumber>;
15
+ }, "strip", z.ZodTypeAny, {
16
+ apiKey: string;
17
+ baseUrl: string;
18
+ autoRecall: boolean;
19
+ autoCapture: boolean;
20
+ recallTopK: number;
21
+ recallTimeoutMs: number;
22
+ recallMode: "fast" | "full" | "balanced";
23
+ fileSync: boolean;
24
+ transcriptSync: boolean;
25
+ reflectIntervalMs: number;
26
+ }, {
27
+ apiKey: string;
28
+ baseUrl?: string | undefined;
29
+ autoRecall?: boolean | undefined;
30
+ autoCapture?: boolean | undefined;
31
+ recallTopK?: number | undefined;
32
+ recallTimeoutMs?: number | undefined;
33
+ recallMode?: "fast" | "full" | "balanced" | undefined;
34
+ fileSync?: boolean | undefined;
35
+ transcriptSync?: boolean | undefined;
36
+ reflectIntervalMs?: number | undefined;
37
+ }>;
38
+ export type CortexConfig = z.infer<typeof CortexConfigSchema>;
39
+ /**
40
+ * Config schema compatible with OpenClaw's pluginConfigSchema interface.
41
+ * OpenClaw calls safeParse() during plugin registration.
42
+ */
43
+ export declare const configSchema: {
44
+ safeParse(value: unknown): z.SafeParseReturnType<{
45
+ apiKey: string;
46
+ baseUrl?: string | undefined;
47
+ autoRecall?: boolean | undefined;
48
+ autoCapture?: boolean | undefined;
49
+ recallTopK?: number | undefined;
50
+ recallTimeoutMs?: number | undefined;
51
+ recallMode?: "fast" | "full" | "balanced" | undefined;
52
+ fileSync?: boolean | undefined;
53
+ transcriptSync?: boolean | undefined;
54
+ reflectIntervalMs?: number | undefined;
55
+ }, {
56
+ apiKey: string;
57
+ baseUrl: string;
58
+ autoRecall: boolean;
59
+ autoCapture: boolean;
60
+ recallTopK: number;
61
+ recallTimeoutMs: number;
62
+ recallMode: "fast" | "full" | "balanced";
63
+ fileSync: boolean;
64
+ transcriptSync: boolean;
65
+ reflectIntervalMs: number;
66
+ }>;
67
+ };
68
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,UAAU,yCAAuC,CAAC;AAC/D,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAc7B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;GAGG;AACH,eAAO,MAAM,YAAY;qBACN,OAAO;;;;;;;;;;;;;;;;;;;;;;;CAGzB,CAAC"}
package/dist/config.js ADDED
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+ export const RecallMode = z.enum(["fast", "balanced", "full"]);
3
+ export const CortexConfigSchema = z.object({
4
+ apiKey: z.string().min(1, "apiKey is required"),
5
+ baseUrl: z
6
+ .string()
7
+ .url("baseUrl must be a valid URL")
8
+ .default("https://q5p64iw9c9.execute-api.us-east-1.amazonaws.com/prod"),
9
+ autoRecall: z.boolean().default(true),
10
+ autoCapture: z.boolean().default(true),
11
+ recallTopK: z.number().int().min(1).max(20).default(5),
12
+ recallTimeoutMs: z.number().int().min(100).max(10000).default(2000),
13
+ recallMode: RecallMode.default("fast"),
14
+ fileSync: z.boolean().default(true),
15
+ transcriptSync: z.boolean().default(true),
16
+ reflectIntervalMs: z.number().int().min(0).default(3_600_000),
17
+ });
18
+ /**
19
+ * Config schema compatible with OpenClaw's pluginConfigSchema interface.
20
+ * OpenClaw calls safeParse() during plugin registration.
21
+ */
22
+ export const configSchema = {
23
+ safeParse(value) {
24
+ return CortexConfigSchema.safeParse(value);
25
+ },
26
+ };
27
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;AAG/D,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,oBAAoB,CAAC;IAC/C,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,GAAG,CAAC,6BAA6B,CAAC;SAClC,OAAO,CAAC,6DAA6D,CAAC;IACzE,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACrC,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACtC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACtD,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IACnE,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;IACtC,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACnC,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACzC,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;CAC9D,CAAC,CAAC;AAIH;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,SAAS,CAAC,KAAc;QACtB,OAAO,kBAAkB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC;CACF,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { CortexClient } from "../client.js";
2
+ import type { CortexConfig } from "../config.js";
3
+ import type { RetryQueue } from "../utils/retry-queue.js";
4
+ interface AgentEndEvent {
5
+ messages: unknown[];
6
+ success: boolean;
7
+ error?: string;
8
+ durationMs?: number;
9
+ }
10
+ interface AgentContext {
11
+ agentId?: string;
12
+ sessionKey?: string;
13
+ sessionId?: string;
14
+ workspaceDir?: string;
15
+ }
16
+ type Logger = {
17
+ debug?(...args: unknown[]): void;
18
+ info(...args: unknown[]): void;
19
+ warn(...args: unknown[]): void;
20
+ error(...args: unknown[]): void;
21
+ };
22
+ export declare function createCaptureHandler(client: CortexClient, config: CortexConfig, logger: Logger, retryQueue?: RetryQueue): (event: AgentEndEvent, ctx: AgentContext) => Promise<void>;
23
+ export {};
24
+ //# sourceMappingURL=capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/hooks/capture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAuB,MAAM,cAAc,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,UAAU,aAAa;IACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,KAAK,MAAM,GAAG;IACZ,KAAK,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACjC,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CACjC,CAAC;AA+BF,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,UAAU,IAIT,OAAO,aAAa,EAAE,KAAK,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC,CA+CtE"}
@@ -0,0 +1,66 @@
1
+ const MIN_CONTENT_LENGTH = 20;
2
+ const RECENT_MESSAGES_COUNT = 20;
3
+ function extractContent(content) {
4
+ if (typeof content === "string")
5
+ return content;
6
+ if (Array.isArray(content)) {
7
+ return content
8
+ .filter((block) => typeof block === "object" &&
9
+ block !== null &&
10
+ "type" in block &&
11
+ block.type === "text" &&
12
+ "text" in block)
13
+ .map((block) => block.text)
14
+ .join("\n");
15
+ }
16
+ return "";
17
+ }
18
+ function isWorthCapturing(messages) {
19
+ const hasUser = messages.some((m) => m.role === "user" && m.content.length > MIN_CONTENT_LENGTH);
20
+ const hasAssistant = messages.some((m) => m.role === "assistant" && m.content.length > MIN_CONTENT_LENGTH);
21
+ return hasUser && hasAssistant;
22
+ }
23
+ export function createCaptureHandler(client, config, logger, retryQueue) {
24
+ let captureCounter = 0;
25
+ return async (event, ctx) => {
26
+ if (!config.autoCapture)
27
+ return;
28
+ if (!event.success)
29
+ return;
30
+ if (!event.messages?.length)
31
+ return;
32
+ try {
33
+ const recent = event.messages.slice(-RECENT_MESSAGES_COUNT);
34
+ const normalized = recent
35
+ .filter((msg) => typeof msg === "object" &&
36
+ msg !== null &&
37
+ "role" in msg &&
38
+ "content" in msg)
39
+ .map((msg) => ({
40
+ role: String(msg.role),
41
+ content: extractContent(msg.content),
42
+ }))
43
+ .filter((msg) => msg.content.length > 0);
44
+ if (!isWorthCapturing(normalized)) {
45
+ logger.debug?.("Cortex capture: skipping — not enough substantive content");
46
+ return;
47
+ }
48
+ const sessionId = ctx.sessionKey ?? ctx.sessionId;
49
+ const doIngest = async () => {
50
+ const res = await client.ingestConversation(normalized, sessionId);
51
+ logger.debug?.(`Cortex capture: ingested ${res.facts.length} facts, ${res.entities.length} entities (${res.nodes_created} nodes)`);
52
+ };
53
+ // Fire-and-forget with retry on failure
54
+ doIngest().catch((err) => {
55
+ logger.warn("Cortex capture failed, queuing for retry:", err);
56
+ if (retryQueue) {
57
+ retryQueue.enqueue(doIngest, `capture-${++captureCounter}`);
58
+ }
59
+ });
60
+ }
61
+ catch (err) {
62
+ logger.warn("Cortex capture error:", err);
63
+ }
64
+ };
65
+ }
66
+ //# sourceMappingURL=capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/hooks/capture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { CortexClient } from "../client.js";
2
+ import type { CortexConfig } from "../config.js";
3
+ import { LatencyMetrics } from "../utils/metrics.js";
4
+ interface BeforeAgentStartEvent {
5
+ prompt: string;
6
+ messages?: unknown[];
7
+ }
8
+ interface AgentContext {
9
+ agentId?: string;
10
+ sessionKey?: string;
11
+ sessionId?: string;
12
+ workspaceDir?: string;
13
+ }
14
+ interface BeforeAgentStartResult {
15
+ prependContext?: string;
16
+ }
17
+ type Logger = {
18
+ debug?(...args: unknown[]): void;
19
+ info(...args: unknown[]): void;
20
+ warn(...args: unknown[]): void;
21
+ error(...args: unknown[]): void;
22
+ };
23
+ export declare function createRecallHandler(client: CortexClient, config: CortexConfig, logger: Logger, metrics?: LatencyMetrics): {
24
+ (event: BeforeAgentStartEvent, _ctx: AgentContext): Promise<BeforeAgentStartResult | void>;
25
+ metrics: LatencyMetrics;
26
+ };
27
+ export {};
28
+ //# sourceMappingURL=recall.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../../src/hooks/recall.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,UAAU,qBAAqB;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;CACtB;AAED,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,sBAAsB;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,KAAK,MAAM,GAAG;IACZ,KAAK,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACjC,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CACjC,CAAC;AAUF,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,cAAc;YAOf,qBAAqB,QACtB,YAAY,GACjB,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC;;EAmE1C"}
@@ -0,0 +1,68 @@
1
+ import { formatMemories } from "../utils/format.js";
2
+ import { LatencyMetrics } from "../utils/metrics.js";
3
+ /**
4
+ * Cold-start detection: if the first N requests all timeout or fail,
5
+ * assume the ECS task is cold and disable recall temporarily.
6
+ * Re-enable after a cooldown period.
7
+ */
8
+ const COLD_START_WINDOW = 3; // consecutive failures to trigger cold-start
9
+ const COLD_START_COOLDOWN_MS = 30_000; // wait 30s before retrying
10
+ export function createRecallHandler(client, config, logger, metrics) {
11
+ const recallMetrics = metrics ?? new LatencyMetrics();
12
+ let consecutiveFailures = 0;
13
+ let coldStartUntil = 0;
14
+ const handler = async (event, _ctx) => {
15
+ if (!config.autoRecall)
16
+ return;
17
+ const prompt = event.prompt?.trim();
18
+ if (!prompt || prompt.length < 5)
19
+ return;
20
+ // Cold-start gate: skip recall while service is warming
21
+ if (coldStartUntil > Date.now()) {
22
+ logger.debug?.("Cortex recall: skipped (cold-start cooldown)");
23
+ return;
24
+ }
25
+ const start = Date.now();
26
+ try {
27
+ // recallMode maps to Cortex API mode parameter:
28
+ // "fast" = BM25 + semantic only (~80-150ms server-side)
29
+ // "balanced" = adds light reranking (~150-300ms)
30
+ // "full" = adds graph traversal + full reranker (~300-600ms)
31
+ const apiMode = config.recallMode === "balanced" ? "fast" : config.recallMode;
32
+ const response = await client.retrieve(prompt, config.recallTopK, apiMode, config.recallTimeoutMs);
33
+ const elapsed = Date.now() - start;
34
+ recallMetrics.record(elapsed);
35
+ consecutiveFailures = 0; // reset on success
36
+ if (!response.results?.length)
37
+ return;
38
+ const formatted = formatMemories(response.results);
39
+ if (!formatted)
40
+ return;
41
+ logger.debug?.(`Cortex recall: ${response.results.length} memories in ${elapsed}ms`);
42
+ return { prependContext: formatted };
43
+ }
44
+ catch (err) {
45
+ const elapsed = Date.now() - start;
46
+ recallMetrics.record(elapsed);
47
+ consecutiveFailures++;
48
+ // Enter cold-start cooldown after consecutive failures
49
+ if (consecutiveFailures >= COLD_START_WINDOW) {
50
+ coldStartUntil = Date.now() + COLD_START_COOLDOWN_MS;
51
+ logger.warn(`Cortex recall: ${consecutiveFailures} consecutive failures, disabling for ${COLD_START_COOLDOWN_MS / 1000}s`);
52
+ consecutiveFailures = 0;
53
+ }
54
+ // Silent degradation — proceed without memories
55
+ if (err.name === "AbortError") {
56
+ logger.debug?.("Cortex recall timed out, proceeding without memories");
57
+ }
58
+ else {
59
+ logger.warn("Cortex recall failed:", err);
60
+ }
61
+ return;
62
+ }
63
+ };
64
+ // Expose metrics for observability
65
+ handler.metrics = recallMetrics;
66
+ return handler;
67
+ }
68
+ //# sourceMappingURL=recall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recall.js","sourceRoot":"","sources":["../../src/hooks/recall.ts"],"names":[],"mappings":"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"}