opencode-lcm 0.13.2 → 0.13.4
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/CHANGELOG.md +13 -0
- package/dist/store-artifacts.js +3 -3
- package/dist/store-search.js +3 -3
- package/dist/store.js +47 -22
- package/package.json +1 -1
- package/src/store-artifacts.ts +3 -3
- package/src/store-search.ts +9 -3
- package/src/store.ts +62 -29
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.13.4] - 2026-04-09
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Publish validation now keeps the Bun-on-Windows lightweight capture regression test portable across non-Windows CI runners
|
|
14
|
+
- Republish the current malformed-message and Bun Windows capture fixes to npm after the failed 0.13.3 release check
|
|
15
|
+
|
|
16
|
+
## [0.13.3] - 2026-04-09
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- Bun on Windows now tolerates part-update capture when the parent message has not been materialized yet
|
|
20
|
+
- Additional malformed-message hardening now covers `message.info.time.created` reads and grep scan fallback paths
|
|
21
|
+
- Restored CI-clean formatting after the PR #5 merge so release validation and publish can complete
|
|
22
|
+
|
|
10
23
|
## [0.13.2] - 2026-04-08
|
|
11
24
|
|
|
12
25
|
### Fixed
|
package/dist/store-artifacts.js
CHANGED
|
@@ -273,7 +273,7 @@ export async function externalizeMessage(bindings, message) {
|
|
|
273
273
|
const storedInfo = parseJson(JSON.stringify(message.info));
|
|
274
274
|
const storedParts = [];
|
|
275
275
|
for (const part of message.parts) {
|
|
276
|
-
const { storedPart, artifacts: nextArtifacts } = await externalizePart(bindings, part, message.info
|
|
276
|
+
const { storedPart, artifacts: nextArtifacts } = await externalizePart(bindings, part, message.info?.time?.created ?? 0);
|
|
277
277
|
artifacts.push(...nextArtifacts);
|
|
278
278
|
storedParts.push(storedPart);
|
|
279
279
|
}
|
|
@@ -292,7 +292,7 @@ export async function externalizeSession(bindings, session) {
|
|
|
292
292
|
const storedInfo = parseJson(JSON.stringify(message.info));
|
|
293
293
|
const storedParts = [];
|
|
294
294
|
for (const part of message.parts) {
|
|
295
|
-
const { storedPart, artifacts: nextArtifacts } = await externalizePart(bindings, part, message.info
|
|
295
|
+
const { storedPart, artifacts: nextArtifacts } = await externalizePart(bindings, part, message.info?.time?.created ?? 0);
|
|
296
296
|
artifacts.push(...nextArtifacts);
|
|
297
297
|
storedParts.push(storedPart);
|
|
298
298
|
}
|
|
@@ -335,7 +335,7 @@ export function persistStoredSessionSync(bindings, storedSession, artifacts) {
|
|
|
335
335
|
const insertMessage = db.prepare('INSERT INTO messages (message_id, session_id, created_at, info_json) VALUES (?, ?, ?, ?)');
|
|
336
336
|
const insertPart = db.prepare('INSERT INTO parts (part_id, session_id, message_id, sort_key, part_json) VALUES (?, ?, ?, ?, ?)');
|
|
337
337
|
for (const message of storedSession.messages) {
|
|
338
|
-
insertMessage.run(message.info.id, storedSession.sessionID, message.info
|
|
338
|
+
insertMessage.run(message.info.id, storedSession.sessionID, message.info?.time?.created ?? 0, JSON.stringify(message.info));
|
|
339
339
|
message.parts.forEach((part, index) => {
|
|
340
340
|
insertPart.run(part.id, storedSession.sessionID, part.messageID, index, JSON.stringify(part));
|
|
341
341
|
});
|
package/dist/store-search.js
CHANGED
|
@@ -202,7 +202,7 @@ export function searchByScan(deps, query, sessionIDs, limit = 5) {
|
|
|
202
202
|
id: message.info.id,
|
|
203
203
|
type: message.info.role,
|
|
204
204
|
sessionID: session.sessionID,
|
|
205
|
-
timestamp: message.info
|
|
205
|
+
timestamp: message.info?.time?.created ?? 0,
|
|
206
206
|
snippet: buildSnippet(blob, query),
|
|
207
207
|
content: blob,
|
|
208
208
|
sourceKind: 'message',
|
|
@@ -255,7 +255,7 @@ function insertMessageSearchRowsSync(deps, session) {
|
|
|
255
255
|
const content = deps.guessMessageText(message, deps.ignoreToolPrefixes);
|
|
256
256
|
if (!content)
|
|
257
257
|
continue;
|
|
258
|
-
insert.run(session.sessionID, message.info.id, message.info.role, String(message.info
|
|
258
|
+
insert.run(session.sessionID, message.info.id, message.info.role, String(message.info?.time?.created ?? 0), content);
|
|
259
259
|
}
|
|
260
260
|
}
|
|
261
261
|
export function replaceMessageSearchRowSync(deps, sessionID, message) {
|
|
@@ -264,7 +264,7 @@ export function replaceMessageSearchRowSync(deps, sessionID, message) {
|
|
|
264
264
|
const content = deps.guessMessageText(message, deps.ignoreToolPrefixes);
|
|
265
265
|
if (!content)
|
|
266
266
|
return;
|
|
267
|
-
db.prepare('INSERT INTO message_fts (session_id, message_id, role, created_at, content) VALUES (?, ?, ?, ?, ?)').run(sessionID, message.info.id, message.info.role, String(message.info
|
|
267
|
+
db.prepare('INSERT INTO message_fts (session_id, message_id, role, created_at, content) VALUES (?, ?, ?, ?, ?)').run(sessionID, message.info.id, message.info.role, String(message.info?.time?.created ?? 0), content);
|
|
268
268
|
}
|
|
269
269
|
export function replaceSummarySearchRowsSync(deps, sessionIDs) {
|
|
270
270
|
const db = deps.getDb();
|
package/dist/store.js
CHANGED
|
@@ -417,6 +417,13 @@ export function resolveCaptureHydrationMode(options) {
|
|
|
417
417
|
// hydration there until Bun/Windows is proven stable again.
|
|
418
418
|
return isBunRuntime && platform === 'win32' ? 'full' : 'targeted';
|
|
419
419
|
}
|
|
420
|
+
function shouldUseLightweightPartCapture(event, options) {
|
|
421
|
+
const isBunRuntime = options?.isBunRuntime ?? (typeof globalThis === 'object' && 'Bun' in globalThis);
|
|
422
|
+
const platform = options?.platform ?? process.platform;
|
|
423
|
+
if (!isBunRuntime || platform !== 'win32')
|
|
424
|
+
return false;
|
|
425
|
+
return event.type === 'message.part.updated' || event.type === 'message.part.removed';
|
|
426
|
+
}
|
|
420
427
|
function isSqliteRuntimeImportError(runtime, error) {
|
|
421
428
|
const code = typeof error === 'object' && error && 'code' in error && typeof error.code === 'string'
|
|
422
429
|
? error.code
|
|
@@ -970,9 +977,11 @@ export class SqliteLcmStore {
|
|
|
970
977
|
}
|
|
971
978
|
if (!normalized.sessionID || !shouldPersistSession)
|
|
972
979
|
return;
|
|
973
|
-
const session =
|
|
974
|
-
? this.readSessionForCaptureSync(normalized)
|
|
975
|
-
:
|
|
980
|
+
const session = shouldUseLightweightPartCapture(normalized)
|
|
981
|
+
? this.readSessionForCaptureSync(normalized, { hydrateArtifacts: false })
|
|
982
|
+
: resolveCaptureHydrationMode() === 'targeted'
|
|
983
|
+
? this.readSessionForCaptureSync(normalized)
|
|
984
|
+
: this.readSessionSync(normalized.sessionID);
|
|
976
985
|
const previousParentSessionID = session.parentSessionID;
|
|
977
986
|
const shouldSyncDerivedState = this.shouldSyncDerivedSessionStateForEvent(session, normalized);
|
|
978
987
|
let next = this.applyEvent(session, normalized);
|
|
@@ -1253,7 +1262,7 @@ export class SqliteLcmStore {
|
|
|
1253
1262
|
issues.push('unexpected-summary-edges');
|
|
1254
1263
|
return issues.length > 0 ? { sessionID: session.sessionID, issues } : undefined;
|
|
1255
1264
|
}
|
|
1256
|
-
const latestMessageCreated = archived.at(-1)?.info
|
|
1265
|
+
const latestMessageCreated = archived.at(-1)?.info?.time?.created ?? 0;
|
|
1257
1266
|
const archivedSignature = this.buildArchivedSignature(archived);
|
|
1258
1267
|
const rootIDs = state ? parseJson(state.root_node_ids_json) : [];
|
|
1259
1268
|
const roots = rootIDs
|
|
@@ -1364,7 +1373,7 @@ export class SqliteLcmStore {
|
|
|
1364
1373
|
case 'message.updated': {
|
|
1365
1374
|
const existing = session.messages.find((message) => message.info.id === payload.properties.info.id);
|
|
1366
1375
|
if (existing) {
|
|
1367
|
-
return this.isMessageArchivedSync(session.sessionID, existing.info.id, existing.info
|
|
1376
|
+
return this.isMessageArchivedSync(session.sessionID, existing.info.id, existing.info?.time?.created ?? 0);
|
|
1368
1377
|
}
|
|
1369
1378
|
return this.readMessageCountSync(session.sessionID) >= this.options.freshTailMessages;
|
|
1370
1379
|
}
|
|
@@ -1378,13 +1387,13 @@ export class SqliteLcmStore {
|
|
|
1378
1387
|
const message = session.messages.find((entry) => entry.info.id === payload.properties.part.messageID);
|
|
1379
1388
|
if (!message)
|
|
1380
1389
|
return false;
|
|
1381
|
-
return this.isMessageArchivedSync(session.sessionID, message.info.id, message.info
|
|
1390
|
+
return this.isMessageArchivedSync(session.sessionID, message.info.id, message.info?.time?.created ?? 0);
|
|
1382
1391
|
}
|
|
1383
1392
|
case 'message.part.removed': {
|
|
1384
1393
|
const message = session.messages.find((entry) => entry.info.id === payload.properties.messageID);
|
|
1385
1394
|
if (!message)
|
|
1386
1395
|
return false;
|
|
1387
|
-
return this.isMessageArchivedSync(session.sessionID, message.info.id, message.info
|
|
1396
|
+
return this.isMessageArchivedSync(session.sessionID, message.info.id, message.info?.time?.created ?? 0);
|
|
1388
1397
|
}
|
|
1389
1398
|
default:
|
|
1390
1399
|
return false;
|
|
@@ -2744,7 +2753,7 @@ export class SqliteLcmStore {
|
|
|
2744
2753
|
for (const message of messages) {
|
|
2745
2754
|
hash.update(message.info.id);
|
|
2746
2755
|
hash.update(message.info.role);
|
|
2747
|
-
hash.update(String(message.info
|
|
2756
|
+
hash.update(String(message.info?.time?.created ?? 0));
|
|
2748
2757
|
hash.update(guessMessageText(message, this.options.interop.ignoreToolPrefixes));
|
|
2749
2758
|
hash.update(JSON.stringify(listFiles(message)));
|
|
2750
2759
|
hash.update(JSON.stringify(this.listTools([message])));
|
|
@@ -2768,7 +2777,7 @@ export class SqliteLcmStore {
|
|
|
2768
2777
|
this.clearSummaryGraphSync(sessionID);
|
|
2769
2778
|
return [];
|
|
2770
2779
|
}
|
|
2771
|
-
const latestMessageCreated = archivedMessages.at(-1)?.info
|
|
2780
|
+
const latestMessageCreated = archivedMessages.at(-1)?.info?.time?.created ?? 0;
|
|
2772
2781
|
const archivedSignature = this.buildArchivedSignature(archivedMessages);
|
|
2773
2782
|
const state = safeQueryOne(this.getDb().prepare('SELECT * FROM summary_state WHERE session_id = ?'), [sessionID], 'ensureSummaryGraphSync');
|
|
2774
2783
|
if (state &&
|
|
@@ -2932,7 +2941,7 @@ export class SqliteLcmStore {
|
|
|
2932
2941
|
latest_message_created = excluded.latest_message_created,
|
|
2933
2942
|
archived_signature = excluded.archived_signature,
|
|
2934
2943
|
root_node_ids_json = excluded.root_node_ids_json,
|
|
2935
|
-
updated_at = excluded.updated_at`).run(sessionID, archivedMessages.length, archivedMessages.at(-1)?.info
|
|
2944
|
+
updated_at = excluded.updated_at`).run(sessionID, archivedMessages.length, archivedMessages.at(-1)?.info?.time?.created ?? 0, archivedSignature, JSON.stringify(roots.map((node) => node.nodeID)), now);
|
|
2936
2945
|
});
|
|
2937
2946
|
return roots;
|
|
2938
2947
|
}
|
|
@@ -3639,7 +3648,7 @@ export class SqliteLcmStore {
|
|
|
3639
3648
|
}
|
|
3640
3649
|
return parentSessionID;
|
|
3641
3650
|
}
|
|
3642
|
-
readSessionForCaptureSync(event) {
|
|
3651
|
+
readSessionForCaptureSync(event, options) {
|
|
3643
3652
|
const sessionID = event.sessionID;
|
|
3644
3653
|
if (!sessionID)
|
|
3645
3654
|
return emptySession('');
|
|
@@ -3647,19 +3656,19 @@ export class SqliteLcmStore {
|
|
|
3647
3656
|
const payload = event.payload;
|
|
3648
3657
|
switch (payload.type) {
|
|
3649
3658
|
case 'message.updated': {
|
|
3650
|
-
const message = this.readMessageSync(sessionID, payload.properties.info.id);
|
|
3659
|
+
const message = this.readMessageSync(sessionID, payload.properties.info.id, options);
|
|
3651
3660
|
if (message)
|
|
3652
3661
|
session.messages = [message];
|
|
3653
3662
|
return session;
|
|
3654
3663
|
}
|
|
3655
3664
|
case 'message.part.updated': {
|
|
3656
|
-
const message = this.readMessageSync(sessionID, payload.properties.part.messageID);
|
|
3665
|
+
const message = this.readMessageSync(sessionID, payload.properties.part.messageID, options);
|
|
3657
3666
|
if (message)
|
|
3658
3667
|
session.messages = [message];
|
|
3659
3668
|
return session;
|
|
3660
3669
|
}
|
|
3661
3670
|
case 'message.part.removed': {
|
|
3662
|
-
const message = this.readMessageSync(sessionID, payload.properties.messageID);
|
|
3671
|
+
const message = this.readMessageSync(sessionID, payload.properties.messageID, options);
|
|
3663
3672
|
if (message)
|
|
3664
3673
|
session.messages = [message];
|
|
3665
3674
|
return session;
|
|
@@ -3668,16 +3677,19 @@ export class SqliteLcmStore {
|
|
|
3668
3677
|
return session;
|
|
3669
3678
|
}
|
|
3670
3679
|
}
|
|
3671
|
-
readMessageSync(sessionID, messageID) {
|
|
3680
|
+
readMessageSync(sessionID, messageID, options) {
|
|
3672
3681
|
const db = this.getDb();
|
|
3673
3682
|
const row = safeQueryOne(db.prepare('SELECT * FROM messages WHERE session_id = ? AND message_id = ?'), [sessionID, messageID], 'readMessageSync');
|
|
3674
3683
|
if (!row)
|
|
3675
3684
|
return undefined;
|
|
3685
|
+
const hydrateArtifacts = options?.hydrateArtifacts ?? true;
|
|
3676
3686
|
const artifactsByPart = new Map();
|
|
3677
|
-
|
|
3678
|
-
const
|
|
3679
|
-
|
|
3680
|
-
|
|
3687
|
+
if (hydrateArtifacts) {
|
|
3688
|
+
for (const artifact of this.readArtifactsForMessageSync(messageID)) {
|
|
3689
|
+
const list = artifactsByPart.get(artifact.partID) ?? [];
|
|
3690
|
+
list.push(artifact);
|
|
3691
|
+
artifactsByPart.set(artifact.partID, list);
|
|
3692
|
+
}
|
|
3681
3693
|
}
|
|
3682
3694
|
const parts = db
|
|
3683
3695
|
.prepare('SELECT * FROM parts WHERE session_id = ? AND message_id = ? ORDER BY sort_key ASC, part_id ASC')
|
|
@@ -3694,7 +3706,8 @@ export class SqliteLcmStore {
|
|
|
3694
3706
|
info,
|
|
3695
3707
|
parts: parts.map((partRow) => {
|
|
3696
3708
|
const part = parseJson(partRow.part_json);
|
|
3697
|
-
|
|
3709
|
+
if (hydrateArtifacts)
|
|
3710
|
+
hydratePartFromArtifacts(part, artifactsByPart.get(part.id) ?? []);
|
|
3698
3711
|
return part;
|
|
3699
3712
|
}),
|
|
3700
3713
|
};
|
|
@@ -3744,22 +3757,34 @@ export class SqliteLcmStore {
|
|
|
3744
3757
|
return;
|
|
3745
3758
|
case 'message.part.updated': {
|
|
3746
3759
|
const message = session.messages.find((entry) => entry.info.id === payload.properties.part.messageID);
|
|
3760
|
+
const preservedArtifacts = message
|
|
3761
|
+
? this.readArtifactsForMessageSync(message.info.id).filter((artifact) => artifact.partID !== payload.properties.part.id)
|
|
3762
|
+
: [];
|
|
3747
3763
|
const externalized = message ? await this.externalizeMessage(message) : undefined;
|
|
3748
3764
|
withTransaction(this.getDb(), 'capture', () => {
|
|
3749
3765
|
this.upsertSessionRowSync(session);
|
|
3750
3766
|
if (externalized) {
|
|
3751
|
-
this.replaceStoredMessageSync(session.sessionID, externalized.storedMessage,
|
|
3767
|
+
this.replaceStoredMessageSync(session.sessionID, externalized.storedMessage, [
|
|
3768
|
+
...preservedArtifacts,
|
|
3769
|
+
...externalized.artifacts,
|
|
3770
|
+
]);
|
|
3752
3771
|
}
|
|
3753
3772
|
});
|
|
3754
3773
|
return;
|
|
3755
3774
|
}
|
|
3756
3775
|
case 'message.part.removed': {
|
|
3757
3776
|
const message = session.messages.find((entry) => entry.info.id === payload.properties.messageID);
|
|
3777
|
+
const preservedArtifacts = message
|
|
3778
|
+
? this.readArtifactsForMessageSync(message.info.id).filter((artifact) => artifact.partID !== payload.properties.partID)
|
|
3779
|
+
: [];
|
|
3758
3780
|
const externalized = message ? await this.externalizeMessage(message) : undefined;
|
|
3759
3781
|
withTransaction(this.getDb(), 'capture', () => {
|
|
3760
3782
|
this.upsertSessionRowSync(session);
|
|
3761
3783
|
if (externalized) {
|
|
3762
|
-
this.replaceStoredMessageSync(session.sessionID, externalized.storedMessage,
|
|
3784
|
+
this.replaceStoredMessageSync(session.sessionID, externalized.storedMessage, [
|
|
3785
|
+
...preservedArtifacts,
|
|
3786
|
+
...externalized.artifacts,
|
|
3787
|
+
]);
|
|
3763
3788
|
}
|
|
3764
3789
|
});
|
|
3765
3790
|
return;
|
package/package.json
CHANGED
package/src/store-artifacts.ts
CHANGED
|
@@ -479,7 +479,7 @@ export async function externalizeMessage(
|
|
|
479
479
|
const { storedPart, artifacts: nextArtifacts } = await externalizePart(
|
|
480
480
|
bindings,
|
|
481
481
|
part,
|
|
482
|
-
message.info
|
|
482
|
+
message.info?.time?.created ?? 0,
|
|
483
483
|
);
|
|
484
484
|
artifacts.push(...nextArtifacts);
|
|
485
485
|
storedParts.push(storedPart);
|
|
@@ -509,7 +509,7 @@ export async function externalizeSession(
|
|
|
509
509
|
const { storedPart, artifacts: nextArtifacts } = await externalizePart(
|
|
510
510
|
bindings,
|
|
511
511
|
part,
|
|
512
|
-
message.info
|
|
512
|
+
message.info?.time?.created ?? 0,
|
|
513
513
|
);
|
|
514
514
|
artifacts.push(...nextArtifacts);
|
|
515
515
|
storedParts.push(storedPart);
|
|
@@ -607,7 +607,7 @@ export function persistStoredSessionSync(
|
|
|
607
607
|
insertMessage.run(
|
|
608
608
|
message.info.id,
|
|
609
609
|
storedSession.sessionID,
|
|
610
|
-
message.info
|
|
610
|
+
message.info?.time?.created ?? 0,
|
|
611
611
|
JSON.stringify(message.info),
|
|
612
612
|
);
|
|
613
613
|
|
package/src/store-search.ts
CHANGED
|
@@ -296,7 +296,7 @@ export function searchByScan(
|
|
|
296
296
|
id: message.info.id,
|
|
297
297
|
type: message.info.role,
|
|
298
298
|
sessionID: session.sessionID,
|
|
299
|
-
timestamp: message.info
|
|
299
|
+
timestamp: message.info?.time?.created ?? 0,
|
|
300
300
|
snippet: buildSnippet(blob, query),
|
|
301
301
|
content: blob,
|
|
302
302
|
sourceKind: 'message',
|
|
@@ -361,7 +361,7 @@ function insertMessageSearchRowsSync(deps: FtsDeps, session: NormalizedSession):
|
|
|
361
361
|
session.sessionID,
|
|
362
362
|
message.info.id,
|
|
363
363
|
message.info.role,
|
|
364
|
-
String(message.info
|
|
364
|
+
String(message.info?.time?.created ?? 0),
|
|
365
365
|
content,
|
|
366
366
|
);
|
|
367
367
|
}
|
|
@@ -380,7 +380,13 @@ export function replaceMessageSearchRowSync(
|
|
|
380
380
|
|
|
381
381
|
db.prepare(
|
|
382
382
|
'INSERT INTO message_fts (session_id, message_id, role, created_at, content) VALUES (?, ?, ?, ?, ?)',
|
|
383
|
-
).run(
|
|
383
|
+
).run(
|
|
384
|
+
sessionID,
|
|
385
|
+
message.info.id,
|
|
386
|
+
message.info.role,
|
|
387
|
+
String(message.info?.time?.created ?? 0),
|
|
388
|
+
content,
|
|
389
|
+
);
|
|
384
390
|
}
|
|
385
391
|
|
|
386
392
|
export function replaceSummarySearchRowsSync(deps: FtsDeps, sessionIDs?: string[]): void {
|
package/src/store.ts
CHANGED
|
@@ -613,6 +613,9 @@ type CaptureHydrationOptions = {
|
|
|
613
613
|
isBunRuntime?: boolean;
|
|
614
614
|
platform?: string | undefined;
|
|
615
615
|
};
|
|
616
|
+
type ReadMessageOptions = {
|
|
617
|
+
hydrateArtifacts?: boolean;
|
|
618
|
+
};
|
|
616
619
|
|
|
617
620
|
function normalizeSqliteRuntimeOverride(value: string | undefined): SqliteRuntime | 'auto' {
|
|
618
621
|
const normalized = value?.trim().toLowerCase();
|
|
@@ -652,6 +655,17 @@ export function resolveCaptureHydrationMode(
|
|
|
652
655
|
return isBunRuntime && platform === 'win32' ? 'full' : 'targeted';
|
|
653
656
|
}
|
|
654
657
|
|
|
658
|
+
function shouldUseLightweightPartCapture(
|
|
659
|
+
event: CapturedEvent,
|
|
660
|
+
options?: CaptureHydrationOptions,
|
|
661
|
+
): boolean {
|
|
662
|
+
const isBunRuntime =
|
|
663
|
+
options?.isBunRuntime ?? (typeof globalThis === 'object' && 'Bun' in globalThis);
|
|
664
|
+
const platform = options?.platform ?? process.platform;
|
|
665
|
+
if (!isBunRuntime || platform !== 'win32') return false;
|
|
666
|
+
return event.type === 'message.part.updated' || event.type === 'message.part.removed';
|
|
667
|
+
}
|
|
668
|
+
|
|
655
669
|
function isSqliteRuntimeImportError(runtime: SqliteRuntime, error: unknown): boolean {
|
|
656
670
|
const code =
|
|
657
671
|
typeof error === 'object' && error && 'code' in error && typeof error.code === 'string'
|
|
@@ -1281,8 +1295,9 @@ export class SqliteLcmStore {
|
|
|
1281
1295
|
|
|
1282
1296
|
if (!normalized.sessionID || !shouldPersistSession) return;
|
|
1283
1297
|
|
|
1284
|
-
const session =
|
|
1285
|
-
|
|
1298
|
+
const session = shouldUseLightweightPartCapture(normalized)
|
|
1299
|
+
? this.readSessionForCaptureSync(normalized, { hydrateArtifacts: false })
|
|
1300
|
+
: resolveCaptureHydrationMode() === 'targeted'
|
|
1286
1301
|
? this.readSessionForCaptureSync(normalized)
|
|
1287
1302
|
: this.readSessionSync(normalized.sessionID);
|
|
1288
1303
|
const previousParentSessionID = session.parentSessionID;
|
|
@@ -1695,7 +1710,7 @@ export class SqliteLcmStore {
|
|
|
1695
1710
|
return issues.length > 0 ? { sessionID: session.sessionID, issues } : undefined;
|
|
1696
1711
|
}
|
|
1697
1712
|
|
|
1698
|
-
const latestMessageCreated = archived.at(-1)?.info
|
|
1713
|
+
const latestMessageCreated = archived.at(-1)?.info?.time?.created ?? 0;
|
|
1699
1714
|
const archivedSignature = this.buildArchivedSignature(archived);
|
|
1700
1715
|
const rootIDs = state ? parseJson<string[]>(state.root_node_ids_json) : [];
|
|
1701
1716
|
const roots = rootIDs
|
|
@@ -1848,7 +1863,7 @@ export class SqliteLcmStore {
|
|
|
1848
1863
|
return this.isMessageArchivedSync(
|
|
1849
1864
|
session.sessionID,
|
|
1850
1865
|
existing.info.id,
|
|
1851
|
-
existing.info
|
|
1866
|
+
existing.info?.time?.created ?? 0,
|
|
1852
1867
|
);
|
|
1853
1868
|
}
|
|
1854
1869
|
|
|
@@ -1873,7 +1888,7 @@ export class SqliteLcmStore {
|
|
|
1873
1888
|
return this.isMessageArchivedSync(
|
|
1874
1889
|
session.sessionID,
|
|
1875
1890
|
message.info.id,
|
|
1876
|
-
message.info
|
|
1891
|
+
message.info?.time?.created ?? 0,
|
|
1877
1892
|
);
|
|
1878
1893
|
}
|
|
1879
1894
|
case 'message.part.removed': {
|
|
@@ -1884,7 +1899,7 @@ export class SqliteLcmStore {
|
|
|
1884
1899
|
return this.isMessageArchivedSync(
|
|
1885
1900
|
session.sessionID,
|
|
1886
1901
|
message.info.id,
|
|
1887
|
-
message.info
|
|
1902
|
+
message.info?.time?.created ?? 0,
|
|
1888
1903
|
);
|
|
1889
1904
|
}
|
|
1890
1905
|
default:
|
|
@@ -3619,7 +3634,7 @@ export class SqliteLcmStore {
|
|
|
3619
3634
|
for (const message of messages) {
|
|
3620
3635
|
hash.update(message.info.id);
|
|
3621
3636
|
hash.update(message.info.role);
|
|
3622
|
-
hash.update(String(message.info
|
|
3637
|
+
hash.update(String(message.info?.time?.created ?? 0));
|
|
3623
3638
|
hash.update(guessMessageText(message, this.options.interop.ignoreToolPrefixes));
|
|
3624
3639
|
hash.update(JSON.stringify(listFiles(message)));
|
|
3625
3640
|
hash.update(JSON.stringify(this.listTools([message])));
|
|
@@ -3650,7 +3665,7 @@ export class SqliteLcmStore {
|
|
|
3650
3665
|
return [];
|
|
3651
3666
|
}
|
|
3652
3667
|
|
|
3653
|
-
const latestMessageCreated = archivedMessages.at(-1)?.info
|
|
3668
|
+
const latestMessageCreated = archivedMessages.at(-1)?.info?.time?.created ?? 0;
|
|
3654
3669
|
const archivedSignature = this.buildArchivedSignature(archivedMessages);
|
|
3655
3670
|
const state = safeQueryOne<SummaryStateRow>(
|
|
3656
3671
|
this.getDb().prepare('SELECT * FROM summary_state WHERE session_id = ?'),
|
|
@@ -3890,7 +3905,7 @@ export class SqliteLcmStore {
|
|
|
3890
3905
|
).run(
|
|
3891
3906
|
sessionID,
|
|
3892
3907
|
archivedMessages.length,
|
|
3893
|
-
archivedMessages.at(-1)?.info
|
|
3908
|
+
archivedMessages.at(-1)?.info?.time?.created ?? 0,
|
|
3894
3909
|
archivedSignature,
|
|
3895
3910
|
JSON.stringify(roots.map((node) => node.nodeID)),
|
|
3896
3911
|
now,
|
|
@@ -4872,7 +4887,10 @@ export class SqliteLcmStore {
|
|
|
4872
4887
|
return parentSessionID;
|
|
4873
4888
|
}
|
|
4874
4889
|
|
|
4875
|
-
private readSessionForCaptureSync(
|
|
4890
|
+
private readSessionForCaptureSync(
|
|
4891
|
+
event: CapturedEvent,
|
|
4892
|
+
options?: ReadMessageOptions,
|
|
4893
|
+
): NormalizedSession {
|
|
4876
4894
|
const sessionID = event.sessionID;
|
|
4877
4895
|
if (!sessionID) return emptySession('');
|
|
4878
4896
|
|
|
@@ -4881,17 +4899,17 @@ export class SqliteLcmStore {
|
|
|
4881
4899
|
|
|
4882
4900
|
switch (payload.type) {
|
|
4883
4901
|
case 'message.updated': {
|
|
4884
|
-
const message = this.readMessageSync(sessionID, payload.properties.info.id);
|
|
4902
|
+
const message = this.readMessageSync(sessionID, payload.properties.info.id, options);
|
|
4885
4903
|
if (message) session.messages = [message];
|
|
4886
4904
|
return session;
|
|
4887
4905
|
}
|
|
4888
4906
|
case 'message.part.updated': {
|
|
4889
|
-
const message = this.readMessageSync(sessionID, payload.properties.part.messageID);
|
|
4907
|
+
const message = this.readMessageSync(sessionID, payload.properties.part.messageID, options);
|
|
4890
4908
|
if (message) session.messages = [message];
|
|
4891
4909
|
return session;
|
|
4892
4910
|
}
|
|
4893
4911
|
case 'message.part.removed': {
|
|
4894
|
-
const message = this.readMessageSync(sessionID, payload.properties.messageID);
|
|
4912
|
+
const message = this.readMessageSync(sessionID, payload.properties.messageID, options);
|
|
4895
4913
|
if (message) session.messages = [message];
|
|
4896
4914
|
return session;
|
|
4897
4915
|
}
|
|
@@ -4900,7 +4918,11 @@ export class SqliteLcmStore {
|
|
|
4900
4918
|
}
|
|
4901
4919
|
}
|
|
4902
4920
|
|
|
4903
|
-
private readMessageSync(
|
|
4921
|
+
private readMessageSync(
|
|
4922
|
+
sessionID: string,
|
|
4923
|
+
messageID: string,
|
|
4924
|
+
options?: ReadMessageOptions,
|
|
4925
|
+
): ConversationMessage | undefined {
|
|
4904
4926
|
const db = this.getDb();
|
|
4905
4927
|
const row = safeQueryOne<MessageRow>(
|
|
4906
4928
|
db.prepare('SELECT * FROM messages WHERE session_id = ? AND message_id = ?'),
|
|
@@ -4909,11 +4931,14 @@ export class SqliteLcmStore {
|
|
|
4909
4931
|
);
|
|
4910
4932
|
if (!row) return undefined;
|
|
4911
4933
|
|
|
4934
|
+
const hydrateArtifacts = options?.hydrateArtifacts ?? true;
|
|
4912
4935
|
const artifactsByPart = new Map<string, ArtifactData[]>();
|
|
4913
|
-
|
|
4914
|
-
const
|
|
4915
|
-
|
|
4916
|
-
|
|
4936
|
+
if (hydrateArtifacts) {
|
|
4937
|
+
for (const artifact of this.readArtifactsForMessageSync(messageID)) {
|
|
4938
|
+
const list = artifactsByPart.get(artifact.partID) ?? [];
|
|
4939
|
+
list.push(artifact);
|
|
4940
|
+
artifactsByPart.set(artifact.partID, list);
|
|
4941
|
+
}
|
|
4917
4942
|
}
|
|
4918
4943
|
|
|
4919
4944
|
const parts = db
|
|
@@ -4939,7 +4964,7 @@ export class SqliteLcmStore {
|
|
|
4939
4964
|
info,
|
|
4940
4965
|
parts: parts.map((partRow) => {
|
|
4941
4966
|
const part = parseJson<Part>(partRow.part_json);
|
|
4942
|
-
hydratePartFromArtifacts(part, artifactsByPart.get(part.id) ?? []);
|
|
4967
|
+
if (hydrateArtifacts) hydratePartFromArtifacts(part, artifactsByPart.get(part.id) ?? []);
|
|
4943
4968
|
return part;
|
|
4944
4969
|
}),
|
|
4945
4970
|
};
|
|
@@ -5002,15 +5027,19 @@ export class SqliteLcmStore {
|
|
|
5002
5027
|
const message = session.messages.find(
|
|
5003
5028
|
(entry) => entry.info.id === payload.properties.part.messageID,
|
|
5004
5029
|
);
|
|
5030
|
+
const preservedArtifacts = message
|
|
5031
|
+
? this.readArtifactsForMessageSync(message.info.id).filter(
|
|
5032
|
+
(artifact) => artifact.partID !== payload.properties.part.id,
|
|
5033
|
+
)
|
|
5034
|
+
: [];
|
|
5005
5035
|
const externalized = message ? await this.externalizeMessage(message) : undefined;
|
|
5006
5036
|
withTransaction(this.getDb(), 'capture', () => {
|
|
5007
5037
|
this.upsertSessionRowSync(session);
|
|
5008
5038
|
if (externalized) {
|
|
5009
|
-
this.replaceStoredMessageSync(
|
|
5010
|
-
|
|
5011
|
-
externalized.
|
|
5012
|
-
|
|
5013
|
-
);
|
|
5039
|
+
this.replaceStoredMessageSync(session.sessionID, externalized.storedMessage, [
|
|
5040
|
+
...preservedArtifacts,
|
|
5041
|
+
...externalized.artifacts,
|
|
5042
|
+
]);
|
|
5014
5043
|
}
|
|
5015
5044
|
});
|
|
5016
5045
|
return;
|
|
@@ -5019,15 +5048,19 @@ export class SqliteLcmStore {
|
|
|
5019
5048
|
const message = session.messages.find(
|
|
5020
5049
|
(entry) => entry.info.id === payload.properties.messageID,
|
|
5021
5050
|
);
|
|
5051
|
+
const preservedArtifacts = message
|
|
5052
|
+
? this.readArtifactsForMessageSync(message.info.id).filter(
|
|
5053
|
+
(artifact) => artifact.partID !== payload.properties.partID,
|
|
5054
|
+
)
|
|
5055
|
+
: [];
|
|
5022
5056
|
const externalized = message ? await this.externalizeMessage(message) : undefined;
|
|
5023
5057
|
withTransaction(this.getDb(), 'capture', () => {
|
|
5024
5058
|
this.upsertSessionRowSync(session);
|
|
5025
5059
|
if (externalized) {
|
|
5026
|
-
this.replaceStoredMessageSync(
|
|
5027
|
-
|
|
5028
|
-
externalized.
|
|
5029
|
-
|
|
5030
|
-
);
|
|
5060
|
+
this.replaceStoredMessageSync(session.sessionID, externalized.storedMessage, [
|
|
5061
|
+
...preservedArtifacts,
|
|
5062
|
+
...externalized.artifacts,
|
|
5063
|
+
]);
|
|
5031
5064
|
}
|
|
5032
5065
|
});
|
|
5033
5066
|
return;
|