@persistio/openclaw-plugin 0.1.4 → 0.1.6
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 +13 -0
- package/dist/client.d.ts +12 -1
- package/dist/client.js +40 -4
- package/dist/index.js +80 -6
- package/dist/ingest-policy.d.ts +48 -0
- package/dist/ingest-policy.js +380 -0
- package/openclaw.plugin.json +64 -1
- package/package.json +3 -2
- package/src/client.ts +53 -5
- package/src/index.ts +101 -8
- package/src/ingest-policy.ts +508 -0
package/README.md
CHANGED
|
@@ -26,6 +26,7 @@ Then register it in your OpenClaw config:
|
|
|
26
26
|
"config": {
|
|
27
27
|
"baseURL": "https://api.persistio.ai",
|
|
28
28
|
"apiKey": "your-vault-api-key",
|
|
29
|
+
"recallMinSimilarity": 0.3,
|
|
29
30
|
"send": {
|
|
30
31
|
"roles": {
|
|
31
32
|
"user": "enabled",
|
|
@@ -48,13 +49,25 @@ Then register it in your OpenClaw config:
|
|
|
48
49
|
| `apiKey` | string | ✅ | — | Vault API key |
|
|
49
50
|
| `tokenBudget` | number | | `2000` | Max tokens to inject into the system prompt |
|
|
50
51
|
| `recallTopK` | number | | `10` | Number of memories to retrieve per recall |
|
|
52
|
+
| `recallMinSimilarity` | number from `0` to `1` | | Persistio server default | Optional semantic recall quality floor |
|
|
51
53
|
| `recallTimeout` | number | | `5000` | HTTP timeout for recall requests (ms) |
|
|
54
|
+
| `ingest.timeoutMs` | number | | `30000` | HTTP timeout for ingest requests (ms). Timed-out requests are treated as ambiguous and not retried automatically |
|
|
55
|
+
| `ingest.maxChunkChars` | number | | `6000` | Maximum characters per chunk sent to Persistio |
|
|
56
|
+
| `ingest.maxChunksPerTurn` | number | | `12` | Maximum chunks sent from a single OpenClaw turn |
|
|
57
|
+
| `ingest.skipSubagentSessions` | boolean | | `true` | Skip `agent:*` sessions unless they are `agent:main:*` |
|
|
58
|
+
| `ingest.user.maxCharsPerMessage` | number | | `24000` | Maximum user-message characters considered for ingest before chunking |
|
|
59
|
+
| `ingest.agent.mode` | `"bounded"` or `"raw"` | | `"bounded"` | Assistant ingest shaping mode. `bounded` collapses obvious large noisy blocks before chunking |
|
|
60
|
+
| `ingest.agent.maxCharsPerMessage` | number | | `24000` | Maximum assistant-message characters considered after filtering |
|
|
61
|
+
| `ingest.agent.maxCharsAfterFiltering` | number | | `9000` | Maximum assistant-message characters retained after deterministic filtering |
|
|
62
|
+
| `ingest.agent.maxCharsPerTurn` | number | | `24000` | Maximum assistant-message characters sent from one turn |
|
|
52
63
|
| `send.roles.user` | `"enabled"` or `"disabled"` | | `"enabled"` | Send user messages to Persistio ingest |
|
|
53
64
|
| `send.roles.agent` | `"enabled"` or `"disabled"` | | `"enabled"` | Send agent/assistant messages to Persistio ingest |
|
|
54
65
|
| `send.roles.tool` | `"enabled"` or `"disabled"` | | `"disabled"` | Send tool messages to Persistio ingest |
|
|
55
66
|
|
|
56
67
|
`agent_end` receives a snapshot of the active OpenClaw transcript, so the plugin deduplicates per session and only sends each user, agent, or enabled tool message once per plugin process. Deduplication keys are bounded in memory and expire after 24 hours of session inactivity.
|
|
57
68
|
|
|
69
|
+
Assistant ingest is bounded before any network call. By default the plugin skips non-main `agent:*` sessions, collapses oversized code/log/diff/blob/table-shaped assistant content into omission markers, caps assistant ingest per message and per turn, then chunks all ingest content below `ingest.maxChunkChars`. Persistio still performs server-side extraction and curation; the plugin only enforces a deterministic transport-safe shape.
|
|
70
|
+
|
|
58
71
|
## Tools exposed
|
|
59
72
|
|
|
60
73
|
| Tool | Description |
|
package/dist/client.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import type { PersistioIngestPolicy } from './ingest-policy.js';
|
|
1
2
|
export interface PersistioConfig {
|
|
2
3
|
baseURL: string;
|
|
3
4
|
apiKey: string;
|
|
4
5
|
tokenBudget: number;
|
|
5
6
|
recallTopK: number;
|
|
7
|
+
recallMinSimilarity?: number;
|
|
6
8
|
recallTimeout: number;
|
|
9
|
+
ingest: PersistioIngestPolicy;
|
|
7
10
|
send: PersistioSendConfig;
|
|
8
11
|
}
|
|
9
12
|
export type PersistioSendRoleStatus = 'enabled' | 'disabled';
|
|
@@ -22,7 +25,11 @@ export interface PersistioMemory {
|
|
|
22
25
|
categories: string[];
|
|
23
26
|
confidence: number;
|
|
24
27
|
}
|
|
28
|
+
export interface GetMemoryOptions {
|
|
29
|
+
includePending?: boolean;
|
|
30
|
+
}
|
|
25
31
|
export interface RecallBundle {
|
|
32
|
+
global_user_rules?: string[];
|
|
26
33
|
user_rules: string[];
|
|
27
34
|
user_preferences: string[];
|
|
28
35
|
task_patterns: string[];
|
|
@@ -35,16 +42,19 @@ export interface RecallBundle {
|
|
|
35
42
|
}
|
|
36
43
|
export interface RecallBundleResponse {
|
|
37
44
|
bundle: RecallBundle;
|
|
45
|
+
related_bundle?: RecallBundle;
|
|
38
46
|
}
|
|
39
47
|
export declare class PersistioClient {
|
|
40
48
|
private readonly baseURL;
|
|
41
49
|
private readonly apiKey;
|
|
42
50
|
private readonly recallTopK;
|
|
51
|
+
private readonly recallMinSimilarity?;
|
|
43
52
|
private readonly recallTimeout;
|
|
53
|
+
private readonly ingestTimeout;
|
|
44
54
|
constructor(config: PersistioConfig);
|
|
45
55
|
private headers;
|
|
46
56
|
recall(query: string): Promise<PersistioMemory[]>;
|
|
47
|
-
recallBundle(query: string, topK?: number): Promise<
|
|
57
|
+
recallBundle(query: string, topK?: number): Promise<RecallBundleResponse>;
|
|
48
58
|
ingest(sessionId: string, chunks: Array<{
|
|
49
59
|
role: string;
|
|
50
60
|
content: string;
|
|
@@ -52,5 +62,6 @@ export declare class PersistioClient {
|
|
|
52
62
|
}>): Promise<void>;
|
|
53
63
|
addMemory(data: string, subject: string): Promise<void>;
|
|
54
64
|
deleteMemory(id: string): Promise<void>;
|
|
65
|
+
getMemory(id: string, options?: GetMemoryOptions): Promise<PersistioMemory | null>;
|
|
55
66
|
listMemories(): Promise<PersistioMemory[]>;
|
|
56
67
|
}
|
package/dist/client.js
CHANGED
|
@@ -2,12 +2,16 @@ export class PersistioClient {
|
|
|
2
2
|
baseURL;
|
|
3
3
|
apiKey;
|
|
4
4
|
recallTopK;
|
|
5
|
+
recallMinSimilarity;
|
|
5
6
|
recallTimeout;
|
|
7
|
+
ingestTimeout;
|
|
6
8
|
constructor(config) {
|
|
7
9
|
this.baseURL = config.baseURL.replace(/\/$/, '');
|
|
8
10
|
this.apiKey = config.apiKey;
|
|
9
11
|
this.recallTopK = config.recallTopK;
|
|
12
|
+
this.recallMinSimilarity = config.recallMinSimilarity;
|
|
10
13
|
this.recallTimeout = config.recallTimeout;
|
|
14
|
+
this.ingestTimeout = config.ingest.timeoutMs;
|
|
11
15
|
}
|
|
12
16
|
headers() {
|
|
13
17
|
return {
|
|
@@ -16,10 +20,14 @@ export class PersistioClient {
|
|
|
16
20
|
};
|
|
17
21
|
}
|
|
18
22
|
async recall(query) {
|
|
23
|
+
const body = { query, top_k: this.recallTopK, include_pending: true };
|
|
24
|
+
if (typeof this.recallMinSimilarity === 'number') {
|
|
25
|
+
body.min_similarity = this.recallMinSimilarity;
|
|
26
|
+
}
|
|
19
27
|
const res = await fetch(`${this.baseURL}/v1/recall`, {
|
|
20
28
|
method: 'POST',
|
|
21
29
|
headers: this.headers(),
|
|
22
|
-
body: JSON.stringify(
|
|
30
|
+
body: JSON.stringify(body),
|
|
23
31
|
signal: AbortSignal.timeout(this.recallTimeout),
|
|
24
32
|
});
|
|
25
33
|
if (!res.ok)
|
|
@@ -28,16 +36,20 @@ export class PersistioClient {
|
|
|
28
36
|
return data.memories ?? [];
|
|
29
37
|
}
|
|
30
38
|
async recallBundle(query, topK) {
|
|
39
|
+
const body = { query, top_k: topK ?? this.recallTopK, include_pending: true };
|
|
40
|
+
if (typeof this.recallMinSimilarity === 'number') {
|
|
41
|
+
body.min_similarity = this.recallMinSimilarity;
|
|
42
|
+
}
|
|
31
43
|
const res = await fetch(`${this.baseURL}/v1/recall?format=bundle`, {
|
|
32
44
|
method: 'POST',
|
|
33
45
|
headers: this.headers(),
|
|
34
|
-
body: JSON.stringify(
|
|
46
|
+
body: JSON.stringify(body),
|
|
35
47
|
signal: AbortSignal.timeout(this.recallTimeout),
|
|
36
48
|
});
|
|
37
49
|
if (!res.ok)
|
|
38
50
|
throw new Error(`Persistio recallBundle failed: ${res.status}`);
|
|
39
51
|
const data = await res.json();
|
|
40
|
-
return data
|
|
52
|
+
return data;
|
|
41
53
|
}
|
|
42
54
|
async ingest(sessionId, chunks) {
|
|
43
55
|
if (chunks.length === 0)
|
|
@@ -46,9 +58,10 @@ export class PersistioClient {
|
|
|
46
58
|
method: 'POST',
|
|
47
59
|
headers: this.headers(),
|
|
48
60
|
body: JSON.stringify({ session_id: sessionId, chunks }),
|
|
61
|
+
signal: AbortSignal.timeout(this.ingestTimeout),
|
|
49
62
|
});
|
|
50
63
|
if (!res.ok)
|
|
51
|
-
throw new Error(
|
|
64
|
+
throw new Error(await formatHttpError('ingest', res));
|
|
52
65
|
}
|
|
53
66
|
async addMemory(data, subject) {
|
|
54
67
|
const res = await fetch(`${this.baseURL}/v1/memories`, {
|
|
@@ -67,6 +80,17 @@ export class PersistioClient {
|
|
|
67
80
|
if (!res.ok)
|
|
68
81
|
throw new Error(`Persistio deleteMemory failed: ${res.status}`);
|
|
69
82
|
}
|
|
83
|
+
async getMemory(id, options = {}) {
|
|
84
|
+
const query = options.includePending ? '?include_pending=true' : '';
|
|
85
|
+
const res = await fetch(`${this.baseURL}/v1/memories/${id}${query}`, {
|
|
86
|
+
headers: this.headers(),
|
|
87
|
+
});
|
|
88
|
+
if (res.status === 404)
|
|
89
|
+
return null;
|
|
90
|
+
if (!res.ok)
|
|
91
|
+
throw new Error(`Persistio getMemory failed: ${res.status}`);
|
|
92
|
+
return await res.json();
|
|
93
|
+
}
|
|
70
94
|
async listMemories() {
|
|
71
95
|
const res = await fetch(`${this.baseURL}/v1/memories`, {
|
|
72
96
|
headers: this.headers(),
|
|
@@ -77,3 +101,15 @@ export class PersistioClient {
|
|
|
77
101
|
return data.items ?? [];
|
|
78
102
|
}
|
|
79
103
|
}
|
|
104
|
+
async function formatHttpError(operation, res) {
|
|
105
|
+
let detail = '';
|
|
106
|
+
try {
|
|
107
|
+
detail = (await res.text()).trim().slice(0, 500);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// Ignore response body read failures; the status is still actionable.
|
|
111
|
+
}
|
|
112
|
+
return detail
|
|
113
|
+
? `Persistio ${operation} failed: ${res.status} ${detail}`
|
|
114
|
+
: `Persistio ${operation} failed: ${res.status}`;
|
|
115
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { definePluginEntry } from 'openclaw/plugin-sdk/plugin-entry';
|
|
2
2
|
import { Type } from '@sinclair/typebox';
|
|
3
3
|
import { PersistioClient } from './client.js';
|
|
4
|
+
import { prepareMessageForIngest, resolveIngestPolicy, shouldIngestSession, } from './ingest-policy.js';
|
|
4
5
|
const DEFAULT_SEND_ROLES = {
|
|
5
6
|
user: 'enabled',
|
|
6
7
|
agent: 'enabled',
|
|
@@ -25,6 +26,11 @@ function resolveSendConfig(raw) {
|
|
|
25
26
|
},
|
|
26
27
|
};
|
|
27
28
|
}
|
|
29
|
+
function resolveRecallMinSimilarity(value) {
|
|
30
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 1
|
|
31
|
+
? value
|
|
32
|
+
: undefined;
|
|
33
|
+
}
|
|
28
34
|
function resolveConfig(raw) {
|
|
29
35
|
const c = (raw ?? {});
|
|
30
36
|
return {
|
|
@@ -32,7 +38,9 @@ function resolveConfig(raw) {
|
|
|
32
38
|
apiKey: typeof c['apiKey'] === 'string' ? c['apiKey'] : '',
|
|
33
39
|
tokenBudget: typeof c['tokenBudget'] === 'number' ? c['tokenBudget'] : 2000,
|
|
34
40
|
recallTopK: typeof c['recallTopK'] === 'number' ? c['recallTopK'] : 10,
|
|
41
|
+
recallMinSimilarity: resolveRecallMinSimilarity(c['recallMinSimilarity']),
|
|
35
42
|
recallTimeout: typeof c['recallTimeout'] === 'number' ? c['recallTimeout'] : 5000,
|
|
43
|
+
ingest: resolveIngestPolicy(c['ingest']),
|
|
36
44
|
send: resolveSendConfig(c),
|
|
37
45
|
};
|
|
38
46
|
}
|
|
@@ -102,7 +110,7 @@ function buildRecallQuery(event) {
|
|
|
102
110
|
parts.push(`[task: ${taskType}]`);
|
|
103
111
|
return truncate(parts.join('\n'), 600);
|
|
104
112
|
}
|
|
105
|
-
function buildMemoryBlock(bundle, budget) {
|
|
113
|
+
function buildMemoryBlock(bundle, budget, relatedBundle) {
|
|
106
114
|
const sections = [
|
|
107
115
|
{ title: 'Behavioural rules', items: bundle.user_rules },
|
|
108
116
|
{ title: 'Preferences', items: bundle.user_preferences },
|
|
@@ -114,6 +122,9 @@ function buildMemoryBlock(bundle, budget) {
|
|
|
114
122
|
{ title: 'System facts', items: bundle.system_facts },
|
|
115
123
|
{ title: 'Domain knowledge', items: bundle.domain_knowledge },
|
|
116
124
|
];
|
|
125
|
+
if (relatedBundle) {
|
|
126
|
+
sections.push({ title: 'Related behavioural rules', items: relatedBundle.user_rules }, { title: 'Related preferences', items: relatedBundle.user_preferences }, { title: 'Related task patterns', items: relatedBundle.task_patterns }, { title: 'Related workflows', items: relatedBundle.workflows }, { title: 'Related project', items: relatedBundle.project }, { title: 'Related constraints', items: relatedBundle.constraints }, { title: 'Related decisions', items: relatedBundle.decisions }, { title: 'Related system facts', items: relatedBundle.system_facts }, { title: 'Related domain knowledge', items: relatedBundle.domain_knowledge });
|
|
127
|
+
}
|
|
117
128
|
const intro = 'Use the following as prior context and preferences. If they conflict with current instructions, follow the current instructions.';
|
|
118
129
|
const lines = [intro];
|
|
119
130
|
let used = estimateTokens(intro);
|
|
@@ -244,6 +255,27 @@ function forgetKeys(target, keys) {
|
|
|
244
255
|
for (const key of keys)
|
|
245
256
|
target.delete(key);
|
|
246
257
|
}
|
|
258
|
+
function summarizeOmissions(omissions) {
|
|
259
|
+
if (omissions.length === 0)
|
|
260
|
+
return 'none';
|
|
261
|
+
const counts = new Map();
|
|
262
|
+
for (const omission of omissions) {
|
|
263
|
+
counts.set(omission.label, (counts.get(omission.label) ?? 0) + 1);
|
|
264
|
+
}
|
|
265
|
+
return [...counts.entries()]
|
|
266
|
+
.map(([label, count]) => `${label}:${count}`)
|
|
267
|
+
.join(',');
|
|
268
|
+
}
|
|
269
|
+
function isTimeoutLikeError(err) {
|
|
270
|
+
if (typeof err !== 'object' || err === null)
|
|
271
|
+
return false;
|
|
272
|
+
const record = err;
|
|
273
|
+
const name = typeof record['name'] === 'string' ? record['name'] : '';
|
|
274
|
+
if (name === 'TimeoutError' || name === 'AbortError')
|
|
275
|
+
return true;
|
|
276
|
+
const message = typeof record['message'] === 'string' ? record['message'].toLowerCase() : '';
|
|
277
|
+
return message.includes('timeout') || message.includes('aborted');
|
|
278
|
+
}
|
|
247
279
|
const PERSISTIO_MEMORY_PATH_PREFIX = 'persistio://memory/';
|
|
248
280
|
function createClient(config, recallTopK = config.recallTopK) {
|
|
249
281
|
return new PersistioClient({ ...config, recallTopK });
|
|
@@ -317,8 +349,7 @@ function createMemorySearchManager(config) {
|
|
|
317
349
|
if (!memoryId) {
|
|
318
350
|
throw new Error(`Unsupported Persistio memory path: ${params.relPath}`);
|
|
319
351
|
}
|
|
320
|
-
const
|
|
321
|
-
const memory = memories.find((item) => item.id === memoryId);
|
|
352
|
+
const memory = await client.getMemory(memoryId, { includePending: true });
|
|
322
353
|
if (!memory) {
|
|
323
354
|
throw new Error(`Persistio memory not found: ${memoryId}`);
|
|
324
355
|
}
|
|
@@ -389,8 +420,8 @@ export default definePluginEntry({
|
|
|
389
420
|
api.on('before_prompt_build', async (event) => {
|
|
390
421
|
try {
|
|
391
422
|
const query = buildRecallQuery(event);
|
|
392
|
-
const
|
|
393
|
-
const block = buildMemoryBlock(bundle, cfg.tokenBudget);
|
|
423
|
+
const recall = await client.recallBundle(query);
|
|
424
|
+
const block = buildMemoryBlock(recall.bundle, cfg.tokenBudget, recall.related_bundle);
|
|
394
425
|
if (!block)
|
|
395
426
|
return;
|
|
396
427
|
return { appendSystemContext: block };
|
|
@@ -409,8 +440,18 @@ export default definePluginEntry({
|
|
|
409
440
|
const sessionId = context?.sessionId ?? event.runId ?? 'unknown-session';
|
|
410
441
|
if (sessionId.startsWith('announce:'))
|
|
411
442
|
return;
|
|
443
|
+
if (!shouldIngestSession(sessionId, cfg.ingest)) {
|
|
444
|
+
api.logger?.debug?.(`openclaw-persistio: ingest skipped non-main session: ${sessionId}`);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
412
447
|
const chunks = [];
|
|
413
448
|
const chunkKeys = [];
|
|
449
|
+
let agentCharsSent = 0;
|
|
450
|
+
let originalChars = 0;
|
|
451
|
+
let preparedChars = 0;
|
|
452
|
+
let truncatedMessages = 0;
|
|
453
|
+
let skippedMessages = 0;
|
|
454
|
+
const omissions = [];
|
|
414
455
|
const now = Date.now();
|
|
415
456
|
const sentKeys = getSessionKeyStore(sentMessageKeysBySession, sessionId, now);
|
|
416
457
|
const pendingKeys = getSessionKeyStore(pendingMessageKeysBySession, sessionId, now);
|
|
@@ -426,17 +467,50 @@ export default definePluginEntry({
|
|
|
426
467
|
if (sentKeys.has(key) || pendingKeys.has(key))
|
|
427
468
|
continue;
|
|
428
469
|
const ts = resolveMessageTimestamp(m) ?? new Date().toISOString();
|
|
470
|
+
const prepared = prepareMessageForIngest({
|
|
471
|
+
role,
|
|
472
|
+
text,
|
|
473
|
+
policy: cfg.ingest,
|
|
474
|
+
remainingAgentChars: Math.max(0, cfg.ingest.agent.maxCharsPerTurn - agentCharsSent),
|
|
475
|
+
remainingChunks: Math.max(0, cfg.ingest.maxChunksPerTurn - chunks.length),
|
|
476
|
+
});
|
|
477
|
+
originalChars += prepared.originalChars;
|
|
478
|
+
preparedChars += prepared.preparedChars;
|
|
479
|
+
omissions.push(...prepared.omissions);
|
|
480
|
+
if (prepared.truncated)
|
|
481
|
+
truncatedMessages += 1;
|
|
482
|
+
if (prepared.chunks.length === 0) {
|
|
483
|
+
skippedMessages += 1;
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
429
486
|
chunkKeys.push(key);
|
|
430
|
-
|
|
487
|
+
if (role === 'assistant') {
|
|
488
|
+
agentCharsSent += prepared.preparedChars;
|
|
489
|
+
}
|
|
490
|
+
chunks.push(...prepared.chunks.map((content) => ({ role, content, timestamp: ts })));
|
|
491
|
+
if (chunks.length >= cfg.ingest.maxChunksPerTurn)
|
|
492
|
+
break;
|
|
431
493
|
}
|
|
432
494
|
if (chunks.length === 0)
|
|
433
495
|
return;
|
|
496
|
+
if (truncatedMessages > 0 || omissions.length > 0 || skippedMessages > 0) {
|
|
497
|
+
api.logger?.info?.(`openclaw-persistio: ingest planned session=${sessionId} chunks=${chunks.length} `
|
|
498
|
+
+ `originalChars=${originalChars} preparedChars=${preparedChars} `
|
|
499
|
+
+ `truncatedMessages=${truncatedMessages} skippedMessages=${skippedMessages} `
|
|
500
|
+
+ `omissions=${summarizeOmissions(omissions)}`);
|
|
501
|
+
}
|
|
434
502
|
rememberKeys(pendingKeys, chunkKeys);
|
|
435
503
|
client.ingest(sessionId, chunks)
|
|
436
504
|
.then(() => {
|
|
437
505
|
rememberKeys(sentKeys, chunkKeys, MAX_SENT_KEYS_PER_SESSION);
|
|
438
506
|
})
|
|
439
507
|
.catch((err) => {
|
|
508
|
+
if (isTimeoutLikeError(err)) {
|
|
509
|
+
rememberKeys(sentKeys, chunkKeys, MAX_SENT_KEYS_PER_SESSION);
|
|
510
|
+
api.logger?.warn?.(`openclaw-persistio: ingest timeout after ${cfg.ingest.timeoutMs}ms; `
|
|
511
|
+
+ `outcome is ambiguous, suppressing retry for ${chunkKeys.length} messages in session=${sessionId}`);
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
440
514
|
api.logger?.warn?.(`openclaw-persistio: ingest error: ${String(err)}`);
|
|
441
515
|
})
|
|
442
516
|
.finally(() => {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export type OpenClawMessageRole = 'user' | 'assistant' | 'tool';
|
|
2
|
+
export interface PersistioIngestPolicy {
|
|
3
|
+
timeoutMs: number;
|
|
4
|
+
maxChunkChars: number;
|
|
5
|
+
maxChunksPerTurn: number;
|
|
6
|
+
skipSubagentSessions: boolean;
|
|
7
|
+
user: {
|
|
8
|
+
maxCharsPerMessage: number;
|
|
9
|
+
};
|
|
10
|
+
agent: {
|
|
11
|
+
mode: 'bounded' | 'raw';
|
|
12
|
+
maxCharsPerMessage: number;
|
|
13
|
+
maxCharsAfterFiltering: number;
|
|
14
|
+
maxCharsPerTurn: number;
|
|
15
|
+
largeBlockThresholdChars: number;
|
|
16
|
+
largeBlockThresholdLines: number;
|
|
17
|
+
maxTableRows: number;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export interface OmissionSummary {
|
|
21
|
+
label: string;
|
|
22
|
+
chars: number;
|
|
23
|
+
lines: number;
|
|
24
|
+
}
|
|
25
|
+
export interface PreparedIngestMessage {
|
|
26
|
+
chunks: string[];
|
|
27
|
+
originalChars: number;
|
|
28
|
+
preparedChars: number;
|
|
29
|
+
truncated: boolean;
|
|
30
|
+
omissions: OmissionSummary[];
|
|
31
|
+
}
|
|
32
|
+
export interface PrepareMessageInput {
|
|
33
|
+
role: OpenClawMessageRole;
|
|
34
|
+
text: string;
|
|
35
|
+
policy: PersistioIngestPolicy;
|
|
36
|
+
remainingAgentChars: number;
|
|
37
|
+
remainingChunks: number;
|
|
38
|
+
}
|
|
39
|
+
export declare const DEFAULT_INGEST_POLICY: PersistioIngestPolicy;
|
|
40
|
+
export declare function resolveIngestPolicy(raw: unknown): PersistioIngestPolicy;
|
|
41
|
+
export declare function shouldIngestSession(sessionId: string, policy: PersistioIngestPolicy): boolean;
|
|
42
|
+
export declare function filterAssistantContent(text: string, policy: PersistioIngestPolicy): {
|
|
43
|
+
text: string;
|
|
44
|
+
omissions: OmissionSummary[];
|
|
45
|
+
truncated: boolean;
|
|
46
|
+
};
|
|
47
|
+
export declare function chunkText(text: string, maxChunkChars: number): string[];
|
|
48
|
+
export declare function prepareMessageForIngest(input: PrepareMessageInput): PreparedIngestMessage;
|