maka-agent 0.2.0-dev.64.20260929 → 0.2.0-dev.67.20261002
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 +1 -1
- package/THIRD_PARTY_NOTICES.txt +3 -3
- package/dist/pi-tui-runner.js +26 -29
- package/dist/tui-copy-catalog.js +9 -9
- package/native/runtime-host-peer/prebuilds/darwin-arm64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/linux-arm64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/linux-x64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/win32-x64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
- package/node_modules/@maka/core/dist/settings.js +2 -2
- package/node_modules/@maka/core/dist/tool-ledger-scanner.js +53 -150
- package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +8 -1
- package/node_modules/@maka/runtime/dist/conversation-copy.js +6 -0
- package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +17 -0
- package/node_modules/@maka/runtime/dist/session-manager.js +25 -40
- package/node_modules/@maka/runtime/dist/stream-graph-coordinator.js +79 -13
- package/node_modules/@maka/runtime/dist/stream-graph-projection.js +64 -0
- package/node_modules/@maka/runtime/dist/stream-graph-read-model.js +138 -20
- package/node_modules/@maka/runtime/dist/tool-availability.js +10 -3
- package/node_modules/@maka/runtime-host/dist/candidate-entry.js +15 -0
- package/node_modules/@maka/runtime-host/dist/candidate-startup-failure.js +5 -0
- package/node_modules/@maka/runtime-host/dist/client/session-catalog-summary.js +1 -0
- package/node_modules/@maka/runtime-host/dist/client/startup-error.js +5 -0
- package/node_modules/@maka/runtime-host/dist/protocol/agent-graph.js +46 -1
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +14 -1
- package/node_modules/@maka/runtime-host/dist/protocol/operations.js +5 -1
- package/node_modules/@maka/runtime-host/dist/protocol/session-catalog.js +12 -0
- package/node_modules/@maka/runtime-host/dist/protocol/session-retirement.js +46 -10
- package/node_modules/@maka/runtime-host/dist/protocol/storage-usage.js +155 -0
- package/node_modules/@maka/runtime-host/dist/server/agent-graph-coordinator.js +23 -0
- package/node_modules/@maka/runtime-host/dist/server/canonical-turn-snapshot.js +5 -0
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +27 -6
- package/node_modules/@maka/runtime-host/dist/server/hosted-execution-tool-profile.js +2 -0
- package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +6 -0
- package/node_modules/@maka/runtime-host/dist/server/session-retirement-coordinator.js +112 -36
- package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +27 -1
- package/node_modules/@maka/runtime-host/dist/server/storage-usage-coordinator.js +67 -0
- package/node_modules/@maka/runtime-host/dist/server/workhub-inspection-tool.js +208 -0
- package/node_modules/@maka/storage/dist/git-worktree-child-executor.js +3 -1
- package/node_modules/@maka/storage/dist/operational-state-store.js +0 -13
- package/node_modules/@maka/storage/dist/session-store.js +9 -6
- package/node_modules/@maka/storage/dist/sqlite-file-set.js +22 -0
- package/node_modules/@maka/storage/dist/sqlite-long-term-memory-store.js +1 -3
- package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +10 -260
- package/node_modules/@maka/storage/dist/sqlite-session-catalog-query.js +1 -0
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-schema.js +18 -6
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +28 -6
- package/node_modules/@maka/storage/dist/storage-footprint.js +239 -0
- package/node_modules/@maka/storage/dist/storage-writer-composition.js +10 -1
- package/node_modules/axios/CHANGELOG.md +62 -0
- package/node_modules/axios/README.md +297 -5
- package/node_modules/axios/dist/axios.js +728 -170
- package/node_modules/axios/dist/axios.min.js +3 -3
- package/node_modules/axios/dist/browser/axios.cjs +871 -188
- package/node_modules/axios/dist/esm/axios.js +871 -188
- package/node_modules/axios/dist/esm/axios.min.js +2 -2
- package/node_modules/axios/dist/node/axios.cjs +1037 -225
- package/node_modules/axios/lib/adapters/fetch.js +64 -11
- package/node_modules/axios/lib/adapters/http.js +140 -67
- package/node_modules/axios/lib/adapters/xhr.js +52 -3
- package/node_modules/axios/lib/core/Axios.js +43 -20
- package/node_modules/axios/lib/core/AxiosError.js +33 -2
- package/node_modules/axios/lib/core/AxiosHeaders.js +124 -1
- package/node_modules/axios/lib/core/InterceptorManager.js +107 -8
- package/node_modules/axios/lib/core/buildFullPath.js +41 -15
- package/node_modules/axios/lib/core/dispatchRequest.js +8 -2
- package/node_modules/axios/lib/core/mergeConfig.js +19 -4
- package/node_modules/axios/lib/core/methodList.js +17 -0
- package/node_modules/axios/lib/core/setFormDataHeaders.js +27 -0
- package/node_modules/axios/lib/defaults/index.js +2 -1
- package/node_modules/axios/lib/env/data.js +1 -1
- package/node_modules/axios/lib/helpers/Http2Sessions.js +2 -0
- package/node_modules/axios/lib/helpers/HttpStatusCode.js +12 -1
- package/node_modules/axios/lib/helpers/combineURLs.js +11 -3
- package/node_modules/axios/lib/helpers/composeSignals.js +12 -1
- package/node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js +115 -54
- package/node_modules/axios/lib/helpers/formDataToJSON.js +11 -5
- package/node_modules/axios/lib/helpers/fromDataURI.js +5 -4
- package/node_modules/axios/lib/helpers/normalizeURLForProtocolCheck.js +24 -0
- package/node_modules/axios/lib/helpers/parseHeaders.js +5 -3
- package/node_modules/axios/lib/helpers/progressEventReducer.js +4 -4
- package/node_modules/axios/lib/helpers/resolveConfig.js +5 -17
- package/node_modules/axios/lib/helpers/shouldBypassProxy.js +300 -5
- package/node_modules/axios/lib/helpers/throttle.js +3 -2
- package/node_modules/axios/lib/helpers/toFormData.js +17 -23
- package/node_modules/axios/lib/platform/node/classes/Buffer.js +11 -0
- package/node_modules/axios/lib/utils.js +151 -18
- package/node_modules/axios/package.json +21 -19
- package/node_modules/brace-expansion/dist/commonjs/index.js +69 -25
- package/node_modules/brace-expansion/dist/esm/index.js +68 -24
- package/node_modules/brace-expansion/package.json +2 -1
- package/node_modules/fast-uri/index.js +10 -6
- package/node_modules/fast-uri/package.json +1 -1
- package/package.json +1 -1
|
@@ -311,7 +311,7 @@ class SqliteSessionStore {
|
|
|
311
311
|
return (await this.metadata.list(filter, 'ordinary'))
|
|
312
312
|
.filter((record) => record.header.transcriptLedgerVersion !== 0)
|
|
313
313
|
.filter((record) => record.header.conversationCopy?.state !== 'preparing')
|
|
314
|
-
.map(
|
|
314
|
+
.map(toCatalogRecordSummary);
|
|
315
315
|
}
|
|
316
316
|
async listCatalogPage(filter, cursor, limit, expectedRevision) {
|
|
317
317
|
await this.ensureCatalogProjectionReadable();
|
|
@@ -330,7 +330,7 @@ class SqliteSessionStore {
|
|
|
330
330
|
records: page.records.map((record) => ({
|
|
331
331
|
...projectHeaderSnapshot(record),
|
|
332
332
|
activityAt: record.activityAt,
|
|
333
|
-
summary:
|
|
333
|
+
summary: toCatalogRecordSummary(record),
|
|
334
334
|
})),
|
|
335
335
|
hasMore: page.hasMore,
|
|
336
336
|
};
|
|
@@ -360,7 +360,7 @@ class SqliteSessionStore {
|
|
|
360
360
|
return {
|
|
361
361
|
...projectHeaderSnapshot(record),
|
|
362
362
|
activityAt: record.activityAt,
|
|
363
|
-
summary:
|
|
363
|
+
summary: toCatalogRecordSummary(record),
|
|
364
364
|
};
|
|
365
365
|
}
|
|
366
366
|
async readMessagesSnapshot(sessionId) {
|
|
@@ -597,9 +597,12 @@ function projectStableSessionCreateProbe(probe) {
|
|
|
597
597
|
? { kind: 'existing', record: projectHeaderSnapshot(probe.record) }
|
|
598
598
|
: probe;
|
|
599
599
|
}
|
|
600
|
-
function
|
|
600
|
+
function toCatalogRecordSummary(record) {
|
|
601
601
|
return {
|
|
602
|
-
...toSummary(header),
|
|
603
|
-
...(lastMessagePreview === undefined
|
|
602
|
+
...toSummary(record.header),
|
|
603
|
+
...(record.lastMessagePreview === undefined
|
|
604
|
+
? {}
|
|
605
|
+
: { lastMessagePreview: record.lastMessagePreview }),
|
|
606
|
+
...(record.archivedAt === undefined ? {} : { archivedAt: record.archivedAt }),
|
|
604
607
|
};
|
|
605
608
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
3
|
+
* or more contributor license agreements. See the NOTICE file
|
|
4
|
+
* distributed with this work for additional information
|
|
5
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
6
|
+
* to you under the Apache License, Version 2.0 (the
|
|
7
|
+
* "License"); you may not use this file except in compliance
|
|
8
|
+
* with the License. You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing,
|
|
13
|
+
* software distributed under the License is distributed on an
|
|
14
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
15
|
+
* KIND, either express or implied. See the License for the
|
|
16
|
+
* specific language governing permissions and limitations
|
|
17
|
+
* under the License.
|
|
18
|
+
*/
|
|
19
|
+
/** The files SQLite may keep beside a database, in any journal mode. */
|
|
20
|
+
export function sqliteDatabaseSidecars(path) {
|
|
21
|
+
return [`${path}-wal`, `${path}-shm`, `${path}-journal`];
|
|
22
|
+
}
|
|
@@ -20,6 +20,7 @@ import { createHash, randomUUID } from 'node:crypto';
|
|
|
20
20
|
import { closeSync, constants as fsConstants, fchmodSync, fstatSync, lstatSync, openSync, } from 'node:fs';
|
|
21
21
|
import { createRequire } from 'node:module';
|
|
22
22
|
import { MemoryItemStoreConflictError, isMemoryItemKind, isMemoryItemOrigin, isMemoryKeyOrigin, isMemoryKeyType, isMemoryLifecycleState, isMemoryScopeType, isMemoryStatementType, isMemoryTemporalType, normalizeLongTermMemoryContent, validateMemoryTemporalBounds, } from '@maka/core/long-term-memory';
|
|
23
|
+
import { sqliteDatabaseSidecars as databaseSidecars } from './sqlite-file-set.js';
|
|
23
24
|
import { assertSupportedSqliteLongTermMemorySchemaVersion, configureSqliteLongTermMemoryDatabase, migrateSqliteLongTermMemoryDatabase, readSqliteLongTermMemorySchemaVersion, } from './sqlite-long-term-memory-schema.js';
|
|
24
25
|
const MAX_MUTATIONS_PER_OPERATION = 32;
|
|
25
26
|
const MAX_KEYS_PER_ITEM = 32;
|
|
@@ -1591,9 +1592,6 @@ function secureFile(path, create, allowUnlinked) {
|
|
|
1591
1592
|
closeSync(descriptor);
|
|
1592
1593
|
}
|
|
1593
1594
|
}
|
|
1594
|
-
function databaseSidecars(path) {
|
|
1595
|
-
return [`${path}-wal`, `${path}-shm`, `${path}-journal`];
|
|
1596
|
-
}
|
|
1597
1595
|
function isNodeError(error) {
|
|
1598
1596
|
return typeof error === 'object' && error !== null && 'code' in error;
|
|
1599
1597
|
}
|
|
@@ -29,7 +29,7 @@ import { stableJsonStringify } from '@maka/core/tool-args-identity';
|
|
|
29
29
|
import { mergeRuntimePartialSnapshots, groupRuntimePartialSnapshots, compareRuntimePartialSnapshots, partialRuntimeStream, completedPartialRuntimeStreamKey, } from './runtime-partial-values.js';
|
|
30
30
|
import { assertPreparedInput, assertOutcomeInput, assertPreparedIdentity, assertOutcomeIdentity, } from './tool-commit-validation.js';
|
|
31
31
|
import { encodeCanonicalRuntimeEvent } from '@maka/core/canonical-runtime-event';
|
|
32
|
-
import { scanToolLedger, referencedToolOperationIds,
|
|
32
|
+
import { scanToolLedger, referencedToolOperationIds, ToolLedgerCorruptionError, ToolLedgerRejectionError, validateGenericToolLedgerAppend, validateToolLedgerTransition, } from '@maka/core/tool-ledger-scanner';
|
|
33
33
|
import { buildImmutableRuntimePrefix, buildImmutableRuntimePrefixProof, continuationStartEventMatchesClaim, decodeContinuationClaim, } from '@maka/core/runtime-boundary';
|
|
34
34
|
import { assertToolRecoveryEventBundle, interpretScannedToolRecovery, } from '@maka/core/tool-recovery-bundle';
|
|
35
35
|
import { configureSqliteRuntimeDatabase, migrateSqliteRuntimeDatabase, readUserVersion, RUNTIME_RECOVERY_AUTHORITY_CAPABILITY, RUNTIME_RECOVERY_AUTHORITY_CAPABILITY_VERSION, RUNTIME_CONTINUATION_AUTHORITY_CAPABILITY, RUNTIME_CONTINUATION_AUTHORITY_CAPABILITY_VERSION, RUNTIME_WORKSPACE_VERSION_AUTHORITY_CAPABILITY, RUNTIME_WORKSPACE_VERSION_AUTHORITY_CAPABILITY_VERSION, runtimeEventKind, SQLITE_RUNTIME_SCHEMA_VERSION, } from './sqlite-runtime-schema.js';
|
|
@@ -43,12 +43,6 @@ export { SQLITE_RUNTIME_SCHEMA_VERSION } from './sqlite-runtime-schema.js';
|
|
|
43
43
|
const RUNTIME_EVENT_SCAN_BATCH_SIZE = 128;
|
|
44
44
|
const RUNTIME_PARTIAL_SEGMENT_TARGET_BYTES = 64 * 1024;
|
|
45
45
|
const RECOVERY_MESSAGE_QUERY_BATCH_SIZE = 400;
|
|
46
|
-
const TOOL_LEDGER_CACHE_EVENT_OVERHEAD_BYTES = 1024;
|
|
47
|
-
const DEFAULT_TOOL_LEDGER_CACHE_BUDGET = {
|
|
48
|
-
maxEntries: 32,
|
|
49
|
-
maxEstimatedBytes: 16 * 1024 * 1024,
|
|
50
|
-
maxSingleEntryEstimatedBytes: 8 * 1024 * 1024,
|
|
51
|
-
};
|
|
52
46
|
const IMMUTABLE_STEERING_SQL_PREDICATE = `
|
|
53
47
|
event_kind = 'text'
|
|
54
48
|
AND CASE
|
|
@@ -80,19 +74,6 @@ function requireRuntimeEventScanCount(value) {
|
|
|
80
74
|
}
|
|
81
75
|
return value;
|
|
82
76
|
}
|
|
83
|
-
function normalizeToolLedgerCacheBudget(override) {
|
|
84
|
-
const budget = { ...DEFAULT_TOOL_LEDGER_CACHE_BUDGET, ...override };
|
|
85
|
-
for (const [name, value] of Object.entries(budget)) {
|
|
86
|
-
if (!Number.isSafeInteger(value) || value < 1) {
|
|
87
|
-
throw new Error(`Invalid tool ledger cache ${name}`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return budget;
|
|
91
|
-
}
|
|
92
|
-
function estimateToolLedgerCacheBytes(storedPayloadBytes, eventCount) {
|
|
93
|
-
const estimate = storedPayloadBytes * 2 + eventCount * TOOL_LEDGER_CACHE_EVENT_OVERHEAD_BYTES;
|
|
94
|
-
return Number.isSafeInteger(estimate) ? estimate : Number.MAX_SAFE_INTEGER;
|
|
95
|
-
}
|
|
96
77
|
const require = createRequire(import.meta.url);
|
|
97
78
|
function loadDatabaseSync() {
|
|
98
79
|
return require('node:sqlite').DatabaseSync;
|
|
@@ -114,26 +95,11 @@ export class SqliteRuntimeStore {
|
|
|
114
95
|
workspaceVersionAuthorityCapability = WORKSPACE_VERSION_AUTHORITY_CAPABILITY_V1;
|
|
115
96
|
db;
|
|
116
97
|
databaseLease;
|
|
117
|
-
toolLedgerCacheBudget;
|
|
118
|
-
toolLedgerCache = new Map();
|
|
119
|
-
toolLedgerCacheEstimatedBytes = 0;
|
|
120
|
-
toolLedgerCacheEventCount = 0;
|
|
121
|
-
toolLedgerCacheMetrics = {
|
|
122
|
-
hits: 0,
|
|
123
|
-
misses: 0,
|
|
124
|
-
budgetEvictions: 0,
|
|
125
|
-
terminalEvictions: 0,
|
|
126
|
-
transientEntries: 0,
|
|
127
|
-
};
|
|
128
|
-
uncommittedToolLedgerStates = new Map();
|
|
129
|
-
toolLedgerCacheVersion;
|
|
130
|
-
localCommittedWriteRevision = 0;
|
|
131
98
|
closed = false;
|
|
132
99
|
uncommittedEventSessions = new Set();
|
|
133
100
|
eventCommitListeners = new Set();
|
|
134
101
|
constructor(path, options = {}) {
|
|
135
102
|
this.options = options;
|
|
136
|
-
this.toolLedgerCacheBudget = normalizeToolLedgerCacheBudget(options.toolLedgerCacheBudget);
|
|
137
103
|
if (options.readOnly && options.databaseLease) {
|
|
138
104
|
throw new Error('Operational state database leases cannot be opened read-only');
|
|
139
105
|
}
|
|
@@ -196,8 +162,6 @@ export class SqliteRuntimeStore {
|
|
|
196
162
|
if (this.closed)
|
|
197
163
|
return;
|
|
198
164
|
this.closed = true;
|
|
199
|
-
this.clearToolLedgerCache();
|
|
200
|
-
this.uncommittedToolLedgerStates.clear();
|
|
201
165
|
if (this.databaseLease)
|
|
202
166
|
this.databaseLease.close();
|
|
203
167
|
else
|
|
@@ -241,7 +205,6 @@ export class SqliteRuntimeStore {
|
|
|
241
205
|
existing.at(-1)?.id !== canonicalEvent.id) {
|
|
242
206
|
throw new Error('Terminal RuntimeEvent must be the immutable ledger tail');
|
|
243
207
|
}
|
|
244
|
-
this.invalidateToolLedgerCacheForInvocation(canonicalEvent.invocationId);
|
|
245
208
|
return;
|
|
246
209
|
}
|
|
247
210
|
const existingTerminal = existing.find(isTerminalRuntimeEvent);
|
|
@@ -3086,14 +3049,7 @@ export class SqliteRuntimeStore {
|
|
|
3086
3049
|
}
|
|
3087
3050
|
transaction(operation) {
|
|
3088
3051
|
if (this.databaseLease) {
|
|
3089
|
-
|
|
3090
|
-
return this.databaseLease.transaction('write', () => {
|
|
3091
|
-
// A sibling lease may have changed the shared transaction view since
|
|
3092
|
-
// this store last used its reconstructible cache.
|
|
3093
|
-
if (nested)
|
|
3094
|
-
this.clearToolLedgerCache();
|
|
3095
|
-
return operation();
|
|
3096
|
-
});
|
|
3052
|
+
return this.databaseLease.transaction('write', operation);
|
|
3097
3053
|
}
|
|
3098
3054
|
this.db.exec('BEGIN IMMEDIATE');
|
|
3099
3055
|
let result;
|
|
@@ -3108,17 +3064,10 @@ export class SqliteRuntimeStore {
|
|
|
3108
3064
|
catch {
|
|
3109
3065
|
// Preserve the protocol failure that caused rollback.
|
|
3110
3066
|
}
|
|
3111
|
-
// Reducers may have loaded rows written earlier in this transaction as
|
|
3112
|
-
// their immutable base. Bump the local view even on rollback so the next
|
|
3113
|
-
// admission discards that phantom base before retrying.
|
|
3114
|
-
this.localCommittedWriteRevision += 1;
|
|
3115
3067
|
this.settleEventCommits(false);
|
|
3116
|
-
this.settleToolLedgerStates(false);
|
|
3117
3068
|
throw error;
|
|
3118
3069
|
}
|
|
3119
|
-
this.localCommittedWriteRevision += 1;
|
|
3120
3070
|
this.settleEventCommits(true);
|
|
3121
|
-
this.settleToolLedgerStates(true);
|
|
3122
3071
|
return result;
|
|
3123
3072
|
}
|
|
3124
3073
|
noteEventCommit(sessionId) {
|
|
@@ -3336,12 +3285,9 @@ export class SqliteRuntimeStore {
|
|
|
3336
3285
|
}
|
|
3337
3286
|
}
|
|
3338
3287
|
assertToolLedgerTransition(candidateEvents, expectedTransition) {
|
|
3339
|
-
const
|
|
3340
|
-
const
|
|
3341
|
-
|
|
3342
|
-
const appendedEncodings = canonicalEncodings.filter(({ event }) => entry.reducer.event(event.id) === undefined);
|
|
3343
|
-
const validation = validateIncrementalToolLedgerTransition({
|
|
3344
|
-
reducer: entry.reducer,
|
|
3288
|
+
const canonicalEvents = candidateEvents.map((event) => encodeCanonicalRuntimeEvent(event).event);
|
|
3289
|
+
const validation = validateToolLedgerTransition({
|
|
3290
|
+
existingEvents: this.readToolLedgerDependencies(canonicalEvents),
|
|
3345
3291
|
candidateEvents: canonicalEvents,
|
|
3346
3292
|
expectedTransition,
|
|
3347
3293
|
});
|
|
@@ -3351,40 +3297,15 @@ export class SqliteRuntimeStore {
|
|
|
3351
3297
|
}
|
|
3352
3298
|
throw new ToolLedgerRejectionError(validation.code, validation.eventId);
|
|
3353
3299
|
}
|
|
3354
|
-
if (validation.appendedEvents === 0)
|
|
3355
|
-
return;
|
|
3356
|
-
this.noteToolLedgerState(entry, validation.checkpoint, canonicalEvents.map((event) => event.invocationId), {
|
|
3357
|
-
eventCount: validation.appendedEvents,
|
|
3358
|
-
estimatedBytes: estimateToolLedgerCacheBytes(appendedEncodings.reduce((bytes, encoding) => bytes + Buffer.byteLength(encoding.json, 'utf8'), 0), validation.appendedEvents),
|
|
3359
|
-
});
|
|
3360
3300
|
}
|
|
3361
|
-
|
|
3362
|
-
const
|
|
3363
|
-
|
|
3364
|
-
this.refreshToolLedgerCacheVersion();
|
|
3365
|
-
const directInvocationIds = new Set(candidateEvents.map((event) => event.invocationId));
|
|
3366
|
-
const directOperationIds = referencedToolOperationIds(candidateEvents);
|
|
3367
|
-
for (const invocationId of this.toolLedgerOperationInvocations(directOperationIds)) {
|
|
3368
|
-
directInvocationIds.add(invocationId);
|
|
3369
|
-
}
|
|
3370
|
-
for (const [key, entry] of this.toolLedgerCache) {
|
|
3371
|
-
if (entry.seedInvocationIds.size === directInvocationIds.size &&
|
|
3372
|
-
[...directInvocationIds].every((invocationId) => entry.seedInvocationIds.has(invocationId))) {
|
|
3373
|
-
this.toolLedgerCacheMetrics.hits += 1;
|
|
3374
|
-
this.touchToolLedgerCacheEntry(key, entry);
|
|
3375
|
-
return entry;
|
|
3376
|
-
}
|
|
3377
|
-
}
|
|
3378
|
-
this.toolLedgerCacheMetrics.misses += 1;
|
|
3379
|
-
const invocationIds = new Set(directInvocationIds);
|
|
3380
|
-
const operationIds = new Set(directOperationIds);
|
|
3301
|
+
readToolLedgerDependencies(candidateEvents) {
|
|
3302
|
+
const invocationIds = new Set(candidateEvents.map((event) => event.invocationId));
|
|
3303
|
+
const operationIds = referencedToolOperationIds(candidateEvents);
|
|
3381
3304
|
const resolvedOperationIds = new Set();
|
|
3382
3305
|
const loadedInvocationIds = new Set();
|
|
3383
3306
|
const scopedEvents = [];
|
|
3384
|
-
let storedPayloadBytes = 0;
|
|
3385
3307
|
const readInvocation = this.db.prepare(`
|
|
3386
|
-
SELECT event_id, session_id, invocation_id, run_id, turn_id, event_seq, payload_json
|
|
3387
|
-
length(CAST(payload_json AS BLOB)) AS stored_bytes
|
|
3308
|
+
SELECT event_id, session_id, invocation_id, run_id, turn_id, event_seq, payload_json
|
|
3388
3309
|
FROM runtime_events
|
|
3389
3310
|
WHERE invocation_id = ?
|
|
3390
3311
|
ORDER BY event_seq ASC, event_id ASC
|
|
@@ -3407,7 +3328,6 @@ export class SqliteRuntimeStore {
|
|
|
3407
3328
|
loadedInvocationIds.add(invocationId);
|
|
3408
3329
|
const rows = readInvocation.all(invocationId);
|
|
3409
3330
|
for (const row of rows) {
|
|
3410
|
-
storedPayloadBytes += requireRuntimeEventScanCount(row.stored_bytes);
|
|
3411
3331
|
const event = decodeRuntimeEventStorageRow(row);
|
|
3412
3332
|
scopedEvents.push({ event, eventSeq: row.event_seq });
|
|
3413
3333
|
if (event.refs?.parentOperationId)
|
|
@@ -3415,31 +3335,10 @@ export class SqliteRuntimeStore {
|
|
|
3415
3335
|
}
|
|
3416
3336
|
}
|
|
3417
3337
|
}
|
|
3418
|
-
const sortedSeedInvocationIds = [...directInvocationIds].sort();
|
|
3419
|
-
const sortedInvocationIds = [...invocationIds].sort();
|
|
3420
|
-
const key = JSON.stringify([sortedSeedInvocationIds, sortedInvocationIds]);
|
|
3421
|
-
const existing = this.toolLedgerCache.get(key);
|
|
3422
|
-
if (existing) {
|
|
3423
|
-
this.touchToolLedgerCacheEntry(key, existing);
|
|
3424
|
-
return existing;
|
|
3425
|
-
}
|
|
3426
3338
|
scopedEvents.sort((left, right) => left.event.invocationId.localeCompare(right.event.invocationId) ||
|
|
3427
3339
|
left.eventSeq - right.eventSeq ||
|
|
3428
3340
|
left.event.id.localeCompare(right.event.id));
|
|
3429
|
-
|
|
3430
|
-
reducer: new ToolLedgerReducer(scopedEvents.map(({ event }) => event)),
|
|
3431
|
-
seedInvocationIds: new Set(sortedSeedInvocationIds),
|
|
3432
|
-
invocationIds: new Set(sortedInvocationIds),
|
|
3433
|
-
eventCount: scopedEvents.length,
|
|
3434
|
-
estimatedBytes: estimateToolLedgerCacheBytes(storedPayloadBytes, scopedEvents.length),
|
|
3435
|
-
};
|
|
3436
|
-
if (this.toolLedgerEntryExceedsAdmissionBudget(entry)) {
|
|
3437
|
-
this.toolLedgerCacheMetrics.transientEntries += 1;
|
|
3438
|
-
return entry;
|
|
3439
|
-
}
|
|
3440
|
-
this.retainToolLedgerCacheEntry(key, entry);
|
|
3441
|
-
this.trimToolLedgerCache();
|
|
3442
|
-
return entry;
|
|
3341
|
+
return scopedEvents.map(({ event }) => event);
|
|
3443
3342
|
}
|
|
3444
3343
|
toolLedgerOperationInvocations(operationIds) {
|
|
3445
3344
|
const ids = [...new Set(operationIds)].sort();
|
|
@@ -3459,149 +3358,6 @@ export class SqliteRuntimeStore {
|
|
|
3459
3358
|
.all(...ids);
|
|
3460
3359
|
return new Set(rows.map((row) => row.invocation_id));
|
|
3461
3360
|
}
|
|
3462
|
-
noteToolLedgerState(entry, checkpoint, invocationIds, delta) {
|
|
3463
|
-
const reducer = entry.reducer;
|
|
3464
|
-
const existing = this.uncommittedToolLedgerStates.get(reducer);
|
|
3465
|
-
if (existing) {
|
|
3466
|
-
for (const invocationId of invocationIds)
|
|
3467
|
-
existing.changedInvocationIds.add(invocationId);
|
|
3468
|
-
this.adjustToolLedgerCacheEntry(entry, delta);
|
|
3469
|
-
return;
|
|
3470
|
-
}
|
|
3471
|
-
if (this.uncommittedToolLedgerStates.size === 0 && this.databaseLease) {
|
|
3472
|
-
this.databaseLease.onTransactionSettled((committed) => this.settleToolLedgerStates(committed));
|
|
3473
|
-
}
|
|
3474
|
-
this.uncommittedToolLedgerStates.set(reducer, {
|
|
3475
|
-
checkpoint,
|
|
3476
|
-
changedInvocationIds: new Set(invocationIds),
|
|
3477
|
-
entry,
|
|
3478
|
-
estimatedBytesBefore: entry.estimatedBytes,
|
|
3479
|
-
eventCountBefore: entry.eventCount,
|
|
3480
|
-
});
|
|
3481
|
-
this.adjustToolLedgerCacheEntry(entry, delta);
|
|
3482
|
-
}
|
|
3483
|
-
settleToolLedgerStates(committed) {
|
|
3484
|
-
const states = [...this.uncommittedToolLedgerStates.entries()];
|
|
3485
|
-
this.uncommittedToolLedgerStates.clear();
|
|
3486
|
-
if (states.length === 0)
|
|
3487
|
-
return;
|
|
3488
|
-
if (!committed) {
|
|
3489
|
-
for (const [reducer, state] of states.reverse()) {
|
|
3490
|
-
reducer.rollback(state.checkpoint);
|
|
3491
|
-
this.restoreToolLedgerCacheEntry(state);
|
|
3492
|
-
}
|
|
3493
|
-
this.trimToolLedgerCache();
|
|
3494
|
-
return;
|
|
3495
|
-
}
|
|
3496
|
-
const retained = new Set(states.map(([reducer]) => reducer));
|
|
3497
|
-
const changedInvocationIds = new Set(states.flatMap(([, state]) => [...state.changedInvocationIds]));
|
|
3498
|
-
for (const [key, entry] of this.toolLedgerCache) {
|
|
3499
|
-
if (retained.has(entry.reducer))
|
|
3500
|
-
continue;
|
|
3501
|
-
if ([...entry.invocationIds].some((id) => changedInvocationIds.has(id))) {
|
|
3502
|
-
this.deleteToolLedgerCacheEntry(key);
|
|
3503
|
-
}
|
|
3504
|
-
}
|
|
3505
|
-
for (const [reducer, state] of states)
|
|
3506
|
-
reducer.commit(state.checkpoint);
|
|
3507
|
-
this.toolLedgerCacheVersion = this.currentToolLedgerCacheVersion();
|
|
3508
|
-
this.trimToolLedgerCache();
|
|
3509
|
-
}
|
|
3510
|
-
refreshToolLedgerCacheVersion() {
|
|
3511
|
-
if (this.uncommittedToolLedgerStates.size > 0) {
|
|
3512
|
-
throw new Error('Cannot invalidate tool ledger state during an open write transaction');
|
|
3513
|
-
}
|
|
3514
|
-
this.clearToolLedgerCache();
|
|
3515
|
-
this.toolLedgerCacheVersion = this.currentToolLedgerCacheVersion();
|
|
3516
|
-
}
|
|
3517
|
-
retainToolLedgerCacheEntry(key, entry) {
|
|
3518
|
-
entry.cacheKey = key;
|
|
3519
|
-
this.toolLedgerCache.set(key, entry);
|
|
3520
|
-
this.toolLedgerCacheEstimatedBytes += entry.estimatedBytes;
|
|
3521
|
-
this.toolLedgerCacheEventCount += entry.eventCount;
|
|
3522
|
-
}
|
|
3523
|
-
touchToolLedgerCacheEntry(key, entry) {
|
|
3524
|
-
this.toolLedgerCache.delete(key);
|
|
3525
|
-
this.toolLedgerCache.set(key, entry);
|
|
3526
|
-
}
|
|
3527
|
-
adjustToolLedgerCacheEntry(entry, delta) {
|
|
3528
|
-
entry.estimatedBytes += delta.estimatedBytes;
|
|
3529
|
-
entry.eventCount += delta.eventCount;
|
|
3530
|
-
if (entry.cacheKey && this.toolLedgerCache.get(entry.cacheKey) === entry) {
|
|
3531
|
-
this.toolLedgerCacheEstimatedBytes += delta.estimatedBytes;
|
|
3532
|
-
this.toolLedgerCacheEventCount += delta.eventCount;
|
|
3533
|
-
}
|
|
3534
|
-
}
|
|
3535
|
-
restoreToolLedgerCacheEntry(state) {
|
|
3536
|
-
const entry = state.entry;
|
|
3537
|
-
if (entry.cacheKey && this.toolLedgerCache.get(entry.cacheKey) === entry) {
|
|
3538
|
-
this.toolLedgerCacheEstimatedBytes += state.estimatedBytesBefore - entry.estimatedBytes;
|
|
3539
|
-
this.toolLedgerCacheEventCount += state.eventCountBefore - entry.eventCount;
|
|
3540
|
-
}
|
|
3541
|
-
entry.estimatedBytes = state.estimatedBytesBefore;
|
|
3542
|
-
entry.eventCount = state.eventCountBefore;
|
|
3543
|
-
}
|
|
3544
|
-
deleteToolLedgerCacheEntry(key, reason) {
|
|
3545
|
-
const entry = this.toolLedgerCache.get(key);
|
|
3546
|
-
if (!entry)
|
|
3547
|
-
return;
|
|
3548
|
-
this.toolLedgerCache.delete(key);
|
|
3549
|
-
if (entry.cacheKey === key)
|
|
3550
|
-
entry.cacheKey = undefined;
|
|
3551
|
-
this.toolLedgerCacheEstimatedBytes -= entry.estimatedBytes;
|
|
3552
|
-
this.toolLedgerCacheEventCount -= entry.eventCount;
|
|
3553
|
-
if (reason === 'budget')
|
|
3554
|
-
this.toolLedgerCacheMetrics.budgetEvictions += 1;
|
|
3555
|
-
if (reason === 'terminal')
|
|
3556
|
-
this.toolLedgerCacheMetrics.terminalEvictions += 1;
|
|
3557
|
-
}
|
|
3558
|
-
clearToolLedgerCache() {
|
|
3559
|
-
for (const entry of this.toolLedgerCache.values())
|
|
3560
|
-
entry.cacheKey = undefined;
|
|
3561
|
-
this.toolLedgerCache.clear();
|
|
3562
|
-
this.toolLedgerCacheEstimatedBytes = 0;
|
|
3563
|
-
this.toolLedgerCacheEventCount = 0;
|
|
3564
|
-
}
|
|
3565
|
-
invalidateToolLedgerCacheForInvocation(invocationId) {
|
|
3566
|
-
for (const [key, entry] of this.toolLedgerCache) {
|
|
3567
|
-
if (entry.invocationIds.has(invocationId)) {
|
|
3568
|
-
this.deleteToolLedgerCacheEntry(key, 'terminal');
|
|
3569
|
-
}
|
|
3570
|
-
}
|
|
3571
|
-
}
|
|
3572
|
-
toolLedgerEntryExceedsAdmissionBudget(entry) {
|
|
3573
|
-
return entry.estimatedBytes > this.toolLedgerCacheBudget.maxSingleEntryEstimatedBytes;
|
|
3574
|
-
}
|
|
3575
|
-
toolLedgerCacheExceedsBudget() {
|
|
3576
|
-
return (this.toolLedgerCache.size > this.toolLedgerCacheBudget.maxEntries ||
|
|
3577
|
-
this.toolLedgerCacheEstimatedBytes > this.toolLedgerCacheBudget.maxEstimatedBytes);
|
|
3578
|
-
}
|
|
3579
|
-
trimToolLedgerCache() {
|
|
3580
|
-
for (;;) {
|
|
3581
|
-
let victim;
|
|
3582
|
-
for (const [key, entry] of this.toolLedgerCache) {
|
|
3583
|
-
if (this.uncommittedToolLedgerStates.has(entry.reducer))
|
|
3584
|
-
continue;
|
|
3585
|
-
if (this.toolLedgerEntryExceedsAdmissionBudget(entry)) {
|
|
3586
|
-
victim = key;
|
|
3587
|
-
break;
|
|
3588
|
-
}
|
|
3589
|
-
}
|
|
3590
|
-
if (!victim && this.toolLedgerCacheExceedsBudget()) {
|
|
3591
|
-
victim = [...this.toolLedgerCache].find(([, entry]) => !this.uncommittedToolLedgerStates.has(entry.reducer))?.[0];
|
|
3592
|
-
}
|
|
3593
|
-
if (!victim)
|
|
3594
|
-
return;
|
|
3595
|
-
this.deleteToolLedgerCacheEntry(victim, 'budget');
|
|
3596
|
-
}
|
|
3597
|
-
}
|
|
3598
|
-
currentToolLedgerCacheVersion() {
|
|
3599
|
-
return `${this.runtimeDataVersion()}:${this.databaseLease?.writeViewRevision() ?? this.localCommittedWriteRevision}`;
|
|
3600
|
-
}
|
|
3601
|
-
runtimeDataVersion() {
|
|
3602
|
-
const row = this.db.prepare('PRAGMA data_version').get();
|
|
3603
|
-
return row.data_version;
|
|
3604
|
-
}
|
|
3605
3361
|
assertInvocationIdentity(events) {
|
|
3606
3362
|
const candidates = new Map();
|
|
3607
3363
|
const runs = new Map();
|
|
@@ -3832,9 +3588,6 @@ export class SqliteRuntimeStore {
|
|
|
3832
3588
|
if (!allowExactDuplicate) {
|
|
3833
3589
|
throw new Error(`RuntimeEvent ${canonicalEvent.id} already exists outside this tool transaction`);
|
|
3834
3590
|
}
|
|
3835
|
-
if (isTerminalRuntimeEvent(canonicalEvent)) {
|
|
3836
|
-
this.invalidateToolLedgerCacheForInvocation(canonicalEvent.invocationId);
|
|
3837
|
-
}
|
|
3838
3591
|
return this.runtimeEventSeq(canonicalEvent.id);
|
|
3839
3592
|
}
|
|
3840
3593
|
this.assertContinuationAuthorityAllowsEvent(canonicalEvent, authorizedPendingContinuationClaimId);
|
|
@@ -3868,9 +3621,6 @@ export class SqliteRuntimeStore {
|
|
|
3868
3621
|
recordTranscriptTurnExtent(this.db, { ...canonicalEvent, kind: runtimeEventKind(canonicalEvent) }, ordinal);
|
|
3869
3622
|
this.noteEventCommit(canonicalEvent.sessionId);
|
|
3870
3623
|
this.deleteCompletedPartialSnapshot(canonicalEvent);
|
|
3871
|
-
if (isTerminalRuntimeEvent(canonicalEvent)) {
|
|
3872
|
-
this.invalidateToolLedgerCacheForInvocation(canonicalEvent.invocationId);
|
|
3873
|
-
}
|
|
3874
3624
|
return next;
|
|
3875
3625
|
}
|
|
3876
3626
|
deleteCompletedPartialSnapshot(event) {
|
|
@@ -49,6 +49,7 @@ export function buildSqliteSessionCatalogPageQuery(filter, cursor) {
|
|
|
49
49
|
metadata.payload_json,
|
|
50
50
|
metadata.metadata_version,
|
|
51
51
|
metadata.committed_at,
|
|
52
|
+
metadata.archived_at,
|
|
52
53
|
projection.activity_at,
|
|
53
54
|
projection.last_message_preview
|
|
54
55
|
FROM session_catalog_projection projection
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* specific language governing permissions and limitations
|
|
17
17
|
* under the License.
|
|
18
18
|
*/
|
|
19
|
-
export const SQLITE_SESSION_METADATA_SCHEMA_VERSION =
|
|
19
|
+
export const SQLITE_SESSION_METADATA_SCHEMA_VERSION = 41;
|
|
20
20
|
export const SQLITE_SESSION_MESSAGE_CHUNK_BYTES = 64 * 1024;
|
|
21
21
|
export const SQLITE_SESSION_MESSAGE_CHUNK_MARKER = '{"$maka":"session-message-chunks-v1"}';
|
|
22
22
|
export const SQLITE_AGENT_GRAPH_CONTROL_TABLES = [
|
|
@@ -32,6 +32,16 @@ export const SQLITE_AGENT_GRAPH_CONTROL_TABLES = [
|
|
|
32
32
|
'agent_graph_supervisor_wake_attempts',
|
|
33
33
|
];
|
|
34
34
|
const MIGRATIONS = new Map([
|
|
35
|
+
[
|
|
36
|
+
41,
|
|
37
|
+
`
|
|
38
|
+
-- When the Session last entered the archive, owned by the lifecycle
|
|
39
|
+
-- writer alone. Rows archived before this column existed keep NULL: the
|
|
40
|
+
-- time they were archived was never recorded, and neither committed_at nor
|
|
41
|
+
-- activity says when.
|
|
42
|
+
ALTER TABLE session_metadata ADD COLUMN archived_at INTEGER;
|
|
43
|
+
`,
|
|
44
|
+
],
|
|
35
45
|
[
|
|
36
46
|
40,
|
|
37
47
|
`
|
|
@@ -1370,13 +1380,15 @@ export function migrateSqliteSessionMetadataDatabase(db, options = {}) {
|
|
|
1370
1380
|
const sql = MIGRATIONS.get(version);
|
|
1371
1381
|
if (!sql)
|
|
1372
1382
|
throw new Error(`Missing SQLite session metadata migration ${version}`);
|
|
1373
|
-
// Versions 32, 35, and
|
|
1374
|
-
// path can replay them onto a database that already carries
|
|
1375
|
-
// table shape. SQLite has no `ADD COLUMN IF NOT EXISTS`, so
|
|
1376
|
-
// live here.
|
|
1383
|
+
// Versions 32, 35, 37, and 41 each add one column, and the post-merge
|
|
1384
|
+
// convergence path can replay them onto a database that already carries
|
|
1385
|
+
// the current table shape. SQLite has no `ADD COLUMN IF NOT EXISTS`, so
|
|
1386
|
+
// the guards live here.
|
|
1377
1387
|
const columnAlreadyPresent = (version === 32 && hasColumn(db, 'message_admissions', 'submitted_intent_json')) ||
|
|
1378
1388
|
(version === 35 && hasColumn(db, 'message_admissions', 'skill_invocation_json')) ||
|
|
1379
|
-
(version === 37 &&
|
|
1389
|
+
(version === 37 &&
|
|
1390
|
+
hasColumn(db, 'cancelled_message_admissions', 'cancellation_claim_id')) ||
|
|
1391
|
+
(version === 41 && hasColumn(db, 'session_metadata', 'archived_at'));
|
|
1380
1392
|
if (!columnAlreadyPresent) {
|
|
1381
1393
|
db.exec(sql);
|
|
1382
1394
|
}
|
|
@@ -740,6 +740,7 @@ export class SqliteSessionMetadataStore {
|
|
|
740
740
|
metadata.payload_json,
|
|
741
741
|
metadata.metadata_version,
|
|
742
742
|
metadata.committed_at,
|
|
743
|
+
metadata.archived_at,
|
|
743
744
|
projection.activity_at,
|
|
744
745
|
projection.last_message_preview
|
|
745
746
|
FROM session_catalog_projection projection
|
|
@@ -954,6 +955,7 @@ export class SqliteSessionMetadataStore {
|
|
|
954
955
|
metadata.payload_json,
|
|
955
956
|
metadata.metadata_version,
|
|
956
957
|
metadata.committed_at,
|
|
958
|
+
metadata.archived_at,
|
|
957
959
|
COALESCE(projection.activity_at, 0) AS activity_at,
|
|
958
960
|
projection.last_message_preview
|
|
959
961
|
FROM session_metadata metadata
|
|
@@ -3307,7 +3309,10 @@ export class SqliteSessionMetadataStore {
|
|
|
3307
3309
|
this.assertOpen();
|
|
3308
3310
|
const identities = uniqueVersionedSessionIdentities(sessions);
|
|
3309
3311
|
return this.transaction(() => {
|
|
3310
|
-
|
|
3312
|
+
// One instant for the whole set, so a family archived together reads as
|
|
3313
|
+
// archived together.
|
|
3314
|
+
const archivedAt = this.now();
|
|
3315
|
+
const records = identities.map(({ sessionId, expectedVersion }) => this.setArchivedSync(sessionId, expectedVersion, isArchived, archivedAt));
|
|
3311
3316
|
if (isArchived)
|
|
3312
3317
|
this.deleteGoalAuthorities(identities);
|
|
3313
3318
|
return records;
|
|
@@ -3349,7 +3354,7 @@ export class SqliteSessionMetadataStore {
|
|
|
3349
3354
|
}
|
|
3350
3355
|
const deletedAt = this.now();
|
|
3351
3356
|
for (const { sessionId, expectedVersion } of archiveIdentities) {
|
|
3352
|
-
this.setArchivedSync(sessionId, expectedVersion, true);
|
|
3357
|
+
this.setArchivedSync(sessionId, expectedVersion, true, deletedAt);
|
|
3353
3358
|
}
|
|
3354
3359
|
for (const { sessionId } of present) {
|
|
3355
3360
|
const deleted = this.db
|
|
@@ -3570,7 +3575,7 @@ export class SqliteSessionMetadataStore {
|
|
|
3570
3575
|
}, sessionId);
|
|
3571
3576
|
return this.persistHeaderSync(sessionId, current, next, options);
|
|
3572
3577
|
}
|
|
3573
|
-
setArchivedSync(sessionId, expectedVersion, isArchived) {
|
|
3578
|
+
setArchivedSync(sessionId, expectedVersion, isArchived, archivedAt) {
|
|
3574
3579
|
const current = this.readRecordSync(sessionId);
|
|
3575
3580
|
if (!current)
|
|
3576
3581
|
throw new SessionNotFoundError(sessionId);
|
|
@@ -3578,7 +3583,13 @@ export class SqliteSessionMetadataStore {
|
|
|
3578
3583
|
throw new SessionMetadataVersionConflictError(sessionId, expectedVersion, current.metadataVersion);
|
|
3579
3584
|
}
|
|
3580
3585
|
const next = normalizeSessionHeader({ ...current.header, isArchived }, sessionId);
|
|
3581
|
-
|
|
3586
|
+
// A Session already in the requested state is a no-op below, so an
|
|
3587
|
+
// archived Session keeps the time it was first archived; only a real
|
|
3588
|
+
// transition writes the column. Every other writer leaves it alone.
|
|
3589
|
+
return this.persistHeaderSync(sessionId, current, next, {
|
|
3590
|
+
skipNoop: true,
|
|
3591
|
+
archivedAt: isArchived ? archivedAt : null,
|
|
3592
|
+
});
|
|
3582
3593
|
}
|
|
3583
3594
|
persistHeaderSync(sessionId, current, next, options = {}) {
|
|
3584
3595
|
if (next.id !== sessionId) {
|
|
@@ -3610,10 +3621,11 @@ export class SqliteSessionMetadataStore {
|
|
|
3610
3621
|
llm_connection_slug = ?,
|
|
3611
3622
|
model = ?,
|
|
3612
3623
|
metadata_version = ?,
|
|
3613
|
-
committed_at =
|
|
3624
|
+
committed_at = ?,
|
|
3625
|
+
archived_at = CASE WHEN ? = 1 THEN ? ELSE archived_at END
|
|
3614
3626
|
WHERE session_id = ? AND metadata_version = ?
|
|
3615
3627
|
`)
|
|
3616
|
-
.run(JSON.stringify(next), next.createdAt, next.lastMessageAt ?? null, next.name, booleanInteger(next.isFlagged), booleanInteger(next.isArchived), next.parentSessionId ?? null, next.subagentParent?.parentSessionId ?? null, next.revisionRootSessionId ?? null, next.revisionIndex ?? null, booleanInteger(next.hasUnread), next.backend, next.llmConnectionSlug, next.model, metadataVersion, committedAt, sessionId, current.metadataVersion);
|
|
3628
|
+
.run(JSON.stringify(next), next.createdAt, next.lastMessageAt ?? null, next.name, booleanInteger(next.isFlagged), booleanInteger(next.isArchived), next.parentSessionId ?? null, next.subagentParent?.parentSessionId ?? null, next.revisionRootSessionId ?? null, next.revisionIndex ?? null, booleanInteger(next.hasUnread), next.backend, next.llmConnectionSlug, next.model, metadataVersion, committedAt, options.archivedAt === undefined ? 0 : 1, options.archivedAt ?? null, sessionId, current.metadataVersion);
|
|
3617
3629
|
if (updated.changes !== 1) {
|
|
3618
3630
|
throw new SessionMetadataConflictError(`Session metadata compare-and-set failed: ${sessionId}`);
|
|
3619
3631
|
}
|
|
@@ -4495,12 +4507,22 @@ function decodeCatalogRecord(row) {
|
|
|
4495
4507
|
throw new Error(`Invalid SQLite Session catalog activity for ${row.session_id}`);
|
|
4496
4508
|
}
|
|
4497
4509
|
const lastMessagePreview = decodeCatalogPreview(row.last_message_preview, row.session_id);
|
|
4510
|
+
const archivedAt = decodeCatalogArchivedAt(row.archived_at, row.session_id);
|
|
4498
4511
|
return {
|
|
4499
4512
|
...decodeRecord(row),
|
|
4500
4513
|
activityAt: row.activity_at,
|
|
4501
4514
|
...(lastMessagePreview === undefined ? {} : { lastMessagePreview }),
|
|
4515
|
+
...(archivedAt === undefined ? {} : { archivedAt }),
|
|
4502
4516
|
};
|
|
4503
4517
|
}
|
|
4518
|
+
function decodeCatalogArchivedAt(value, sessionId) {
|
|
4519
|
+
if (value === null || value === undefined)
|
|
4520
|
+
return undefined;
|
|
4521
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {
|
|
4522
|
+
throw new Error(`Invalid SQLite Session archive time for ${sessionId}`);
|
|
4523
|
+
}
|
|
4524
|
+
return value;
|
|
4525
|
+
}
|
|
4504
4526
|
function decodeCatalogPreview(value, sessionId) {
|
|
4505
4527
|
if (value === null || value === undefined)
|
|
4506
4528
|
return undefined;
|