@persistio/openclaw-plugin 0.1.5 → 0.1.7
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 +19 -2
- package/dist/client.d.ts +7 -0
- package/dist/client.js +129 -57
- package/dist/index.js +212 -36
- package/dist/ingest-policy.d.ts +48 -0
- package/dist/ingest-policy.js +380 -0
- package/openclaw.plugin.json +83 -4
- package/package.json +2 -2
- package/src/client.ts +133 -51
- package/src/index.ts +264 -45
- package/src/ingest-policy.ts +508 -0
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',
|
|
@@ -9,6 +10,31 @@ const DEFAULT_SEND_ROLES = {
|
|
|
9
10
|
const MESSAGE_KEY_TTL_MS = 24 * 60 * 60 * 1000;
|
|
10
11
|
const MAX_TRACKED_SESSIONS = 250;
|
|
11
12
|
const MAX_SENT_KEYS_PER_SESSION = 2000;
|
|
13
|
+
const RECALL_CIRCUIT_BREAKER_FAILURE_THRESHOLD = 3;
|
|
14
|
+
const RECALL_CIRCUIT_BREAKER_COOLDOWN_MS = 60_000;
|
|
15
|
+
const RECALL_GUARD_MARGIN_MS = 250;
|
|
16
|
+
class RecallCircuitBreaker {
|
|
17
|
+
consecutiveFailures = 0;
|
|
18
|
+
openedUntil = 0;
|
|
19
|
+
canAttempt(now = Date.now()) {
|
|
20
|
+
return now >= this.openedUntil;
|
|
21
|
+
}
|
|
22
|
+
remainingMs(now = Date.now()) {
|
|
23
|
+
return Math.max(0, this.openedUntil - now);
|
|
24
|
+
}
|
|
25
|
+
recordSuccess() {
|
|
26
|
+
this.consecutiveFailures = 0;
|
|
27
|
+
this.openedUntil = 0;
|
|
28
|
+
}
|
|
29
|
+
recordFailure(now = Date.now()) {
|
|
30
|
+
this.consecutiveFailures += 1;
|
|
31
|
+
if (this.consecutiveFailures >= RECALL_CIRCUIT_BREAKER_FAILURE_THRESHOLD) {
|
|
32
|
+
this.openedUntil = now + RECALL_CIRCUIT_BREAKER_COOLDOWN_MS;
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
12
38
|
function resolveSendConfig(raw) {
|
|
13
39
|
const send = raw['send'];
|
|
14
40
|
const roles = typeof send === 'object' && send !== null
|
|
@@ -30,15 +56,21 @@ function resolveRecallMinSimilarity(value) {
|
|
|
30
56
|
? value
|
|
31
57
|
: undefined;
|
|
32
58
|
}
|
|
59
|
+
function resolvePositiveInteger(value, fallback) {
|
|
60
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 1
|
|
61
|
+
? Math.floor(value)
|
|
62
|
+
: fallback;
|
|
63
|
+
}
|
|
33
64
|
function resolveConfig(raw) {
|
|
34
65
|
const c = (raw ?? {});
|
|
35
66
|
return {
|
|
36
67
|
baseURL: typeof c['baseURL'] === 'string' ? c['baseURL'] : '',
|
|
37
68
|
apiKey: typeof c['apiKey'] === 'string' ? c['apiKey'] : '',
|
|
38
|
-
tokenBudget:
|
|
39
|
-
recallTopK:
|
|
69
|
+
tokenBudget: resolvePositiveInteger(c['tokenBudget'], 2000),
|
|
70
|
+
recallTopK: resolvePositiveInteger(c['recallTopK'], 10),
|
|
40
71
|
recallMinSimilarity: resolveRecallMinSimilarity(c['recallMinSimilarity']),
|
|
41
|
-
recallTimeout:
|
|
72
|
+
recallTimeout: resolvePositiveInteger(c['recallTimeout'], 5000),
|
|
73
|
+
ingest: resolveIngestPolicy(c['ingest']),
|
|
42
74
|
send: resolveSendConfig(c),
|
|
43
75
|
};
|
|
44
76
|
}
|
|
@@ -108,20 +140,27 @@ function buildRecallQuery(event) {
|
|
|
108
140
|
parts.push(`[task: ${taskType}]`);
|
|
109
141
|
return truncate(parts.join('\n'), 600);
|
|
110
142
|
}
|
|
143
|
+
function toStringArray(value) {
|
|
144
|
+
return Array.isArray(value)
|
|
145
|
+
? value.filter((item) => typeof item === 'string')
|
|
146
|
+
: [];
|
|
147
|
+
}
|
|
111
148
|
function buildMemoryBlock(bundle, budget, relatedBundle) {
|
|
149
|
+
if (!bundle || typeof bundle !== 'object')
|
|
150
|
+
return '';
|
|
112
151
|
const sections = [
|
|
113
|
-
{ title: 'Behavioural rules', items: bundle.user_rules },
|
|
114
|
-
{ title: 'Preferences', items: bundle.user_preferences },
|
|
115
|
-
{ title: 'Task patterns', items: bundle.task_patterns },
|
|
116
|
-
{ title: 'Workflows', items: bundle.workflows },
|
|
117
|
-
{ title: 'Project', items: bundle.project },
|
|
118
|
-
{ title: 'Constraints', items: bundle.constraints },
|
|
119
|
-
{ title: 'Decisions', items: bundle.decisions },
|
|
120
|
-
{ title: 'System facts', items: bundle.system_facts },
|
|
121
|
-
{ title: 'Domain knowledge', items: bundle.domain_knowledge },
|
|
152
|
+
{ title: 'Behavioural rules', items: toStringArray(bundle.user_rules) },
|
|
153
|
+
{ title: 'Preferences', items: toStringArray(bundle.user_preferences) },
|
|
154
|
+
{ title: 'Task patterns', items: toStringArray(bundle.task_patterns) },
|
|
155
|
+
{ title: 'Workflows', items: toStringArray(bundle.workflows) },
|
|
156
|
+
{ title: 'Project', items: toStringArray(bundle.project) },
|
|
157
|
+
{ title: 'Constraints', items: toStringArray(bundle.constraints) },
|
|
158
|
+
{ title: 'Decisions', items: toStringArray(bundle.decisions) },
|
|
159
|
+
{ title: 'System facts', items: toStringArray(bundle.system_facts) },
|
|
160
|
+
{ title: 'Domain knowledge', items: toStringArray(bundle.domain_knowledge) },
|
|
122
161
|
];
|
|
123
|
-
if (relatedBundle) {
|
|
124
|
-
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 });
|
|
162
|
+
if (relatedBundle && typeof relatedBundle === 'object') {
|
|
163
|
+
sections.push({ title: 'Related behavioural rules', items: toStringArray(relatedBundle.user_rules) }, { title: 'Related preferences', items: toStringArray(relatedBundle.user_preferences) }, { title: 'Related task patterns', items: toStringArray(relatedBundle.task_patterns) }, { title: 'Related workflows', items: toStringArray(relatedBundle.workflows) }, { title: 'Related project', items: toStringArray(relatedBundle.project) }, { title: 'Related constraints', items: toStringArray(relatedBundle.constraints) }, { title: 'Related decisions', items: toStringArray(relatedBundle.decisions) }, { title: 'Related system facts', items: toStringArray(relatedBundle.system_facts) }, { title: 'Related domain knowledge', items: toStringArray(relatedBundle.domain_knowledge) });
|
|
125
164
|
}
|
|
126
165
|
const intro = 'Use the following as prior context and preferences. If they conflict with current instructions, follow the current instructions.';
|
|
127
166
|
const lines = [intro];
|
|
@@ -253,6 +292,66 @@ function forgetKeys(target, keys) {
|
|
|
253
292
|
for (const key of keys)
|
|
254
293
|
target.delete(key);
|
|
255
294
|
}
|
|
295
|
+
function summarizeOmissions(omissions) {
|
|
296
|
+
if (omissions.length === 0)
|
|
297
|
+
return 'none';
|
|
298
|
+
const counts = new Map();
|
|
299
|
+
for (const omission of omissions) {
|
|
300
|
+
counts.set(omission.label, (counts.get(omission.label) ?? 0) + 1);
|
|
301
|
+
}
|
|
302
|
+
return [...counts.entries()]
|
|
303
|
+
.map(([label, count]) => `${label}:${count}`)
|
|
304
|
+
.join(',');
|
|
305
|
+
}
|
|
306
|
+
function isTimeoutLikeError(err) {
|
|
307
|
+
if (typeof err !== 'object' || err === null)
|
|
308
|
+
return false;
|
|
309
|
+
const record = err;
|
|
310
|
+
const name = typeof record['name'] === 'string' ? record['name'] : '';
|
|
311
|
+
if (name === 'TimeoutError' || name === 'AbortError')
|
|
312
|
+
return true;
|
|
313
|
+
const message = typeof record['message'] === 'string' ? record['message'].toLowerCase() : '';
|
|
314
|
+
return message.includes('timeout') || message.includes('aborted');
|
|
315
|
+
}
|
|
316
|
+
async function runGuardedRecall(args) {
|
|
317
|
+
const now = Date.now();
|
|
318
|
+
if (!args.breaker.canAttempt(now)) {
|
|
319
|
+
args.logger?.warn?.(`openclaw-persistio: ${args.operation} skipped; recall circuit breaker open `
|
|
320
|
+
+ `for ${args.breaker.remainingMs(now)}ms`);
|
|
321
|
+
return args.fallback;
|
|
322
|
+
}
|
|
323
|
+
try {
|
|
324
|
+
const result = await withPluginDeadline(args.operation, args.timeoutMs + RECALL_GUARD_MARGIN_MS, args.run);
|
|
325
|
+
args.breaker.recordSuccess();
|
|
326
|
+
return result;
|
|
327
|
+
}
|
|
328
|
+
catch (err) {
|
|
329
|
+
const opened = args.breaker.recordFailure();
|
|
330
|
+
args.logger?.warn?.(`openclaw-persistio: ${args.operation} failed open: ${String(err)}`
|
|
331
|
+
+ (opened ? `; recall circuit breaker open for ${RECALL_CIRCUIT_BREAKER_COOLDOWN_MS}ms` : ''));
|
|
332
|
+
return args.fallback;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
async function withPluginDeadline(operation, timeoutMs, run) {
|
|
336
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
337
|
+
return run();
|
|
338
|
+
}
|
|
339
|
+
let timeout;
|
|
340
|
+
const deadline = new Promise((_resolve, reject) => {
|
|
341
|
+
timeout = setTimeout(() => {
|
|
342
|
+
const err = new Error(`Persistio ${operation} exceeded plugin deadline after ${timeoutMs}ms`);
|
|
343
|
+
err.name = 'TimeoutError';
|
|
344
|
+
reject(err);
|
|
345
|
+
}, timeoutMs);
|
|
346
|
+
});
|
|
347
|
+
try {
|
|
348
|
+
return await Promise.race([run(), deadline]);
|
|
349
|
+
}
|
|
350
|
+
finally {
|
|
351
|
+
if (timeout)
|
|
352
|
+
clearTimeout(timeout);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
256
355
|
const PERSISTIO_MEMORY_PATH_PREFIX = 'persistio://memory/';
|
|
257
356
|
function createClient(config, recallTopK = config.recallTopK) {
|
|
258
357
|
return new PersistioClient({ ...config, recallTopK });
|
|
@@ -295,7 +394,7 @@ async function probePersistio(client) {
|
|
|
295
394
|
return { ok: false, error: String(err) };
|
|
296
395
|
}
|
|
297
396
|
}
|
|
298
|
-
function createMemorySearchManager(config) {
|
|
397
|
+
function createMemorySearchManager(config, recallBreaker, logger) {
|
|
299
398
|
const client = createClient(config);
|
|
300
399
|
return {
|
|
301
400
|
async search(query, opts) {
|
|
@@ -304,7 +403,14 @@ function createMemorySearchManager(config) {
|
|
|
304
403
|
}
|
|
305
404
|
const recallTopK = typeof opts?.maxResults === 'number' ? opts.maxResults : config.recallTopK;
|
|
306
405
|
const recallClient = createClient(config, recallTopK);
|
|
307
|
-
const memories = await
|
|
406
|
+
const memories = await runGuardedRecall({
|
|
407
|
+
operation: 'memory search recall',
|
|
408
|
+
timeoutMs: config.recallTimeout,
|
|
409
|
+
fallback: [],
|
|
410
|
+
breaker: recallBreaker,
|
|
411
|
+
logger,
|
|
412
|
+
run: () => recallClient.recall(query),
|
|
413
|
+
});
|
|
308
414
|
return memories
|
|
309
415
|
.map((memory) => {
|
|
310
416
|
const score = normalizeMemoryScore(memory);
|
|
@@ -361,11 +467,11 @@ function createMemorySearchManager(config) {
|
|
|
361
467
|
},
|
|
362
468
|
};
|
|
363
469
|
}
|
|
364
|
-
function createMemoryRuntime(config) {
|
|
470
|
+
function createMemoryRuntime(config, recallBreaker, logger) {
|
|
365
471
|
return {
|
|
366
472
|
async getMemorySearchManager() {
|
|
367
473
|
return {
|
|
368
|
-
manager: createMemorySearchManager(config),
|
|
474
|
+
manager: createMemorySearchManager(config, recallBreaker, logger),
|
|
369
475
|
};
|
|
370
476
|
},
|
|
371
477
|
resolveMemoryBackendConfig() {
|
|
@@ -384,10 +490,11 @@ export default definePluginEntry({
|
|
|
384
490
|
return;
|
|
385
491
|
}
|
|
386
492
|
const client = createClient(cfg);
|
|
493
|
+
const recallBreaker = new RecallCircuitBreaker();
|
|
387
494
|
const sentMessageKeysBySession = new Map();
|
|
388
495
|
const pendingMessageKeysBySession = new Map();
|
|
389
496
|
api.registerMemoryCapability({
|
|
390
|
-
runtime: createMemoryRuntime(cfg),
|
|
497
|
+
runtime: createMemoryRuntime(cfg, recallBreaker, api.logger),
|
|
391
498
|
});
|
|
392
499
|
// -------------------------------------------------------------------------
|
|
393
500
|
// before_prompt_build — recall relevant memories and inject into context
|
|
@@ -395,18 +502,22 @@ export default definePluginEntry({
|
|
|
395
502
|
// Return: { appendSystemContext?: string }
|
|
396
503
|
// -------------------------------------------------------------------------
|
|
397
504
|
api.on('before_prompt_build', async (event) => {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
505
|
+
const query = buildRecallQuery(event);
|
|
506
|
+
const block = await runGuardedRecall({
|
|
507
|
+
operation: 'before_prompt_build recall',
|
|
508
|
+
timeoutMs: cfg.recallTimeout,
|
|
509
|
+
fallback: '',
|
|
510
|
+
breaker: recallBreaker,
|
|
511
|
+
logger: api.logger,
|
|
512
|
+
run: async () => {
|
|
513
|
+
const recall = await client.recallBundle(query);
|
|
514
|
+
return buildMemoryBlock(recall.bundle, cfg.tokenBudget, recall.related_bundle);
|
|
515
|
+
},
|
|
516
|
+
});
|
|
517
|
+
if (!block)
|
|
518
|
+
return;
|
|
519
|
+
return { appendSystemContext: block };
|
|
520
|
+
}, { timeoutMs: cfg.recallTimeout + RECALL_GUARD_MARGIN_MS + 250 });
|
|
410
521
|
// -------------------------------------------------------------------------
|
|
411
522
|
// agent_end — ingest new turn messages (fire and forget)
|
|
412
523
|
// Event: { runId?, messages: unknown[], success: boolean, error?, durationMs? }
|
|
@@ -417,8 +528,18 @@ export default definePluginEntry({
|
|
|
417
528
|
const sessionId = context?.sessionId ?? event.runId ?? 'unknown-session';
|
|
418
529
|
if (sessionId.startsWith('announce:'))
|
|
419
530
|
return;
|
|
531
|
+
if (!shouldIngestSession(sessionId, cfg.ingest)) {
|
|
532
|
+
api.logger?.debug?.(`openclaw-persistio: ingest skipped non-main session: ${sessionId}`);
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
420
535
|
const chunks = [];
|
|
421
536
|
const chunkKeys = [];
|
|
537
|
+
let agentCharsSent = 0;
|
|
538
|
+
let originalChars = 0;
|
|
539
|
+
let preparedChars = 0;
|
|
540
|
+
let truncatedMessages = 0;
|
|
541
|
+
let skippedMessages = 0;
|
|
542
|
+
const omissions = [];
|
|
422
543
|
const now = Date.now();
|
|
423
544
|
const sentKeys = getSessionKeyStore(sentMessageKeysBySession, sessionId, now);
|
|
424
545
|
const pendingKeys = getSessionKeyStore(pendingMessageKeysBySession, sessionId, now);
|
|
@@ -434,17 +555,50 @@ export default definePluginEntry({
|
|
|
434
555
|
if (sentKeys.has(key) || pendingKeys.has(key))
|
|
435
556
|
continue;
|
|
436
557
|
const ts = resolveMessageTimestamp(m) ?? new Date().toISOString();
|
|
558
|
+
const prepared = prepareMessageForIngest({
|
|
559
|
+
role,
|
|
560
|
+
text,
|
|
561
|
+
policy: cfg.ingest,
|
|
562
|
+
remainingAgentChars: Math.max(0, cfg.ingest.agent.maxCharsPerTurn - agentCharsSent),
|
|
563
|
+
remainingChunks: Math.max(0, cfg.ingest.maxChunksPerTurn - chunks.length),
|
|
564
|
+
});
|
|
565
|
+
originalChars += prepared.originalChars;
|
|
566
|
+
preparedChars += prepared.preparedChars;
|
|
567
|
+
omissions.push(...prepared.omissions);
|
|
568
|
+
if (prepared.truncated)
|
|
569
|
+
truncatedMessages += 1;
|
|
570
|
+
if (prepared.chunks.length === 0) {
|
|
571
|
+
skippedMessages += 1;
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
437
574
|
chunkKeys.push(key);
|
|
438
|
-
|
|
575
|
+
if (role === 'assistant') {
|
|
576
|
+
agentCharsSent += prepared.preparedChars;
|
|
577
|
+
}
|
|
578
|
+
chunks.push(...prepared.chunks.map((content) => ({ role, content, timestamp: ts })));
|
|
579
|
+
if (chunks.length >= cfg.ingest.maxChunksPerTurn)
|
|
580
|
+
break;
|
|
439
581
|
}
|
|
440
582
|
if (chunks.length === 0)
|
|
441
583
|
return;
|
|
584
|
+
if (truncatedMessages > 0 || omissions.length > 0 || skippedMessages > 0) {
|
|
585
|
+
api.logger?.info?.(`openclaw-persistio: ingest planned session=${sessionId} chunks=${chunks.length} `
|
|
586
|
+
+ `originalChars=${originalChars} preparedChars=${preparedChars} `
|
|
587
|
+
+ `truncatedMessages=${truncatedMessages} skippedMessages=${skippedMessages} `
|
|
588
|
+
+ `omissions=${summarizeOmissions(omissions)}`);
|
|
589
|
+
}
|
|
442
590
|
rememberKeys(pendingKeys, chunkKeys);
|
|
443
591
|
client.ingest(sessionId, chunks)
|
|
444
592
|
.then(() => {
|
|
445
593
|
rememberKeys(sentKeys, chunkKeys, MAX_SENT_KEYS_PER_SESSION);
|
|
446
594
|
})
|
|
447
595
|
.catch((err) => {
|
|
596
|
+
if (isTimeoutLikeError(err)) {
|
|
597
|
+
rememberKeys(sentKeys, chunkKeys, MAX_SENT_KEYS_PER_SESSION);
|
|
598
|
+
api.logger?.warn?.(`openclaw-persistio: ingest timeout after ${cfg.ingest.timeoutMs}ms; `
|
|
599
|
+
+ `outcome is ambiguous, suppressing retry for ${chunkKeys.length} messages in session=${sessionId}`);
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
448
602
|
api.logger?.warn?.(`openclaw-persistio: ingest error: ${String(err)}`);
|
|
449
603
|
})
|
|
450
604
|
.finally(() => {
|
|
@@ -471,10 +625,17 @@ export default definePluginEntry({
|
|
|
471
625
|
}),
|
|
472
626
|
async execute(_id, params) {
|
|
473
627
|
const p = params;
|
|
474
|
-
const overrideTopK =
|
|
628
|
+
const overrideTopK = resolvePositiveInteger(p.top_k, cfg.recallTopK);
|
|
475
629
|
const overrideCfg = { ...cfg, recallTopK: overrideTopK };
|
|
476
|
-
const
|
|
477
|
-
const memories = await
|
|
630
|
+
const recallClient = createClient(overrideCfg);
|
|
631
|
+
const memories = await runGuardedRecall({
|
|
632
|
+
operation: 'memory_search tool recall',
|
|
633
|
+
timeoutMs: cfg.recallTimeout,
|
|
634
|
+
fallback: [],
|
|
635
|
+
breaker: recallBreaker,
|
|
636
|
+
logger: api.logger,
|
|
637
|
+
run: () => recallClient.recall(p.query),
|
|
638
|
+
});
|
|
478
639
|
const text = memories.length > 0
|
|
479
640
|
? memories.map(m => `- ${m.data} [${m.subject}]`).join('\n')
|
|
480
641
|
: 'No memories found.';
|
|
@@ -491,7 +652,22 @@ export default definePluginEntry({
|
|
|
491
652
|
}),
|
|
492
653
|
async execute(_id, params) {
|
|
493
654
|
const p = params;
|
|
494
|
-
|
|
655
|
+
try {
|
|
656
|
+
await client.addMemory(p.data, p.subject);
|
|
657
|
+
}
|
|
658
|
+
catch (err) {
|
|
659
|
+
if (isTimeoutLikeError(err)) {
|
|
660
|
+
api.logger?.warn?.(`openclaw-persistio: memory_add timeout after ${cfg.ingest.timeoutMs}ms; outcome is ambiguous`);
|
|
661
|
+
return {
|
|
662
|
+
content: [{
|
|
663
|
+
type: 'text',
|
|
664
|
+
text: 'Memory store request timed out; it may still complete. Check memory_list before retrying.',
|
|
665
|
+
}],
|
|
666
|
+
details: { ambiguous: true },
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
throw err;
|
|
670
|
+
}
|
|
495
671
|
return { content: [{ type: 'text', text: 'Memory stored.' }], details: null };
|
|
496
672
|
},
|
|
497
673
|
});
|
|
@@ -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;
|