maka-agent 0.2.0-dev.14.20260902 → 0.2.0-dev.16.20260903
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/cli-core.js +0 -1
- package/dist/pi-transcript.js +48 -0
- package/dist/pi-tui-form-interaction.js +497 -0
- package/dist/pi-tui-pickers.js +256 -55
- package/dist/pi-tui-runner.js +215 -12
- package/dist/runtime-host-cli.js +17 -42
- package/dist/runtime-host-lifecycle-transaction.js +31 -13
- package/dist/runtime-host-managed-lifecycle-manager.js +1 -1
- package/dist/runtime-host-onboarding.js +3 -1
- package/dist/runtime-host-openrc-service.js +469 -0
- package/dist/runtime-host-run-command.js +6 -2
- package/dist/runtime-host-service-command.js +3 -3
- package/dist/runtime-host-service-management-command.js +43 -15
- package/dist/runtime-host-session-channel.js +3 -0
- package/dist/runtime-host-session-driver.js +21 -6
- package/dist/runtime-host-setup-command.js +30 -31
- package/dist/tui-context-refresh.js +103 -0
- package/dist/tui-copy-catalog.js +73 -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/node_modules/@maka/core/dist/chat-model-choice.js +4 -0
- package/node_modules/@maka/core/dist/computer-use.js +27 -92
- package/node_modules/@maka/core/dist/interaction.js +577 -3
- package/node_modules/@maka/core/dist/llm-connections.js +4 -0
- package/node_modules/@maka/core/dist/local-memory.js +2 -2
- package/node_modules/@maka/core/dist/model-call-usage-projection.js +3 -0
- package/node_modules/@maka/core/dist/model-metadata.js +26 -7
- package/node_modules/@maka/core/dist/model-thinking.js +17 -0
- package/node_modules/@maka/core/dist/provider-registry.js +1 -0
- package/node_modules/@maka/core/dist/runtime-event.js +23 -1
- package/node_modules/@maka/core/dist/scheduled-task.js +4 -0
- package/node_modules/@maka/core/dist/session.js +95 -2
- package/node_modules/@maka/core/dist/text-sanitize.js +19 -0
- package/node_modules/@maka/core/dist/usage-ledger-merge.js +3 -0
- package/node_modules/@maka/core/dist/usage-record-schema.js +11 -5
- package/node_modules/@maka/core/dist/workhub-creation-intent.js +75 -9
- package/node_modules/@maka/core/dist/workhub-session-resolver.js +50 -0
- package/node_modules/@maka/core/package.json +2 -0
- package/node_modules/@maka/eval/dist/harbor-external-subject.js +2 -1
- package/node_modules/@maka/eval/dist/harness-executor.js +3 -2
- package/node_modules/@maka/eval/dist/install-preflight.js +39 -10
- package/node_modules/@maka/eval/dist/process-termination.js +83 -0
- package/node_modules/@maka/mcp/dist/sep-2243.js +3 -3
- package/node_modules/@maka/runtime/dist/agent-run.js +6 -3
- package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +332 -118
- package/node_modules/@maka/runtime/dist/ai-sdk-compaction-contract.js +6 -1
- package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +171 -341
- package/node_modules/@maka/runtime/dist/bots/telegram-bridge.js +3 -26
- package/node_modules/@maka/runtime/dist/bundled-skill-catalog.generated.js +1 -1
- package/node_modules/@maka/runtime/dist/computer-use-codec.js +1 -141
- package/node_modules/@maka/runtime/dist/computer-use-tools.js +23 -105
- package/node_modules/@maka/runtime/dist/context-budget-policy.js +20 -26
- package/node_modules/@maka/runtime/dist/context-budget.js +18 -20
- package/node_modules/@maka/runtime/dist/conversation-copy.js +23 -19
- package/node_modules/@maka/runtime/dist/cua-frame-state.js +1 -69
- package/node_modules/@maka/runtime/dist/github-copilot-oauth-enrollment.js +267 -0
- package/node_modules/@maka/runtime/dist/history-compact-checkpoint.js +6 -9
- package/node_modules/@maka/runtime/dist/history-compact-summarizer.js +67 -23
- package/node_modules/@maka/runtime/dist/history-compact-summary-validation.js +11 -18
- package/node_modules/@maka/runtime/dist/history-compaction.js +66 -73
- package/node_modules/@maka/runtime/dist/interaction-authority.js +69 -0
- package/node_modules/@maka/runtime/dist/mcp-tools.js +13 -1
- package/node_modules/@maka/runtime/dist/memory-extraction.js +11 -11
- package/node_modules/@maka/runtime/dist/model-adapter.js +24 -6
- package/node_modules/@maka/runtime/dist/model-factory.js +14 -5
- package/node_modules/@maka/runtime/dist/oauth-provider-contracts.js +28 -1
- package/node_modules/@maka/runtime/dist/openai-codex-history-compactor.js +7 -6
- package/node_modules/@maka/runtime/dist/opencode-session-header.js +29 -0
- package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +11 -1
- package/node_modules/@maka/runtime/dist/runtime-kernel.js +12 -11
- package/node_modules/@maka/runtime/dist/runtime-read-model.js +51 -13
- package/node_modules/@maka/runtime/dist/scheduled-task-tools.js +3 -0
- package/node_modules/@maka/runtime/dist/session-event-runtime-mapper.js +26 -0
- package/node_modules/@maka/runtime/dist/session-manager.js +1 -0
- package/node_modules/@maka/runtime/dist/session-projection-helpers.js +16 -1
- package/node_modules/@maka/runtime/dist/stream-graph-projection.js +6 -0
- package/node_modules/@maka/runtime/dist/stream-graph-read-model.js +5 -0
- package/node_modules/@maka/runtime/dist/stream-usage-fallback-fetch.js +74 -0
- package/node_modules/@maka/runtime/dist/subscription-credentials.js +51 -4
- package/node_modules/@maka/runtime/dist/subscription-model-fetch.js +47 -3
- package/node_modules/@maka/runtime/dist/system-prompt/main-session-prompt.js +20 -1
- package/node_modules/@maka/runtime/dist/test-connection.js +18 -11
- package/node_modules/@maka/runtime/dist/tool-runtime.js +183 -0
- package/node_modules/@maka/runtime/package.json +1 -0
- package/node_modules/@maka/runtime-host/dist/adapter/session-projector.js +14 -0
- package/node_modules/@maka/runtime-host/dist/client/client-capability-channel.js +84 -1
- package/node_modules/@maka/runtime-host/dist/client/host-profile.js +68 -51
- package/node_modules/@maka/runtime-host/dist/client/index.js +1 -1
- package/node_modules/@maka/runtime-host/dist/client/owner-connection-code.js +8 -5
- package/node_modules/@maka/runtime-host/dist/client/peer-client.js +342 -36
- package/node_modules/@maka/runtime-host/dist/client/reconnect-lifecycle.js +60 -4
- package/node_modules/@maka/runtime-host/dist/peer-mesh/index.js +3 -3
- package/node_modules/@maka/runtime-host/dist/peer-mesh/limits.js +1 -1
- package/node_modules/@maka/runtime-host/dist/peer-mesh/model.js +48 -60
- package/node_modules/@maka/runtime-host/dist/peer-mesh/node.js +847 -431
- package/node_modules/@maka/runtime-host/dist/peer-mesh/owner.js +33 -74
- package/node_modules/@maka/runtime-host/dist/peer-mesh/store.js +82 -69
- package/node_modules/@maka/runtime-host/dist/peer-reachability/index.js +21 -0
- package/node_modules/@maka/runtime-host/dist/peer-reachability/model.js +202 -0
- package/node_modules/@maka/runtime-host/dist/peer-reachability/owner.js +119 -0
- package/node_modules/@maka/runtime-host/dist/peer-reachability/publisher.js +245 -0
- package/node_modules/@maka/runtime-host/dist/protocol/agent-graph.js +4 -1
- package/node_modules/@maka/runtime-host/dist/protocol/client-capability.js +68 -0
- package/node_modules/@maka/runtime-host/dist/protocol/connection-effects.js +15 -8
- package/node_modules/@maka/runtime-host/dist/protocol/host-status.js +7 -23
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +47 -1
- package/node_modules/@maka/runtime-host/dist/protocol/oauth.js +25 -1
- package/node_modules/@maka/runtime-host/dist/protocol/operations.js +1 -0
- package/node_modules/@maka/runtime-host/dist/protocol/peer-mesh.js +14 -31
- package/node_modules/@maka/runtime-host/dist/protocol/scheduled-task.js +19 -6
- package/node_modules/@maka/runtime-host/dist/protocol/session-collaboration.js +36 -1
- package/node_modules/@maka/runtime-host/dist/protocol/session-revision.js +11 -2
- package/node_modules/@maka/runtime-host/dist/protocol/usage-pricing.js +16 -2
- package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +51 -2
- package/node_modules/@maka/runtime-host/dist/server/access-authority.js +35 -2
- package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +1 -0
- package/node_modules/@maka/runtime-host/dist/server/client-capability-coordinator.js +12 -10
- package/node_modules/@maka/runtime-host/dist/server/client-capability-invocation-broker.js +163 -30
- package/node_modules/@maka/runtime-host/dist/server/connection-effect-coordinator.js +38 -14
- package/node_modules/@maka/runtime-host/dist/server/daily-review-coordinator.js +45 -22
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +78 -20
- package/node_modules/@maka/runtime-host/dist/server/execution-model-authority.js +4 -2
- package/node_modules/@maka/runtime-host/dist/server/execution-model-composition.js +2 -1
- package/node_modules/@maka/runtime-host/dist/server/execution-service.js +49 -28
- package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +3 -6
- package/node_modules/@maka/runtime-host/dist/server/interaction-coordinator.js +130 -27
- package/node_modules/@maka/runtime-host/dist/server/interaction-projection.js +30 -1
- package/node_modules/@maka/runtime-host/dist/server/listener-set.js +2 -4
- package/node_modules/@maka/runtime-host/dist/server/message-coordinator.js +16 -3
- package/node_modules/@maka/runtime-host/dist/server/oauth-coordinator.js +66 -3
- package/node_modules/@maka/runtime-host/dist/server/oauth-execution-authority.js +20 -3
- package/node_modules/@maka/runtime-host/dist/server/peer-listener.js +8 -21
- package/node_modules/@maka/runtime-host/dist/server/peer-mesh-authority.js +1 -1
- package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +6 -3
- package/node_modules/@maka/runtime-host/dist/server/scheduled-task-coordinator.js +72 -12
- package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +48 -18
- package/node_modules/@maka/runtime-host/dist/server/session-turn-access-request-coordinator.js +43 -26
- package/node_modules/@maka/runtime-host/dist/server/usage-pricing-coordinator.js +15 -1
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +229 -4
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +146 -8
- package/node_modules/@maka/runtime-host/dist/transport/peer-native.js +32 -6
- package/node_modules/@maka/runtime-host/package.json +1 -0
- package/node_modules/@maka/storage/dist/agent-run-store.js +18 -5
- package/node_modules/@maka/storage/dist/codex-session-adapter.js +14 -0
- package/node_modules/@maka/storage/dist/execution-stores.js +5 -0
- package/node_modules/@maka/storage/dist/interaction-store.js +13 -1
- package/node_modules/@maka/storage/dist/runtime-policy/connection-catalog-document.js +9 -3
- package/node_modules/@maka/storage/dist/runtime-policy/coordinator.js +49 -19
- package/node_modules/@maka/storage/dist/runtime-policy/oauth-login-receipt-document.js +3 -1
- package/node_modules/@maka/storage/dist/runtime-policy/onboarding-transaction.js +13 -5
- package/node_modules/@maka/storage/dist/session-copy-cleanup.js +4 -2
- package/node_modules/@maka/storage/dist/session-store.js +39 -6
- package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +16 -9
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-schema.js +30 -3
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +117 -0
- package/node_modules/@maka/storage/dist/sqlite-usage-store.js +29 -6
- package/node_modules/@maka/storage/dist/usage-stores.js +3 -1
- package/package.json +1 -1
|
@@ -0,0 +1,119 @@
|
|
|
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 { chmod, mkdir } from 'node:fs/promises';
|
|
20
|
+
import { join } from 'node:path';
|
|
21
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
22
|
+
import { acquireFileLifetimeOwner, } from '@maka/storage/file-lifetime-owner';
|
|
23
|
+
import { createRuntimeHostPeerClient } from '../client/peer-client.js';
|
|
24
|
+
import { RuntimeHostPermanentReconnectError } from '../client/reconnect-lifecycle.js';
|
|
25
|
+
import { openPeerReachabilityPublisher, PeerReachabilityPostCommitError, } from './publisher.js';
|
|
26
|
+
const REACHABILITY_WATCH_TIMEOUT_MS = 60_000;
|
|
27
|
+
const REACHABILITY_RETRY_INTERVAL_MS = 5_000;
|
|
28
|
+
export async function openRuntimeHostPeerEndpointOwner(input) {
|
|
29
|
+
await mkdir(input.dataRoot, { recursive: true, mode: 0o700 });
|
|
30
|
+
if (process.platform !== 'win32')
|
|
31
|
+
await chmod(input.dataRoot, 0o700);
|
|
32
|
+
const rootOwner = await acquireFileLifetimeOwner(join(input.dataRoot, 'peer-endpoint.owner'));
|
|
33
|
+
let client;
|
|
34
|
+
let reachability;
|
|
35
|
+
try {
|
|
36
|
+
client = createRuntimeHostPeerClient({
|
|
37
|
+
nativePath: input.nativePath,
|
|
38
|
+
keyPath: input.keyPath,
|
|
39
|
+
relayAnchorPath: join(input.dataRoot, 'relay-anchors.json'),
|
|
40
|
+
...(input.expectedPeerId ? { expectedPeerId: input.expectedPeerId } : {}),
|
|
41
|
+
...(input.listenAddresses ? { listenAddresses: input.listenAddresses } : {}),
|
|
42
|
+
...(input.coordinationRelays ? { coordinationRelays: input.coordinationRelays } : {}),
|
|
43
|
+
...(input.automaticRelayDiscovery === undefined
|
|
44
|
+
? {}
|
|
45
|
+
: { automaticRelayDiscovery: input.automaticRelayDiscovery }),
|
|
46
|
+
...(input.webRtcStunUrls === undefined ? {} : { webRtcStunUrls: input.webRtcStunUrls }),
|
|
47
|
+
});
|
|
48
|
+
const peerId = client.identity().peerId;
|
|
49
|
+
reachability = await openPeerReachabilityPublisher({
|
|
50
|
+
dataRoot: join(input.dataRoot, peerId),
|
|
51
|
+
peer: client,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
await reachability?.close().catch(() => undefined);
|
|
56
|
+
await client?.close().catch(() => undefined);
|
|
57
|
+
await rootOwner.close().catch(() => undefined);
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
let closeTask;
|
|
61
|
+
const ownedClient = client;
|
|
62
|
+
const ownedReachability = reachability;
|
|
63
|
+
const lifetime = new AbortController();
|
|
64
|
+
const maintenance = maintainReachability(ownedClient, ownedReachability, lifetime.signal, input.onBackgroundReachabilityError);
|
|
65
|
+
void maintenance.catch(() => undefined);
|
|
66
|
+
return Object.freeze({
|
|
67
|
+
client: ownedClient,
|
|
68
|
+
reachability: ownedReachability,
|
|
69
|
+
closed: maintenance,
|
|
70
|
+
close: () => {
|
|
71
|
+
lifetime.abort();
|
|
72
|
+
closeTask ??= closeEndpointOwner(ownedClient, ownedReachability, rootOwner, maintenance);
|
|
73
|
+
return closeTask;
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
async function closeEndpointOwner(client, reachability, rootOwner, maintenance) {
|
|
78
|
+
const errors = [];
|
|
79
|
+
await client.close().catch((error) => errors.push(error));
|
|
80
|
+
await maintenance.catch((error) => errors.push(error));
|
|
81
|
+
await reachability.close().catch((error) => errors.push(error));
|
|
82
|
+
await rootOwner.close().catch((error) => errors.push(error));
|
|
83
|
+
if (errors.length === 1)
|
|
84
|
+
throw errors[0];
|
|
85
|
+
if (errors.length > 1) {
|
|
86
|
+
throw new AggregateError(errors, 'Unable to close Runtime Host peer endpoint owner');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function maintainReachability(client, publisher, signal, onError) {
|
|
90
|
+
let generation = client.reachability().generation;
|
|
91
|
+
while (!signal.aborted) {
|
|
92
|
+
try {
|
|
93
|
+
await publisher.refresh();
|
|
94
|
+
const observed = await client.watchReachability(generation, REACHABILITY_WATCH_TIMEOUT_MS);
|
|
95
|
+
generation = observed.generation;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
if (signal.aborted)
|
|
99
|
+
return;
|
|
100
|
+
if (error instanceof PeerReachabilityPostCommitError ||
|
|
101
|
+
error instanceof RuntimeHostPermanentReconnectError) {
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
onError?.(error);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// A diagnostic observer cannot control the endpoint lifetime.
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
await delay(REACHABILITY_RETRY_INTERVAL_MS, undefined, { signal });
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
if (signal.aborted)
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
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 { chmod, lstat, mkdir, open, readFile, rename, unlink } from 'node:fs/promises';
|
|
20
|
+
import { dirname, join } from 'node:path';
|
|
21
|
+
import { performance } from 'node:perf_hooks';
|
|
22
|
+
import { authenticateSignedPeerReachabilityLease, canonicalPeerReachabilityLease, decodeSignedPeerReachabilityLease, isPeerReachabilityLeaseCurrent, PEER_REACHABILITY_LEASE_TTL_MS, PEER_REACHABILITY_REFRESH_LEAD_MS, peerReachabilityLeaseReceipt, peerReachabilityLeaseSigningBytes, samePeerReachabilityRoutes, verifySignedPeerReachabilityLease, } from './model.js';
|
|
23
|
+
const STATE_FILE = 'peer-reachability.json';
|
|
24
|
+
const MAX_STATE_BYTES = 64 * 1_024;
|
|
25
|
+
export async function openPeerReachabilityPublisher(input) {
|
|
26
|
+
await mkdir(input.dataRoot, { recursive: true, mode: 0o700 });
|
|
27
|
+
if (process.platform !== 'win32')
|
|
28
|
+
await chmod(input.dataRoot, 0o700);
|
|
29
|
+
const now = input.now ?? Date.now;
|
|
30
|
+
const monotonicNow = input.monotonicNow ?? performance.now.bind(performance);
|
|
31
|
+
const current = await readState(join(input.dataRoot, STATE_FILE), input.peer);
|
|
32
|
+
const publisher = new PeerReachabilityPublisherImpl(join(input.dataRoot, STATE_FILE), input.peer, now, monotonicNow, current);
|
|
33
|
+
await publisher.refresh();
|
|
34
|
+
return publisher;
|
|
35
|
+
}
|
|
36
|
+
class PeerReachabilityPublisherImpl {
|
|
37
|
+
path;
|
|
38
|
+
peer;
|
|
39
|
+
now;
|
|
40
|
+
monotonicNow;
|
|
41
|
+
#current;
|
|
42
|
+
#receipt;
|
|
43
|
+
#tail = Promise.resolve();
|
|
44
|
+
#failure;
|
|
45
|
+
#closed = false;
|
|
46
|
+
#closeTask;
|
|
47
|
+
#listeners = new Set();
|
|
48
|
+
constructor(path, peer, now, monotonicNow, current) {
|
|
49
|
+
this.path = path;
|
|
50
|
+
this.peer = peer;
|
|
51
|
+
this.now = now;
|
|
52
|
+
this.monotonicNow = monotonicNow;
|
|
53
|
+
this.#current = current;
|
|
54
|
+
if (current) {
|
|
55
|
+
this.#receipt = peerReachabilityLeaseReceipt({
|
|
56
|
+
signed: current,
|
|
57
|
+
wallNow: this.now(),
|
|
58
|
+
monotonicNow: this.monotonicNow(),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
current() {
|
|
63
|
+
this.#assertOpen();
|
|
64
|
+
if (!this.#current)
|
|
65
|
+
throw new Error('Peer reachability publisher is not initialized');
|
|
66
|
+
return this.#current;
|
|
67
|
+
}
|
|
68
|
+
subscribe(listener) {
|
|
69
|
+
this.#assertOpen();
|
|
70
|
+
this.#listeners.add(listener);
|
|
71
|
+
return () => this.#listeners.delete(listener);
|
|
72
|
+
}
|
|
73
|
+
refresh() {
|
|
74
|
+
this.#assertOpen();
|
|
75
|
+
const task = this.#tail.then(async () => {
|
|
76
|
+
this.#assertOpen();
|
|
77
|
+
const identity = this.peer.identity();
|
|
78
|
+
const reachability = this.peer.reachability();
|
|
79
|
+
const now = this.now();
|
|
80
|
+
const monotonicNow = this.monotonicNow();
|
|
81
|
+
if (this.#current &&
|
|
82
|
+
this.#current.lease.peerId === identity.peerId &&
|
|
83
|
+
this.#current.lease.issuedAt <= now &&
|
|
84
|
+
this.#current.lease.expiresAt > now + PEER_REACHABILITY_REFRESH_LEAD_MS &&
|
|
85
|
+
isPeerReachabilityLeaseCurrent(this.#current, this.#receipt, monotonicNow + PEER_REACHABILITY_REFRESH_LEAD_MS) &&
|
|
86
|
+
samePeerReachabilityRoutes(this.#current.lease, reachability)) {
|
|
87
|
+
return this.#current;
|
|
88
|
+
}
|
|
89
|
+
const revision = (this.#current?.lease.revision ?? 0) + 1;
|
|
90
|
+
const lease = canonicalPeerReachabilityLease({
|
|
91
|
+
version: 1,
|
|
92
|
+
peerId: identity.peerId,
|
|
93
|
+
revision,
|
|
94
|
+
issuedAt: now,
|
|
95
|
+
expiresAt: now + PEER_REACHABILITY_LEASE_TTL_MS,
|
|
96
|
+
directRoutes: reachability.listenAddresses,
|
|
97
|
+
coordinationRoutes: reachability.activeCoordinationRelays,
|
|
98
|
+
});
|
|
99
|
+
const identityProof = await this.peer.signIdentity(peerReachabilityLeaseSigningBytes(lease));
|
|
100
|
+
const signed = decodeSignedPeerReachabilityLease({
|
|
101
|
+
lease,
|
|
102
|
+
publicKey: identityProof.publicKey.toString('base64url'),
|
|
103
|
+
signature: identityProof.signature.toString('base64url'),
|
|
104
|
+
});
|
|
105
|
+
verifySignedPeerReachabilityLease({
|
|
106
|
+
value: signed,
|
|
107
|
+
expectedPeerId: identity.peerId,
|
|
108
|
+
now,
|
|
109
|
+
verifyIdentity: this.peer.verifyIdentity.bind(this.peer),
|
|
110
|
+
});
|
|
111
|
+
try {
|
|
112
|
+
await writeState(this.path, signed);
|
|
113
|
+
this.#adopt(signed, now, monotonicNow);
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (error instanceof PeerReachabilityPostCommitError) {
|
|
117
|
+
this.#adopt(signed, now, monotonicNow);
|
|
118
|
+
this.#notify(signed);
|
|
119
|
+
this.#failure = error;
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
throw new PeerReachabilityPersistenceError(error);
|
|
123
|
+
}
|
|
124
|
+
this.#notify(signed);
|
|
125
|
+
return signed;
|
|
126
|
+
});
|
|
127
|
+
this.#tail = task.then(() => undefined, () => undefined);
|
|
128
|
+
return task;
|
|
129
|
+
}
|
|
130
|
+
close() {
|
|
131
|
+
this.#closeTask ??= this.#close();
|
|
132
|
+
return this.#closeTask;
|
|
133
|
+
}
|
|
134
|
+
async #close() {
|
|
135
|
+
this.#closed = true;
|
|
136
|
+
await this.#tail;
|
|
137
|
+
this.#listeners.clear();
|
|
138
|
+
}
|
|
139
|
+
#notify(lease) {
|
|
140
|
+
for (const listener of this.#listeners) {
|
|
141
|
+
try {
|
|
142
|
+
listener(lease);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Reachability publication remains authoritative even if an observer fails.
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
#assertOpen() {
|
|
150
|
+
if (this.#closed)
|
|
151
|
+
throw new Error('Peer reachability publisher is closed');
|
|
152
|
+
if (this.#failure)
|
|
153
|
+
throw this.#failure;
|
|
154
|
+
}
|
|
155
|
+
#adopt(signed, wallNow, monotonicNow) {
|
|
156
|
+
this.#current = signed;
|
|
157
|
+
this.#receipt = peerReachabilityLeaseReceipt({ signed, wallNow, monotonicNow });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async function readState(path, peer) {
|
|
161
|
+
try {
|
|
162
|
+
const stat = await lstat(path);
|
|
163
|
+
if (!stat.isFile() || stat.size > MAX_STATE_BYTES) {
|
|
164
|
+
throw new Error('Invalid peer reachability state file');
|
|
165
|
+
}
|
|
166
|
+
const document = JSON.parse(await readFile(path, 'utf8'));
|
|
167
|
+
if (!document || typeof document !== 'object' || Array.isArray(document)) {
|
|
168
|
+
throw new Error('Invalid peer reachability state document');
|
|
169
|
+
}
|
|
170
|
+
const record = document;
|
|
171
|
+
if (record.version !== 1 || Object.keys(record).length !== 2) {
|
|
172
|
+
throw new Error('Invalid peer reachability state document');
|
|
173
|
+
}
|
|
174
|
+
return authenticateSignedPeerReachabilityLease({
|
|
175
|
+
value: record.current,
|
|
176
|
+
expectedPeerId: peer.identity().peerId,
|
|
177
|
+
verifyIdentity: peer.verifyIdentity.bind(peer),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
if (isNodeError(error, 'ENOENT'))
|
|
182
|
+
return undefined;
|
|
183
|
+
throw error;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async function writeState(path, current) {
|
|
187
|
+
const document = `${JSON.stringify({ version: 1, current }, null, 2)}\n`;
|
|
188
|
+
if (Buffer.byteLength(document) > MAX_STATE_BYTES) {
|
|
189
|
+
throw new Error('Peer reachability state is too large');
|
|
190
|
+
}
|
|
191
|
+
const temporary = `${path}.tmp`;
|
|
192
|
+
let replaced = false;
|
|
193
|
+
try {
|
|
194
|
+
await unlink(temporary).catch((error) => {
|
|
195
|
+
if (!isNodeError(error, 'ENOENT'))
|
|
196
|
+
throw error;
|
|
197
|
+
});
|
|
198
|
+
const handle = await open(temporary, 'wx', 0o600);
|
|
199
|
+
try {
|
|
200
|
+
await handle.writeFile(document, 'utf8');
|
|
201
|
+
await handle.sync();
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
await handle.close();
|
|
205
|
+
}
|
|
206
|
+
if (process.platform !== 'win32')
|
|
207
|
+
await chmod(temporary, 0o600);
|
|
208
|
+
await rename(temporary, path);
|
|
209
|
+
replaced = true;
|
|
210
|
+
try {
|
|
211
|
+
await syncDirectory(dirname(path));
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
throw new PeerReachabilityPostCommitError(error);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
finally {
|
|
218
|
+
if (!replaced)
|
|
219
|
+
await unlink(temporary).catch(() => undefined);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
export class PeerReachabilityPersistenceError extends Error {
|
|
223
|
+
constructor(cause) {
|
|
224
|
+
super('Peer reachability state could not be persisted', { cause });
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
export class PeerReachabilityPostCommitError extends Error {
|
|
228
|
+
constructor(cause) {
|
|
229
|
+
super('Peer reachability state was replaced but its durability could not be confirmed; reopen it', { cause });
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async function syncDirectory(path) {
|
|
233
|
+
if (process.platform === 'win32')
|
|
234
|
+
return;
|
|
235
|
+
const handle = await open(path, 'r');
|
|
236
|
+
try {
|
|
237
|
+
await handle.sync();
|
|
238
|
+
}
|
|
239
|
+
finally {
|
|
240
|
+
await handle.close();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function isNodeError(error, code) {
|
|
244
|
+
return error instanceof Error && 'code' in error && error.code === code;
|
|
245
|
+
}
|
|
@@ -673,7 +673,9 @@ function decodeSignal(value) {
|
|
|
673
673
|
const record = requireShapedRecord(value, 'agent graph signal', ['kind'], ['reason', 'status']);
|
|
674
674
|
if (record.kind === 'attention') {
|
|
675
675
|
requireExactRecord(record, 'agent graph attention signal', ['kind', 'reason']);
|
|
676
|
-
if (record.reason !== 'permission_request' &&
|
|
676
|
+
if (record.reason !== 'permission_request' &&
|
|
677
|
+
record.reason !== 'user_question_request' &&
|
|
678
|
+
record.reason !== 'form_request') {
|
|
677
679
|
throw invalidProtocolFrame('Invalid agent graph attention reason');
|
|
678
680
|
}
|
|
679
681
|
return { kind: record.kind, reason: record.reason };
|
|
@@ -854,6 +856,7 @@ function requireFacet(value) {
|
|
|
854
856
|
value === 'permission_request' ||
|
|
855
857
|
value === 'permission_decision' ||
|
|
856
858
|
value === 'user_question_request' ||
|
|
859
|
+
value === 'form_request' ||
|
|
857
860
|
value === 'transfer' ||
|
|
858
861
|
value === 'usage' ||
|
|
859
862
|
value === 'completed' ||
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* under the License.
|
|
18
18
|
*/
|
|
19
19
|
import { TOOL_ACTIVITY_KINDS } from '@maka/core/events';
|
|
20
|
+
import { decodeInteractionAnswer, projectInteractionFormRequest, } from '@maka/core/interaction';
|
|
20
21
|
import { assertExactKeys, requireCount, requireEntityId, requireExactRecord, requireRecord, requireString, } from './codec.js';
|
|
21
22
|
import { invalidProtocolFrame } from './errors.js';
|
|
22
23
|
import { defineHostPathOperation, defineOperation } from './operation-spec.js';
|
|
@@ -241,6 +242,19 @@ export function decodeClientCapabilityClientFrame(value) {
|
|
|
241
242
|
data,
|
|
242
243
|
};
|
|
243
244
|
}
|
|
245
|
+
case 'client.capability.interaction_request':
|
|
246
|
+
assertExactKeys(frame, 'Client Capability interaction request frame', [
|
|
247
|
+
'kind',
|
|
248
|
+
'invocationId',
|
|
249
|
+
'interactionId',
|
|
250
|
+
'request',
|
|
251
|
+
]);
|
|
252
|
+
return {
|
|
253
|
+
kind: frame.kind,
|
|
254
|
+
invocationId: requireEntityId(frame.invocationId, 'invocationId'),
|
|
255
|
+
interactionId: requireEntityId(frame.interactionId, 'interactionId'),
|
|
256
|
+
request: decodeClientCapabilityFormRequest(frame.request),
|
|
257
|
+
};
|
|
244
258
|
default:
|
|
245
259
|
throw invalidProtocolFrame('Invalid Client Capability client frame kind');
|
|
246
260
|
}
|
|
@@ -330,6 +344,19 @@ export function decodeClientCapabilityHostFrame(value) {
|
|
|
330
344
|
kind: frame.kind,
|
|
331
345
|
invocationId: requireEntityId(frame.invocationId, 'invocationId'),
|
|
332
346
|
};
|
|
347
|
+
case 'client.capability.interaction_result':
|
|
348
|
+
assertExactKeys(frame, 'Client Capability interaction result frame', [
|
|
349
|
+
'kind',
|
|
350
|
+
'invocationId',
|
|
351
|
+
'interactionId',
|
|
352
|
+
'result',
|
|
353
|
+
]);
|
|
354
|
+
return {
|
|
355
|
+
kind: frame.kind,
|
|
356
|
+
invocationId: requireEntityId(frame.invocationId, 'invocationId'),
|
|
357
|
+
interactionId: requireEntityId(frame.interactionId, 'interactionId'),
|
|
358
|
+
result: decodeClientCapabilityFormResult(frame.result),
|
|
359
|
+
};
|
|
333
360
|
case 'client.capability.registration_release':
|
|
334
361
|
assertExactKeys(frame, 'Client Capability registration release frame', [
|
|
335
362
|
'kind',
|
|
@@ -359,6 +386,45 @@ export function decodeClientCapabilityResult(value) {
|
|
|
359
386
|
: {}),
|
|
360
387
|
};
|
|
361
388
|
}
|
|
389
|
+
function decodeClientCapabilityFormRequest(value) {
|
|
390
|
+
const record = requireExactRecord(value, 'Client Capability form request', [
|
|
391
|
+
'message',
|
|
392
|
+
'requester',
|
|
393
|
+
'fields',
|
|
394
|
+
]);
|
|
395
|
+
let request;
|
|
396
|
+
try {
|
|
397
|
+
request = projectInteractionFormRequest({
|
|
398
|
+
toolUseId: 'client-capability-interaction',
|
|
399
|
+
message: record.message,
|
|
400
|
+
requester: record.requester,
|
|
401
|
+
fields: record.fields,
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
catch {
|
|
405
|
+
throw invalidProtocolFrame('Invalid Client Capability form request');
|
|
406
|
+
}
|
|
407
|
+
return {
|
|
408
|
+
message: request.message,
|
|
409
|
+
requester: request.requester,
|
|
410
|
+
fields: request.fields,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
function decodeClientCapabilityFormResult(value) {
|
|
414
|
+
const record = requireRecord(value, 'Client Capability form result');
|
|
415
|
+
let answer;
|
|
416
|
+
try {
|
|
417
|
+
answer = decodeInteractionAnswer({ kind: 'form', ...record });
|
|
418
|
+
}
|
|
419
|
+
catch {
|
|
420
|
+
throw invalidProtocolFrame('Invalid Client Capability form result');
|
|
421
|
+
}
|
|
422
|
+
if (answer.kind !== 'form')
|
|
423
|
+
throw invalidProtocolFrame('Invalid Client Capability form result');
|
|
424
|
+
return answer.action === 'accept'
|
|
425
|
+
? { action: 'accept', values: answer.values }
|
|
426
|
+
: { action: answer.action };
|
|
427
|
+
}
|
|
362
428
|
function decodeClientCapabilityOffer(value) {
|
|
363
429
|
const record = requireRecord(value, 'Client Capability offer');
|
|
364
430
|
assertOptionalExactKeys(record, 'Client Capability offer', ['offerId', 'version', 'affinity', 'hostPathAccess', 'label', 'tools'], ['description']);
|
|
@@ -820,6 +886,7 @@ const CLIENT_CAPABILITY_CLIENT_FRAME_KINDS = new Set([
|
|
|
820
886
|
'client.capability.result',
|
|
821
887
|
'client.capability.result_start',
|
|
822
888
|
'client.capability.result_chunk',
|
|
889
|
+
'client.capability.interaction_request',
|
|
823
890
|
]);
|
|
824
891
|
const CLIENT_CAPABILITY_HOST_FRAME_KINDS = new Set([
|
|
825
892
|
'client.capability.call',
|
|
@@ -828,4 +895,5 @@ const CLIENT_CAPABILITY_HOST_FRAME_KINDS = new Set([
|
|
|
828
895
|
'client.capability.release',
|
|
829
896
|
'client.capability.registration_release',
|
|
830
897
|
'client.capability.admitted',
|
|
898
|
+
'client.capability.interaction_result',
|
|
831
899
|
]);
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
* specific language governing permissions and limitations
|
|
17
17
|
* under the License.
|
|
18
18
|
*/
|
|
19
|
-
import { CONNECTION_CATALOG_MAX_MODELS_PER_CONNECTION, decodeConnectionModelId, decodeConnectionModel, decodeConnectionSlug, decodeProviderType, decodeConnectionTestSummary, decodeConnectionVersionBasis, RuntimePolicyDomainDecodeError, } from '@maka/core/runtime-policy';
|
|
20
|
-
import { requireCount, requireEntityId, requireExactRecord, requireRecord, requireString, } from './codec.js';
|
|
19
|
+
import { CONNECTION_CATALOG_MAX_MODELS_PER_CONNECTION, decodeConnectionModelId, decodeConnectionModel, decodeConnectionName, decodeConnectionSlug, decodeProviderType, decodeConnectionTestSummary, decodeConnectionVersionBasis, RuntimePolicyDomainDecodeError, } from '@maka/core/runtime-policy';
|
|
20
|
+
import { requireCount, requireEntityId, requireExactRecord, requireRecord, requireShapedRecord, requireString, } from './codec.js';
|
|
21
21
|
import { invalidProtocolFrame } from './errors.js';
|
|
22
22
|
import { defineOperation } from './operation-spec.js';
|
|
23
23
|
const EFFECT_ERRORS = [
|
|
@@ -91,9 +91,8 @@ export function decodeConnectionOnboardingSaveInput(value) {
|
|
|
91
91
|
baseUrl: input.baseUrl,
|
|
92
92
|
});
|
|
93
93
|
if (!Array.isArray(input.enabledModelIds) ||
|
|
94
|
-
input.enabledModelIds.length === 0 ||
|
|
95
94
|
input.enabledModelIds.length > CONNECTION_CATALOG_MAX_MODELS_PER_CONNECTION) {
|
|
96
|
-
throw invalidProtocolFrame('Connection onboarding
|
|
95
|
+
throw invalidProtocolFrame('Connection onboarding enabled models exceed the limit');
|
|
97
96
|
}
|
|
98
97
|
const enabledModelIds = input.enabledModelIds.map((modelId) => decodeDomain(() => decodeConnectionModelId(modelId)));
|
|
99
98
|
if (new Set(enabledModelIds).size !== enabledModelIds.length) {
|
|
@@ -140,6 +139,7 @@ export function decodeConnectionOnboardingSaveResult(value) {
|
|
|
140
139
|
rejected.reason !== 'base_url_not_configured' &&
|
|
141
140
|
rejected.reason !== 'catalog_full' &&
|
|
142
141
|
rejected.reason !== 'model_unavailable' &&
|
|
142
|
+
rejected.reason !== 'slug_taken' &&
|
|
143
143
|
rejected.reason !== 'superseded')) {
|
|
144
144
|
throw invalidProtocolFrame('Invalid connection onboarding save rejection');
|
|
145
145
|
}
|
|
@@ -164,13 +164,19 @@ export function decodeConnectionOnboardingVerifyInput(value) {
|
|
|
164
164
|
function decodeConnectionOnboardingTarget(value) {
|
|
165
165
|
const target = requireRecord(value, 'connection onboarding target');
|
|
166
166
|
if (target.kind === 'create') {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
]);
|
|
167
|
+
// slug/name are optional so a surface that accepts the derived identity
|
|
168
|
+
// can keep talking to any Host vintage; a surface that lets the user name
|
|
169
|
+
// the connection must tolerate an older Host rejecting the extra fields.
|
|
170
|
+
const exact = requireShapedRecord(target, 'create connection onboarding target', ['kind', 'providerType'], ['slug', 'name']);
|
|
171
171
|
return {
|
|
172
172
|
kind: 'create',
|
|
173
173
|
providerType: decodeDomain(() => decodeProviderType(exact.providerType)),
|
|
174
|
+
...(exact.slug === undefined
|
|
175
|
+
? {}
|
|
176
|
+
: { slug: decodeDomain(() => decodeConnectionSlug(exact.slug)) }),
|
|
177
|
+
...(exact.name === undefined
|
|
178
|
+
? {}
|
|
179
|
+
: { name: decodeDomain(() => decodeConnectionName(exact.name)) }),
|
|
174
180
|
};
|
|
175
181
|
}
|
|
176
182
|
if (target.kind === 'existing') {
|
|
@@ -216,6 +222,7 @@ export function decodeConnectionOnboardingVerifyResult(value) {
|
|
|
216
222
|
rejected.reason !== 'connection_not_found' &&
|
|
217
223
|
rejected.reason !== 'credential_not_configured' &&
|
|
218
224
|
rejected.reason !== 'base_url_not_configured' &&
|
|
225
|
+
rejected.reason !== 'slug_taken' &&
|
|
219
226
|
rejected.reason !== 'catalog_full')) {
|
|
220
227
|
throw invalidProtocolFrame('Invalid connection onboarding rejection');
|
|
221
228
|
}
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
import { invalidProtocolFrame } from './errors.js';
|
|
20
20
|
import { requireCount, requireEncodedByteLimit, requireExactRecord, requireId, requireRecord, requireString, requireUtf8String, } from './codec.js';
|
|
21
21
|
import { defineOperation } from './operation-spec.js';
|
|
22
|
+
import { decodeSignedPeerReachabilityLease, } from '../peer-reachability/model.js';
|
|
22
23
|
export function isHostActivityIdle(activity) {
|
|
23
24
|
return (activity.connections === 0 &&
|
|
24
25
|
activity.activeOperations === 0 &&
|
|
@@ -27,9 +28,6 @@ export function isHostActivityIdle(activity) {
|
|
|
27
28
|
export const HOST_DIAGNOSTICS_RESULT_MAX_BYTES = 72 * 1024;
|
|
28
29
|
export const HOST_DIAGNOSTIC_LOG_MAX_ENTRIES = 256;
|
|
29
30
|
export const HOST_DIAGNOSTIC_LOG_MAX_ENTRY_BYTES = 10 * 1024;
|
|
30
|
-
const HOST_PEER_ID_MAX_BYTES = 160;
|
|
31
|
-
const HOST_PEER_ADDRESS_MAX_BYTES = 2 * 1024;
|
|
32
|
-
const HOST_PEER_ROUTE_MAX = 16;
|
|
33
31
|
export const HOST_BOOTSTRAP_OPERATION_SPECS = {
|
|
34
32
|
'host.status': defineOperation({
|
|
35
33
|
mode: 'query',
|
|
@@ -53,16 +51,6 @@ export const HOST_BOOTSTRAP_OPERATION_SPECS = {
|
|
|
53
51
|
decodeOutput: decodeHostUpgradePrepareResult,
|
|
54
52
|
}),
|
|
55
53
|
};
|
|
56
|
-
function decodePeerAddresses(value, label) {
|
|
57
|
-
if (!Array.isArray(value) || value.length > HOST_PEER_ROUTE_MAX) {
|
|
58
|
-
throw invalidProtocolFrame(`Invalid ${label}`);
|
|
59
|
-
}
|
|
60
|
-
const addresses = value.map((address) => requireString(address, label, HOST_PEER_ADDRESS_MAX_BYTES));
|
|
61
|
-
if (new Set(addresses).size !== addresses.length) {
|
|
62
|
-
throw invalidProtocolFrame(`Duplicate ${label}`);
|
|
63
|
-
}
|
|
64
|
-
return Object.freeze(addresses);
|
|
65
|
-
}
|
|
66
54
|
function decodeEmptyHostInput(value, label) {
|
|
67
55
|
requireExactRecord(value, label, []);
|
|
68
56
|
return {};
|
|
@@ -205,16 +193,12 @@ function decodeHostStatusFields(record) {
|
|
|
205
193
|
};
|
|
206
194
|
}
|
|
207
195
|
function decodeHostPeerEndpoint(value) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
peerId: requireString(record.peerId, 'Runtime Host peer id', HOST_PEER_ID_MAX_BYTES),
|
|
215
|
-
routeHints: decodePeerAddresses(record.routeHints, 'Runtime Host peer route hints'),
|
|
216
|
-
coordinationRelays: decodePeerAddresses(record.coordinationRelays, 'Runtime Host peer coordination relays'),
|
|
217
|
-
};
|
|
196
|
+
try {
|
|
197
|
+
return decodeSignedPeerReachabilityLease(value);
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
throw invalidProtocolFrame('Invalid Runtime Host peer reachability lease');
|
|
201
|
+
}
|
|
218
202
|
}
|
|
219
203
|
function requirePlatform(value) {
|
|
220
204
|
if (value === 'aix' ||
|
|
@@ -61,7 +61,53 @@ export const RUNTIME_HOST_REGISTRATION_SCHEMA_VERSION = 1;
|
|
|
61
61
|
export const RUNTIME_HOST_PROTOCOL_VERSION = 0;
|
|
62
62
|
// Increment when the same protocol version no longer guarantees safe Client-Host
|
|
63
63
|
// interoperability. Mismatches are rejected before domain commands are admitted.
|
|
64
|
-
export const RUNTIME_HOST_COMPATIBILITY_EPOCH =
|
|
64
|
+
export const RUNTIME_HOST_COMPATIBILITY_EPOCH = 109;
|
|
65
|
+
// 109: accepted Client Capability invocations may carry one bounded nested form
|
|
66
|
+
// Interaction request/result round trip.
|
|
67
|
+
// 108: Session Interaction snapshots, forwarded Runtime events, and Agent Graph
|
|
68
|
+
// activity may carry the provider-neutral `form` request/answer contract.
|
|
69
|
+
// 107: `token_usage` anchors record the model and connection that produced
|
|
70
|
+
// them. The record decodes against a closed allowlist, so an older client
|
|
71
|
+
// rejects the two new keys and, with them, the Session that carries them.
|
|
72
|
+
// 106: Session transcripts gain five `system_note` kinds
|
|
73
|
+
// (`context_provider_dropping`, `context_window_suggestion`,
|
|
74
|
+
// `context_window_overrun`, `context_reported_window_exceeded`,
|
|
75
|
+
// `context_overflow_after_compaction`) and
|
|
76
|
+
// `token_usage` records reshape `lastRequestAnchor` to
|
|
77
|
+
// `{ inputTokens, outputTokens }`, all behind closed allowlists in
|
|
78
|
+
// @maka/core. An older client that handshakes would fail
|
|
79
|
+
// `decodeStoredMessage` on the first transcript carrying them, so the pair
|
|
80
|
+
// must refuse each other at the handshake instead (#4559).
|
|
81
|
+
// 105: Usage summaries may carry the recorded call-time total and per-Session
|
|
82
|
+
// tool-invocation totals. Older Clients reject the unknown fields, so a newer
|
|
83
|
+
// Host's usage summary is unreadable to them.
|
|
84
|
+
// 104: WorkHub Coordination actions add closed direct-stop proposals,
|
|
85
|
+
// confirmations, expected-state preconditions, and outcomes. Older peers
|
|
86
|
+
// reject these strict shapes.
|
|
87
|
+
// 103: `github-copilot` joins `OAUTH_LOGIN_PROVIDERS`, the Host answers the
|
|
88
|
+
// closed `oauth.enrollment.query`, and `connection.onboarding.save` admits
|
|
89
|
+
// canonical OAuth material with an empty enable-all-discovered selection.
|
|
90
|
+
// Older peers reject these wire values, so incompatible pairs must fail the
|
|
91
|
+
// handshake. Re-derived from current `main`; epoch 102 is claimed by open PRs.
|
|
92
|
+
// 101: Session Turn requests can carry regeneration intents and Guests can
|
|
93
|
+
// atomically withdraw pending requests. Older peers do not share this command
|
|
94
|
+
// vocabulary or the expanded Guest operation grant.
|
|
95
|
+
// 100: `session.branch.create` makes `sourceTurnId` optional, so a side
|
|
96
|
+
// conversation can fork with an empty context (no copied messages, no
|
|
97
|
+
// fabricated `branchOfTurnId`) instead of requiring a settled turn. An older
|
|
98
|
+
// Host's required-field check rejects the request that omits `sourceTurnId`;
|
|
99
|
+
// the handshake keeps mixed-version peers apart. `session.revision.create`
|
|
100
|
+
// still requires `sourceTurnId`, and its wire shape and fingerprint are
|
|
101
|
+
// unchanged.
|
|
102
|
+
// 99: ScheduledTask Agent execution templates carry immutable Connection
|
|
103
|
+
// identity. Older peers cannot preserve the ID/slug/model binding and could
|
|
104
|
+
// silently route a deleted Connection to a same-slug replacement.
|
|
105
|
+
// 98: Peer Mesh invitations carry signed reachability leases and member route
|
|
106
|
+
// projections use the convergent recovery state machine. Older peers decode a
|
|
107
|
+
// different strict wire shape.
|
|
108
|
+
// 97: Host status replaces unsigned route arrays with a self-signed, bounded
|
|
109
|
+
// reachability lease. Older peers cannot validate the locator revision or its
|
|
110
|
+
// target identity before retaining it for reconnect.
|
|
65
111
|
// 96: Read image tool results may carry durable `session_context` refs.
|
|
66
112
|
// 95: Catalog entries carry `describedByMetadata`, so a client asks the
|
|
67
113
|
// Host-resolved entry — not its own bundled table — whether a model needs a
|