maka-agent 0.2.0-dev.22.20260905 → 0.2.0-dev.24.20260907
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/acp/maka-acp-agent.js +2 -1
- package/dist/acp/session-configuration.js +143 -0
- package/dist/acp/session-registry.js +90 -4
- package/dist/cli-core.js +2 -0
- package/dist/pi-transcript.js +5 -12
- package/dist/pi-tui-runner.js +74 -4
- package/dist/runtime-host-cli-context.js +167 -78
- package/dist/runtime-host-cli-installation.js +8 -2
- package/dist/runtime-host-cli.js +31 -1
- package/dist/runtime-host-handoff-surface.js +81 -0
- package/dist/runtime-host-installed-update-bootstrap.js +13 -0
- package/dist/runtime-host-installed-update-coordinator.js +33 -0
- package/dist/runtime-host-lifecycle-transaction.js +9 -1
- package/dist/runtime-host-local-handoff.js +37 -4
- package/dist/runtime-host-local-managed-activation.js +84 -0
- package/dist/runtime-host-local-source-retirement.js +18 -2
- package/dist/runtime-host-managed-lifecycle-manager.js +1 -0
- package/dist/runtime-host-operator-retirement.js +50 -0
- package/dist/runtime-host-service-manager.js +3 -0
- package/dist/runtime-host-session-driver.js +4 -25
- package/dist/runtime-host-session-update.js +62 -0
- package/dist/runtime-host-tui-command.js +38 -73
- package/dist/runtime-host-tui-context.js +1 -0
- package/dist/runtime-host-tui-owner.js +226 -0
- package/dist/tui-copy-catalog.js +140 -3
- package/dist/tui-host-owner-copy.js +24 -0
- 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/bot-events.js +18 -63
- package/node_modules/@maka/core/dist/canonical-runtime-event.js +3 -1
- package/node_modules/@maka/core/dist/model-call-attempt.js +0 -82
- package/node_modules/@maka/core/dist/model-call-usage-projection.js +0 -186
- package/node_modules/@maka/core/dist/model-failure.js +40 -0
- package/node_modules/@maka/core/dist/model-metadata.generated.js +4 -4
- package/node_modules/@maka/core/dist/model-metadata.js +3 -3
- package/node_modules/@maka/core/dist/model-web-search.js +5 -4
- package/node_modules/@maka/core/dist/provider-registry.js +45 -4
- package/node_modules/@maka/core/dist/record-schema.js +22 -2
- package/node_modules/@maka/core/dist/redaction.js +41 -58
- package/node_modules/@maka/core/dist/runtime-boundary.js +31 -11
- package/node_modules/@maka/core/dist/runtime-event.js +37 -6
- package/node_modules/@maka/core/dist/runtime-handoff.js +98 -0
- package/node_modules/@maka/core/dist/runtime-invocation.js +1 -1
- package/node_modules/@maka/core/dist/runtime-logical-execution.js +112 -0
- package/node_modules/@maka/core/dist/session-trace.js +5 -1
- package/node_modules/@maka/core/dist/session.js +54 -52
- package/node_modules/@maka/core/dist/slash-command-catalog.js +2 -0
- package/node_modules/@maka/core/dist/tool-result-archive-evidence.js +20 -0
- package/node_modules/@maka/core/dist/usage-ledger-merge.js +7 -9
- package/node_modules/@maka/core/dist/usage-record-schema.js +26 -35
- package/node_modules/@maka/core/dist/workhub-creation-intent.js +34 -20
- package/node_modules/@maka/core/package.json +4 -0
- package/node_modules/@maka/eval/harbor/egress-proxy/entrypoint.sh +2 -1
- package/node_modules/@maka/mcp/dist/index.js +131 -1
- package/node_modules/@maka/runtime/dist/agent-run.js +272 -105
- package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +13 -5
- package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +109 -34
- package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +155 -134
- package/node_modules/@maka/runtime/dist/bots/base-adapter.js +17 -0
- package/node_modules/@maka/runtime/dist/bots/bot-test.js +38 -22
- package/node_modules/@maka/runtime/dist/bots/dingtalk-bridge.js +7 -5
- package/node_modules/@maka/runtime/dist/bots/discord-bridge.js +4 -4
- package/node_modules/@maka/runtime/dist/bots/feishu-bridge.js +4 -5
- package/node_modules/@maka/runtime/dist/bots/qq-bridge.js +6 -4
- package/node_modules/@maka/runtime/dist/bots/slack-bridge.js +3 -4
- package/node_modules/@maka/runtime/dist/bots/telegram-bridge.js +4 -5
- package/node_modules/@maka/runtime/dist/bots/wechat-bridge.js +17 -19
- package/node_modules/@maka/runtime/dist/bots/wecom-bridge.js +5 -6
- package/node_modules/@maka/runtime/dist/bots/ws-bridge-base.js +2 -3
- package/node_modules/@maka/runtime/dist/context-budget.js +14 -9
- package/node_modules/@maka/runtime/dist/conversation-copy.js +5 -4
- package/node_modules/@maka/runtime/dist/goal-continuation.js +36 -4
- package/node_modules/@maka/runtime/dist/history-compact-checkpoint.js +18 -9
- package/node_modules/@maka/runtime/dist/history-compact-summarizer.js +30 -22
- package/node_modules/@maka/runtime/dist/history-compaction.js +29 -4
- package/node_modules/@maka/runtime/dist/ledger-tool-result-archive-reader.js +106 -0
- package/node_modules/@maka/runtime/dist/message-authority.js +9 -0
- package/node_modules/@maka/runtime/dist/model-adapter.js +19 -98
- package/node_modules/@maka/runtime/dist/model-factory.js +19 -81
- package/node_modules/@maka/runtime/dist/model-fetcher.js +7 -0
- package/node_modules/@maka/runtime/dist/model-runtime.js +85 -111
- package/node_modules/@maka/runtime/dist/native-web-search-tool.js +2 -1
- package/node_modules/@maka/runtime/dist/openai-codex-history-compactor.js +2 -2
- package/node_modules/@maka/runtime/dist/opencode-session-header.js +4 -2
- package/node_modules/@maka/runtime/dist/provider-error-classification.js +84 -123
- package/node_modules/@maka/runtime/dist/provider-request-telemetry.js +68 -108
- package/node_modules/@maka/runtime/dist/run-handoff-gate.js +97 -0
- package/node_modules/@maka/runtime/dist/runtime-event-backfill.js +82 -54
- package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +117 -159
- package/node_modules/@maka/runtime/dist/runtime-kernel.js +150 -112
- package/node_modules/@maka/runtime/dist/runtime-ledger-repair.js +160 -79
- package/node_modules/@maka/runtime/dist/runtime-read-model.js +30 -89
- package/node_modules/@maka/runtime/dist/runtime-resume.js +80 -4
- package/node_modules/@maka/runtime/dist/session-event-runtime-mapper.js +5 -0
- package/node_modules/@maka/runtime/dist/session-manager.js +171 -288
- package/node_modules/@maka/runtime/dist/session-projection-helpers.js +0 -27
- package/node_modules/@maka/runtime/dist/session-trace-projection.js +3 -30
- package/node_modules/@maka/runtime/dist/subscription-model-fetch.js +3 -4
- package/node_modules/@maka/runtime/dist/test-connection.js +16 -16
- package/node_modules/@maka/runtime/dist/tool-result-archive-encoding.js +38 -0
- package/node_modules/@maka/runtime/dist/tool-runtime.js +3 -61
- package/node_modules/@maka/runtime/package.json +1 -0
- package/node_modules/@maka/runtime-host/dist/adapter/session-projector.js +35 -0
- package/node_modules/@maka/runtime-host/dist/candidate-entry.js +4 -1
- package/node_modules/@maka/runtime-host/dist/client/connect-or-spawn.js +9 -1
- package/node_modules/@maka/runtime-host/dist/client/connection.js +3 -0
- package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +156 -0
- package/node_modules/@maka/runtime-host/dist/client/host-handoff.js +273 -0
- package/node_modules/@maka/runtime-host/dist/client/host-retirement.js +26 -5
- package/node_modules/@maka/runtime-host/dist/client/index.js +3 -1
- package/node_modules/@maka/runtime-host/dist/client/launcher.js +3 -0
- package/node_modules/@maka/runtime-host/dist/client/peer-client.js +13 -0
- package/node_modules/@maka/runtime-host/dist/client/registered-host-termination.js +0 -59
- package/node_modules/@maka/runtime-host/dist/client/remote-compatibility-error.js +2 -0
- package/node_modules/@maka/runtime-host/dist/client/session-subscription.js +27 -5
- package/node_modules/@maka/runtime-host/dist/operator/index.js +2 -1
- package/node_modules/@maka/runtime-host/dist/operator/retirement-cancellation.js +20 -0
- package/node_modules/@maka/runtime-host/dist/peer-mesh/node.js +28 -16
- package/node_modules/@maka/runtime-host/dist/protocol/external-session.js +4 -0
- package/node_modules/@maka/runtime-host/dist/protocol/host-status.js +29 -12
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +37 -1
- package/node_modules/@maka/runtime-host/dist/protocol/operations.js +2 -0
- package/node_modules/@maka/runtime-host/dist/protocol/session-collaboration.js +28 -1
- package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +40 -20
- package/node_modules/@maka/runtime-host/dist/protocol/session-transcript.js +0 -5
- package/node_modules/@maka/runtime-host/dist/protocol/session-turns.js +29 -58
- package/node_modules/@maka/runtime-host/dist/protocol/turn.js +11 -1
- package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +33 -0
- package/node_modules/@maka/runtime-host/dist/server/access-authority.js +26 -1
- package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +6 -1
- package/node_modules/@maka/runtime-host/dist/server/canonical-turn-snapshot.js +19 -4
- package/node_modules/@maka/runtime-host/dist/server/canonical-usage-reader.js +24 -11
- package/node_modules/@maka/runtime-host/dist/server/connection-session.js +7 -6
- package/node_modules/@maka/runtime-host/dist/server/daily-review-coordinator.js +7 -4
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +168 -28
- package/node_modules/@maka/runtime-host/dist/server/execution-model-authority.js +5 -5
- package/node_modules/@maka/runtime-host/dist/server/execution-model-composition.js +3 -2
- package/node_modules/@maka/runtime-host/dist/server/external-session-coordinator.js +6 -3
- package/node_modules/@maka/runtime-host/dist/server/goal-coordinator.js +40 -1
- package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +108 -23
- package/node_modules/@maka/runtime-host/dist/server/host-residency-registry.js +13 -7
- package/node_modules/@maka/runtime-host/dist/server/hosted-execution-admission-registry.js +3 -1
- package/node_modules/@maka/runtime-host/dist/server/hosted-execution-recovery.js +124 -62
- package/node_modules/@maka/runtime-host/dist/server/message-coordinator.js +85 -8
- package/node_modules/@maka/runtime-host/dist/server/root-admission-owner.js +7 -0
- package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +344 -71
- package/node_modules/@maka/runtime-host/dist/server/scheduled-task-coordinator.js +37 -2
- package/node_modules/@maka/runtime-host/dist/server/serial-outbound-writer.js +45 -3
- package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +201 -12
- package/node_modules/@maka/runtime-host/dist/server/session-continuity-coordinator.js +87 -25
- package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +8 -55
- package/node_modules/@maka/runtime-host/dist/server/session-sidecar-purge.js +1 -16
- package/node_modules/@maka/runtime-host/dist/server/session-transcript-pager.js +0 -1
- package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +460 -70
- package/node_modules/@maka/runtime-host/dist/server/shared-session-transcript.js +1 -1
- package/node_modules/@maka/runtime-host/dist/server/storage-maintenance.js +109 -0
- package/node_modules/@maka/runtime-host/dist/server/usage-pricing-coordinator.js +4 -11
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +44 -15
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +6 -2
- package/node_modules/@maka/storage/dist/agent-run-store.js +44 -0
- package/node_modules/@maka/storage/dist/artifact-store.js +21 -10
- package/node_modules/@maka/storage/dist/artifact-stores.js +1 -1
- package/node_modules/@maka/storage/dist/claude-code-session-adapter.js +0 -4
- package/node_modules/@maka/storage/dist/codex-session-adapter.js +0 -2
- package/node_modules/@maka/storage/dist/context-offload-snapshot.js +325 -0
- package/node_modules/@maka/storage/dist/conversation-operational-state.js +4 -0
- package/node_modules/@maka/storage/dist/execution-stores.js +11 -7
- package/node_modules/@maka/storage/dist/file-session-repository.js +1012 -0
- package/node_modules/@maka/storage/dist/model-call-ledger.js +199 -32
- package/node_modules/@maka/storage/dist/model-call-usage-sql.js +136 -0
- package/node_modules/@maka/storage/dist/opencode-session-adapter.js +0 -4
- package/node_modules/@maka/storage/dist/operational-state-backup.js +9 -5
- package/node_modules/@maka/storage/dist/operational-state-store-public.js +1 -1
- package/node_modules/@maka/storage/dist/operational-state-store.js +5 -3
- package/node_modules/@maka/storage/dist/runtime-event-persistence.js +1 -0
- package/node_modules/@maka/storage/dist/runtime-transcript-query.js +308 -0
- package/node_modules/@maka/storage/dist/session-bundle-policy.js +24 -4
- package/node_modules/@maka/storage/dist/session-message-projection.js +15 -0
- package/node_modules/@maka/storage/dist/session-repository.js +767 -0
- package/node_modules/@maka/storage/dist/session-store.js +25 -99
- package/node_modules/@maka/storage/dist/sqlite-artifact-metadata.js +10 -3
- package/node_modules/@maka/storage/dist/sqlite-context-offload-store.js +24 -8
- package/node_modules/@maka/storage/dist/sqlite-core-execution-schema.js +17 -1
- package/node_modules/@maka/storage/dist/sqlite-runtime-schema.js +44 -1
- package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +129 -25
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +109 -892
- package/node_modules/@maka/storage/dist/sqlite-usage-schema.js +200 -20
- package/node_modules/@maka/storage/dist/tool-result-archive-evidence.js +111 -0
- package/node_modules/@maka/storage/dist/usage-stores.js +6 -2
- package/node_modules/@maka/storage/package.json +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,325 @@
|
|
|
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
|
+
import { createHash } from 'node:crypto';
|
|
20
|
+
import { createReadStream } from 'node:fs';
|
|
21
|
+
import { chmod, copyFile, lstat, mkdir, realpath } from 'node:fs/promises';
|
|
22
|
+
import { dirname, join, resolve } from 'node:path';
|
|
23
|
+
import { backup, DatabaseSync } from 'node:sqlite';
|
|
24
|
+
import { isCanonicalStorageRef } from '@maka/core/events';
|
|
25
|
+
import { discoverMarkedStorageRoot, runWithStorageRootLease, tryAcquireInteractiveRootOwner, } from './root-authority.js';
|
|
26
|
+
import { migrateSqliteContextOffloadDatabase, SQLITE_CONTEXT_OFFLOAD_SCHEMA_VERSION, } from './sqlite-context-offload-schema.js';
|
|
27
|
+
import { CONTEXT_OFFLOAD_DATABASE_NAME, CONTEXT_OFFLOAD_VALUES_DIRECTORY_NAME, } from './sqlite-context-offload-store.js';
|
|
28
|
+
import { syncDirectoryChain, syncFile } from './stable-storage.js';
|
|
29
|
+
import { SQLITE_SESSION_MESSAGE_CHUNK_MARKER } from './sqlite-session-metadata-schema.js';
|
|
30
|
+
/**
|
|
31
|
+
* Existing artifact-only snapshots keep their old admission contract. Context
|
|
32
|
+
* snapshots require the root owner: a Session gate does not fence global GC.
|
|
33
|
+
* The callback must recheck absence before publishing an artifact-only snapshot.
|
|
34
|
+
*/
|
|
35
|
+
export async function withOfflineContextSnapshot(root, operation) {
|
|
36
|
+
if (!(await exists(join(root, CONTEXT_OFFLOAD_DATABASE_NAME))))
|
|
37
|
+
return operation(false);
|
|
38
|
+
const capability = await discoverMarkedStorageRoot({ path: root });
|
|
39
|
+
const owner = await tryAcquireInteractiveRootOwner(capability);
|
|
40
|
+
if (!owner)
|
|
41
|
+
throw new Error('Context snapshot requires an offline Storage Root; stop the Runtime Host first');
|
|
42
|
+
try {
|
|
43
|
+
return await runWithStorageRootLease(owner.lease, 'interactive', 'write', () => operation(true));
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
await owner.close();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Copies under the offline owner and the caller's Artifact lock; never mutates the source DB. */
|
|
50
|
+
export async function copyContextSnapshot(sourceRoot, targetRoot, contextLocked, sessionId) {
|
|
51
|
+
const sourcePath = join(sourceRoot, CONTEXT_OFFLOAD_DATABASE_NAME);
|
|
52
|
+
if (!(await exists(sourcePath)))
|
|
53
|
+
return false;
|
|
54
|
+
if (!contextLocked)
|
|
55
|
+
throw new Error('Context storage appeared during snapshot; retry with the Runtime Host stopped');
|
|
56
|
+
await assertRegularPath(sourceRoot, CONTEXT_OFFLOAD_DATABASE_NAME);
|
|
57
|
+
const targetPath = join(targetRoot, CONTEXT_OFFLOAD_DATABASE_NAME);
|
|
58
|
+
const source = new DatabaseSync(sourcePath, { readOnly: true });
|
|
59
|
+
try {
|
|
60
|
+
await backup(source, targetPath);
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
source.close();
|
|
64
|
+
}
|
|
65
|
+
await chmod(targetPath, 0o600);
|
|
66
|
+
const target = new DatabaseSync(targetPath);
|
|
67
|
+
try {
|
|
68
|
+
target.exec('PRAGMA foreign_keys = ON');
|
|
69
|
+
migrateSqliteContextOffloadDatabase(target);
|
|
70
|
+
target.exec('BEGIN IMMEDIATE');
|
|
71
|
+
if (sessionId !== undefined)
|
|
72
|
+
target.prepare('DELETE FROM context_refs WHERE session_id <> ?').run(sessionId);
|
|
73
|
+
target.exec(`
|
|
74
|
+
DELETE FROM context_gc_candidates;
|
|
75
|
+
DELETE FROM context_file_deletions;
|
|
76
|
+
DELETE FROM context_blobs WHERE NOT EXISTS (
|
|
77
|
+
SELECT 1 FROM context_refs WHERE context_refs.blob_id = context_blobs.blob_id
|
|
78
|
+
);
|
|
79
|
+
DELETE FROM context_session_usage;
|
|
80
|
+
INSERT INTO context_session_usage
|
|
81
|
+
SELECT r.session_id, count(*), sum(b.size_bytes)
|
|
82
|
+
FROM context_refs r JOIN context_blobs b USING(blob_id) GROUP BY r.session_id;
|
|
83
|
+
UPDATE context_store_usage SET
|
|
84
|
+
blob_count = (SELECT count(*) FROM context_blobs),
|
|
85
|
+
physical_bytes = (SELECT coalesce(sum(size_bytes), 0) FROM context_blobs)
|
|
86
|
+
WHERE singleton = 1;
|
|
87
|
+
COMMIT;
|
|
88
|
+
PRAGMA journal_mode = DELETE;
|
|
89
|
+
VACUUM;
|
|
90
|
+
`);
|
|
91
|
+
// VACUUM on the private destination removes other Sessions' deleted bytes,
|
|
92
|
+
// including SQLite free pages. It is never run on the live source.
|
|
93
|
+
for (const row of target
|
|
94
|
+
.prepare("SELECT blob_id, payload, size_bytes FROM context_blobs WHERE storage_kind = 'managed_file'")
|
|
95
|
+
.iterate()) {
|
|
96
|
+
const path = managedPath(row.blob_id, row.payload);
|
|
97
|
+
await assertRegularPath(sourceRoot, path);
|
|
98
|
+
const destination = join(targetRoot, path);
|
|
99
|
+
await mkdir(dirname(destination), { recursive: true, mode: 0o700 });
|
|
100
|
+
await copyFile(join(sourceRoot, path), destination);
|
|
101
|
+
await chmod(destination, 0o600);
|
|
102
|
+
await syncFile(destination);
|
|
103
|
+
await syncDirectoryChain(dirname(destination), targetRoot);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
finally {
|
|
107
|
+
target.close();
|
|
108
|
+
}
|
|
109
|
+
await syncFile(targetPath);
|
|
110
|
+
await syncDirectoryChain(targetRoot, targetRoot);
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
export async function planContextSnapshotFiles(root, sessionId) {
|
|
114
|
+
const path = join(root, CONTEXT_OFFLOAD_DATABASE_NAME);
|
|
115
|
+
if (!(await exists(path)))
|
|
116
|
+
return [];
|
|
117
|
+
await assertRegularPath(root, CONTEXT_OFFLOAD_DATABASE_NAME);
|
|
118
|
+
const database = new DatabaseSync(path, { readOnly: true });
|
|
119
|
+
try {
|
|
120
|
+
const version = Number(database.prepare('PRAGMA user_version').get()?.user_version);
|
|
121
|
+
if (![1, 2, SQLITE_CONTEXT_OFFLOAD_SCHEMA_VERSION].includes(version))
|
|
122
|
+
throw new Error('Unsupported context snapshot schema');
|
|
123
|
+
const files = [CONTEXT_OFFLOAD_DATABASE_NAME];
|
|
124
|
+
if (version < 3)
|
|
125
|
+
return files;
|
|
126
|
+
for (const row of database
|
|
127
|
+
.prepare(`SELECT DISTINCT b.blob_id, b.payload FROM context_refs r
|
|
128
|
+
JOIN context_blobs b ON b.blob_id = r.blob_id
|
|
129
|
+
WHERE r.session_id = ? AND b.storage_kind = 'managed_file' ORDER BY b.blob_id`)
|
|
130
|
+
.iterate(sessionId)) {
|
|
131
|
+
const file = managedPath(row.blob_id, row.payload);
|
|
132
|
+
await assertRegularPath(root, file);
|
|
133
|
+
files.push(file);
|
|
134
|
+
}
|
|
135
|
+
return files;
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
database.close();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/** Verifies both payload integrity and typed ledger/message references before publication. */
|
|
142
|
+
export async function validateContextSnapshot(root) {
|
|
143
|
+
let context;
|
|
144
|
+
const contextPath = join(root, CONTEXT_OFFLOAD_DATABASE_NAME);
|
|
145
|
+
try {
|
|
146
|
+
if (await exists(contextPath)) {
|
|
147
|
+
await assertRegularPath(root, CONTEXT_OFFLOAD_DATABASE_NAME);
|
|
148
|
+
context = new DatabaseSync(contextPath, { readOnly: true });
|
|
149
|
+
if (context.prepare('PRAGMA user_version').get()?.user_version !==
|
|
150
|
+
SQLITE_CONTEXT_OFFLOAD_SCHEMA_VERSION)
|
|
151
|
+
throw new Error('Unsupported context snapshot schema');
|
|
152
|
+
if (context.prepare('PRAGMA integrity_check').get()?.integrity_check !== 'ok' ||
|
|
153
|
+
context.prepare('PRAGMA foreign_key_check').get())
|
|
154
|
+
throw new Error('Invalid context snapshot database');
|
|
155
|
+
for (const row of context
|
|
156
|
+
.prepare('SELECT blob_id, storage_kind, payload, size_bytes FROM context_blobs')
|
|
157
|
+
.iterate()) {
|
|
158
|
+
const digest = blobHash(row.blob_id);
|
|
159
|
+
if (!Number.isSafeInteger(row.size_bytes) || Number(row.size_bytes) < 0)
|
|
160
|
+
throw new Error('Invalid context snapshot size');
|
|
161
|
+
if (row.storage_kind === 'managed_file') {
|
|
162
|
+
const path = managedPath(row.blob_id, row.payload);
|
|
163
|
+
await assertRegularPath(root, path);
|
|
164
|
+
const info = await lstat(join(root, path));
|
|
165
|
+
if (info.size !== row.size_bytes || (await hashFile(join(root, path))) !== digest) {
|
|
166
|
+
throw new Error('Context snapshot payload size/hash mismatch');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else if (row.storage_kind !== 'inline' ||
|
|
170
|
+
!(row.payload instanceof Uint8Array) ||
|
|
171
|
+
row.payload.byteLength !== row.size_bytes ||
|
|
172
|
+
createHash('sha256').update(row.payload).digest('hex') !== digest) {
|
|
173
|
+
throw new Error('Context snapshot inline payload size/hash mismatch');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const actual = context
|
|
177
|
+
.prepare('SELECT count(*) AS n, coalesce(sum(size_bytes), 0) AS bytes FROM context_blobs')
|
|
178
|
+
.get();
|
|
179
|
+
const usage = context
|
|
180
|
+
.prepare('SELECT blob_count, physical_bytes FROM context_store_usage WHERE singleton = 1')
|
|
181
|
+
.get();
|
|
182
|
+
if (usage?.blob_count !== actual.n || usage.physical_bytes !== actual.bytes)
|
|
183
|
+
throw new Error('Context snapshot usage mismatch');
|
|
184
|
+
if (context
|
|
185
|
+
.prepare(`SELECT 1 FROM (
|
|
186
|
+
SELECT r.session_id, count(*) AS reference_count, sum(b.size_bytes) AS logical_bytes
|
|
187
|
+
FROM context_refs r JOIN context_blobs b USING(blob_id) GROUP BY r.session_id
|
|
188
|
+
EXCEPT SELECT session_id, reference_count, logical_bytes FROM context_session_usage
|
|
189
|
+
) LIMIT 1`)
|
|
190
|
+
.get())
|
|
191
|
+
throw new Error('Context snapshot Session usage mismatch');
|
|
192
|
+
}
|
|
193
|
+
validateLedgerContextRefs(root, context);
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
context?.close();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function validateLedgerContextRefs(root, context) {
|
|
200
|
+
const runtime = new DatabaseSync(join(root, 'runtime.sqlite'), { readOnly: true });
|
|
201
|
+
const find = context?.prepare('SELECT 1 FROM context_refs WHERE session_id = ? AND ref_id = ?');
|
|
202
|
+
const check = (value, sessionId) => {
|
|
203
|
+
const ref = record(value);
|
|
204
|
+
if (ref.kind !== 'session_context')
|
|
205
|
+
return;
|
|
206
|
+
if (!isCanonicalStorageRef(value) ||
|
|
207
|
+
ref.sessionId !== sessionId ||
|
|
208
|
+
!find?.get(sessionId, String(ref.refId)))
|
|
209
|
+
throw new Error('Snapshot has a missing or cross-Session context reference');
|
|
210
|
+
};
|
|
211
|
+
const content = (value, sessionId) => {
|
|
212
|
+
const item = record(value);
|
|
213
|
+
if (item.kind === 'image')
|
|
214
|
+
check(item.ref, sessionId);
|
|
215
|
+
};
|
|
216
|
+
const attachments = (value, sessionId) => {
|
|
217
|
+
const item = record(value);
|
|
218
|
+
if (Array.isArray(item.attachments)) {
|
|
219
|
+
for (const attachment of item.attachments)
|
|
220
|
+
check(record(attachment).ref, sessionId);
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
const projection = (value, sessionId) => {
|
|
224
|
+
const item = record(value);
|
|
225
|
+
if (item.kind === 'content' && Array.isArray(item.parts)) {
|
|
226
|
+
for (const part of item.parts) {
|
|
227
|
+
const entry = record(part);
|
|
228
|
+
if (entry.kind === 'artifact')
|
|
229
|
+
check(entry.ref, sessionId);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
try {
|
|
234
|
+
for (const row of runtime
|
|
235
|
+
.prepare('SELECT session_id, payload_json FROM runtime_events')
|
|
236
|
+
.iterate()) {
|
|
237
|
+
const event = record(JSON.parse(String(row.payload_json)));
|
|
238
|
+
const item = record(event.content);
|
|
239
|
+
const sessionId = String(row.session_id);
|
|
240
|
+
if (item.kind === 'text')
|
|
241
|
+
attachments(item, sessionId);
|
|
242
|
+
if (item.kind === 'function_response') {
|
|
243
|
+
content(item.result, sessionId);
|
|
244
|
+
projection(item.modelProjection, sessionId);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
for (const row of runtime
|
|
248
|
+
.prepare("SELECT session_id, record_json FROM core_agent_run_events WHERE event_type = 'model_projection_transition_recorded'")
|
|
249
|
+
.iterate()) {
|
|
250
|
+
const event = record(JSON.parse(String(row.record_json)));
|
|
251
|
+
projection(record(record(event.data).transition).replacement, String(row.session_id));
|
|
252
|
+
}
|
|
253
|
+
const chunks = runtime.prepare('SELECT data FROM session_message_chunks WHERE session_id = ? AND sequence = ? ORDER BY chunk_index');
|
|
254
|
+
for (const row of runtime
|
|
255
|
+
.prepare('SELECT session_id, sequence, record_json FROM session_messages')
|
|
256
|
+
.iterate()) {
|
|
257
|
+
const encoded = row.record_json === SQLITE_SESSION_MESSAGE_CHUNK_MARKER
|
|
258
|
+
? Buffer.concat(chunks.all(row.session_id, row.sequence).map((chunk) => {
|
|
259
|
+
if (!(chunk.data instanceof Uint8Array))
|
|
260
|
+
throw new Error('Invalid snapshot message chunk');
|
|
261
|
+
return Buffer.from(chunk.data);
|
|
262
|
+
})).toString('utf8')
|
|
263
|
+
: String(row.record_json);
|
|
264
|
+
const message = record(JSON.parse(encoded));
|
|
265
|
+
const sessionId = String(row.session_id);
|
|
266
|
+
if (message.type === 'user')
|
|
267
|
+
attachments(message, sessionId);
|
|
268
|
+
if (message.type === 'tool_result')
|
|
269
|
+
content(message.content, sessionId);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
finally {
|
|
273
|
+
runtime.close();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function record(value) {
|
|
277
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
278
|
+
? value
|
|
279
|
+
: {};
|
|
280
|
+
}
|
|
281
|
+
function blobHash(value) {
|
|
282
|
+
if (!(value instanceof Uint8Array) || value.byteLength !== 32)
|
|
283
|
+
throw new Error('Invalid context snapshot blob identity');
|
|
284
|
+
return Buffer.from(value).toString('hex');
|
|
285
|
+
}
|
|
286
|
+
function managedPath(blobId, payload) {
|
|
287
|
+
const digest = blobHash(blobId);
|
|
288
|
+
const expected = `sha256/${digest.slice(0, 2)}/${digest}`;
|
|
289
|
+
if (!(payload instanceof Uint8Array) || !Buffer.from(payload).equals(Buffer.from(expected))) {
|
|
290
|
+
throw new Error('Invalid context snapshot managed locator');
|
|
291
|
+
}
|
|
292
|
+
return `${CONTEXT_OFFLOAD_VALUES_DIRECTORY_NAME}/${expected}`;
|
|
293
|
+
}
|
|
294
|
+
async function assertRegularPath(root, relativePath) {
|
|
295
|
+
const canonical = await realpath(root);
|
|
296
|
+
const parts = relativePath.split('/');
|
|
297
|
+
let path = canonical;
|
|
298
|
+
for (const [index, part] of parts.entries()) {
|
|
299
|
+
path = join(path, part);
|
|
300
|
+
const info = await lstat(path);
|
|
301
|
+
if (info.isSymbolicLink() ||
|
|
302
|
+
(index === parts.length - 1 ? !info.isFile() : !info.isDirectory())) {
|
|
303
|
+
throw new Error('Context snapshot path must not contain symlinks or special files');
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
if ((await realpath(path)) !== resolve(canonical, relativePath))
|
|
307
|
+
throw new Error('Context snapshot path escaped its root');
|
|
308
|
+
}
|
|
309
|
+
async function hashFile(path) {
|
|
310
|
+
const hash = createHash('sha256');
|
|
311
|
+
for await (const chunk of createReadStream(path))
|
|
312
|
+
hash.update(chunk);
|
|
313
|
+
return hash.digest('hex');
|
|
314
|
+
}
|
|
315
|
+
async function exists(path) {
|
|
316
|
+
try {
|
|
317
|
+
await lstat(path);
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT')
|
|
322
|
+
return false;
|
|
323
|
+
throw error;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
@@ -67,6 +67,10 @@ class SqliteConversationOperationalStateStore {
|
|
|
67
67
|
database
|
|
68
68
|
.prepare('DELETE FROM core_root_turn_start_rejections WHERE session_id = ?')
|
|
69
69
|
.run(sessionId);
|
|
70
|
+
// Cascades this run's events and the Usage projection's checkpoints.
|
|
71
|
+
// `usage_model_call_attempts` is deliberately absent from this list:
|
|
72
|
+
// deleting a conversation must not erase its spend from all-time Usage
|
|
73
|
+
// totals, so those rows outlive the authority they were projected from.
|
|
70
74
|
database.prepare('DELETE FROM core_agent_runs WHERE session_id = ?').run(sessionId);
|
|
71
75
|
database
|
|
72
76
|
.prepare('DELETE FROM core_client_capability_session_grants WHERE session_id = ?')
|
|
@@ -29,7 +29,7 @@ const executionStoresReaderKinds = new WeakMap();
|
|
|
29
29
|
const executionStoresWritersByLease = new WeakMap();
|
|
30
30
|
const executionStoresWritersOpeningByLease = new WeakMap();
|
|
31
31
|
export { normalizeRootTurnAdmissionPayload, rootTurnAdmissionRecordFits, } from './agent-run-store.js';
|
|
32
|
-
export { isSessionNotFoundError
|
|
32
|
+
export { isSessionNotFoundError } from './session-store.js';
|
|
33
33
|
export { SessionMetadataConflictError, SessionMetadataVersionConflictError, } from './sqlite-session-metadata-store.js';
|
|
34
34
|
export { submittedTurnIntentsEqual } from './submitted-turn-intent.js';
|
|
35
35
|
export function authenticateExecutionStoresWriter(stores, expectedKind) {
|
|
@@ -140,6 +140,7 @@ async function createExecutionStoresForWrite(lease, kind, extension) {
|
|
|
140
140
|
readSandboxBoundaryRequest: (sessionId, requestId) => run(() => sessionStore.readSandboxBoundaryRequest(sessionId, requestId)),
|
|
141
141
|
listPendingSandboxBoundaryRequests: (sessionId) => run(() => sessionStore.listPendingSandboxBoundaryRequests(sessionId)),
|
|
142
142
|
listSandboxBoundaryRestartClosures: (sessionId) => run(() => sessionStore.listSandboxBoundaryRestartClosures(sessionId)),
|
|
143
|
+
hasExplicitSandboxBoundaryDenial: (identities) => run(() => sessionStore.hasExplicitSandboxBoundaryDenial(identities)),
|
|
143
144
|
settleSandboxBoundaryRequest: (input) => run(() => sessionStore.settleSandboxBoundaryRequest(input)),
|
|
144
145
|
setExecutionBoundaryKind: (sessionId, boundaryKind, projection) => run(() => sessionStore.setExecutionBoundaryKind(sessionId, boundaryKind, projection)),
|
|
145
146
|
list: (filter) => run(() => sessionStore.list(filter)),
|
|
@@ -151,19 +152,16 @@ async function createExecutionStoresForWrite(lease, kind, extension) {
|
|
|
151
152
|
readCatalogRecord: (sessionId) => run(() => sessionStore.readCatalogRecord(sessionId)),
|
|
152
153
|
probeSessionRemoval: (sessionId) => run(() => sessionStore.probeSessionRemoval(sessionId)),
|
|
153
154
|
readMessagesSnapshot: (sessionId) => run(() => sessionStore.readMessagesSnapshot(sessionId)),
|
|
154
|
-
readTranscriptPageSnapshot: (sessionId, request) => run(() => sessionStore.readTranscriptPageSnapshot(sessionId, request)),
|
|
155
|
-
readTranscriptRecordsSnapshot: (sessionId, request) => run(() => sessionStore.readTranscriptRecordsSnapshot(sessionId, request)),
|
|
156
155
|
readTranscriptMessagesSnapshot: (sessionId, request) => run(() => sessionStore.readTranscriptMessagesSnapshot(sessionId, request)),
|
|
157
156
|
readTranscriptHighWaterSnapshot: (sessionId) => run(() => sessionStore.readTranscriptHighWaterSnapshot(sessionId)),
|
|
158
|
-
readTurnContributionsSnapshot: (sessionId, throughSequence, position, maxContributions) => run(() => sessionStore.readTurnContributionsSnapshot(sessionId, throughSequence, position, maxContributions)),
|
|
159
|
-
readTurnLandmarksSnapshot: (sessionId, maxLandmarks) => run(() => sessionStore.readTurnLandmarksSnapshot(sessionId, maxLandmarks)),
|
|
160
|
-
readMessagesForRecovery: (sessionId) => run(() => sessionStore.readMessagesForRecovery(sessionId)),
|
|
161
157
|
listTurnsSnapshot: (sessionId) => run(() => sessionStore.listTurnsSnapshot(sessionId)),
|
|
162
158
|
readHeader: (sessionId) => run(() => sessionStore.readHeader(sessionId)),
|
|
163
159
|
readMessages: (sessionId) => run(() => sessionStore.readMessages(sessionId)),
|
|
160
|
+
readMessagesAfter: (sessionId, request) => run(() => sessionStore.readMessagesAfter(sessionId, request)),
|
|
164
161
|
listTurns: (sessionId) => run(() => sessionStore.listTurns(sessionId)),
|
|
165
162
|
appendMessage: (sessionId, message) => run(() => sessionStore.appendMessage(sessionId, message)),
|
|
166
163
|
appendMessages: (sessionId, messages) => run(() => sessionStore.appendMessages(sessionId, messages)),
|
|
164
|
+
commitMessageCatalogProjection: (sessionId, message) => run(() => sessionStore.commitMessageCatalogProjection(sessionId, message)),
|
|
167
165
|
commitMessageAdmission: (admission) => run(() => sessionStore.commitMessageAdmission(admission)),
|
|
168
166
|
readMessageAdmission: (sessionId, messageId) => run(() => sessionStore.readMessageAdmission(sessionId, messageId)),
|
|
169
167
|
hasCancelledMessageAdmission: (sessionId, messageId) => run(() => sessionStore.hasCancelledMessageAdmission(sessionId, messageId)),
|
|
@@ -177,7 +175,6 @@ async function createExecutionStoresForWrite(lease, kind, extension) {
|
|
|
177
175
|
updateHeader: (sessionId, patch) => run(() => sessionStore.updateHeader(sessionId, patch)),
|
|
178
176
|
updateHeaderVersioned: (sessionId, patch, expectedRevision) => run(() => sessionStore.updateHeaderVersioned(sessionId, patch, expectedRevision)),
|
|
179
177
|
updateSessionConfiguration: (sessionId, input) => run(() => sessionStore.updateSessionConfiguration(sessionId, input)),
|
|
180
|
-
markSessionReadThroughMessage: (sessionId, messageId) => run(() => sessionStore.markSessionReadThroughMessage(sessionId, messageId)),
|
|
181
178
|
setFlagged: (sessionId, isFlagged) => run(() => sessionStore.setFlagged(sessionId, isFlagged)),
|
|
182
179
|
rename: (sessionId, name) => run(() => sessionStore.rename(sessionId, name)),
|
|
183
180
|
setGeneratedTitleIfAbsent: (sessionId, title) => run(() => sessionStore.setGeneratedTitleIfAbsent(sessionId, title)),
|
|
@@ -210,6 +207,7 @@ async function createExecutionStoresForWrite(lease, kind, extension) {
|
|
|
210
207
|
repairEventProjection: (sessionId, type, event, options) => run(() => agentRunStore.repairEventProjection(sessionId, type, event, options)),
|
|
211
208
|
admitRootTurn: (input) => run(() => agentRunStore.admitRootTurn(input)),
|
|
212
209
|
readRootTurnAdmission: (sessionId, turnId) => run(() => agentRunStore.readRootTurnAdmission(sessionId, turnId)),
|
|
210
|
+
readRootTurnContinuationAdmission: (sessionId, sourceTurnId, sourceRunId) => run(() => agentRunStore.readRootTurnContinuationAdmission(sessionId, sourceTurnId, sourceRunId)),
|
|
213
211
|
readRootTurnStartRejection: (sessionId, turnId) => run(() => agentRunStore.readRootTurnStartRejection(sessionId, turnId)),
|
|
214
212
|
commitRootTurnStartRejection: (input) => run(() => agentRunStore.commitRootTurnStartRejection(input)),
|
|
215
213
|
readRootTurnSourceMessageReceipt: (sessionId, sourceMessageId) => run(() => agentRunStore.readRootTurnSourceMessageReceipt(sessionId, sourceMessageId)),
|
|
@@ -235,6 +233,10 @@ async function createExecutionStoresForWrite(lease, kind, extension) {
|
|
|
235
233
|
readInvocation: (sessionId, invocationId) => run(() => runtimeEventStore.readInvocation(sessionId, invocationId)),
|
|
236
234
|
readSessionRuntimeEvents: (sessionId) => run(() => runtimeEventStore.readSessionRuntimeEvents(sessionId)),
|
|
237
235
|
readSessionRuntimeEventEntries: (sessionId) => run(() => runtimeEventStore.readSessionRuntimeEventEntries(sessionId)),
|
|
236
|
+
resequenceSessionEventOrdinals: (sessionId) => run(() => runtimeEventStore.resequenceSessionEventOrdinals(sessionId)),
|
|
237
|
+
readTranscriptHighWater: (sessionId) => run(() => runtimeEventStore.readTranscriptHighWater(sessionId)),
|
|
238
|
+
readTranscriptInvocations: (sessionId, request) => run(() => runtimeEventStore.readTranscriptInvocations(sessionId, request)),
|
|
239
|
+
readTranscriptLandmarks: (sessionId, throughOrdinal, limit) => run(() => runtimeEventStore.readTranscriptLandmarks(sessionId, throughOrdinal, limit)),
|
|
238
240
|
claimContinuation: (input) => run(() => runtimeEventStore.claimContinuation(input)),
|
|
239
241
|
readContinuationClaimByBoundary: (boundaryDigest) => run(() => runtimeEventStore.readContinuationClaimByBoundary(boundaryDigest)),
|
|
240
242
|
readContinuationClaimStateByBoundary: (boundaryDigest) => run(() => runtimeEventStore.readContinuationClaimStateByBoundary(boundaryDigest)),
|
|
@@ -302,6 +304,7 @@ async function openExecutionStoresForRead(lease, kind, extension) {
|
|
|
302
304
|
readEventsByTypeBounded: (sessionId, runId, type, budget) => run(() => agentRunStore.readEventsByTypeBounded(sessionId, runId, type, budget)),
|
|
303
305
|
readEventProjection: (sessionId, type) => run(() => agentRunStore.readEventProjection(sessionId, type)),
|
|
304
306
|
readRootTurnAdmission: (sessionId, turnId) => run(() => agentRunStore.readRootTurnAdmission(sessionId, turnId)),
|
|
307
|
+
readRootTurnContinuationAdmission: (sessionId, sourceTurnId, sourceRunId) => run(() => agentRunStore.readRootTurnContinuationAdmission(sessionId, sourceTurnId, sourceRunId)),
|
|
305
308
|
readRootTurnSourceMessageReceipt: (sessionId, sourceMessageId) => run(() => agentRunStore.readRootTurnSourceMessageReceipt(sessionId, sourceMessageId)),
|
|
306
309
|
},
|
|
307
310
|
runtimeEventStore: {
|
|
@@ -314,6 +317,7 @@ async function openExecutionStoresForRead(lease, kind, extension) {
|
|
|
314
317
|
listSessionInvocationsPage: (sessionId, input) => run(() => runtimeEventStore.listSessionInvocationsPage(sessionId, input)),
|
|
315
318
|
readInvocation: (sessionId, invocationId) => run(() => runtimeEventStore.readInvocation(sessionId, invocationId)),
|
|
316
319
|
readSessionRuntimeEvents: (sessionId) => run(() => runtimeEventStore.readSessionRuntimeEvents(sessionId)),
|
|
320
|
+
readSessionRuntimeEventEntries: (sessionId) => run(() => runtimeEventStore.readSessionRuntimeEventEntries(sessionId)),
|
|
317
321
|
},
|
|
318
322
|
};
|
|
319
323
|
freezeExecutionStoresFacade(stores);
|