maka-agent 0.2.0-dev.12.20260901 → 0.2.0-dev.14.20260902
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/THIRD_PARTY_NOTICES.txt +2 -2
- package/dist/acp/maka-acp-agent.js +6 -3
- package/dist/acp/session-registry.js +307 -0
- package/dist/acp/stdio-server.js +20 -1
- package/dist/cli-core.js +15 -2
- package/dist/pi-transcript.js +1 -1
- package/dist/pi-tui-layout.js +1 -1
- package/dist/pi-tui-mcp-status.js +1 -1
- package/dist/pi-tui-runner.js +1 -1
- package/dist/runtime-host-access-command.js +37 -4
- package/dist/runtime-host-capability-provider-command.js +16 -2
- package/dist/runtime-host-cli-context.js +73 -3
- package/dist/runtime-host-cli.js +37 -6
- package/dist/runtime-host-run-command.js +3 -1
- package/dist/runtime-host-update-command.js +59 -31
- package/dist/tui-copy-catalog.js +4 -2
- 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/node_modules/@maka/core/dist/attachments.js +12 -0
- package/node_modules/@maka/core/dist/connection-error-copy.js +17 -34
- package/node_modules/@maka/core/dist/events.js +0 -13
- package/node_modules/@maka/core/dist/maka-wordmark.js +23 -0
- package/node_modules/@maka/core/dist/model-catalog.js +22 -1
- package/node_modules/@maka/core/dist/runtime-event.js +1 -0
- package/node_modules/@maka/core/dist/runtime-policy/connection-catalog-codec.js +50 -1
- package/node_modules/@maka/core/dist/runtime-policy/credential-vault-codec.js +9 -1
- package/node_modules/@maka/core/dist/runtime-policy/model-catalog-entry-codec.js +10 -1
- package/node_modules/@maka/core/dist/runtime-policy/policy-codec.js +75 -0
- package/node_modules/@maka/core/dist/runtime-policy.js +4 -2
- package/node_modules/@maka/core/dist/session.js +1 -0
- package/node_modules/@maka/core/dist/settings.js +10 -2
- package/node_modules/@maka/core/dist/usage-record-schema.js +11 -1
- package/node_modules/@maka/core/package.json +2 -1
- package/node_modules/@maka/mcp/dist/index.js +1 -0
- package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +52 -80
- package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +178 -140
- package/node_modules/@maka/runtime/dist/archive-read-tool.js +26 -5
- package/node_modules/@maka/runtime/dist/builtin-tools.js +27 -2
- package/node_modules/@maka/runtime/dist/context-budget-policy.js +0 -12
- package/node_modules/@maka/runtime/dist/conversation-copy.js +66 -43
- package/node_modules/@maka/runtime/dist/durable-tool-result-projection.js +31 -0
- package/node_modules/@maka/runtime/dist/history-compact-error.js +10 -2
- package/node_modules/@maka/runtime/dist/history-compact-input-fit.js +7 -1
- package/node_modules/@maka/runtime/dist/history-compaction.js +13 -22
- package/node_modules/@maka/runtime/dist/model-history.js +41 -16
- package/node_modules/@maka/runtime/dist/provider-image-overflow-recovery.js +12 -31
- package/node_modules/@maka/runtime/dist/runtime-event-backfill.js +3 -0
- package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +13 -2
- package/node_modules/@maka/runtime/dist/session-event-runtime-mapper.js +3 -6
- package/node_modules/@maka/runtime/dist/shell-tools.js +77 -1
- package/node_modules/@maka/runtime/dist/tool-availability.js +74 -5
- package/node_modules/@maka/runtime/dist/tool-result-archive-resource.js +333 -52
- package/node_modules/@maka/runtime/dist/tool-result-archive-transition.js +34 -3
- package/node_modules/@maka/runtime/dist/tool-runtime.js +12 -0
- package/node_modules/@maka/runtime-host/dist/adapter/session-projector.js +0 -3
- package/node_modules/@maka/runtime-host/dist/client/catalog-reader.js +40 -13
- package/node_modules/@maka/runtime-host/dist/client/connection.js +50 -31
- package/node_modules/@maka/runtime-host/dist/client/host-profile.js +48 -4
- package/node_modules/@maka/runtime-host/dist/client/index.js +2 -2
- package/node_modules/@maka/runtime-host/dist/client/owner-connection-code.js +32 -1
- package/node_modules/@maka/runtime-host/dist/client/peer-client.js +22 -4
- package/node_modules/@maka/runtime-host/dist/operator/access-management-frame.js +10 -1
- package/node_modules/@maka/runtime-host/dist/peer-mesh/node.js +56 -12
- package/node_modules/@maka/runtime-host/dist/peer-mesh/owner.js +3 -0
- package/node_modules/@maka/runtime-host/dist/protocol/configuration.js +55 -9
- package/node_modules/@maka/runtime-host/dist/protocol/host-status.js +37 -0
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +17 -1
- package/node_modules/@maka/runtime-host/dist/protocol/network-proxy.js +1 -7
- package/node_modules/@maka/runtime-host/dist/protocol/operations.js +2 -0
- package/node_modules/@maka/runtime-host/dist/protocol/runtime-policy.js +48 -1
- package/node_modules/@maka/runtime-host/dist/protocol/session-collaboration.js +4 -2
- package/node_modules/@maka/runtime-host/dist/protocol/turn.js +2 -12
- package/node_modules/@maka/runtime-host/dist/server/access-authority.js +2 -1
- package/node_modules/@maka/runtime-host/dist/server/agent-graph-execution-coordinator.js +1 -2
- package/node_modules/@maka/runtime-host/dist/server/canonical-turn-snapshot.js +0 -9
- package/node_modules/@maka/runtime-host/dist/server/configuration-coordinator.js +20 -1
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +46 -24
- package/node_modules/@maka/runtime-host/dist/server/execution-service.js +4 -1
- package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +15 -0
- package/node_modules/@maka/runtime-host/dist/server/listener-set.js +8 -4
- package/node_modules/@maka/runtime-host/dist/server/network-proxy-coordinator.js +0 -1
- package/node_modules/@maka/runtime-host/dist/server/peer-listener.js +3 -0
- package/node_modules/@maka/runtime-host/dist/server/runtime-policy-coordinator.js +28 -1
- package/node_modules/@maka/runtime-host/dist/server/session-retirement-coordinator.js +3 -3
- package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +35 -3
- package/node_modules/@maka/runtime-host/dist/server/session-sidecar-purge.js +16 -0
- package/node_modules/@maka/storage/dist/runtime-policy/coordinator.js +189 -6
- package/node_modules/@maka/storage/dist/runtime-policy-stores.js +4 -1
- package/node_modules/@maka/storage/dist/settings-store.js +16 -25
- package/node_modules/fast-uri/index.js +215 -47
- package/node_modules/fast-uri/lib/schemes.js +9 -4
- package/node_modules/fast-uri/lib/utils.js +396 -92
- package/node_modules/fast-uri/package.json +1 -1
- package/node_modules/qs/.github/THREAT_MODEL.md +3 -3
- package/node_modules/qs/CHANGELOG.md +15 -0
- package/node_modules/qs/README.md +19 -1
- package/node_modules/qs/dist/qs.js +21 -21
- package/node_modules/qs/eslint.config.mjs +1 -1
- package/node_modules/qs/lib/parse.js +3 -4
- package/node_modules/qs/lib/stringify.js +23 -8
- package/node_modules/qs/lib/utils.js +10 -3
- package/node_modules/qs/package.json +4 -4
- package/package.json +1 -1
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
import { createHash, randomUUID } from 'node:crypto';
|
|
20
20
|
import { MAX_READ_IMAGE_BYTES } from '@maka/core/attachments';
|
|
21
21
|
import { messageContentDigest, normalizeMessageContent } from '@maka/core/events';
|
|
22
|
-
import {
|
|
22
|
+
import { NO_REAL_CONNECTION_CODE } from '@maka/core/connection-error-copy';
|
|
23
23
|
import { generalizedErrorMessage } from '@maka/core/redaction';
|
|
24
24
|
import { emptyPlanSessionState } from '@maka/core/plan';
|
|
25
25
|
import { isDeepResearchSession, WORKHUB_COORDINATION_SESSION_ID, WORKHUB_COORDINATION_REPLACEMENT_SCHEMA_VERSION, } from '@maka/core/session';
|
|
@@ -42,8 +42,9 @@ import { SessionActivityRegistry } from '@maka/runtime/goal-turn-lifecycle';
|
|
|
42
42
|
import { ShellRunProcessManager } from '@maka/runtime/shell-run-manager';
|
|
43
43
|
import { resolveShellPlan, resolveTurnShellPlan, validateShellPreference, } from '@maka/runtime/shell-detect';
|
|
44
44
|
import { createAgentGraphControlStore } from '@maka/storage/agent-graph-control-store';
|
|
45
|
-
import { createArtifactAttachmentResourceReader
|
|
46
|
-
import {
|
|
45
|
+
import { createArtifactAttachmentResourceReader } from '@maka/storage/artifact-stores';
|
|
46
|
+
import { createReadImageSnapshotStore } from '@maka/storage/read-image-snapshot-store';
|
|
47
|
+
import { isSessionNotFoundError } from '@maka/storage/execution-stores';
|
|
47
48
|
import { createExternalSessionAdapterRegistry } from '@maka/storage/external-sessions';
|
|
48
49
|
import { createGitWorktreeChildExecutor } from '@maka/storage/git-worktree-child-executor';
|
|
49
50
|
import { runWithStorageRootLease } from '@maka/storage/root-authority';
|
|
@@ -121,22 +122,23 @@ import { createHostWebSearchService, createHostWebSearchToolFromService, resolve
|
|
|
121
122
|
import { createHostWebFetchService, createHostWebFetchToolFromService } from './web-fetch-tool.js';
|
|
122
123
|
import { createHostExecutionArtifactServices } from './execution-artifacts.js';
|
|
123
124
|
import { createRuntimeHostWorkspaceExecutionComposition, RuntimeHostWorkspaceExecutionError, } from './workspace-execution-composition.js';
|
|
124
|
-
const
|
|
125
|
+
const GIBIBYTE = 1024 * 1024 * 1024;
|
|
126
|
+
const CONTEXT_OFFLOAD_LIMITS = Object.freeze({
|
|
125
127
|
ownerMaxBytes: Object.freeze({
|
|
126
128
|
read_image_snapshot: MAX_READ_IMAGE_BYTES,
|
|
127
129
|
tool_result_archive: 0,
|
|
128
130
|
}),
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
sessionLogicalBytes:
|
|
132
|
-
workspacePhysicalBytes:
|
|
131
|
+
// Read images are bounded individually and logically per Session. Physical
|
|
132
|
+
// bytes are content-addressed across Sessions and bounded per workspace.
|
|
133
|
+
sessionLogicalBytes: GIBIBYTE,
|
|
134
|
+
workspacePhysicalBytes: 20 * GIBIBYTE,
|
|
133
135
|
});
|
|
134
136
|
export function runtimeHostFilesystemWorkerRuntime(versions) {
|
|
135
137
|
return versions.electron ? 'electron' : 'node';
|
|
136
138
|
}
|
|
137
139
|
export async function createExecutionRuntimeHostComposition(context, options = {}, dependencies = {}) {
|
|
138
140
|
const storage = await openStorageWriterComposition(context.owner.lease, {
|
|
139
|
-
contextOffloadLimits:
|
|
141
|
+
contextOffloadLimits: CONTEXT_OFFLOAD_LIMITS,
|
|
140
142
|
afterRuntimePolicyOpened: async (stores) => {
|
|
141
143
|
if (options.bootstrapRuntimePolicy !== false) {
|
|
142
144
|
await ensureBootstrapRuntimePolicy({
|
|
@@ -148,7 +150,7 @@ export async function createExecutionRuntimeHostComposition(context, options = {
|
|
|
148
150
|
},
|
|
149
151
|
});
|
|
150
152
|
if (storage.contextOffloadUnavailable) {
|
|
151
|
-
console.error(`[runtime-host] optional context-offload
|
|
153
|
+
console.error(`[runtime-host] optional context-offload Store could not be opened: ${generalizedErrorMessage(storage.contextOffloadUnavailable.cause)}`);
|
|
152
154
|
}
|
|
153
155
|
const stores = storage.execution;
|
|
154
156
|
let graphControlStore;
|
|
@@ -180,6 +182,25 @@ export async function createExecutionRuntimeHostComposition(context, options = {
|
|
|
180
182
|
const openedContextOffloadReader = openedContextOffloadStore
|
|
181
183
|
? createInteractiveContextOffloadReader(openedContextOffloadStore)
|
|
182
184
|
: undefined;
|
|
185
|
+
const contextOffloadAuthority = openedContextOffloadStore
|
|
186
|
+
? openedContextOffloadStore
|
|
187
|
+
: storage.contextOffloadUnavailable
|
|
188
|
+
? {
|
|
189
|
+
copyReferences: async () => {
|
|
190
|
+
throw new Error('Context-offload Store is unavailable during Session copy', {
|
|
191
|
+
cause: storage.contextOffloadUnavailable?.cause,
|
|
192
|
+
});
|
|
193
|
+
},
|
|
194
|
+
retireSession: async (_sessionId) => {
|
|
195
|
+
throw new Error('Context-offload Store is unavailable during Session retirement', {
|
|
196
|
+
cause: storage.contextOffloadUnavailable?.cause,
|
|
197
|
+
});
|
|
198
|
+
},
|
|
199
|
+
collectGarbage: async () => {
|
|
200
|
+
throw new Error('Context-offload Store is unavailable during context garbage collection', { cause: storage.contextOffloadUnavailable?.cause });
|
|
201
|
+
},
|
|
202
|
+
}
|
|
203
|
+
: undefined;
|
|
183
204
|
const openedUsageStores = storage.usage;
|
|
184
205
|
const openedShellRunStore = storage.shellRuns;
|
|
185
206
|
const worktreeChildExecutor = createGitWorktreeChildExecutor({
|
|
@@ -194,7 +215,7 @@ export async function createExecutionRuntimeHostComposition(context, options = {
|
|
|
194
215
|
// product's existing answer for these rows: this task came from the retired
|
|
195
216
|
// local simulation, configure a real model and start a new one.
|
|
196
217
|
backends.register('fake', () => {
|
|
197
|
-
throw new Error(`${NO_REAL_CONNECTION_CODE}:fake_backend:
|
|
218
|
+
throw new Error(`${NO_REAL_CONNECTION_CODE}:fake_backend: Runtime Host cannot send on a retired local-simulation connection; configure a real model and start a new task`);
|
|
198
219
|
});
|
|
199
220
|
const runtimePolicyActivation = new RuntimePolicyActivationGate();
|
|
200
221
|
const runtimePolicy = new HostRuntimePolicyCoordinator(runtimePolicyStores, runtimePolicyActivation, applyRuntimePolicyMutationEffects, async (input) => {
|
|
@@ -270,7 +291,18 @@ export async function createExecutionRuntimeHostComposition(context, options = {
|
|
|
270
291
|
}),
|
|
271
292
|
backgroundTasks: runtimeResources,
|
|
272
293
|
ptyControls: runtimeResources,
|
|
273
|
-
|
|
294
|
+
...(openedContextOffloadStore
|
|
295
|
+
? {
|
|
296
|
+
snapshotImage: async (input) => createReadImageSnapshotStore(openedContextOffloadStore, input.sessionId).snapshot({
|
|
297
|
+
ownerId: input.ownerId,
|
|
298
|
+
bytes: input.bytes,
|
|
299
|
+
mimeType: input.mimeType,
|
|
300
|
+
}),
|
|
301
|
+
releaseImageSnapshot: async (input) => {
|
|
302
|
+
await openedContextOffloadStore.releaseReference(input);
|
|
303
|
+
},
|
|
304
|
+
}
|
|
305
|
+
: {}),
|
|
274
306
|
...(sandboxManager ? { sandboxManager } : {}),
|
|
275
307
|
...(filesystemWorker ? { filesystemWorker } : {}),
|
|
276
308
|
};
|
|
@@ -1215,6 +1247,7 @@ export async function createExecutionRuntimeHostComposition(context, options = {
|
|
|
1215
1247
|
stores,
|
|
1216
1248
|
artifacts: openedArtifactStore,
|
|
1217
1249
|
sessionTodo: sessionTodoStore,
|
|
1250
|
+
...(contextOffloadAuthority ? { contextOffload: contextOffloadAuthority } : {}),
|
|
1218
1251
|
manager,
|
|
1219
1252
|
admission: sessionAdmission,
|
|
1220
1253
|
continuity: continuityCoordinator,
|
|
@@ -1239,18 +1272,7 @@ export async function createExecutionRuntimeHostComposition(context, options = {
|
|
|
1239
1272
|
continuity: continuityCoordinator,
|
|
1240
1273
|
artifacts: openedArtifactStore,
|
|
1241
1274
|
sessionTodo: sessionTodoStore,
|
|
1242
|
-
|
|
1243
|
-
if (!openedContextOffloadStore) {
|
|
1244
|
-
throw new Error('Context-offload reader is unavailable during Session removal', {
|
|
1245
|
-
cause: storage.contextOffloadUnavailable?.cause,
|
|
1246
|
-
});
|
|
1247
|
-
}
|
|
1248
|
-
for (const sessionId of sessionIds) {
|
|
1249
|
-
if ((await openedContextOffloadStore.usage(sessionId)).references > 0) {
|
|
1250
|
-
throw new SessionMetadataConflictError('Session removal does not support Session context references yet');
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
},
|
|
1275
|
+
...(contextOffloadAuthority ? { contextOffload: contextOffloadAuthority } : {}),
|
|
1254
1276
|
purgeOperationalState: async (sessionId) => {
|
|
1255
1277
|
await stores.purgeConversationOperationalState(sessionId);
|
|
1256
1278
|
await openedPlanStore.purgeSessionState(sessionId);
|
|
@@ -55,6 +55,9 @@ export async function startExecutionRuntimeHostService(options, dependencies = {
|
|
|
55
55
|
...options.peer,
|
|
56
56
|
dataRoot: options.peer.meshDataRoot,
|
|
57
57
|
endpointKind: 'host',
|
|
58
|
+
onBackgroundReconcileError: (error) => {
|
|
59
|
+
console.error('[runtime-host] Peer Mesh background synchronization failed:', error);
|
|
60
|
+
},
|
|
58
61
|
});
|
|
59
62
|
}
|
|
60
63
|
catch (error) {
|
|
@@ -109,7 +112,7 @@ export async function startExecutionRuntimeHostService(options, dependencies = {
|
|
|
109
112
|
throw error;
|
|
110
113
|
}
|
|
111
114
|
}
|
|
112
|
-
function attachPeerOwnerCleanup(listeners, owner) {
|
|
115
|
+
export function attachPeerOwnerCleanup(listeners, owner) {
|
|
113
116
|
return {
|
|
114
117
|
...listeners,
|
|
115
118
|
cleanup: async () => {
|
|
@@ -569,6 +569,7 @@ export class RuntimeHostKernel {
|
|
|
569
569
|
return outcome;
|
|
570
570
|
}
|
|
571
571
|
#statusSnapshot() {
|
|
572
|
+
const peer = this.peerListeners[0];
|
|
572
573
|
return {
|
|
573
574
|
hostEpoch: this.hostEpoch,
|
|
574
575
|
compositionId: this.compositionDescriptor.id,
|
|
@@ -577,6 +578,15 @@ export class RuntimeHostKernel {
|
|
|
577
578
|
connections: this.#acceptedTransports.size,
|
|
578
579
|
activeOperations: this.#activeOperations,
|
|
579
580
|
activeResidencies: this.#residencies.activeCount,
|
|
581
|
+
...(peer
|
|
582
|
+
? {
|
|
583
|
+
peerEndpoint: {
|
|
584
|
+
peerId: peer.peerId,
|
|
585
|
+
routeHints: peer.listenAddresses,
|
|
586
|
+
coordinationRelays: peer.coordinationRelays,
|
|
587
|
+
},
|
|
588
|
+
}
|
|
589
|
+
: {}),
|
|
580
590
|
};
|
|
581
591
|
}
|
|
582
592
|
#activitySnapshot() {
|
|
@@ -588,6 +598,11 @@ export class RuntimeHostKernel {
|
|
|
588
598
|
};
|
|
589
599
|
}
|
|
590
600
|
#hasUpgradeBlockingActivity() {
|
|
601
|
+
// The request's own accepted transport is expected. Any other live
|
|
602
|
+
// connection arrived after discovery or remained attached and therefore
|
|
603
|
+
// requires explicit interruption authority before retirement.
|
|
604
|
+
if (this.#acceptedTransports.size > 1)
|
|
605
|
+
return true;
|
|
591
606
|
if (this.#activeCommandOperations > 1)
|
|
592
607
|
return true;
|
|
593
608
|
return this.#residencies.snapshot().some(({ label }) => label !== 'process-retention');
|
|
@@ -51,16 +51,20 @@ export async function startRuntimeHostAuthenticatedListenerSet(input, options) {
|
|
|
51
51
|
}
|
|
52
52
|
export function createRuntimeHostListenerSet(local, additional = []) {
|
|
53
53
|
const listeners = Object.freeze([local, ...additional]);
|
|
54
|
+
const peerListeners = Object.freeze(additional.filter(isRuntimeHostPeerListener).map((listener) => Object.freeze({
|
|
55
|
+
peerId: listener.peerId,
|
|
56
|
+
listenAddresses: Object.freeze([...listener.listenAddresses]),
|
|
57
|
+
get coordinationRelays() {
|
|
58
|
+
return Object.freeze([...listener.coordinationRelays]);
|
|
59
|
+
},
|
|
60
|
+
})));
|
|
54
61
|
return {
|
|
55
62
|
listeners,
|
|
56
63
|
localEndpoint: local.endpoint,
|
|
57
64
|
websocketEndpoints: Object.freeze(additional
|
|
58
65
|
.filter((listener) => listener.kind === 'websocket')
|
|
59
66
|
.map((listener) => listener.endpoint)),
|
|
60
|
-
peerListeners
|
|
61
|
-
peerId: listener.peerId,
|
|
62
|
-
listenAddresses: Object.freeze([...listener.listenAddresses]),
|
|
63
|
-
}))),
|
|
67
|
+
peerListeners,
|
|
64
68
|
closeAdmission: () => settleListeners(listeners, (listener) => listener.closeAdmission()),
|
|
65
69
|
cleanup: () => settleListeners([...listeners].reverse(), (listener) => listener.cleanup()),
|
|
66
70
|
};
|
|
@@ -29,7 +29,6 @@ export class HostNetworkProxyCoordinator {
|
|
|
29
29
|
try {
|
|
30
30
|
const resolved = await this.policy.resolveNetworkProxyExecution({
|
|
31
31
|
...(input.networkProxy ? { networkProxy: input.networkProxy } : {}),
|
|
32
|
-
...(input.password ? { secretOverride: input.password } : {}),
|
|
33
32
|
});
|
|
34
33
|
if (resolved.kind === 'credential_not_configured') {
|
|
35
34
|
return {
|
|
@@ -66,6 +66,9 @@ class RuntimeHostPeerListener {
|
|
|
66
66
|
.serveApplication((stream) => this.#acceptStream(stream), this.#serveLifetime.signal)
|
|
67
67
|
.catch(captureFailure);
|
|
68
68
|
}
|
|
69
|
+
get coordinationRelays() {
|
|
70
|
+
return this.#client.identity().coordinationRelays;
|
|
71
|
+
}
|
|
69
72
|
closeAdmission() {
|
|
70
73
|
this.#closeAdmissionTask ??= (async () => {
|
|
71
74
|
this.#admitting = false;
|
|
@@ -29,6 +29,7 @@ export class HostRuntimePolicyCoordinator {
|
|
|
29
29
|
handlers = {
|
|
30
30
|
'runtime.policy.query': () => this.#queryPolicy(),
|
|
31
31
|
'runtime.policy.mutate': (input) => this.#mutatePolicy(input),
|
|
32
|
+
'runtime.policy.network-proxy.update': (input) => this.#updateNetworkProxy(input),
|
|
32
33
|
'connection.catalog.query': (input) => this.#queryCatalog(input),
|
|
33
34
|
'connection.catalog.create': (input) => this.#createConnection(input),
|
|
34
35
|
'connection.catalog.update': (input) => this.#updateConnection(input),
|
|
@@ -65,6 +66,27 @@ export class HostRuntimePolicyCoordinator {
|
|
|
65
66
|
return projectPolicyMutation(await this.#stores.runtimePolicy.mutate(input));
|
|
66
67
|
});
|
|
67
68
|
}
|
|
69
|
+
async #updateNetworkProxy(input) {
|
|
70
|
+
return this.#storeMutation(async () => {
|
|
71
|
+
try {
|
|
72
|
+
await this.validateMutation({
|
|
73
|
+
expectedRevision: input.expectedPolicyRevision,
|
|
74
|
+
operation: { kind: 'set_network_proxy', value: input.networkProxy },
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
throw new RuntimePolicyStoreError('invalid_policy_input', 'Network proxy update failed Host validation', { cause: error });
|
|
79
|
+
}
|
|
80
|
+
const result = await this.#stores.operations.updateNetworkProxy(input);
|
|
81
|
+
return result.kind === 'committed'
|
|
82
|
+
? {
|
|
83
|
+
kind: 'committed',
|
|
84
|
+
revision: result.snapshot.revision,
|
|
85
|
+
credentialStatus: result.credentialStatus,
|
|
86
|
+
}
|
|
87
|
+
: result;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
68
90
|
async #queryCatalog(input) {
|
|
69
91
|
const stored = await this.#storeQuery(() => this.#stores.connectionCatalog.getSnapshot());
|
|
70
92
|
if (!stored.ok)
|
|
@@ -143,7 +165,9 @@ export class HostRuntimePolicyCoordinator {
|
|
|
143
165
|
async #setCredential(input) {
|
|
144
166
|
return this.#storeMutation(async () => {
|
|
145
167
|
const result = await this.#stores.credentialVault.set(input);
|
|
146
|
-
if (result.kind === 'connection_not_found' ||
|
|
168
|
+
if (result.kind === 'connection_not_found' ||
|
|
169
|
+
result.kind === 'connection_stale' ||
|
|
170
|
+
result.kind === 'credential_stale') {
|
|
147
171
|
return result;
|
|
148
172
|
}
|
|
149
173
|
const status = result.snapshot.entries.find((entry) => sameLocator(entry.locator, input.locator));
|
|
@@ -156,6 +180,9 @@ export class HostRuntimePolicyCoordinator {
|
|
|
156
180
|
async #deleteCredential(input) {
|
|
157
181
|
return this.#storeMutation(async () => {
|
|
158
182
|
const result = await this.#stores.credentialVault.delete(input);
|
|
183
|
+
if (result.kind === 'connection_stale') {
|
|
184
|
+
throw invariantFailure('Credential deletion returned an impossible connection conflict');
|
|
185
|
+
}
|
|
159
186
|
if (result.kind === 'connection_not_found' || result.kind === 'credential_stale') {
|
|
160
187
|
return result;
|
|
161
188
|
}
|
|
@@ -68,7 +68,7 @@ export class HostSessionRetirementCoordinator {
|
|
|
68
68
|
#continuity;
|
|
69
69
|
#artifacts;
|
|
70
70
|
#sessionTodo;
|
|
71
|
-
#
|
|
71
|
+
#contextOffload;
|
|
72
72
|
#purgeOperationalState;
|
|
73
73
|
#purgeAgentGraphState;
|
|
74
74
|
#worktrees;
|
|
@@ -95,7 +95,7 @@ export class HostSessionRetirementCoordinator {
|
|
|
95
95
|
this.#continuity = options.continuity;
|
|
96
96
|
this.#artifacts = options.artifacts;
|
|
97
97
|
this.#sessionTodo = options.sessionTodo;
|
|
98
|
-
this.#
|
|
98
|
+
this.#contextOffload = options.contextOffload;
|
|
99
99
|
this.#purgeOperationalState = options.purgeOperationalState;
|
|
100
100
|
this.#purgeAgentGraphState = options.purgeAgentGraphState;
|
|
101
101
|
this.#worktrees = options.worktrees;
|
|
@@ -201,7 +201,6 @@ export class HostSessionRetirementCoordinator {
|
|
|
201
201
|
if (plan.archive.sessionIds.length > 0) {
|
|
202
202
|
archiveHandles = await this.#prepareRetirement(plan.archive, 'archive');
|
|
203
203
|
}
|
|
204
|
-
await this.#assertNoContextOffloadReferences?.(plan.remove.sessionIds);
|
|
205
204
|
const allSessionIds = [...plan.remove.sessionIds, ...plan.archive.sessionIds];
|
|
206
205
|
await this.#finalizeWorkspacePatches(allSessionIds);
|
|
207
206
|
await this.#disposeBackends(allSessionIds);
|
|
@@ -494,6 +493,7 @@ export class HostSessionRetirementCoordinator {
|
|
|
494
493
|
purgeSessionSidecars({
|
|
495
494
|
artifacts: this.#artifacts,
|
|
496
495
|
sessionTodo: this.#sessionTodo,
|
|
496
|
+
...(this.#contextOffload ? { contextOffload: this.#contextOffload } : {}),
|
|
497
497
|
purgeOperationalState: this.#purgeOperationalState,
|
|
498
498
|
}, sessionId),
|
|
499
499
|
this.#purgeAgentGraphState(sessionId),
|
|
@@ -20,7 +20,7 @@ import { createHash, randomUUID } from 'node:crypto';
|
|
|
20
20
|
import { isDeepResearchSession } from '@maka/core/deep-research';
|
|
21
21
|
import { SIDE_CONVERSATION_SESSION_LABEL } from '@maka/core/side-conversation';
|
|
22
22
|
import { isWorkHubCoordinationSessionId, isWorkHubCoordinationSessionTarget, sessionRevisionFamilyId, } from '@maka/core/session';
|
|
23
|
-
import { archivedToolResultContainsLinkedChildReferences, archivedToolResultContainsConversationOwnedReferences, cloneConversationRuntimeLedger, collectConversationCopyLinkedChildReferences, collectConversationCopySessionFileRefs, createConversationCopySlice, prepareConversationRuntimeLedgerCopy, } from '@maka/runtime/conversation-copy';
|
|
23
|
+
import { archivedToolResultContainsLinkedChildReferences, archivedToolResultContainsConversationOwnedReferences, cloneConversationRuntimeLedger, collectConversationCopyLinkedChildReferences, collectConversationCopySessionContextRefIds, collectConversationCopySessionFileRefs, createConversationCopySlice, prepareConversationRuntimeLedgerCopy, } from '@maka/runtime/conversation-copy';
|
|
24
24
|
import { isArchivedToolResultPlaceholder } from '@maka/runtime/context-budget';
|
|
25
25
|
import { decodeModelProjectionTransition, MODEL_PROJECTION_TRANSITION_EVENT_TYPE, } from '@maka/core/model-projection-transition';
|
|
26
26
|
import { authenticateInteractiveArtifactStoreWriter, } from '@maka/storage/artifact-stores';
|
|
@@ -52,7 +52,7 @@ export class HostSessionRevisionCoordinator {
|
|
|
52
52
|
const copies = (await this.#stores.sessionStore.listHeaders()).filter((header) => header.conversationCopy !== undefined);
|
|
53
53
|
for (const header of copies) {
|
|
54
54
|
if (header.conversationCopy.state === 'preparing')
|
|
55
|
-
await this.#
|
|
55
|
+
await this.#discardDuringRecovery(header);
|
|
56
56
|
}
|
|
57
57
|
const committed = copies.filter((header) => header.conversationCopy.state === 'committed');
|
|
58
58
|
const retained = new Set(committed
|
|
@@ -85,10 +85,18 @@ export class HostSessionRevisionCoordinator {
|
|
|
85
85
|
await this.options.manager.commitRevisionVersion(header.id);
|
|
86
86
|
}
|
|
87
87
|
else {
|
|
88
|
-
await this.#
|
|
88
|
+
await this.#discardDuringRecovery(header);
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
+
async #discardDuringRecovery(header) {
|
|
93
|
+
try {
|
|
94
|
+
await this.#discard(header);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
console.error(`[runtime-host] conversation copy cleanup deferred during recovery (${header.id}): ${conversationCopyCommitFailureDiagnostic(error)}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
92
100
|
async #copy(kind, input) {
|
|
93
101
|
if (isWorkHubCoordinationSessionId(input.targetSessionId)) {
|
|
94
102
|
return copyFailure('operation_conflict', 'Target Session identity is reserved for WorkHub coordination');
|
|
@@ -315,6 +323,28 @@ export class HostSessionRevisionCoordinator {
|
|
|
315
323
|
.filter(({ serializedResult }) => archivedToolResultContainsLinkedChildReferences(serializedResult) ||
|
|
316
324
|
archivedToolResultContainsConversationOwnedReferences(serializedResult, input.sourceSessionId, linkedReferences.references))
|
|
317
325
|
.map(({ descriptor, serializedResult }) => [descriptor.artifactId, serializedResult]));
|
|
326
|
+
const sourceContextRefIds = collectConversationCopySessionContextRefIds({
|
|
327
|
+
sourceSessionId: input.sourceSessionId,
|
|
328
|
+
messages: slice.messages,
|
|
329
|
+
runtimeEvents: plan.runs.flatMap(({ runtimeEvents }) => runtimeEvents),
|
|
330
|
+
archivedResults: archivePreflight.serializedResults,
|
|
331
|
+
});
|
|
332
|
+
if (sourceContextRefIds.length > 0 && !this.options.contextOffload) {
|
|
333
|
+
throw new Error('Session context copy authority is unavailable');
|
|
334
|
+
}
|
|
335
|
+
const contextCopy = sourceContextRefIds.length === 0
|
|
336
|
+
? { ok: true, copied: [] }
|
|
337
|
+
: await this.options.contextOffload.copyReferences({
|
|
338
|
+
sourceSessionId: input.sourceSessionId,
|
|
339
|
+
targetSessionId: input.targetSessionId,
|
|
340
|
+
references: sourceContextRefIds.map((sourceRefId) => ({
|
|
341
|
+
sourceRefId,
|
|
342
|
+
targetOwner: { kind: 'read_image_snapshot', ownerId: sourceRefId },
|
|
343
|
+
})),
|
|
344
|
+
});
|
|
345
|
+
if (!contextCopy.ok) {
|
|
346
|
+
throw new Error(`Session context references could not be copied: ${contextCopy.reason}`);
|
|
347
|
+
}
|
|
318
348
|
const artifactCopy = await this.#artifacts.copyConversationArtifacts({
|
|
319
349
|
sourceSessionId: input.sourceSessionId,
|
|
320
350
|
targetSessionId: input.targetSessionId,
|
|
@@ -340,6 +370,7 @@ export class HostSessionRevisionCoordinator {
|
|
|
340
370
|
targetSessionId: input.targetSessionId,
|
|
341
371
|
artifactIds: artifactCopy.artifactIds,
|
|
342
372
|
relativePaths: artifactCopy.relativePaths,
|
|
373
|
+
contextRefs: new Map(contextCopy.copied.map(({ sourceRefId, targetRefId }) => [sourceRefId, targetRefId])),
|
|
343
374
|
linkedChildren: kind === 'side_conversation'
|
|
344
375
|
? {
|
|
345
376
|
mode: 'snapshot',
|
|
@@ -544,6 +575,7 @@ export class HostSessionRevisionCoordinator {
|
|
|
544
575
|
await purgeSessionSidecars({
|
|
545
576
|
artifacts: this.#artifacts,
|
|
546
577
|
sessionTodo: this.#sessionTodo,
|
|
578
|
+
...(this.options.contextOffload ? { contextOffload: this.options.contextOffload } : {}),
|
|
547
579
|
purgeOperationalState: (sessionId) => this.#stores.purgeConversationOperationalState(sessionId),
|
|
548
580
|
}, header.id);
|
|
549
581
|
await this.#stores.sessionStore.discardStableConversationCopy(header.id, copy.requestFingerprint);
|
|
@@ -16,10 +16,26 @@
|
|
|
16
16
|
* specific language governing permissions and limitations
|
|
17
17
|
* under the License.
|
|
18
18
|
*/
|
|
19
|
+
const CONTEXT_GARBAGE_BATCH_BLOBS = 64;
|
|
20
|
+
async function retireContextSession(contextOffload, sessionId) {
|
|
21
|
+
await contextOffload.retireSession(sessionId);
|
|
22
|
+
for (;;) {
|
|
23
|
+
const collected = await contextOffload.collectGarbage({
|
|
24
|
+
olderThan: Number.MAX_SAFE_INTEGER,
|
|
25
|
+
maxBlobs: CONTEXT_GARBAGE_BATCH_BLOBS,
|
|
26
|
+
maxBytes: Number.MAX_SAFE_INTEGER,
|
|
27
|
+
});
|
|
28
|
+
if (!collected.hasMore)
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
19
32
|
export async function purgeSessionSidecars(authority, sessionId) {
|
|
20
33
|
const outcomes = await Promise.allSettled([
|
|
21
34
|
authority.artifacts.purgeSessionArtifacts(sessionId),
|
|
22
35
|
authority.sessionTodo.purgeSessionState(sessionId),
|
|
36
|
+
...(authority.contextOffload
|
|
37
|
+
? [retireContextSession(authority.contextOffload, sessionId)]
|
|
38
|
+
: []),
|
|
23
39
|
authority.purgeOperationalState(sessionId),
|
|
24
40
|
]);
|
|
25
41
|
const failures = outcomes.flatMap((outcome) => outcome.status === 'rejected' ? [outcome.reason] : []);
|