@ubundi/openclaw-cortex 0.7.2 → 1.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.
- package/README.md +24 -4
- package/dist/adapters/cortex/client.d.ts +1 -7
- package/dist/adapters/cortex/client.d.ts.map +1 -1
- package/dist/adapters/cortex/client.js +2 -4
- package/dist/adapters/cortex/client.js.map +1 -1
- package/dist/core/config/schema.d.ts +61 -0
- package/dist/core/config/schema.d.ts.map +1 -0
- package/dist/core/config/schema.js +39 -0
- package/dist/core/config/schema.js.map +1 -0
- package/dist/core/plugin.d.ts +61 -0
- package/dist/core/plugin.d.ts.map +1 -0
- package/dist/core/plugin.js +147 -0
- package/dist/core/plugin.js.map +1 -0
- package/dist/cortex/client.d.ts +142 -0
- package/dist/cortex/client.d.ts.map +1 -0
- package/dist/cortex/client.js +145 -0
- package/dist/cortex/client.js.map +1 -0
- package/dist/features/capture/handler.d.ts +1 -1
- package/dist/features/capture/handler.d.ts.map +1 -1
- package/dist/features/capture/handler.js +6 -30
- package/dist/features/capture/handler.js.map +1 -1
- package/dist/features/reflect/service.d.ts +19 -0
- package/dist/features/reflect/service.d.ts.map +1 -0
- package/dist/features/reflect/service.js +38 -0
- package/dist/features/reflect/service.js.map +1 -0
- package/dist/internal/identity/api-key.js +1 -1
- package/dist/plugin/config/schema.d.ts +0 -5
- package/dist/plugin/config/schema.d.ts.map +1 -1
- package/dist/plugin/config/schema.js +1 -2
- package/dist/plugin/config/schema.js.map +1 -1
- package/dist/plugin/index.d.ts +0 -2
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +9 -25
- package/dist/plugin/index.js.map +1 -1
- package/dist/shared/fs/safe-path.d.ts +8 -0
- package/dist/shared/fs/safe-path.d.ts.map +1 -0
- package/dist/shared/fs/safe-path.js +32 -0
- package/dist/shared/fs/safe-path.js.map +1 -0
- package/dist/shared/metrics/latency-metrics.d.ts +19 -0
- package/dist/shared/metrics/latency-metrics.d.ts.map +1 -0
- package/dist/shared/metrics/latency-metrics.js +45 -0
- package/dist/shared/metrics/latency-metrics.js.map +1 -0
- package/dist/shared/queue/retry-queue.d.ts +31 -0
- package/dist/shared/queue/retry-queue.d.ts.map +1 -0
- package/dist/shared/queue/retry-queue.js +115 -0
- package/dist/shared/queue/retry-queue.js.map +1 -0
- package/dist/shared/transcript/cleaner.d.ts +24 -0
- package/dist/shared/transcript/cleaner.d.ts.map +1 -0
- package/dist/shared/transcript/cleaner.js +96 -0
- package/dist/shared/transcript/cleaner.js.map +1 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { realpath, lstat } from "node:fs/promises";
|
|
2
|
+
/**
|
|
3
|
+
* Resolves a file path and verifies it stays within the allowed root directory.
|
|
4
|
+
* Rejects symlinks and path traversal attempts.
|
|
5
|
+
*
|
|
6
|
+
* Returns the canonical path if safe, or null if the path should be rejected.
|
|
7
|
+
*/
|
|
8
|
+
export async function safePath(filePath, allowedRoot) {
|
|
9
|
+
try {
|
|
10
|
+
// Check for symlinks before resolving
|
|
11
|
+
const stats = await lstat(filePath);
|
|
12
|
+
if (stats.isSymbolicLink()) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
// Resolve to canonical path (resolves .., ., etc.)
|
|
16
|
+
const canonical = await realpath(filePath);
|
|
17
|
+
const canonicalRoot = await realpath(allowedRoot);
|
|
18
|
+
// Ensure the resolved path is within the allowed root
|
|
19
|
+
const normalizedRoot = canonicalRoot.endsWith("/")
|
|
20
|
+
? canonicalRoot
|
|
21
|
+
: canonicalRoot + "/";
|
|
22
|
+
if (canonical !== canonicalRoot && !canonical.startsWith(normalizedRoot)) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
return canonical;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// File doesn't exist or is inaccessible
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=safe-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-path.js","sourceRoot":"","sources":["../../../src/shared/fs/safe-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,QAAgB,EAChB,WAAmB;IAEnB,IAAI,CAAC;QACH,sCAAsC;QACtC,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,mDAAmD;QACnD,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC3C,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,CAAC;QAElD,sDAAsD;QACtD,MAAM,cAAc,GAAG,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC;YAChD,CAAC,CAAC,aAAa;YACf,CAAC,CAAC,aAAa,GAAG,GAAG,CAAC;QAExB,IAAI,SAAS,KAAK,aAAa,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YACzE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,wCAAwC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare class LatencyMetrics {
|
|
2
|
+
private samples;
|
|
3
|
+
private windowSize;
|
|
4
|
+
constructor(windowSize?: number);
|
|
5
|
+
record(durationMs: number): void;
|
|
6
|
+
get count(): number;
|
|
7
|
+
percentile(p: number): number | null;
|
|
8
|
+
get p50(): number | null;
|
|
9
|
+
get p95(): number | null;
|
|
10
|
+
get p99(): number | null;
|
|
11
|
+
summary(): {
|
|
12
|
+
count: number;
|
|
13
|
+
p50: number | null;
|
|
14
|
+
p95: number | null;
|
|
15
|
+
p99: number | null;
|
|
16
|
+
};
|
|
17
|
+
reset(): void;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=latency-metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"latency-metrics.d.ts","sourceRoot":"","sources":["../../../src/shared/metrics/latency-metrics.ts"],"names":[],"mappings":"AAEA,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,SAAsB;IAI5C,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAOhC,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAQpC,IAAI,GAAG,IAAI,MAAM,GAAG,IAAI,CAEvB;IAED,IAAI,GAAG,IAAI,MAAM,GAAG,IAAI,CAEvB;IAED,IAAI,GAAG,IAAI,MAAM,GAAG,IAAI,CAEvB;IAED,OAAO,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;IASxF,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const DEFAULT_WINDOW_SIZE = 100;
|
|
2
|
+
export class LatencyMetrics {
|
|
3
|
+
samples = [];
|
|
4
|
+
windowSize;
|
|
5
|
+
constructor(windowSize = DEFAULT_WINDOW_SIZE) {
|
|
6
|
+
this.windowSize = windowSize;
|
|
7
|
+
}
|
|
8
|
+
record(durationMs) {
|
|
9
|
+
this.samples.push(durationMs);
|
|
10
|
+
if (this.samples.length > this.windowSize) {
|
|
11
|
+
this.samples.shift();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
get count() {
|
|
15
|
+
return this.samples.length;
|
|
16
|
+
}
|
|
17
|
+
percentile(p) {
|
|
18
|
+
if (this.samples.length === 0)
|
|
19
|
+
return null;
|
|
20
|
+
const sorted = [...this.samples].sort((a, b) => a - b);
|
|
21
|
+
const index = Math.ceil((p / 100) * sorted.length) - 1;
|
|
22
|
+
return sorted[Math.max(0, index)];
|
|
23
|
+
}
|
|
24
|
+
get p50() {
|
|
25
|
+
return this.percentile(50);
|
|
26
|
+
}
|
|
27
|
+
get p95() {
|
|
28
|
+
return this.percentile(95);
|
|
29
|
+
}
|
|
30
|
+
get p99() {
|
|
31
|
+
return this.percentile(99);
|
|
32
|
+
}
|
|
33
|
+
summary() {
|
|
34
|
+
return {
|
|
35
|
+
count: this.count,
|
|
36
|
+
p50: this.p50,
|
|
37
|
+
p95: this.p95,
|
|
38
|
+
p99: this.p99,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
reset() {
|
|
42
|
+
this.samples = [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=latency-metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"latency-metrics.js","sourceRoot":"","sources":["../../../src/shared/metrics/latency-metrics.ts"],"names":[],"mappings":"AAAA,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,MAAM,OAAO,cAAc;IACjB,OAAO,GAAa,EAAE,CAAC;IACvB,UAAU,CAAS;IAE3B,YAAY,UAAU,GAAG,mBAAmB;QAC1C,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,MAAM,CAAC,UAAkB;QACvB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC9B,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YAC1C,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IAC7B,CAAC;IAED,UAAU,CAAC,CAAS;QAClB,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAE3C,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACvD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACvD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,GAAG;QACL,OAAO,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAC7B,CAAC;IAED,IAAI,GAAG;QACL,OAAO,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAC7B,CAAC;IAED,IAAI,GAAG;QACL,OAAO,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAC7B,CAAC;IAED,OAAO;QACL,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,GAAG,EAAE,IAAI,CAAC,GAAG;SACd,CAAC;IACJ,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;IACpB,CAAC;CACF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
type Logger = {
|
|
2
|
+
debug?(...args: unknown[]): void;
|
|
3
|
+
info(...args: unknown[]): void;
|
|
4
|
+
warn(...args: unknown[]): void;
|
|
5
|
+
error(...args: unknown[]): void;
|
|
6
|
+
};
|
|
7
|
+
export interface RetryTask {
|
|
8
|
+
id: string;
|
|
9
|
+
execute: () => Promise<void>;
|
|
10
|
+
retries: number;
|
|
11
|
+
nextAttemptAt: number;
|
|
12
|
+
}
|
|
13
|
+
export declare class RetryQueue {
|
|
14
|
+
private logger;
|
|
15
|
+
private maxRetries;
|
|
16
|
+
private maxCapacity;
|
|
17
|
+
private tasksById;
|
|
18
|
+
private taskOrder;
|
|
19
|
+
private timer;
|
|
20
|
+
private taskCounter;
|
|
21
|
+
private isFlushing;
|
|
22
|
+
constructor(logger: Logger, maxRetries?: number, maxCapacity?: number);
|
|
23
|
+
start(): void;
|
|
24
|
+
stop(): void;
|
|
25
|
+
enqueue(execute: () => Promise<void>, label?: string): void;
|
|
26
|
+
get pending(): number;
|
|
27
|
+
private flush;
|
|
28
|
+
private remove;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=retry-queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry-queue.d.ts","sourceRoot":"","sources":["../../../src/shared/queue/retry-queue.ts"],"names":[],"mappings":"AAAA,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;AAEF,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACvB;AAQD,qBAAa,UAAU;IAQnB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,WAAW;IATrB,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,UAAU,CAAS;gBAGjB,MAAM,EAAE,MAAM,EACd,UAAU,SAAc,EACxB,WAAW,SAAe;IAGpC,KAAK,IAAI,IAAI;IAOb,IAAI,IAAI,IAAI;IAcZ,OAAO,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAmC3D,IAAI,OAAO,IAAI,MAAM,CAEpB;YAEa,KAAK;IAwCnB,OAAO,CAAC,MAAM;CAOf"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const BASE_DELAY_MS = 1000;
|
|
2
|
+
const MAX_DELAY_MS = 60_000;
|
|
3
|
+
const MAX_RETRIES = 5;
|
|
4
|
+
const MAX_CAPACITY = 100;
|
|
5
|
+
const FLUSH_INTERVAL_MS = 5000;
|
|
6
|
+
export class RetryQueue {
|
|
7
|
+
logger;
|
|
8
|
+
maxRetries;
|
|
9
|
+
maxCapacity;
|
|
10
|
+
tasksById = new Map();
|
|
11
|
+
taskOrder = [];
|
|
12
|
+
timer = null;
|
|
13
|
+
taskCounter = 0;
|
|
14
|
+
isFlushing = false;
|
|
15
|
+
constructor(logger, maxRetries = MAX_RETRIES, maxCapacity = MAX_CAPACITY) {
|
|
16
|
+
this.logger = logger;
|
|
17
|
+
this.maxRetries = maxRetries;
|
|
18
|
+
this.maxCapacity = maxCapacity;
|
|
19
|
+
}
|
|
20
|
+
start() {
|
|
21
|
+
if (this.timer)
|
|
22
|
+
return;
|
|
23
|
+
this.timer = setInterval(() => {
|
|
24
|
+
void this.flush();
|
|
25
|
+
}, FLUSH_INTERVAL_MS);
|
|
26
|
+
}
|
|
27
|
+
stop() {
|
|
28
|
+
if (this.timer) {
|
|
29
|
+
clearInterval(this.timer);
|
|
30
|
+
this.timer = null;
|
|
31
|
+
}
|
|
32
|
+
const pendingCount = this.pending;
|
|
33
|
+
if (pendingCount > 0) {
|
|
34
|
+
this.logger.warn(`Retry queue stopped with ${pendingCount} pending tasks`);
|
|
35
|
+
}
|
|
36
|
+
this.tasksById.clear();
|
|
37
|
+
this.taskOrder = [];
|
|
38
|
+
this.isFlushing = false;
|
|
39
|
+
}
|
|
40
|
+
enqueue(execute, label) {
|
|
41
|
+
const id = label ?? `task-${++this.taskCounter}`;
|
|
42
|
+
// Deduplicate: if a task with the same label exists, replace it
|
|
43
|
+
const existing = this.tasksById.get(id);
|
|
44
|
+
if (existing) {
|
|
45
|
+
existing.execute = execute;
|
|
46
|
+
existing.retries = 0;
|
|
47
|
+
existing.nextAttemptAt = Date.now();
|
|
48
|
+
this.logger.debug?.(`Retry queue: deduplicated ${id}`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// Capacity check: drop oldest task if at limit
|
|
52
|
+
if (this.pending >= this.maxCapacity) {
|
|
53
|
+
const droppedId = this.taskOrder.shift();
|
|
54
|
+
const dropped = droppedId ? this.tasksById.get(droppedId) : undefined;
|
|
55
|
+
if (droppedId) {
|
|
56
|
+
this.tasksById.delete(droppedId);
|
|
57
|
+
}
|
|
58
|
+
this.logger.warn(`Retry queue: at capacity (${this.maxCapacity}), dropped oldest task ${dropped?.id ?? "unknown"}`);
|
|
59
|
+
}
|
|
60
|
+
this.tasksById.set(id, {
|
|
61
|
+
id,
|
|
62
|
+
execute,
|
|
63
|
+
retries: 0,
|
|
64
|
+
nextAttemptAt: Date.now(),
|
|
65
|
+
});
|
|
66
|
+
this.taskOrder.push(id);
|
|
67
|
+
this.logger.debug?.(`Retry queue: enqueued ${id}`);
|
|
68
|
+
}
|
|
69
|
+
get pending() {
|
|
70
|
+
return this.tasksById.size;
|
|
71
|
+
}
|
|
72
|
+
async flush() {
|
|
73
|
+
if (this.isFlushing)
|
|
74
|
+
return;
|
|
75
|
+
this.isFlushing = true;
|
|
76
|
+
const now = Date.now();
|
|
77
|
+
const ids = [...this.taskOrder];
|
|
78
|
+
try {
|
|
79
|
+
for (const id of ids) {
|
|
80
|
+
const task = this.tasksById.get(id);
|
|
81
|
+
if (!task || task.nextAttemptAt > now)
|
|
82
|
+
continue;
|
|
83
|
+
try {
|
|
84
|
+
await task.execute();
|
|
85
|
+
this.remove(id);
|
|
86
|
+
this.logger.debug?.(`Retry queue: ${task.id} succeeded`);
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
task.retries++;
|
|
90
|
+
if (task.retries >= this.maxRetries) {
|
|
91
|
+
this.remove(id);
|
|
92
|
+
this.logger.warn(`Retry queue: ${task.id} failed after ${this.maxRetries} retries, dropping: ${String(err)}`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const delay = Math.min(BASE_DELAY_MS * Math.pow(2, task.retries), MAX_DELAY_MS);
|
|
96
|
+
task.nextAttemptAt = Date.now() + delay;
|
|
97
|
+
this.logger.debug?.(`Retry queue: ${task.id} retry ${task.retries}/${this.maxRetries} in ${delay}ms`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
this.isFlushing = false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
remove(id) {
|
|
107
|
+
if (!this.tasksById.delete(id))
|
|
108
|
+
return;
|
|
109
|
+
const idx = this.taskOrder.indexOf(id);
|
|
110
|
+
if (idx !== -1) {
|
|
111
|
+
this.taskOrder.splice(idx, 1);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=retry-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry-queue.js","sourceRoot":"","sources":["../../../src/shared/queue/retry-queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ConversationMessage } from "../../cortex/client.js";
|
|
2
|
+
/**
|
|
3
|
+
* Clean a raw JSONL transcript into a conversation suitable for Cortex ingestion.
|
|
4
|
+
*
|
|
5
|
+
* Strips:
|
|
6
|
+
* - System prompt messages (role: "system" / "developer")
|
|
7
|
+
* - Tool call/result events (tool_calls, tool role messages)
|
|
8
|
+
* - Base64 encoded images
|
|
9
|
+
* - Empty messages
|
|
10
|
+
*
|
|
11
|
+
* Preserves:
|
|
12
|
+
* - User messages with speaker attribution
|
|
13
|
+
* - Assistant messages with content
|
|
14
|
+
*/
|
|
15
|
+
export declare function cleanTranscript(jsonlText: string): ConversationMessage[];
|
|
16
|
+
/**
|
|
17
|
+
* Clean only new JSONL lines (from an offset-based append).
|
|
18
|
+
* Returns cleaned messages and whether they're worth ingesting.
|
|
19
|
+
*/
|
|
20
|
+
export declare function cleanTranscriptChunk(newLines: string): {
|
|
21
|
+
messages: ConversationMessage[];
|
|
22
|
+
worthIngesting: boolean;
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=cleaner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleaner.d.ts","sourceRoot":"","sources":["../../../src/shared/transcript/cleaner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAkElE;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,EAAE,CA2BxE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG;IACtD,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,cAAc,EAAE,OAAO,CAAC;CACzB,CAQA"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const BASE64_PATTERN = /data:[^;]+;base64,[A-Za-z0-9+/=]{100,}/g;
|
|
2
|
+
const SYSTEM_ROLES = new Set(["system", "developer"]);
|
|
3
|
+
/**
|
|
4
|
+
* Parse JSONL text into individual events, skipping malformed lines.
|
|
5
|
+
*/
|
|
6
|
+
function parseJsonl(text) {
|
|
7
|
+
const events = [];
|
|
8
|
+
for (const line of text.split("\n")) {
|
|
9
|
+
const trimmed = line.trim();
|
|
10
|
+
if (!trimmed)
|
|
11
|
+
continue;
|
|
12
|
+
try {
|
|
13
|
+
events.push(JSON.parse(trimmed));
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// Skip malformed lines
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return events;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Extract text content from OpenClaw's content field.
|
|
23
|
+
* Content can be a string, an array of content blocks, or nested structures.
|
|
24
|
+
*/
|
|
25
|
+
function extractText(content) {
|
|
26
|
+
if (typeof content === "string")
|
|
27
|
+
return content;
|
|
28
|
+
if (Array.isArray(content)) {
|
|
29
|
+
return content
|
|
30
|
+
.filter((block) => typeof block === "object" &&
|
|
31
|
+
block !== null &&
|
|
32
|
+
"type" in block &&
|
|
33
|
+
"text" in block &&
|
|
34
|
+
block.type === "text")
|
|
35
|
+
.map((block) => block.text)
|
|
36
|
+
.join("\n");
|
|
37
|
+
}
|
|
38
|
+
return "";
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Strip base64 image data, replacing with a placeholder.
|
|
42
|
+
*/
|
|
43
|
+
function stripBase64(text) {
|
|
44
|
+
return text.replace(BASE64_PATTERN, "[base64 image]");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Clean a raw JSONL transcript into a conversation suitable for Cortex ingestion.
|
|
48
|
+
*
|
|
49
|
+
* Strips:
|
|
50
|
+
* - System prompt messages (role: "system" / "developer")
|
|
51
|
+
* - Tool call/result events (tool_calls, tool role messages)
|
|
52
|
+
* - Base64 encoded images
|
|
53
|
+
* - Empty messages
|
|
54
|
+
*
|
|
55
|
+
* Preserves:
|
|
56
|
+
* - User messages with speaker attribution
|
|
57
|
+
* - Assistant messages with content
|
|
58
|
+
*/
|
|
59
|
+
export function cleanTranscript(jsonlText) {
|
|
60
|
+
const events = parseJsonl(jsonlText);
|
|
61
|
+
const messages = [];
|
|
62
|
+
for (const event of events) {
|
|
63
|
+
const role = event.role;
|
|
64
|
+
if (!role)
|
|
65
|
+
continue;
|
|
66
|
+
// Skip system prompts
|
|
67
|
+
if (SYSTEM_ROLES.has(role))
|
|
68
|
+
continue;
|
|
69
|
+
// Skip tool call results
|
|
70
|
+
if (role === "tool" || event.tool_call_id)
|
|
71
|
+
continue;
|
|
72
|
+
// Skip messages that are purely tool calls with no text content
|
|
73
|
+
if (event.tool_calls && !event.content)
|
|
74
|
+
continue;
|
|
75
|
+
const text = extractText(event.content);
|
|
76
|
+
if (!text.trim())
|
|
77
|
+
continue;
|
|
78
|
+
const cleaned = stripBase64(text).trim();
|
|
79
|
+
if (!cleaned || cleaned === "[base64 image]")
|
|
80
|
+
continue;
|
|
81
|
+
messages.push({ role, content: cleaned });
|
|
82
|
+
}
|
|
83
|
+
return messages;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Clean only new JSONL lines (from an offset-based append).
|
|
87
|
+
* Returns cleaned messages and whether they're worth ingesting.
|
|
88
|
+
*/
|
|
89
|
+
export function cleanTranscriptChunk(newLines) {
|
|
90
|
+
const messages = cleanTranscript(newLines);
|
|
91
|
+
// Worth ingesting if there's at least one user + one assistant message
|
|
92
|
+
const hasUser = messages.some((m) => m.role === "user" && m.content.length > 20);
|
|
93
|
+
const hasAssistant = messages.some((m) => m.role === "assistant" && m.content.length > 20);
|
|
94
|
+
return { messages, worthIngesting: hasUser && hasAssistant };
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=cleaner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleaner.js","sourceRoot":"","sources":["../../../src/shared/transcript/cleaner.ts"],"names":[],"mappings":"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"}
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "openclaw-cortex",
|
|
3
3
|
"name": "Cortex Memory",
|
|
4
4
|
"description": "Long-term memory powered by Cortex — Auto-Recall, Auto-Capture, agent tools, /memories command, transcript ingestion, and background file sync",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "1.0.0",
|
|
6
6
|
"kind": "memory",
|
|
7
7
|
"configSchema": {
|
|
8
8
|
"type": "object",
|