@jonathangu/openclawbrain 0.3.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/LICENSE +21 -0
- package/README.md +412 -0
- package/bin/openclawbrain.js +15 -0
- package/docs/END_STATE.md +244 -0
- package/docs/EVIDENCE.md +128 -0
- package/docs/RELEASE_CONTRACT.md +91 -0
- package/docs/agent-tools.md +106 -0
- package/docs/architecture.md +224 -0
- package/docs/configuration.md +178 -0
- package/docs/evidence/2026-03-16/3188b50c4ed30f07dea111e35ce52aabefaced63/brain-teach-session-bound/status.json +87 -0
- package/docs/evidence/2026-03-16/3188b50c4ed30f07dea111e35ce52aabefaced63/brain-teach-session-bound/summary.md +16 -0
- package/docs/evidence/2026-03-16/3188b50c4ed30f07dea111e35ce52aabefaced63/brain-teach-session-bound/trace.json +273 -0
- package/docs/evidence/2026-03-16/3188b50c4ed30f07dea111e35ce52aabefaced63/brain-teach-session-bound/validation-report.json +652 -0
- package/docs/evidence/2026-03-16/4941429588810da5d6f7ef1509f229f83fa08031/channels-status.txt +31 -0
- package/docs/evidence/2026-03-16/4941429588810da5d6f7ef1509f229f83fa08031/config-snapshot.json +66 -0
- package/docs/evidence/2026-03-16/4941429588810da5d6f7ef1509f229f83fa08031/doctor.json +14 -0
- package/docs/evidence/2026-03-16/4941429588810da5d6f7ef1509f229f83fa08031/gateway-probe.txt +34 -0
- package/docs/evidence/2026-03-16/4941429588810da5d6f7ef1509f229f83fa08031/gateway-status.txt +41 -0
- package/docs/evidence/2026-03-16/4941429588810da5d6f7ef1509f229f83fa08031/logs.txt +428 -0
- package/docs/evidence/2026-03-16/4941429588810da5d6f7ef1509f229f83fa08031/status-all.txt +60 -0
- package/docs/evidence/2026-03-16/4941429588810da5d6f7ef1509f229f83fa08031/status.json +223 -0
- package/docs/evidence/2026-03-16/4941429588810da5d6f7ef1509f229f83fa08031/summary.md +13 -0
- package/docs/evidence/2026-03-16/4941429588810da5d6f7ef1509f229f83fa08031/trace.json +4 -0
- package/docs/evidence/2026-03-16/4941429588810da5d6f7ef1509f229f83fa08031/validation-report.json +334 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/channels-status.txt +25 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/config-snapshot.json +91 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/doctor.json +14 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/gateway-probe.txt +36 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/gateway-status.txt +44 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/logs.txt +428 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/short-static-classification/preflight-doctor.json +10 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/short-static-classification/preflight-sdk-probe.json +11 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/short-static-classification/preflight-setup-only.json +12 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/short-static-classification/summary.md +30 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/short-static-classification/validation-report.json +72 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/status-all.txt +63 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/status.json +200 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/summary.md +13 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/trace.json +4 -0
- package/docs/evidence/2026-03-16/7f8dbcb27e741abdeefd5656c210639d0acdd440/validation-report.json +311 -0
- package/docs/evidence/README.md +16 -0
- package/docs/fts5.md +161 -0
- package/docs/tui.md +506 -0
- package/index.ts +1372 -0
- package/openclaw.plugin.json +136 -0
- package/package.json +66 -0
- package/src/assembler.ts +804 -0
- package/src/brain-cli.ts +316 -0
- package/src/brain-core/decay.ts +35 -0
- package/src/brain-core/episode.ts +82 -0
- package/src/brain-core/graph.ts +321 -0
- package/src/brain-core/health.ts +116 -0
- package/src/brain-core/mutator.ts +281 -0
- package/src/brain-core/pack.ts +117 -0
- package/src/brain-core/policy.ts +153 -0
- package/src/brain-core/replay.ts +1 -0
- package/src/brain-core/teacher.ts +105 -0
- package/src/brain-core/trace.ts +40 -0
- package/src/brain-core/traverse.ts +230 -0
- package/src/brain-core/types.ts +405 -0
- package/src/brain-core/update.ts +123 -0
- package/src/brain-harvest/human.ts +46 -0
- package/src/brain-harvest/scanner.ts +98 -0
- package/src/brain-harvest/self.ts +147 -0
- package/src/brain-runtime/assembler-extension.ts +230 -0
- package/src/brain-runtime/evidence-detectors.ts +68 -0
- package/src/brain-runtime/graph-io.ts +72 -0
- package/src/brain-runtime/harvester-extension.ts +98 -0
- package/src/brain-runtime/service.ts +659 -0
- package/src/brain-runtime/tools.ts +109 -0
- package/src/brain-runtime/worker-state.ts +106 -0
- package/src/brain-runtime/worker-supervisor.ts +169 -0
- package/src/brain-store/embedding.ts +179 -0
- package/src/brain-store/init.ts +347 -0
- package/src/brain-store/migrations.ts +188 -0
- package/src/brain-store/store.ts +816 -0
- package/src/brain-worker/child-runner.ts +321 -0
- package/src/brain-worker/jobs.ts +12 -0
- package/src/brain-worker/mutation-job.ts +5 -0
- package/src/brain-worker/promotion-job.ts +5 -0
- package/src/brain-worker/protocol.ts +79 -0
- package/src/brain-worker/teacher-job.ts +5 -0
- package/src/brain-worker/update-job.ts +5 -0
- package/src/brain-worker/worker.ts +422 -0
- package/src/compaction.ts +1332 -0
- package/src/db/config.ts +265 -0
- package/src/db/connection.ts +72 -0
- package/src/db/features.ts +42 -0
- package/src/db/migration.ts +561 -0
- package/src/engine.ts +1995 -0
- package/src/expansion-auth.ts +351 -0
- package/src/expansion-policy.ts +303 -0
- package/src/expansion.ts +383 -0
- package/src/integrity.ts +600 -0
- package/src/large-files.ts +527 -0
- package/src/openclaw-bridge.ts +22 -0
- package/src/retrieval.ts +357 -0
- package/src/store/conversation-store.ts +748 -0
- package/src/store/fts5-sanitize.ts +29 -0
- package/src/store/full-text-fallback.ts +74 -0
- package/src/store/index.ts +29 -0
- package/src/store/summary-store.ts +918 -0
- package/src/summarize.ts +847 -0
- package/src/tools/common.ts +53 -0
- package/src/tools/lcm-conversation-scope.ts +76 -0
- package/src/tools/lcm-describe-tool.ts +234 -0
- package/src/tools/lcm-expand-query-tool.ts +594 -0
- package/src/tools/lcm-expand-tool.delegation.ts +556 -0
- package/src/tools/lcm-expand-tool.ts +448 -0
- package/src/tools/lcm-expansion-recursion-guard.ts +286 -0
- package/src/tools/lcm-grep-tool.ts +200 -0
- package/src/transcript-repair.ts +301 -0
- package/src/types.ts +149 -0
package/src/retrieval.ts
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ConversationStore,
|
|
3
|
+
MessageRecord,
|
|
4
|
+
MessageSearchResult,
|
|
5
|
+
} from "./store/conversation-store.js";
|
|
6
|
+
import type {
|
|
7
|
+
SummaryStore,
|
|
8
|
+
SummaryRecord,
|
|
9
|
+
SummarySearchResult,
|
|
10
|
+
LargeFileRecord,
|
|
11
|
+
} from "./store/summary-store.js";
|
|
12
|
+
|
|
13
|
+
// ── Public interfaces ────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
export interface DescribeResult {
|
|
16
|
+
id: string;
|
|
17
|
+
type: "summary" | "file";
|
|
18
|
+
/** Summary-specific fields */
|
|
19
|
+
summary?: {
|
|
20
|
+
conversationId: number;
|
|
21
|
+
kind: "leaf" | "condensed";
|
|
22
|
+
content: string;
|
|
23
|
+
depth: number;
|
|
24
|
+
tokenCount: number;
|
|
25
|
+
descendantCount: number;
|
|
26
|
+
descendantTokenCount: number;
|
|
27
|
+
sourceMessageTokenCount: number;
|
|
28
|
+
fileIds: string[];
|
|
29
|
+
parentIds: string[];
|
|
30
|
+
childIds: string[];
|
|
31
|
+
messageIds: number[];
|
|
32
|
+
earliestAt: Date | null;
|
|
33
|
+
latestAt: Date | null;
|
|
34
|
+
subtree: Array<{
|
|
35
|
+
summaryId: string;
|
|
36
|
+
parentSummaryId: string | null;
|
|
37
|
+
depthFromRoot: number;
|
|
38
|
+
kind: "leaf" | "condensed";
|
|
39
|
+
depth: number;
|
|
40
|
+
tokenCount: number;
|
|
41
|
+
descendantCount: number;
|
|
42
|
+
descendantTokenCount: number;
|
|
43
|
+
sourceMessageTokenCount: number;
|
|
44
|
+
earliestAt: Date | null;
|
|
45
|
+
latestAt: Date | null;
|
|
46
|
+
childCount: number;
|
|
47
|
+
path: string;
|
|
48
|
+
}>;
|
|
49
|
+
createdAt: Date;
|
|
50
|
+
};
|
|
51
|
+
/** File-specific fields */
|
|
52
|
+
file?: {
|
|
53
|
+
conversationId: number;
|
|
54
|
+
fileName: string | null;
|
|
55
|
+
mimeType: string | null;
|
|
56
|
+
byteSize: number | null;
|
|
57
|
+
storageUri: string;
|
|
58
|
+
explorationSummary: string | null;
|
|
59
|
+
createdAt: Date;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface GrepInput {
|
|
64
|
+
query: string;
|
|
65
|
+
mode: "regex" | "full_text";
|
|
66
|
+
scope: "messages" | "summaries" | "both";
|
|
67
|
+
conversationId?: number;
|
|
68
|
+
since?: Date;
|
|
69
|
+
before?: Date;
|
|
70
|
+
limit?: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface GrepResult {
|
|
74
|
+
messages: MessageSearchResult[];
|
|
75
|
+
summaries: SummarySearchResult[];
|
|
76
|
+
totalMatches: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface ExpandInput {
|
|
80
|
+
summaryId: string;
|
|
81
|
+
/** Max traversal depth (default 1) */
|
|
82
|
+
depth?: number;
|
|
83
|
+
/** Include raw source messages at leaf level */
|
|
84
|
+
includeMessages?: boolean;
|
|
85
|
+
/** Max tokens to return before truncating */
|
|
86
|
+
tokenCap?: number;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface ExpandResult {
|
|
90
|
+
/** Child summaries found */
|
|
91
|
+
children: Array<{
|
|
92
|
+
summaryId: string;
|
|
93
|
+
kind: "leaf" | "condensed";
|
|
94
|
+
content: string;
|
|
95
|
+
tokenCount: number;
|
|
96
|
+
}>;
|
|
97
|
+
/** Source messages (only if includeMessages=true and hitting leaf summaries) */
|
|
98
|
+
messages: Array<{
|
|
99
|
+
messageId: number;
|
|
100
|
+
role: string;
|
|
101
|
+
content: string;
|
|
102
|
+
tokenCount: number;
|
|
103
|
+
}>;
|
|
104
|
+
/** Total estimated tokens in result */
|
|
105
|
+
estimatedTokens: number;
|
|
106
|
+
/** Whether result was truncated due to tokenCap */
|
|
107
|
+
truncated: boolean;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
/** Rough token estimate: ~4 chars per token. */
|
|
113
|
+
function estimateTokens(content: string): number {
|
|
114
|
+
return Math.ceil(content.length / 4);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ── RetrievalEngine ──────────────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
export class RetrievalEngine {
|
|
120
|
+
constructor(
|
|
121
|
+
private conversationStore: ConversationStore,
|
|
122
|
+
private summaryStore: SummaryStore,
|
|
123
|
+
) {}
|
|
124
|
+
|
|
125
|
+
// ── describe ─────────────────────────────────────────────────────────────
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Describe an LCM item by ID.
|
|
129
|
+
*
|
|
130
|
+
* - IDs starting with "sum_" are looked up as summaries (with lineage).
|
|
131
|
+
* - IDs starting with "file_" are looked up as large files.
|
|
132
|
+
* - Returns null if the item is not found.
|
|
133
|
+
*/
|
|
134
|
+
async describe(id: string): Promise<DescribeResult | null> {
|
|
135
|
+
if (id.startsWith("sum_")) {
|
|
136
|
+
return this.describeSummary(id);
|
|
137
|
+
}
|
|
138
|
+
if (id.startsWith("file_")) {
|
|
139
|
+
return this.describeFile(id);
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private async describeSummary(id: string): Promise<DescribeResult | null> {
|
|
145
|
+
const summary = await this.summaryStore.getSummary(id);
|
|
146
|
+
if (!summary) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Fetch lineage in parallel
|
|
151
|
+
const [parents, children, messageIds, subtree] = await Promise.all([
|
|
152
|
+
this.summaryStore.getSummaryParents(id),
|
|
153
|
+
this.summaryStore.getSummaryChildren(id),
|
|
154
|
+
this.summaryStore.getSummaryMessages(id),
|
|
155
|
+
this.summaryStore.getSummarySubtree(id),
|
|
156
|
+
]);
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
id,
|
|
160
|
+
type: "summary",
|
|
161
|
+
summary: {
|
|
162
|
+
conversationId: summary.conversationId,
|
|
163
|
+
kind: summary.kind,
|
|
164
|
+
content: summary.content,
|
|
165
|
+
depth: summary.depth,
|
|
166
|
+
tokenCount: summary.tokenCount,
|
|
167
|
+
descendantCount: summary.descendantCount,
|
|
168
|
+
descendantTokenCount: summary.descendantTokenCount,
|
|
169
|
+
sourceMessageTokenCount: summary.sourceMessageTokenCount,
|
|
170
|
+
fileIds: summary.fileIds,
|
|
171
|
+
parentIds: parents.map((p) => p.summaryId),
|
|
172
|
+
childIds: children.map((c) => c.summaryId),
|
|
173
|
+
messageIds,
|
|
174
|
+
earliestAt: summary.earliestAt,
|
|
175
|
+
latestAt: summary.latestAt,
|
|
176
|
+
subtree: subtree.map((node) => ({
|
|
177
|
+
summaryId: node.summaryId,
|
|
178
|
+
parentSummaryId: node.parentSummaryId,
|
|
179
|
+
depthFromRoot: node.depthFromRoot,
|
|
180
|
+
kind: node.kind,
|
|
181
|
+
depth: node.depth,
|
|
182
|
+
tokenCount: node.tokenCount,
|
|
183
|
+
descendantCount: node.descendantCount,
|
|
184
|
+
descendantTokenCount: node.descendantTokenCount,
|
|
185
|
+
sourceMessageTokenCount: node.sourceMessageTokenCount,
|
|
186
|
+
earliestAt: node.earliestAt,
|
|
187
|
+
latestAt: node.latestAt,
|
|
188
|
+
childCount: node.childCount,
|
|
189
|
+
path: node.path,
|
|
190
|
+
})),
|
|
191
|
+
createdAt: summary.createdAt,
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private async describeFile(id: string): Promise<DescribeResult | null> {
|
|
197
|
+
const file = await this.summaryStore.getLargeFile(id);
|
|
198
|
+
if (!file) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
id,
|
|
204
|
+
type: "file",
|
|
205
|
+
file: {
|
|
206
|
+
conversationId: file.conversationId,
|
|
207
|
+
fileName: file.fileName,
|
|
208
|
+
mimeType: file.mimeType,
|
|
209
|
+
byteSize: file.byteSize,
|
|
210
|
+
storageUri: file.storageUri,
|
|
211
|
+
explorationSummary: file.explorationSummary,
|
|
212
|
+
createdAt: file.createdAt,
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ── grep ─────────────────────────────────────────────────────────────────
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Search compacted history using regex or full-text search.
|
|
221
|
+
*
|
|
222
|
+
* Depending on `scope`, searches messages, summaries, or both (in parallel).
|
|
223
|
+
*/
|
|
224
|
+
async grep(input: GrepInput): Promise<GrepResult> {
|
|
225
|
+
const { query, mode, scope, conversationId, since, before, limit } = input;
|
|
226
|
+
|
|
227
|
+
const searchInput = { query, mode, conversationId, since, before, limit };
|
|
228
|
+
|
|
229
|
+
let messages: MessageSearchResult[] = [];
|
|
230
|
+
let summaries: SummarySearchResult[] = [];
|
|
231
|
+
|
|
232
|
+
if (scope === "messages") {
|
|
233
|
+
messages = await this.conversationStore.searchMessages(searchInput);
|
|
234
|
+
} else if (scope === "summaries") {
|
|
235
|
+
summaries = await this.summaryStore.searchSummaries(searchInput);
|
|
236
|
+
} else {
|
|
237
|
+
// scope === "both" — run in parallel
|
|
238
|
+
[messages, summaries] = await Promise.all([
|
|
239
|
+
this.conversationStore.searchMessages(searchInput),
|
|
240
|
+
this.summaryStore.searchSummaries(searchInput),
|
|
241
|
+
]);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
messages.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
245
|
+
summaries.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
messages,
|
|
249
|
+
summaries,
|
|
250
|
+
totalMatches: messages.length + summaries.length,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ── expand ───────────────────────────────────────────────────────────────
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Expand a summary to its children and/or source messages.
|
|
258
|
+
*
|
|
259
|
+
* - Condensed summaries: returns child summaries, recursing up to `depth`.
|
|
260
|
+
* - Leaf summaries with `includeMessages`: fetches the source messages.
|
|
261
|
+
* - Respects `tokenCap` and sets `truncated` when the cap is exceeded.
|
|
262
|
+
*/
|
|
263
|
+
async expand(input: ExpandInput): Promise<ExpandResult> {
|
|
264
|
+
const depth = input.depth ?? 1;
|
|
265
|
+
const includeMessages = input.includeMessages ?? false;
|
|
266
|
+
const tokenCap = input.tokenCap ?? Infinity;
|
|
267
|
+
|
|
268
|
+
const result: ExpandResult = {
|
|
269
|
+
children: [],
|
|
270
|
+
messages: [],
|
|
271
|
+
estimatedTokens: 0,
|
|
272
|
+
truncated: false,
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
await this.expandRecursive(input.summaryId, depth, includeMessages, tokenCap, result);
|
|
276
|
+
|
|
277
|
+
return result;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private async expandRecursive(
|
|
281
|
+
summaryId: string,
|
|
282
|
+
depth: number,
|
|
283
|
+
includeMessages: boolean,
|
|
284
|
+
tokenCap: number,
|
|
285
|
+
result: ExpandResult,
|
|
286
|
+
): Promise<void> {
|
|
287
|
+
if (depth <= 0) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (result.truncated) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const summary = await this.summaryStore.getSummary(summaryId);
|
|
295
|
+
if (!summary) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (summary.kind === "condensed") {
|
|
300
|
+
const children = await this.summaryStore.getSummaryChildren(summaryId);
|
|
301
|
+
|
|
302
|
+
for (const child of children) {
|
|
303
|
+
if (result.truncated) {
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Check if adding this child would exceed the token cap
|
|
308
|
+
if (result.estimatedTokens + child.tokenCount > tokenCap) {
|
|
309
|
+
result.truncated = true;
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
result.children.push({
|
|
314
|
+
summaryId: child.summaryId,
|
|
315
|
+
kind: child.kind,
|
|
316
|
+
content: child.content,
|
|
317
|
+
tokenCount: child.tokenCount,
|
|
318
|
+
});
|
|
319
|
+
result.estimatedTokens += child.tokenCount;
|
|
320
|
+
|
|
321
|
+
// Recurse into children if depth allows
|
|
322
|
+
if (depth > 1) {
|
|
323
|
+
await this.expandRecursive(child.summaryId, depth - 1, includeMessages, tokenCap, result);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
} else if (summary.kind === "leaf" && includeMessages) {
|
|
327
|
+
// Leaf summary — fetch source messages
|
|
328
|
+
const messageIds = await this.summaryStore.getSummaryMessages(summaryId);
|
|
329
|
+
|
|
330
|
+
for (const msgId of messageIds) {
|
|
331
|
+
if (result.truncated) {
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const msg = await this.conversationStore.getMessageById(msgId);
|
|
336
|
+
if (!msg) {
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const tokenCount = msg.tokenCount || estimateTokens(msg.content);
|
|
341
|
+
|
|
342
|
+
if (result.estimatedTokens + tokenCount > tokenCap) {
|
|
343
|
+
result.truncated = true;
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
result.messages.push({
|
|
348
|
+
messageId: msg.messageId,
|
|
349
|
+
role: msg.role,
|
|
350
|
+
content: msg.content,
|
|
351
|
+
tokenCount,
|
|
352
|
+
});
|
|
353
|
+
result.estimatedTokens += tokenCount;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|