@animalabs/context-manager 0.4.0 → 0.5.1
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/dist/src/adaptive/chunker.d.ts +70 -0
- package/dist/src/adaptive/chunker.d.ts.map +1 -0
- package/dist/src/adaptive/chunker.js +233 -0
- package/dist/src/adaptive/chunker.js.map +1 -0
- package/dist/src/adaptive/folding-strategy.d.ts +118 -0
- package/dist/src/adaptive/folding-strategy.d.ts.map +1 -0
- package/dist/src/adaptive/folding-strategy.js +12 -0
- package/dist/src/adaptive/folding-strategy.js.map +1 -0
- package/dist/src/adaptive/index.d.ts +17 -0
- package/dist/src/adaptive/index.d.ts.map +1 -0
- package/dist/src/adaptive/index.js +23 -0
- package/dist/src/adaptive/index.js.map +1 -0
- package/dist/src/adaptive/picker.d.ts +103 -0
- package/dist/src/adaptive/picker.d.ts.map +1 -0
- package/dist/src/adaptive/picker.js +357 -0
- package/dist/src/adaptive/picker.js.map +1 -0
- package/dist/src/adaptive/render.d.ts +39 -0
- package/dist/src/adaptive/render.d.ts.map +1 -0
- package/dist/src/adaptive/render.js +104 -0
- package/dist/src/adaptive/render.js.map +1 -0
- package/dist/src/adaptive/strategies/flat-profile.d.ts +19 -0
- package/dist/src/adaptive/strategies/flat-profile.d.ts.map +1 -0
- package/dist/src/adaptive/strategies/flat-profile.js +86 -0
- package/dist/src/adaptive/strategies/flat-profile.js.map +1 -0
- package/dist/src/adaptive/strategies/oldest-first.d.ts +19 -0
- package/dist/src/adaptive/strategies/oldest-first.d.ts.map +1 -0
- package/dist/src/adaptive/strategies/oldest-first.js +39 -0
- package/dist/src/adaptive/strategies/oldest-first.js.map +1 -0
- package/dist/src/context-manager.d.ts +5 -0
- package/dist/src/context-manager.d.ts.map +1 -1
- package/dist/src/context-manager.js +22 -0
- package/dist/src/context-manager.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/message-store.d.ts +36 -1
- package/dist/src/message-store.d.ts.map +1 -1
- package/dist/src/message-store.js +134 -8
- package/dist/src/message-store.js.map +1 -1
- package/dist/src/strategies/autobiographical.d.ts +217 -2
- package/dist/src/strategies/autobiographical.d.ts.map +1 -1
- package/dist/src/strategies/autobiographical.js +1525 -37
- package/dist/src/strategies/autobiographical.js.map +1 -1
- package/dist/src/strategies/index.d.ts +1 -1
- package/dist/src/strategies/index.d.ts.map +1 -1
- package/dist/src/strategies/index.js.map +1 -1
- package/dist/src/types/message.d.ts +38 -0
- package/dist/src/types/message.d.ts.map +1 -1
- package/dist/src/types/strategy.d.ts +106 -10
- package/dist/src/types/strategy.d.ts.map +1 -1
- package/dist/src/types/strategy.js +7 -0
- package/dist/src/types/strategy.js.map +1 -1
- package/dist/test/adaptive/branching.test.d.ts +20 -0
- package/dist/test/adaptive/branching.test.d.ts.map +1 -0
- package/dist/test/adaptive/branching.test.js +176 -0
- package/dist/test/adaptive/branching.test.js.map +1 -0
- package/dist/test/adaptive/chunker.test.d.ts +2 -0
- package/dist/test/adaptive/chunker.test.d.ts.map +1 -0
- package/dist/test/adaptive/chunker.test.js +120 -0
- package/dist/test/adaptive/chunker.test.js.map +1 -0
- package/dist/test/adaptive/deep-levels.test.d.ts +10 -0
- package/dist/test/adaptive/deep-levels.test.d.ts.map +1 -0
- package/dist/test/adaptive/deep-levels.test.js +167 -0
- package/dist/test/adaptive/deep-levels.test.js.map +1 -0
- package/dist/test/adaptive/doc-plus-chat.test.d.ts +10 -0
- package/dist/test/adaptive/doc-plus-chat.test.d.ts.map +1 -0
- package/dist/test/adaptive/doc-plus-chat.test.js +194 -0
- package/dist/test/adaptive/doc-plus-chat.test.js.map +1 -0
- package/dist/test/adaptive/hard-fail.test.d.ts +9 -0
- package/dist/test/adaptive/hard-fail.test.d.ts.map +1 -0
- package/dist/test/adaptive/hard-fail.test.js +154 -0
- package/dist/test/adaptive/hard-fail.test.js.map +1 -0
- package/dist/test/adaptive/harness.d.ts +109 -0
- package/dist/test/adaptive/harness.d.ts.map +1 -0
- package/dist/test/adaptive/harness.js +263 -0
- package/dist/test/adaptive/harness.js.map +1 -0
- package/dist/test/adaptive/ingestion.test.d.ts +13 -0
- package/dist/test/adaptive/ingestion.test.d.ts.map +1 -0
- package/dist/test/adaptive/ingestion.test.js +306 -0
- package/dist/test/adaptive/ingestion.test.js.map +1 -0
- package/dist/test/adaptive/integration.test.d.ts +12 -0
- package/dist/test/adaptive/integration.test.d.ts.map +1 -0
- package/dist/test/adaptive/integration.test.js +247 -0
- package/dist/test/adaptive/integration.test.js.map +1 -0
- package/dist/test/adaptive/long-chronicle.test.d.ts +13 -0
- package/dist/test/adaptive/long-chronicle.test.d.ts.map +1 -0
- package/dist/test/adaptive/long-chronicle.test.js +186 -0
- package/dist/test/adaptive/long-chronicle.test.js.map +1 -0
- package/dist/test/adaptive/persistence.test.d.ts +11 -0
- package/dist/test/adaptive/persistence.test.d.ts.map +1 -0
- package/dist/test/adaptive/persistence.test.js +200 -0
- package/dist/test/adaptive/persistence.test.js.map +1 -0
- package/dist/test/adaptive/picker.test.d.ts +2 -0
- package/dist/test/adaptive/picker.test.d.ts.map +1 -0
- package/dist/test/adaptive/picker.test.js +333 -0
- package/dist/test/adaptive/picker.test.js.map +1 -0
- package/dist/test/adaptive/render.test.d.ts +2 -0
- package/dist/test/adaptive/render.test.d.ts.map +1 -0
- package/dist/test/adaptive/render.test.js +109 -0
- package/dist/test/adaptive/render.test.js.map +1 -0
- package/dist/test/adaptive/shard-immutability.test.d.ts +14 -0
- package/dist/test/adaptive/shard-immutability.test.d.ts.map +1 -0
- package/dist/test/adaptive/shard-immutability.test.js +184 -0
- package/dist/test/adaptive/shard-immutability.test.js.map +1 -0
- package/dist/test/adaptive/strategy-integration.test.d.ts +9 -0
- package/dist/test/adaptive/strategy-integration.test.d.ts.map +1 -0
- package/dist/test/adaptive/strategy-integration.test.js +293 -0
- package/dist/test/adaptive/strategy-integration.test.js.map +1 -0
- package/dist/test/message-store-sequence.test.d.ts +25 -0
- package/dist/test/message-store-sequence.test.d.ts.map +1 -0
- package/dist/test/message-store-sequence.test.js +157 -0
- package/dist/test/message-store-sequence.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/adaptive/chunker.ts +323 -0
- package/src/adaptive/folding-strategy.ts +129 -0
- package/src/adaptive/index.ts +51 -0
- package/src/adaptive/picker.ts +442 -0
- package/src/adaptive/render.ts +115 -0
- package/src/adaptive/strategies/flat-profile.ts +96 -0
- package/src/adaptive/strategies/oldest-first.ts +48 -0
- package/src/context-manager.ts +32 -0
- package/src/index.ts +1 -1
- package/src/message-store.ts +147 -8
- package/src/strategies/autobiographical.ts +1635 -38
- package/src/strategies/index.ts +1 -1
- package/src/types/message.ts +43 -0
- package/src/types/strategy.ts +122 -10
package/src/context-manager.ts
CHANGED
|
@@ -211,6 +211,11 @@ export class ContextManager {
|
|
|
211
211
|
|
|
212
212
|
/**
|
|
213
213
|
* Add a message to the store.
|
|
214
|
+
*
|
|
215
|
+
* If the configured strategy implements `chunkIngressMessage` and returns
|
|
216
|
+
* a non-null sharding decision, the message is stored as multiple records
|
|
217
|
+
* sharing a `bodyGroupId` (per the adaptive-resolution design §3.6). The
|
|
218
|
+
* returned MessageId is the first shard's id.
|
|
214
219
|
*/
|
|
215
220
|
addMessage(
|
|
216
221
|
participant: string,
|
|
@@ -218,6 +223,33 @@ export class ContextManager {
|
|
|
218
223
|
metadata?: MessageMetadata,
|
|
219
224
|
causedBy?: MessageId[]
|
|
220
225
|
): MessageId {
|
|
226
|
+
// Optional strategy-driven ingestion-time chunking
|
|
227
|
+
const strategyAny = this.strategy as unknown as {
|
|
228
|
+
chunkIngressMessage?: (
|
|
229
|
+
participant: string,
|
|
230
|
+
content: ContentBlock[]
|
|
231
|
+
) => { bodyGroupId: string; shards: Array<{ content: ContentBlock[]; shardIndex: number }> } | null;
|
|
232
|
+
};
|
|
233
|
+
if (typeof strategyAny.chunkIngressMessage === 'function') {
|
|
234
|
+
const decision = strategyAny.chunkIngressMessage(participant, content);
|
|
235
|
+
if (decision && decision.shards.length > 1) {
|
|
236
|
+
let firstId: MessageId | null = null;
|
|
237
|
+
for (const shard of decision.shards) {
|
|
238
|
+
const message = this.messageStore.append(
|
|
239
|
+
participant,
|
|
240
|
+
shard.content,
|
|
241
|
+
metadata,
|
|
242
|
+
causedBy,
|
|
243
|
+
{
|
|
244
|
+
bodyGroupId: decision.bodyGroupId,
|
|
245
|
+
shardIndex: shard.shardIndex,
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
if (firstId === null) firstId = message.id;
|
|
249
|
+
}
|
|
250
|
+
return firstId!;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
221
253
|
const message = this.messageStore.append(participant, content, metadata, causedBy);
|
|
222
254
|
return message.id;
|
|
223
255
|
}
|
package/src/index.ts
CHANGED
|
@@ -10,7 +10,7 @@ export { BlobManager } from './blob-manager.js';
|
|
|
10
10
|
|
|
11
11
|
// Strategies
|
|
12
12
|
export { PassthroughStrategy } from './strategies/passthrough.js';
|
|
13
|
-
export { AutobiographicalStrategy } from './strategies/autobiographical.js';
|
|
13
|
+
export { AutobiographicalStrategy, type AutobiographicalProgressSnapshot } from './strategies/autobiographical.js';
|
|
14
14
|
export { KnowledgeStrategy } from './strategies/knowledge.js';
|
|
15
15
|
|
|
16
16
|
// Types
|
package/src/message-store.ts
CHANGED
|
@@ -101,14 +101,31 @@ export class MessageStore {
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Optional extra fields for `append`, used by callers that need to set
|
|
106
|
+
* adaptive-resolution metadata (bodyGroupId for shards, initial
|
|
107
|
+
* resolution state, etc.) at ingestion time.
|
|
108
|
+
*/
|
|
109
|
+
static readonly _appendExtraKeys = ['bodyGroupId', 'shardIndex', 'currentResolution', 'lockedByAgent'] as const;
|
|
110
|
+
|
|
104
111
|
/**
|
|
105
112
|
* Append a new message to the store.
|
|
113
|
+
*
|
|
114
|
+
* `extra` is an optional bag of adaptive-resolution metadata
|
|
115
|
+
* (bodyGroupId / shardIndex / currentResolution / lockedByAgent) that
|
|
116
|
+
* callers may set at ingestion. Field semantics match StoredMessage.
|
|
106
117
|
*/
|
|
107
118
|
append(
|
|
108
119
|
participant: string,
|
|
109
120
|
content: ContentBlock[],
|
|
110
121
|
metadata?: MessageMetadata,
|
|
111
|
-
causedBy?: MessageId[]
|
|
122
|
+
causedBy?: MessageId[],
|
|
123
|
+
extra?: {
|
|
124
|
+
bodyGroupId?: string;
|
|
125
|
+
shardIndex?: number;
|
|
126
|
+
currentResolution?: number;
|
|
127
|
+
lockedByAgent?: boolean;
|
|
128
|
+
}
|
|
112
129
|
): StoredMessage {
|
|
113
130
|
// Extract blobs from content
|
|
114
131
|
const storedContent = this.blobManager.extractBlobs(content);
|
|
@@ -120,28 +137,54 @@ export class MessageStore {
|
|
|
120
137
|
metadata,
|
|
121
138
|
timestamp: Date.now(),
|
|
122
139
|
causedBy,
|
|
140
|
+
...(extra ?? {}),
|
|
123
141
|
};
|
|
124
142
|
|
|
125
143
|
const record = this.store.appendToStateJson(this.stateId, partialInternal);
|
|
126
144
|
const index = this.length() - 1;
|
|
127
145
|
|
|
128
|
-
//
|
|
146
|
+
// The append's payload doesn't carry the chronicle record's id /
|
|
147
|
+
// sequence — those are only known once the append returns. We patch
|
|
148
|
+
// them in via editStateItem below. The patch creates a new chronicle
|
|
149
|
+
// record at `record.sequence + 1` (the next sequence; nothing else
|
|
150
|
+
// writes between the append and the edit inside this function).
|
|
151
|
+
//
|
|
152
|
+
// We store the EDIT'S sequence (not the original append's) as the
|
|
153
|
+
// canonical "this message is fully readable at and after this seq"
|
|
154
|
+
// marker. Why: `ContextManager.branchAt(messageId)` forwards
|
|
155
|
+
// `message.sequence` to `chronicle.createBranchAt`, which forks
|
|
156
|
+
// visibility at that exact seq. If `sequence` pointed at the original
|
|
157
|
+
// append (record.sequence), the new branch would see the pre-patch
|
|
158
|
+
// payload (id/sequence undefined). Pointing at the edit's seq
|
|
159
|
+
// includes the patched payload in the inherited records — so a
|
|
160
|
+
// forked branch sees this message in its fully-established form.
|
|
161
|
+
//
|
|
162
|
+
// Invariant: this function does exactly ONE chronicle write between
|
|
163
|
+
// the append and the edit (the edit itself). If that ever changes,
|
|
164
|
+
// the +1 expression must be updated to match (or refactored to
|
|
165
|
+
// capture editStateItem's returned record.sequence — which is
|
|
166
|
+
// chicken-and-egg here since we need the value inside the payload
|
|
167
|
+
// we're writing).
|
|
168
|
+
const commitSequence = record.sequence + 1;
|
|
129
169
|
const fullInternal: StoredMessageInternal = {
|
|
130
170
|
id: record.id,
|
|
131
|
-
sequence:
|
|
171
|
+
sequence: commitSequence,
|
|
132
172
|
...partialInternal,
|
|
133
173
|
};
|
|
134
174
|
this.store.editStateItem(this.stateId, index, Buffer.from(JSON.stringify(fullInternal)));
|
|
135
175
|
|
|
136
|
-
// Build full message with ID and sequence from record
|
|
176
|
+
// Build full message with ID and sequence from record. The sequence
|
|
177
|
+
// we expose is the commit sequence (matches what's stored), so
|
|
178
|
+
// `branchAt(messageId)` forks at the right place for any caller.
|
|
137
179
|
const message: StoredMessage = {
|
|
138
180
|
id: record.id,
|
|
139
|
-
sequence:
|
|
181
|
+
sequence: commitSequence,
|
|
140
182
|
participant,
|
|
141
183
|
content, // Original content with inline data
|
|
142
184
|
metadata,
|
|
143
185
|
timestamp: new Date(partialInternal.timestamp),
|
|
144
186
|
causedBy,
|
|
187
|
+
...(extra ?? {}),
|
|
145
188
|
};
|
|
146
189
|
|
|
147
190
|
// Update index
|
|
@@ -153,6 +196,11 @@ export class MessageStore {
|
|
|
153
196
|
|
|
154
197
|
/**
|
|
155
198
|
* Edit a message's content.
|
|
199
|
+
*
|
|
200
|
+
* Throws if `messageId` belongs to a bodyGroup (i.e., is a shard of a
|
|
201
|
+
* larger sharded message). Editing one shard would silently corrupt the
|
|
202
|
+
* bodyGroup's byte-faithful reassembly invariant. To replace a sharded
|
|
203
|
+
* message, remove the whole bodyGroup and re-append.
|
|
156
204
|
*/
|
|
157
205
|
edit(messageId: MessageId, newContent: ContentBlock[]): void {
|
|
158
206
|
const index = this.idToIndex.get(messageId);
|
|
@@ -165,6 +213,13 @@ export class MessageStore {
|
|
|
165
213
|
throw new Error(`Message not found at index: ${index}`);
|
|
166
214
|
}
|
|
167
215
|
|
|
216
|
+
if (oldMessage.bodyGroupId) {
|
|
217
|
+
throw new Error(
|
|
218
|
+
`Cannot edit shard ${messageId}: it is part of bodyGroup ${oldMessage.bodyGroupId}. ` +
|
|
219
|
+
`Sharded messages are immutable — remove the whole bodyGroup and re-append instead.`,
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
168
223
|
const oldContent = this.blobManager.resolveBlobs(oldMessage.content);
|
|
169
224
|
const storedContent = this.blobManager.extractBlobs(newContent);
|
|
170
225
|
|
|
@@ -181,6 +236,11 @@ export class MessageStore {
|
|
|
181
236
|
|
|
182
237
|
/**
|
|
183
238
|
* Remove a message from the store.
|
|
239
|
+
*
|
|
240
|
+
* For a sharded message (one shard of a bodyGroup), the caller MUST
|
|
241
|
+
* remove all shards in the group together — removing one shard would
|
|
242
|
+
* orphan the rest and break byte-faithful reassembly. Use
|
|
243
|
+
* `removeBodyGroup(id)` for that case.
|
|
184
244
|
*/
|
|
185
245
|
remove(messageId: MessageId): void {
|
|
186
246
|
const index = this.idToIndex.get(messageId);
|
|
@@ -188,14 +248,61 @@ export class MessageStore {
|
|
|
188
248
|
throw new Error(`Message not found: ${messageId}`);
|
|
189
249
|
}
|
|
190
250
|
|
|
251
|
+
const target = this.getInternal(index);
|
|
252
|
+
if (target?.bodyGroupId) {
|
|
253
|
+
throw new Error(
|
|
254
|
+
`Cannot remove shard ${messageId} in isolation: it is part of bodyGroup ${target.bodyGroupId}. ` +
|
|
255
|
+
`Use removeBodyGroup(${messageId}) to remove all shards atomically.`,
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
191
259
|
this.store.redactStateItems(this.stateId, index, index + 1);
|
|
192
260
|
this.rebuildIndex();
|
|
193
261
|
|
|
194
262
|
this.emit({ type: 'remove', messageId });
|
|
195
263
|
}
|
|
196
264
|
|
|
265
|
+
/**
|
|
266
|
+
* Remove every shard of the bodyGroup containing `messageId`. If the
|
|
267
|
+
* message is not part of a bodyGroup, falls back to single-message
|
|
268
|
+
* remove. Atomic from the caller's perspective.
|
|
269
|
+
*/
|
|
270
|
+
removeBodyGroup(messageId: MessageId): void {
|
|
271
|
+
const index = this.idToIndex.get(messageId);
|
|
272
|
+
if (index === undefined) {
|
|
273
|
+
throw new Error(`Message not found: ${messageId}`);
|
|
274
|
+
}
|
|
275
|
+
const target = this.getInternal(index);
|
|
276
|
+
if (!target?.bodyGroupId) {
|
|
277
|
+
// Not sharded — defer to normal remove path (re-look up via getInternal
|
|
278
|
+
// since the normal `remove` checks bodyGroupId).
|
|
279
|
+
this.store.redactStateItems(this.stateId, index, index + 1);
|
|
280
|
+
this.rebuildIndex();
|
|
281
|
+
this.emit({ type: 'remove', messageId });
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
// Find the contiguous run of shards with this bodyGroupId. Shards are
|
|
285
|
+
// stored consecutively (they're appended one after the other at
|
|
286
|
+
// ingestion), so we can scan outward from `index`.
|
|
287
|
+
const groupId = target.bodyGroupId;
|
|
288
|
+
const all = this.getAllInternal();
|
|
289
|
+
let from = index;
|
|
290
|
+
while (from > 0 && all[from - 1].bodyGroupId === groupId) from--;
|
|
291
|
+
let to = index;
|
|
292
|
+
while (to + 1 < all.length && all[to + 1].bodyGroupId === groupId) to++;
|
|
293
|
+
const firstId = all[from].id;
|
|
294
|
+
const lastId = all[to].id;
|
|
295
|
+
this.store.redactStateItems(this.stateId, from, to + 1);
|
|
296
|
+
this.rebuildIndex();
|
|
297
|
+
this.emit({ type: 'removeRange', fromId: firstId, toId: lastId });
|
|
298
|
+
}
|
|
299
|
+
|
|
197
300
|
/**
|
|
198
301
|
* Remove a range of messages from the store.
|
|
302
|
+
*
|
|
303
|
+
* If the range starts or ends in the middle of a bodyGroup, throws —
|
|
304
|
+
* removeRange must align to bodyGroup boundaries. (Use `removeBodyGroup`
|
|
305
|
+
* to remove an entire group, then call `removeRange` over plain messages.)
|
|
199
306
|
*/
|
|
200
307
|
removeRange(fromId: MessageId, toId: MessageId): void {
|
|
201
308
|
const fromIndex = this.idToIndex.get(fromId);
|
|
@@ -208,6 +315,21 @@ export class MessageStore {
|
|
|
208
315
|
throw new Error(`Message not found: ${toId}`);
|
|
209
316
|
}
|
|
210
317
|
|
|
318
|
+
// Verify the range doesn't bisect a bodyGroup.
|
|
319
|
+
const all = this.getAllInternal();
|
|
320
|
+
const startGroup = all[fromIndex].bodyGroupId;
|
|
321
|
+
const endGroup = all[toIndex].bodyGroupId;
|
|
322
|
+
if (startGroup && fromIndex > 0 && all[fromIndex - 1].bodyGroupId === startGroup) {
|
|
323
|
+
throw new Error(
|
|
324
|
+
`removeRange would bisect bodyGroup ${startGroup} at start. Use removeBodyGroup(${fromId}) first.`,
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
if (endGroup && toIndex + 1 < all.length && all[toIndex + 1].bodyGroupId === endGroup) {
|
|
328
|
+
throw new Error(
|
|
329
|
+
`removeRange would bisect bodyGroup ${endGroup} at end. Use removeBodyGroup(${toId}) first.`,
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
211
333
|
this.store.redactStateItems(this.stateId, fromIndex, toIndex + 1);
|
|
212
334
|
this.rebuildIndex();
|
|
213
335
|
|
|
@@ -457,17 +579,34 @@ export class MessageStore {
|
|
|
457
579
|
private internalToStored(
|
|
458
580
|
internal: StoredMessageInternal,
|
|
459
581
|
id: MessageId,
|
|
460
|
-
|
|
582
|
+
_index: number,
|
|
461
583
|
): StoredMessage {
|
|
462
|
-
|
|
584
|
+
const stored: StoredMessage = {
|
|
463
585
|
id,
|
|
464
|
-
|
|
586
|
+
// chronicle record sequence captured when the message was appended
|
|
587
|
+
// (see `add()` line 131: `sequence: record.sequence`). The previous
|
|
588
|
+
// implementation returned the slot index ("// Use index as sequence
|
|
589
|
+
// for now"), which silently corrupted any downstream code that
|
|
590
|
+
// forwarded this number to chronicle APIs expecting a real sequence
|
|
591
|
+
// — most notably `ContextManager.branchAt`, which would fork the
|
|
592
|
+
// chronicle at the index-mistaken-for-sequence and lose every
|
|
593
|
+
// record between the intended fork point and the actual one. For
|
|
594
|
+
// typical autobio sessions the index-vs-sequence ratio is ~1:2
|
|
595
|
+
// (each message append is accompanied by ~1 autobio state update),
|
|
596
|
+
// so /undo of a 800-message conversation forked ~400 messages back.
|
|
597
|
+
sequence: internal.sequence,
|
|
465
598
|
participant: internal.participant,
|
|
466
599
|
content: this.blobManager.resolveBlobs(internal.content),
|
|
467
600
|
metadata: internal.metadata,
|
|
468
601
|
timestamp: new Date(internal.timestamp),
|
|
469
602
|
causedBy: internal.causedBy,
|
|
470
603
|
};
|
|
604
|
+
// Carry adaptive-resolution fields through unchanged.
|
|
605
|
+
if (internal.bodyGroupId !== undefined) stored.bodyGroupId = internal.bodyGroupId;
|
|
606
|
+
if (internal.shardIndex !== undefined) stored.shardIndex = internal.shardIndex;
|
|
607
|
+
if (internal.currentResolution !== undefined) stored.currentResolution = internal.currentResolution;
|
|
608
|
+
if (internal.lockedByAgent !== undefined) stored.lockedByAgent = internal.lockedByAgent;
|
|
609
|
+
return stored;
|
|
471
610
|
}
|
|
472
611
|
}
|
|
473
612
|
|