reploid 0.0.0-stage → 0.1.0
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/apps/poolday/config/chat-files.json +27 -0
- package/apps/poolday/config/partition-generation.js +21 -0
- package/apps/poolday/config/partition-policy.json +74 -0
- package/apps/poolday/config/partition-releases.json +3 -0
- package/apps/poolday/config/work-profile.json +122 -0
- package/apps/poolday/host/chat-view.js +47 -0
- package/apps/poolday/host/earning/client.js +199 -0
- package/apps/poolday/host/earning/contribution.js +168 -0
- package/apps/poolday/host/partition-release.js +33 -0
- package/apps/poolday/host/work-partition-artifact-source.js +37 -0
- package/apps/poolday/host/work-partition-capsule.js +39 -0
- package/apps/poolday/host/work-partition-plan.js +167 -0
- package/apps/poolday/host/work-partition-tokenizer-guard.js +21 -0
- package/apps/poolday/infrastructure/model-storage-lock.js +22 -0
- package/apps/poolday/infrastructure/pack-release-storage.js +52 -0
- package/apps/poolday/pool/pack-operation.js +161 -0
- package/apps/poolday/pool/pack-release-policy.js +44 -0
- package/apps/poolday/pool/peer-pack-data-channel.js +217 -0
- package/apps/poolday/providers/work-adapter.js +67 -0
- package/apps/poolday/providers/work-device.js +33 -0
- package/apps/poolday/providers/work-generation-completion.js +55 -0
- package/apps/poolday/providers/work-provider.js +209 -0
- package/apps/poolday/providers/work-resident-provider.js +113 -0
- package/deploy/artifacts/doppler-gpu-0.7.1.tgz +0 -0
- package/docs/fleet-service.md +214 -0
- package/docs/native-participant.md +534 -0
- package/native-delivery.json +1174 -0
- package/package.json +29 -4
- package/packages/reploid/src/artifacts/binary.js +25 -0
- package/packages/reploid/src/artifacts/canonical-json.js +23 -0
- package/packages/reploid/src/artifacts/custody/exchange.js +402 -0
- package/packages/reploid/src/artifacts/custody/piece-acquisition.js +70 -0
- package/packages/reploid/src/artifacts/custody/runtime.js +404 -0
- package/packages/reploid/src/artifacts/custody/supply-budget.js +19 -0
- package/packages/reploid/src/artifacts/custody-certificate.js +123 -0
- package/packages/reploid/src/artifacts/delivery-attestation.js +64 -0
- package/packages/reploid/src/artifacts/generation-terminal.js +36 -0
- package/packages/reploid/src/artifacts/identity.js +91 -0
- package/packages/reploid/src/artifacts/participant-proofs.js +159 -0
- package/packages/reploid/src/artifacts/receipt.js +131 -0
- package/packages/reploid/src/artifacts/signatures.js +94 -0
- package/packages/reploid/src/artifacts/whole-model-receipt.js +42 -0
- package/packages/reploid/src/cancellation.js +44 -0
- package/packages/reploid/src/config/defaults.json +110 -0
- package/packages/reploid/src/config/index.js +209 -0
- package/packages/reploid/src/config/request-overrides.json +9 -0
- package/packages/reploid/src/config/transport-defaults.json +7 -0
- package/packages/reploid/src/hashing.js +30 -0
- package/packages/reploid/src/measurement/capacity-utilization.js +321 -0
- package/packages/reploid/src/measurement/index.js +5 -0
- package/packages/reploid/src/measurement/readiness-records.js +310 -0
- package/packages/reploid/src/mesh/computer-identity.js +50 -0
- package/packages/reploid/src/mesh/computer-identity.policy.json +8 -0
- package/packages/reploid/src/mesh/contribution.js +141 -0
- package/packages/reploid/src/mesh/generation-recovery.js +58 -0
- package/packages/reploid/src/mesh/gpu-signature-shader.js +27 -0
- package/packages/reploid/src/mesh/gpu-signature.js +136 -0
- package/packages/reploid/src/mesh/gpu-signature.policy.json +11 -0
- package/packages/reploid/src/mesh/index.js +66 -0
- package/packages/reploid/src/mesh/partitions/automatic-ordered-partitions.js +540 -0
- package/packages/reploid/src/mesh/partitions/automatic-partitions.js +298 -0
- package/packages/reploid/src/mesh/partitions/partition-attempt-evidence.js +282 -0
- package/packages/reploid/src/mesh/partitions/partition-attempt-queue-policy.json +6 -0
- package/packages/reploid/src/mesh/partitions/partition-attempt-queue.js +112 -0
- package/packages/reploid/src/mesh/partitions/partition-canonical-contract.js +167 -0
- package/packages/reploid/src/mesh/partitions/partition-canonical-execution.js +168 -0
- package/packages/reploid/src/mesh/partitions/partition-chat-canonical.js +49 -0
- package/packages/reploid/src/mesh/partitions/partition-chat.js +125 -0
- package/packages/reploid/src/mesh/partitions/partition-contract.js +192 -0
- package/packages/reploid/src/mesh/partitions/partition-device-admission.js +96 -0
- package/packages/reploid/src/mesh/partitions/partition-discovery.js +96 -0
- package/packages/reploid/src/mesh/partitions/partition-entry-publication.js +183 -0
- package/packages/reploid/src/mesh/partitions/partition-entry.js +434 -0
- package/packages/reploid/src/mesh/partitions/partition-generation-request.js +33 -0
- package/packages/reploid/src/mesh/partitions/partition-grants.js +277 -0
- package/packages/reploid/src/mesh/partitions/partition-link.js +103 -0
- package/packages/reploid/src/mesh/partitions/partition-network.js +109 -0
- package/packages/reploid/src/mesh/partitions/partition-ordered-chat.js +290 -0
- package/packages/reploid/src/mesh/partitions/partition-ordered-peer.js +415 -0
- package/packages/reploid/src/mesh/partitions/partition-ordered-publication.js +100 -0
- package/packages/reploid/src/mesh/partitions/partition-peer.js +314 -0
- package/packages/reploid/src/mesh/partitions/partition-placement.js +143 -0
- package/packages/reploid/src/mesh/partitions/partition-preparation-progress.js +25 -0
- package/packages/reploid/src/mesh/partitions/partition-receiver-policy.json +7 -0
- package/packages/reploid/src/mesh/partitions/partition-reservations.js +75 -0
- package/packages/reploid/src/mesh/partitions/partition-route-envelope-policy.json +16 -0
- package/packages/reploid/src/mesh/partitions/partition-route-envelope.js +74 -0
- package/packages/reploid/src/mesh/partitions/partition-route-execution.js +409 -0
- package/packages/reploid/src/mesh/partitions/partition-route-network.js +179 -0
- package/packages/reploid/src/mesh/partitions/partition-route-ranking.js +268 -0
- package/packages/reploid/src/mesh/partitions/partition-runner.js +319 -0
- package/packages/reploid/src/mesh/partitions/partition-stage-assignment.js +109 -0
- package/packages/reploid/src/mesh/partitions/partition-stage-commit.js +103 -0
- package/packages/reploid/src/mesh/partitions/partition-step-receiver.js +291 -0
- package/packages/reploid/src/mesh/partitions/partition-summary.js +122 -0
- package/packages/reploid/src/mesh/partitions/preparation-owner.js +40 -0
- package/packages/reploid/src/mesh/partitions/resident-error-codes.json +10 -0
- package/packages/reploid/src/mesh/partitions/resident-partition.js +333 -0
- package/packages/reploid/src/mesh/partitions/resident-route.js +46 -0
- package/packages/reploid/src/mesh/partitions/signed-resident-factory.js +59 -0
- package/packages/reploid/src/mesh/peer-generation.js +896 -0
- package/packages/reploid/src/mesh/peer-identity.js +87 -0
- package/packages/reploid/src/mesh/placement-beliefs.js +107 -0
- package/packages/reploid/src/mesh/preparation-progress.js +46 -0
- package/packages/reploid/src/mesh/provider-hardware.js +11 -0
- package/packages/reploid/src/mesh/remote-generation-requests.js +53 -0
- package/packages/reploid/src/mesh/swarm-coordination.js +140 -0
- package/packages/reploid/src/mesh/web-access-network.js +112 -0
- package/packages/reploid/src/mesh/web-access-policy.json +17 -0
- package/packages/reploid/src/retrieval/citations.js +156 -0
- package/packages/reploid/src/retrieval/claim-support.js +113 -0
- package/packages/reploid/src/retrieval/costs.js +101 -0
- package/packages/reploid/src/retrieval/fixed-provider.js +34 -0
- package/packages/reploid/src/retrieval/index.js +20 -0
- package/packages/reploid/src/retrieval/lexical-support.js +27 -0
- package/packages/reploid/src/retrieval/model-reviewer.js +67 -0
- package/packages/reploid/src/retrieval/page-fetch.json +10 -0
- package/packages/reploid/src/retrieval/page-text.js +182 -0
- package/packages/reploid/src/retrieval/passage.js +37 -0
- package/packages/reploid/src/retrieval/policy.json +14 -0
- package/packages/reploid/src/retrieval/retrieval.js +23 -0
- package/packages/reploid/src/retrieval/review-queue.js +76 -0
- package/packages/reploid/src/retrieval/sources.js +263 -0
- package/packages/reploid/src/retrieval/support-review.js +155 -0
- package/packages/reploid/src/retrieval/text.js +21 -0
- package/packages/reploid/src/rules/contribution.rules.json +8 -0
- package/packages/reploid/src/rules/routing.rules.json +24 -0
- package/packages/reploid/src/transport/assignment.js +571 -0
- package/packages/reploid/src/transport/bounded-channel-writer.js +46 -0
- package/packages/reploid/src/transport/index.js +11 -0
- package/packages/reploid/src/transport/introduction-admission.js +24 -0
- package/packages/reploid/src/transport/introduction-bootstrap.js +112 -0
- package/packages/reploid/src/transport/introduction-policy.json +12 -0
- package/packages/reploid/src/transport/introduction-records.js +90 -0
- package/packages/reploid/src/transport/introductions.js +209 -0
- package/packages/reploid/src/transport/partition-data-channel.js +421 -0
- package/packages/reploid/src/transport/partition-errors.json +16 -0
- package/packages/reploid/src/transport/retry-policy.js +36 -0
- package/packages/reploid/src/transport/room.js +502 -0
- package/packages/reploid/src/transport/sdp-fingerprint.js +5 -0
- package/packages/reploid/src/transport/signaling.js +571 -0
- package/packages/reploid/src/transport/swarm.js +1247 -0
- package/packages/reploid/src/transport/tool-offer-channel.js +137 -0
- package/server/browser-roots.js +42 -0
- package/server/browser-web-worker.js +94 -0
- package/server/chat-completions.js +45 -0
- package/server/fleet/browser-bridge.js +145 -0
- package/server/fleet/contract.js +42 -0
- package/server/fleet/credit-evidence.js +103 -0
- package/server/fleet/credit-recovery.js +175 -0
- package/server/fleet/credits.js +178 -0
- package/server/fleet/execution-admission.js +32 -0
- package/server/fleet/native-host.js +817 -0
- package/server/fleet/placement.js +132 -0
- package/server/fleet/requester.js +346 -0
- package/server/fleet/service.js +311 -0
- package/server/fleet/terminal-policy.js +83 -0
- package/server/fleet/text-api.js +94 -0
- package/server/hashing.js +35 -0
- package/server/http-request-owner.js +49 -0
- package/server/messages.js +57 -0
- package/server/native-canonical-epochs.js +90 -0
- package/server/native-change-log.js +40 -0
- package/server/native-earning.js +203 -0
- package/server/native-generation-journal.js +46 -0
- package/server/native-model-config.js +57 -0
- package/server/native-model-files.js +382 -0
- package/server/native-model-origin.js +54 -0
- package/server/native-model-origins.json +12 -0
- package/server/native-node.js +83 -0
- package/server/native-owner/controls.js +162 -0
- package/server/native-owner/monitor.js +251 -0
- package/server/native-owner/policy.js +273 -0
- package/server/native-owner/rate.js +92 -0
- package/server/native-participant.js +866 -0
- package/server/native-readiness-log.js +30 -0
- package/server/native-release-storage.js +64 -0
- package/server/native-shader-cache.js +369 -0
- package/server/native-supply-budget.js +66 -0
- package/server/native-whole-earning.js +67 -0
- package/server/native-whole-model-fill.js +182 -0
- package/server/native-whole-model.js +130 -0
- package/server/public-web-worker.js +66 -0
- package/server/responses.js +92 -0
- package/server/search/errors.js +47 -0
- package/server/search/page-fetch.js +185 -0
- package/server/text-api.js +83 -0
- package/server/text-recovery.js +45 -0
- package/server/text-request-options.js +23 -0
- package/server/text-requester.js +231 -0
- package/server/token-auth.js +9 -0
- package/server/whole-model-requester.js +99 -0
- package/shared/config/chat-models.json +4685 -0
- package/shared/config/doppler-execution-contracts.js +32 -0
- package/shared/config/doppler-execution-contracts.json +43 -0
- package/shared/config/doppler-generation-contract.js +223 -0
- package/shared/config/doppler-local-models.js +79 -0
- package/shared/config/doppler-package.json +7 -0
- package/shared/config/model-manifests/a0dc69e917133a82780823d17fc771c0f6b882d7c86c571deeaef45be2ff108b.json +6434 -0
- package/shared/config/model-manifests/e985e3cdad60d0cb57d84b436161e66ab5b3f6589a168de6f00b4610e5f1fb59.json +16534 -0
- package/shared/config/model-manifests/fa6eb7bbc3ba63571f8cede780b877d9272bde948697af93dd3d33837cb46137.json +7175 -0
- package/shared/config/model-pieces/qwen-0-8b-pieces.json +1506 -0
- package/shared/config/model-pieces/qwen-2b-pieces.json +4800 -0
- package/shared/config/model-pieces/qwen35b-q4_0-pieces.json +28880 -0
- package/shared/config/reploid-library.json +49 -0
- package/shared/config/swarm-bootstrap.json +21 -0
- package/shared/infrastructure/doppler-runtime-service.js +261 -0
- package/shared/pool/executable-pack.js +87 -0
- package/shared/pool/pack-operation-adapters.js +124 -0
- package/shared/pool/pack-operation-policy.js +75 -0
- package/shared/pool/pool-config.json +2280 -0
- package/shared/vendor/reploid/adapters/doppler-session.js +372 -0
- package/shared/vendor/reploid/artifacts/binary.js +25 -0
- package/shared/vendor/reploid/artifacts/canonical-json.js +23 -0
- package/shared/vendor/reploid/artifacts/delivery-attestation.js +64 -0
- package/shared/vendor/reploid/artifacts/identity.js +91 -0
- package/shared/vendor/reploid/artifacts/manifest-identity.js +17 -0
- package/shared/vendor/reploid/artifacts/participant-proofs.js +159 -0
- package/shared/vendor/reploid/artifacts/signatures.js +94 -0
- package/shared/vendor/reploid/config/defaults.json +110 -0
- package/shared/vendor/reploid/config/index.js +209 -0
- package/shared/vendor/reploid/config/request-overrides.json +9 -0
- package/shared/vendor/reploid/hashing.js +30 -0
- package/shared/vendor/reploid/mesh/generation-context-cache.js +97 -0
- package/shared/vendor/reploid/mesh/partitions/partition-attempt-evidence.js +282 -0
- package/shared/vendor/reploid/mesh/partitions/partition-contract.js +192 -0
- package/shared/vendor/reploid/mesh/partitions/partition-receiver-policy.json +7 -0
- package/shared/vendor/reploid/mesh/partitions/partition-route-ranking.js +268 -0
- package/shared/vendor/reploid/mesh/preparation-progress.js +46 -0
- package/shared/vendor/reploid/mesh/provider-hardware.js +11 -0
- package/shared/vendor/reploid/rules/routing.rules.json +24 -0
- package/shared/vendor/reploid/transport/partition-errors.json +16 -0
- package/README.md +0 -3
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import queuePolicy from './partition-attempt-queue-policy.json' with { type: 'json' };
|
|
2
|
+
import { assertPartition as assert, partitionFailure } from './partition-contract.js';
|
|
3
|
+
|
|
4
|
+
export const ATTEMPT_QUEUE_POLICY_SCHEMA = 'reploid.partition-attempt-queue-policy/v1';
|
|
5
|
+
const POLICY_KEYS = Object.freeze(['schema', 'maxQueuedAttempts', 'maxQueuedPerRequester', 'maxQueueWaitMs']);
|
|
6
|
+
const positive = value => Number.isSafeInteger(value) && value > 0;
|
|
7
|
+
|
|
8
|
+
/** Every member is required and nothing is defaulted in JavaScript. */
|
|
9
|
+
export function validateAttemptQueuePolicy(policy) {
|
|
10
|
+
const keys = policy && typeof policy === 'object' && !Array.isArray(policy) ? Object.keys(policy) : [];
|
|
11
|
+
assert(keys.length === POLICY_KEYS.length && POLICY_KEYS.every(key => keys.includes(key))
|
|
12
|
+
&& policy.schema === ATTEMPT_QUEUE_POLICY_SCHEMA
|
|
13
|
+
&& ['maxQueuedAttempts', 'maxQueuedPerRequester', 'maxQueueWaitMs'].every(key => positive(policy[key]))
|
|
14
|
+
&& policy.maxQueuedPerRequester <= policy.maxQueuedAttempts && policy.maxQueueWaitMs <= 2147483647,
|
|
15
|
+
`Explicit ${ATTEMPT_QUEUE_POLICY_SCHEMA} required: ${POLICY_KEYS.join(', ')}`);
|
|
16
|
+
return Object.freeze({ ...policy });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** The partitions component's own waiting bounds, checked when this module loads. */
|
|
20
|
+
export const ATTEMPT_QUEUE_POLICY = validateAttemptQueuePolicy(queuePolicy);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Coordinator admission for already-authorized ordered attempts. An attempt whose route has no
|
|
24
|
+
* free slot waits here instead of failing; while it waits nothing is tokenized, reserved, granted
|
|
25
|
+
* or disclosed to any stage. Entries are admitted in arrival order: the earliest waiting entry
|
|
26
|
+
* whose route can run it now goes first, so one route's limit never idles another route's
|
|
27
|
+
* capacity and later entries of the same route never overtake earlier ones.
|
|
28
|
+
*
|
|
29
|
+
* `admit()` resolves with a ticket the route owner holds until the attempt's coordinator-side
|
|
30
|
+
* work ends (`release()`); `opened()` marks that the attempt now holds the coordinator stage's
|
|
31
|
+
* own reservation, so a gate can count tickets that have not yet reserved it. Each gate
|
|
32
|
+
* `check({ admitted, opening })` sees its key's live tickets and every ticket not yet opened, and
|
|
33
|
+
* returns true to admit, false to keep waiting, or throws to refuse an entry its route can no
|
|
34
|
+
* longer run (that error is the entry's failure).
|
|
35
|
+
*
|
|
36
|
+
* Bounds fail explicitly: a full queue (overall or for one authenticated requester) with
|
|
37
|
+
* CAPACITY_QUEUE_FULL; a wait reaching the policy limit, or the attempt's own deadline (its
|
|
38
|
+
* disclosure window) first, with CAPACITY_QUEUE_TIMEOUT and `bound` 'policy' or 'authorization'.
|
|
39
|
+
* Cancellation removes the entry with the signal's reason; nothing was held, so nothing settles.
|
|
40
|
+
*/
|
|
41
|
+
export function createPartitionAttemptQueue({ policy, now = Date.now }) {
|
|
42
|
+
const bounds = validateAttemptQueuePolicy(policy);
|
|
43
|
+
assert(typeof now === 'function', 'Queue clock required');
|
|
44
|
+
const waiting = [], tickets = new Set();
|
|
45
|
+
let opening = 0;
|
|
46
|
+
const admittedFor = key => [...tickets].filter(ticket => ticket.key === key).length;
|
|
47
|
+
const ask = entry => entry.check({ admitted: admittedFor(entry.key), opening });
|
|
48
|
+
function grant(key, queuedAt) {
|
|
49
|
+
const record = { key, opened: false };
|
|
50
|
+
tickets.add(record); opening++;
|
|
51
|
+
const queuedMs = queuedAt === null ? 0 : Math.max(0, now() - queuedAt);
|
|
52
|
+
return Object.freeze({ queued: queuedAt !== null, queuedMs,
|
|
53
|
+
opened() { if (!record.opened && tickets.has(record)) { record.opened = true; opening--; } },
|
|
54
|
+
release() {
|
|
55
|
+
if (!tickets.delete(record)) return;
|
|
56
|
+
if (!record.opened) { record.opened = true; opening--; }
|
|
57
|
+
pump();
|
|
58
|
+
} });
|
|
59
|
+
}
|
|
60
|
+
function settle(entry, error) {
|
|
61
|
+
const index = waiting.indexOf(entry);
|
|
62
|
+
if (index < 0) return;
|
|
63
|
+
waiting.splice(index, 1);
|
|
64
|
+
clearTimeout(entry.timer); entry.signal?.removeEventListener('abort', entry.onAbort);
|
|
65
|
+
if (error) entry.reject(error); else entry.resolve(grant(entry.key, entry.queuedAt));
|
|
66
|
+
}
|
|
67
|
+
function pump() {
|
|
68
|
+
for (const entry of [...waiting]) {
|
|
69
|
+
if (!waiting.includes(entry)) continue;
|
|
70
|
+
let admit;
|
|
71
|
+
try { admit = ask(entry) === true; } catch (error) { settle(entry, error); continue; }
|
|
72
|
+
if (admit) settle(entry, null);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return Object.freeze({
|
|
76
|
+
policy: bounds,
|
|
77
|
+
// Async so every refusal, including an already-aborted signal, is a rejection; the decision and
|
|
78
|
+
// any enqueueing still happen synchronously, in call order.
|
|
79
|
+
async admit({ key, attemptId, requesterId, deadlineAt = Infinity, signal, check, onQueued = () => {} }) {
|
|
80
|
+
assert(key !== undefined && key !== null && typeof attemptId === 'string' && attemptId.length > 0
|
|
81
|
+
&& typeof requesterId === 'string' && requesterId.length > 0 && typeof check === 'function'
|
|
82
|
+
&& typeof onQueued === 'function' && (deadlineAt === Infinity || Number.isFinite(deadlineAt)),
|
|
83
|
+
'Queued attempt key, identity, authenticated requester and admission check required');
|
|
84
|
+
signal?.throwIfAborted();
|
|
85
|
+
assert(!waiting.some(entry => entry.attemptId === attemptId), 'Attempt is already waiting for admission');
|
|
86
|
+
// Earlier arrivals take any capacity first; an entry that fits after them is admitted at once.
|
|
87
|
+
pump();
|
|
88
|
+
const entry = { key, attemptId, requesterId, check, signal, queuedAt: null };
|
|
89
|
+
let fits;
|
|
90
|
+
try { fits = ask(entry) === true; } catch (error) { return Promise.reject(error); }
|
|
91
|
+
if (fits) return Promise.resolve(grant(key, null));
|
|
92
|
+
const at = now(), policyAt = at + bounds.maxQueueWaitMs, limit = Math.min(policyAt, deadlineAt);
|
|
93
|
+
const bound = deadlineAt < policyAt ? 'authorization' : 'policy';
|
|
94
|
+
if (limit <= at) return Promise.reject(partitionFailure('CAPACITY_QUEUE_TIMEOUT', { bound }));
|
|
95
|
+
if (waiting.length >= bounds.maxQueuedAttempts
|
|
96
|
+
|| waiting.filter(row => row.requesterId === requesterId).length >= bounds.maxQueuedPerRequester) {
|
|
97
|
+
return Promise.reject(partitionFailure('CAPACITY_QUEUE_FULL'));
|
|
98
|
+
}
|
|
99
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
100
|
+
Object.assign(entry, { resolve, reject, queuedAt: at });
|
|
101
|
+
entry.timer = setTimeout(() => settle(entry, partitionFailure('CAPACITY_QUEUE_TIMEOUT', { bound })), limit - at);
|
|
102
|
+
entry.onAbort = () => settle(entry, signal.reason ?? new Error('Queued attempt cancelled'));
|
|
103
|
+
signal?.addEventListener('abort', entry.onAbort, { once: true });
|
|
104
|
+
waiting.push(entry);
|
|
105
|
+
try { onQueued({ position: waiting.length, queuedAt: at, waitUntil: limit }); } catch {}
|
|
106
|
+
return promise;
|
|
107
|
+
},
|
|
108
|
+
/** Re-evaluate waiting entries after capacity may have changed. */
|
|
109
|
+
pump,
|
|
110
|
+
getState: () => ({ queued: waiting.length, admitted: tickets.size, opening, ...bounds })
|
|
111
|
+
});
|
|
112
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { assertPartition as assert, samePartitionIdentity, canonicalPartitionBinding,
|
|
2
|
+
partitionActivationContract, matchingPartitionActivation } from './partition-contract.js';
|
|
3
|
+
import { verifyPartitionStageCommit } from './partition-stage-commit.js';
|
|
4
|
+
import { PUBLICATION_RECEIPT_SCHEMA } from './partition-ordered-publication.js';
|
|
5
|
+
import { sha256Hex } from '../../artifacts/signatures.js';
|
|
6
|
+
|
|
7
|
+
const SCHEMA = 'reploid.canonical-partition-request/v1';
|
|
8
|
+
const stepKeys = ['schema', 'operation', 'phase', 'identity', 'canonicalAttempt', 'generationId', 'sequence',
|
|
9
|
+
'step', 'tokenPosition', 'inputTokenCount', 'inputTokenIds', 'baseCursorId', 'baseCursor', 'grant', 'continuation'];
|
|
10
|
+
const exact = (value, keys) => assert(value && typeof value === 'object' && !Array.isArray(value)
|
|
11
|
+
&& Object.keys(value).length === keys.length && keys.every(key => Object.hasOwn(value, key)), 'Invalid canonical wire fields');
|
|
12
|
+
|
|
13
|
+
/** Wire admission only. Doppler owns the declared tensor/cursor/publication contracts. */
|
|
14
|
+
export function createCanonicalPartitionContract({ runtime, plan, planId, modelIdentity }) {
|
|
15
|
+
for (const name of ['metadataDigest', 'tokenDigest', 'residentAttemptDigest', 'validateResidentAttemptIdentity',
|
|
16
|
+
'validateResidentCursor', 'validateOrdinaryActivation', 'validateExecutionPublication', 'validateAdmissionPublication',
|
|
17
|
+
'serializeActivationFrame', 'validateActivationFrameForPlan']) assert(typeof runtime?.[name] === 'function', `Canonical partition capability required: ${name}`);
|
|
18
|
+
plan = structuredClone(plan);
|
|
19
|
+
const layout = partitionActivationContract(runtime, plan);
|
|
20
|
+
const hash = (schema, value) => runtime.metadataDigest(schema, value);
|
|
21
|
+
const equal = (a, b) => hash('reploid.canonical-wire-value/v1', a) === hash('reploid.canonical-wire-value/v1', b);
|
|
22
|
+
const binding = request => {
|
|
23
|
+
assert(equal(request.identity, canonicalPartitionBinding(request.identity)), 'Unknown canonical identity fields');
|
|
24
|
+
assert(request.schema === SCHEMA && request.identity.modelId === plan.modelId && request.identity.modelIdentity === modelIdentity
|
|
25
|
+
&& request.identity.planId === planId, 'Canonical wire model/plan mismatch');
|
|
26
|
+
const attempt = runtime.validateResidentAttemptIdentity(request.canonicalAttempt);
|
|
27
|
+
assert(attempt.routeKind === 'two-stage-layer' && attempt.attemptId === request.identity.attemptId
|
|
28
|
+
&& attempt.requesterId === request.identity.requesterId && attempt.generationId === request.generationId
|
|
29
|
+
&& attempt.stages[0].participantId === request.identity.participantA && attempt.stages[1].participantId === request.identity.participantB,
|
|
30
|
+
'Canonical wire attempt mismatch');
|
|
31
|
+
assert(equal(attempt, request.grant.claim.canonicalAttempt) && request.grant.claim.vocabSize === plan.vocabSize
|
|
32
|
+
&& request.grant.claim.generation.generationId === attempt.generationId, 'Canonical wire grant binding mismatch');
|
|
33
|
+
assert(Number.isSafeInteger(request.sequence) && request.sequence >= 0 && request.step === request.sequence,
|
|
34
|
+
'Canonical wire sequence mismatch');
|
|
35
|
+
return attempt;
|
|
36
|
+
};
|
|
37
|
+
const activationHeader = (request, byteLength, payloadDigest) => {
|
|
38
|
+
const attempt = binding(request);
|
|
39
|
+
assert(Number.isSafeInteger(request.tokenPosition) && request.tokenPosition >= 0
|
|
40
|
+
&& Number.isSafeInteger(request.inputTokenCount) && request.inputTokenCount > 0
|
|
41
|
+
&& Array.isArray(request.inputTokenIds) && request.inputTokenIds.length === request.inputTokenCount,
|
|
42
|
+
'Canonical token row mismatch');
|
|
43
|
+
const inputDigest = runtime.tokenDigest(request.inputTokenIds, plan.vocabSize, request.grant.claim.limits.maxPromptTokens);
|
|
44
|
+
let tokenContextDigest = inputDigest;
|
|
45
|
+
if (request.sequence === 0) assert(request.baseCursor === null && request.baseCursorId === null && request.tokenPosition === 0 && attempt.inputDigest === inputDigest,
|
|
46
|
+
'Canonical bootstrap parent mismatch');
|
|
47
|
+
else {
|
|
48
|
+
const cursor = runtime.validateResidentCursor(request.baseCursor, request.grant.claim.generation.policy, plan.vocabSize);
|
|
49
|
+
assert(cursor.cursorId === request.baseCursorId && cursor.generationId === attempt.generationId && !cursor.terminal
|
|
50
|
+
&& cursor.revision + 1 === request.sequence && cursor.materializedTokenCount === request.tokenPosition
|
|
51
|
+
&& request.inputTokenCount === 1 && request.inputTokenIds[0] === cursor.pendingTokenId, 'Canonical decode parent mismatch');
|
|
52
|
+
tokenContextDigest = cursor.acceptedTokenDigest;
|
|
53
|
+
}
|
|
54
|
+
const expectedBytes = request.inputTokenCount * plan.hiddenSize * layout.elementStrideBytes;
|
|
55
|
+
assert(Number.isSafeInteger(expectedBytes) && byteLength === expectedBytes
|
|
56
|
+
&& byteLength <= request.grant.claim.limits.maxActivationBytes && /^sha256:[a-f0-9]{64}$/.test(payloadDigest),
|
|
57
|
+
'Canonical activation byte bound mismatch');
|
|
58
|
+
return { schema: 'doppler.ordinary-activation/v1', attemptDigest: runtime.residentAttemptDigest(attempt),
|
|
59
|
+
sequence: request.sequence, baseCursorId: request.baseCursorId, proposalId: null,
|
|
60
|
+
sourceStageId: attempt.stages[0].stageId, destinationStageId: attempt.stages[1].stageId,
|
|
61
|
+
rows: { start: request.tokenPosition, end: request.tokenPosition + request.inputTokenCount }, tokenContextDigest,
|
|
62
|
+
layout: { dtype: layout.dtype, precision: layout.precision, components: layout.components,
|
|
63
|
+
elementStrideBytes: layout.elementStrideBytes, hiddenSize: plan.hiddenSize, byteOrder: 'little-endian' },
|
|
64
|
+
payloadBytes: byteLength, payloadDigest };
|
|
65
|
+
};
|
|
66
|
+
const validateHeader = (request, byteLength) => {
|
|
67
|
+
try {
|
|
68
|
+
hash(SCHEMA, request); exact(request, [...stepKeys, 'frame']);
|
|
69
|
+
const frame = request.frame;
|
|
70
|
+
exact(frame.metadata, ['identity', 'activation']);
|
|
71
|
+
assert(samePartitionIdentity(frame.metadata.identity, request.identity)
|
|
72
|
+
&& equal(frame.metadata.identity, canonicalPartitionBinding(request.identity)), 'Canonical frame identity mismatch');
|
|
73
|
+
assert(request.phase === 'step' && request.operation === 'step' && frame.schema === layout.schema
|
|
74
|
+
&& matchingPartitionActivation(frame, layout, true) && frame.step === request.step && frame.seqOffset === request.tokenPosition
|
|
75
|
+
&& equal(frame.shape, [1, request.inputTokenCount, plan.hiddenSize]) && frame.byteLength === byteLength,
|
|
76
|
+
'Canonical tensor header mismatch');
|
|
77
|
+
return equal(frame.metadata.activation, activationHeader(request, byteLength, frame.metadata.activation.payloadDigest));
|
|
78
|
+
} catch { return false; }
|
|
79
|
+
};
|
|
80
|
+
return Object.freeze({
|
|
81
|
+
schema: SCHEMA, validateBinding: binding, validateHeader,
|
|
82
|
+
validateControl(request) {
|
|
83
|
+
try {
|
|
84
|
+
hash(SCHEMA, request); const attempt = binding(request);
|
|
85
|
+
if (request.operation === 'settle') {
|
|
86
|
+
exact(request, ['schema', 'operation', 'identity', 'canonicalAttempt', 'generationId', 'sequence', 'step', 'grant']);
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
if (request.operation === 'published') {
|
|
90
|
+
exact(request, [...stepKeys, 'publication', 'receipt', 'commits']);
|
|
91
|
+
return request.phase === 'published';
|
|
92
|
+
}
|
|
93
|
+
exact(request, stepKeys);
|
|
94
|
+
return ['reserve', 'admit'].includes(request.operation) && request.phase === 'admit'
|
|
95
|
+
&& request.sequence === 0 && request.tokenPosition === 0 && request.baseCursor === null && request.baseCursorId === null
|
|
96
|
+
&& request.inputTokenIds?.length === request.inputTokenCount
|
|
97
|
+
&& runtime.tokenDigest(request.inputTokenIds, plan.vocabSize, request.grant.claim.limits.maxPromptTokens) === attempt.inputDigest;
|
|
98
|
+
} catch { return false; }
|
|
99
|
+
},
|
|
100
|
+
async fingerprint(request) {
|
|
101
|
+
const { payload = new Uint8Array(), ...metadata } = structuredClone(request);
|
|
102
|
+
assert(payload instanceof Uint8Array, 'Canonical payload bytes required');
|
|
103
|
+
return hash('reploid.canonical-partition-request-digest/v1', { metadata,
|
|
104
|
+
payloadBytes: payload.byteLength, payloadDigest: await sha256Hex(payload) });
|
|
105
|
+
},
|
|
106
|
+
async serializeActivation(request) {
|
|
107
|
+
const { activationTensor: source, ...metadata } = request;
|
|
108
|
+
hash(SCHEMA, metadata);
|
|
109
|
+
assert(source?.data?.byteLength <= request.grant.claim.limits.maxActivationBytes, 'Canonical activation exceeds grant');
|
|
110
|
+
const { activationTensor, ...control } = structuredClone(request);
|
|
111
|
+
request = control;
|
|
112
|
+
assert(activationTensor?.data?.byteLength <= request.grant.claim.limits.maxActivationBytes, 'Canonical activation exceeds grant');
|
|
113
|
+
const frame = { ...runtime.serializeActivationFrame({ ...activationTensor, metadata: {} }) };
|
|
114
|
+
const payload = new Uint8Array(frame.buffer);
|
|
115
|
+
frame.metadata = { identity: canonicalPartitionBinding(request.identity),
|
|
116
|
+
activation: activationHeader(request, payload.byteLength, await sha256Hex(payload)) };
|
|
117
|
+
const { buffer, ...header } = frame;
|
|
118
|
+
assert(validateHeader({ ...request, frame: header }, payload.byteLength), 'Canonical serialized header mismatch');
|
|
119
|
+
runtime.validateOrdinaryActivation(frame.metadata.activation, payload,
|
|
120
|
+
{ maxRows: request.grant.claim.limits.maxPromptTokens, maxBytes: request.grant.claim.limits.maxActivationBytes });
|
|
121
|
+
runtime.validateActivationFrameForPlan(frame, plan);
|
|
122
|
+
return frame;
|
|
123
|
+
},
|
|
124
|
+
validatePayload(request, payload) {
|
|
125
|
+
const { payload: _receivedBytes, ...metadata } = request;
|
|
126
|
+
request = metadata;
|
|
127
|
+
assert(validateHeader(request, payload.byteLength), 'Canonical activation header rejected');
|
|
128
|
+
const validated = runtime.validateOrdinaryActivation(request.frame.metadata.activation, payload,
|
|
129
|
+
{ maxRows: request.grant.claim.limits.maxPromptTokens, maxBytes: request.grant.claim.limits.maxActivationBytes });
|
|
130
|
+
return runtime.validateActivationFrameForPlan({ ...request.frame, buffer: validated.bytes.buffer }, plan);
|
|
131
|
+
},
|
|
132
|
+
async verifyPublication(request, retained) {
|
|
133
|
+
try {
|
|
134
|
+
hash('reploid.canonical-publication-ack/v1', { request, retained });
|
|
135
|
+
request = structuredClone(request); retained = structuredClone(retained);
|
|
136
|
+
exact(request, [...stepKeys, 'publication', 'receipt', 'commits']);
|
|
137
|
+
assert(request.operation === 'published' && request.phase === 'published', 'Publication phase mismatch');
|
|
138
|
+
const attempt = binding(request), { publication, receipt, commits } = request;
|
|
139
|
+
assert(publication.sequence === request.sequence, 'Publication acknowledgment sequence mismatch');
|
|
140
|
+
if (publication.schema === 'doppler.admission-publication/v1') {
|
|
141
|
+
runtime.validateAdmissionPublication(publication, attempt, request.grant.claim.generation.policy, plan.vocabSize);
|
|
142
|
+
assert(equal(publication.result, retained) && Array.isArray(commits) && commits.length === 0, 'Admission publication mismatch');
|
|
143
|
+
} else {
|
|
144
|
+
runtime.validateExecutionPublication(publication, attempt, request.grant.claim.generation.policy, plan.vocabSize, request.baseCursor);
|
|
145
|
+
assert(Array.isArray(commits) && commits.length === attempt.stages.length, 'Publication evidence cardinality mismatch');
|
|
146
|
+
assert(new Set(commits.map(commit => commit.acknowledgment.stageId)).size === commits.length, 'Duplicate publication evidence');
|
|
147
|
+
for (const stage of attempt.stages) {
|
|
148
|
+
const commit = commits.find(item => item.acknowledgment.stageId === stage.stageId);
|
|
149
|
+
const acknowledgment = publication.acknowledgments.find(item => item.stageId === stage.stageId);
|
|
150
|
+
assert(commit && equal(commit.acknowledgment, acknowledgment)
|
|
151
|
+
&& await verifyPartitionStageCommit({ runtime, attempt, stage, ...commit,
|
|
152
|
+
transition: retained.transition, sequence: request.sequence, baseCursorId: request.baseCursorId }),
|
|
153
|
+
'Publication stage evidence mismatch');
|
|
154
|
+
}
|
|
155
|
+
assert(equal(retained.commit, commits.find(item => item.acknowledgment.stageId === attempt.stages[1].stageId)), 'Publication differs from retained output-stage result');
|
|
156
|
+
}
|
|
157
|
+
exact(receipt, ['schema', 'conversationId', 'writerEpoch', 'index', 'coordinatorEpoch', 'attemptId', 'sequence', 'publicationDigest', 'receiptDigest']);
|
|
158
|
+
const { receiptDigest, ...body } = receipt;
|
|
159
|
+
return body.schema === PUBLICATION_RECEIPT_SCHEMA && body.conversationId === request.identity.threadId
|
|
160
|
+
&& body.writerEpoch === attempt.publisherEpoch && body.coordinatorEpoch === attempt.coordinatorEpoch
|
|
161
|
+
&& body.attemptId === attempt.attemptId && body.sequence === request.sequence
|
|
162
|
+
&& body.publicationDigest === publication.publicationDigest && Number.isSafeInteger(body.index) && body.index >= 0
|
|
163
|
+
&& receiptDigest === hash(body.schema, body);
|
|
164
|
+
} catch { return false; }
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { createCanonicalPartitionContract } from './partition-canonical-contract.js';
|
|
2
|
+
import { verifyPartitionStageCommit } from './partition-stage-commit.js';
|
|
3
|
+
import { assertPartition as assert } from './partition-contract.js';
|
|
4
|
+
|
|
5
|
+
/** One ordinary canonical attempt, inside the existing runner's allocation,
|
|
6
|
+
* FIFO lease and settlement owner. No scheduler, sampler or recovery loop. */
|
|
7
|
+
export async function executeCanonicalPartition({ runtime, plan, deviceA, deviceB, policy, binding, authority,
|
|
8
|
+
canonical, tokenIds, signal, lease, permit, onDelta, receipt, ownDevice }) {
|
|
9
|
+
assert(runtime.hashLayerPartitionPlan(plan) === binding.planId, 'Canonical selected plan identity mismatch');
|
|
10
|
+
const publicationOwner = canonical.publication;
|
|
11
|
+
assert(publicationOwner?.requiresCommitEvidence === true
|
|
12
|
+
&& ['admitAttempt', 'publish', 'reconcile', 'cancel'].every(name => typeof publicationOwner[name] === 'function'),
|
|
13
|
+
'Canonical execution requires durable authenticated publication');
|
|
14
|
+
const hash = (domain, value) => runtime.metadataDigest(domain, value);
|
|
15
|
+
const same = (a, b) => hash('reploid.canonical-execution-value/v1', a) === hash('reploid.canonical-execution-value/v1', b);
|
|
16
|
+
hash('reploid.canonical-execution-input/v1', { attempt: canonical.attempt, generation: canonical.generation,
|
|
17
|
+
deadlineAt: canonical.deadlineAt });
|
|
18
|
+
const { attempt: selected, generation: supplied, deadlineAt } = structuredClone({ attempt: canonical.attempt,
|
|
19
|
+
generation: canonical.generation, deadlineAt: canonical.deadlineAt });
|
|
20
|
+
const attempt = runtime.validateResidentAttemptIdentity(selected);
|
|
21
|
+
const generation = runtime.canonicalGenerationIdentity(supplied.policy, supplied.executionIdentity, plan.vocabSize);
|
|
22
|
+
assert(same(generation, supplied) && attempt.generationId === generation.generationId
|
|
23
|
+
&& attempt.attemptId === binding.attemptId && attempt.requesterId === binding.requesterId
|
|
24
|
+
&& attempt.routeKind === 'two-stage-layer' && attempt.stages.length === 2
|
|
25
|
+
&& attempt.inputDigest === runtime.tokenDigest(tokenIds, plan.vocabSize, policy.maxPromptTokens),
|
|
26
|
+
'Canonical attempt or effective prompt mismatch');
|
|
27
|
+
assert(generation.policy.maxGeneratedTokens <= policy.maxTokens
|
|
28
|
+
&& generation.policy.maxVisibleOutputUtf16 <= policy.maxOutputCharacters
|
|
29
|
+
&& Number.isSafeInteger(deadlineAt) && deadlineAt > Date.now(), 'Canonical allocation or deadline mismatch');
|
|
30
|
+
for (const [index, device] of [deviceA, deviceB].entries()) {
|
|
31
|
+
assert(same(device.getCanonicalGeneration(), generation) && same(device.getCanonicalStage(), attempt.stages[index])
|
|
32
|
+
&& device.id === attempt.stages[index].participantId, 'Canonical resident generation or stage changed');
|
|
33
|
+
}
|
|
34
|
+
const contract = createCanonicalPartitionContract({ runtime, plan, planId: binding.planId, modelIdentity: binding.modelIdentity });
|
|
35
|
+
const expectedAdmission = runtime.admitResidentPrompt(tokenIds, generation.policy, plan.vocabSize, generation.generationId);
|
|
36
|
+
let cursor = null, previous = null, continuationA = null, continuationB = null, admitted = false, cancellation = null;
|
|
37
|
+
let content = '', activationBytes = 0, input = [...tokenIds], position = 0, stopReason = null;
|
|
38
|
+
const tokens = [], steps = [], publications = [];
|
|
39
|
+
const cancel = () => {
|
|
40
|
+
if (!cancellation && admitted) cancellation = publicationOwner.cancel(attempt.attemptId, attempt.coordinatorEpoch)
|
|
41
|
+
.then(() => null, error => error);
|
|
42
|
+
return cancellation;
|
|
43
|
+
};
|
|
44
|
+
const wire = (sequence, phase = 'step') => ({ schema: contract.schema, operation: phase === 'admit' ? 'admit' : 'step', phase,
|
|
45
|
+
identity: binding, canonicalAttempt: attempt, generationId: generation.generationId, sequence, step: sequence,
|
|
46
|
+
tokenPosition: position, inputTokenCount: input.length, inputTokenIds: [...input], baseCursorId: cursor?.cursorId ?? null,
|
|
47
|
+
baseCursor: cursor, grant: authority.executionB, continuation: continuationB });
|
|
48
|
+
const authorize = async request => {
|
|
49
|
+
for (const [action, name] of [['mesh.execute_partition_a', 'executionA'], ['mesh.execute_partition_b', 'executionB'],
|
|
50
|
+
['mesh.transfer_intermediate_activation', 'activation'], ['mesh.transfer_token_context', 'tokenContext'],
|
|
51
|
+
['mesh.transfer_partition_output', 'output']]) {
|
|
52
|
+
await permit(action, authority[name], { step: request.step, sequence: request.sequence, phase: request.phase,
|
|
53
|
+
tokenPosition: request.tokenPosition, inputTokenCount: request.inputTokenCount,
|
|
54
|
+
maxTokens: generation.policy.maxGeneratedTokens, canonicalAttempt: attempt, generationId: generation.generationId });
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const publish = async (request, body, commits) => {
|
|
58
|
+
const publication = { ...body, publicationDigest: hash(body.schema, body) };
|
|
59
|
+
await authorize(request);
|
|
60
|
+
const saved = await publicationOwner.publish(publication, { evidence: commits.map(c => c.evidence) });
|
|
61
|
+
publications.push({ publication, receipt: saved, commits });
|
|
62
|
+
// A transaction receipt is not an ephemeral peer acknowledgment. No next
|
|
63
|
+
// step or UI delivery occurs until the retained B result accepts this one.
|
|
64
|
+
await deviceB.acknowledgeCanonicalPublication({ ...request, publication, receipt: saved, commits, signal });
|
|
65
|
+
previous = publication.publicationDigest;
|
|
66
|
+
return saved;
|
|
67
|
+
};
|
|
68
|
+
try {
|
|
69
|
+
signal.throwIfAborted();
|
|
70
|
+
const request = wire(0, 'admit');
|
|
71
|
+
contract.validateBinding(request);
|
|
72
|
+
await authorize(request);
|
|
73
|
+
const state = await publicationOwner.reconcile(); previous = state.head;
|
|
74
|
+
assert(Array.isArray(state.attempts) && !state.attempts.some(item => item.identity.attemptId === attempt.attemptId
|
|
75
|
+
&& item.identity.coordinatorEpoch === attempt.coordinatorEpoch), 'Canonical attempt was already admitted; retries require a fresh identity');
|
|
76
|
+
await publicationOwner.admitAttempt({ identity: attempt, generationPolicy: generation.policy,
|
|
77
|
+
executionIdentity: generation.executionIdentity, vocabSize: plan.vocabSize, deadlineAt });
|
|
78
|
+
admitted = true; signal.addEventListener('abort', cancel, { once: true }); signal.throwIfAborted();
|
|
79
|
+
await authorize(request);
|
|
80
|
+
ownDevice(deviceA.id);
|
|
81
|
+
receipt.reservations.push(structuredClone(await deviceA.reserve(binding)));
|
|
82
|
+
ownDevice(deviceB.id);
|
|
83
|
+
const reserved = await deviceB.reserveCanonical({ ...request, signal });
|
|
84
|
+
receipt.reservations.push(structuredClone(reserved.reservation));
|
|
85
|
+
await lease(async () => {
|
|
86
|
+
await authorize(request);
|
|
87
|
+
const a = await deviceA.admitCanonicalPrompt({ identity: binding, tokenIds: [...tokenIds], generationId: generation.generationId, signal });
|
|
88
|
+
const b = await deviceB.admitCanonicalPrompt({ ...request, signal });
|
|
89
|
+
assert(same(a, expectedAdmission) && same(b, expectedAdmission), 'Canonical participant prompt admission differs');
|
|
90
|
+
});
|
|
91
|
+
if (!('kind' in expectedAdmission)) {
|
|
92
|
+
await publish(request, { schema: 'doppler.admission-publication/v1', attemptId: attempt.attemptId,
|
|
93
|
+
coordinatorEpoch: attempt.coordinatorEpoch, attemptDigest: runtime.residentAttemptDigest(attempt), sequence: 0,
|
|
94
|
+
expectedRevision: null, previousPublicationDigest: previous, result: expectedAdmission }, []);
|
|
95
|
+
stopReason = expectedAdmission.stopReason;
|
|
96
|
+
} else {
|
|
97
|
+
for (let sequence = 0; sequence < generation.policy.maxGeneratedTokens; sequence++) {
|
|
98
|
+
const queuedAt = performance.now();
|
|
99
|
+
const delivery = await lease(async () => {
|
|
100
|
+
const started = performance.now(), request = wire(sequence);
|
|
101
|
+
const leaseWaitMs = started - queuedAt;
|
|
102
|
+
await authorize(request);
|
|
103
|
+
const a = structuredClone(await deviceA.executeCanonicalGroup0({ identity: binding, canonicalAttempt: attempt,
|
|
104
|
+
tokenIds: [...input], continuation: continuationA, generationId: generation.generationId,
|
|
105
|
+
baseCursorId: request.baseCursorId, sequence, step: sequence, tokenPosition: position,
|
|
106
|
+
inputTokenCount: input.length, executionGrant: authority.executionA, signal }));
|
|
107
|
+
signal.throwIfAborted();
|
|
108
|
+
const frame = await contract.serializeActivation({ ...request, activationTensor: a.activationTensor });
|
|
109
|
+
assert(frame.byteLength <= policy.maxActivationBytes, 'Canonical activation exceeds allocation');
|
|
110
|
+
await authorize(request);
|
|
111
|
+
const b = structuredClone(await deviceB.executeCanonicalFrame({ ...request, frame, signal }));
|
|
112
|
+
signal.throwIfAborted();
|
|
113
|
+
assert(b && same(b.identity, binding) && b.step === sequence && b.tokenPosition === position
|
|
114
|
+
&& await verifyPartitionStageCommit({ runtime, attempt, stage: attempt.stages[1], ...b.commit,
|
|
115
|
+
transition: b.transition, sequence, baseCursorId: request.baseCursorId }), 'Unauthenticated canonical output decision');
|
|
116
|
+
await authorize(request);
|
|
117
|
+
const committed = structuredClone(await deviceA.commitCanonicalTransition({ identity: binding, canonicalAttempt: attempt,
|
|
118
|
+
generationId: generation.generationId, sequence, baseCursorId: request.baseCursorId,
|
|
119
|
+
transition: b.transition, targetCommit: b.commit, signal }));
|
|
120
|
+
assert(same(committed.transition, b.transition) && await verifyPartitionStageCommit({ runtime, attempt,
|
|
121
|
+
stage: attempt.stages[0], ...committed.commit, transition: b.transition, sequence, baseCursorId: request.baseCursorId }),
|
|
122
|
+
'Canonical input stage did not commit the authenticated decision');
|
|
123
|
+
const transition = committed.transition;
|
|
124
|
+
assert(transition.acceptedTokenIds.length === 1 && typeof transition.delta === 'string'
|
|
125
|
+
&& content.length + transition.delta.length <= policy.maxOutputCharacters, 'Canonical ordinary result exceeds allocation');
|
|
126
|
+
const body = { schema: 'doppler.execution-publication/v2', attemptId: attempt.attemptId,
|
|
127
|
+
coordinatorEpoch: attempt.coordinatorEpoch, attemptDigest: runtime.residentAttemptDigest(attempt), sequence,
|
|
128
|
+
expectedRevision: cursor?.revision ?? null, previousPublicationDigest: previous, baseCursorId: request.baseCursorId,
|
|
129
|
+
decisionId: committed.commit.acknowledgment.decisionId, acceptedTokenIds: transition.acceptedTokenIds,
|
|
130
|
+
tokenRange: transition.tokenRange, successor: transition.successor,
|
|
131
|
+
delta: { text: transition.delta, outputDigest: transition.outputDigest }, stoppingOutcome: transition.successor.stopReason,
|
|
132
|
+
acknowledgments: [committed.commit.acknowledgment, b.commit.acknowledgment] };
|
|
133
|
+
const value = { ...body, publicationDigest: hash(body.schema, body) };
|
|
134
|
+
runtime.validateExecutionPublication(value, attempt, generation.policy, plan.vocabSize, cursor);
|
|
135
|
+
return { request, body, commits: [committed.commit, b.commit], transition,
|
|
136
|
+
continuationA: a.continuation, continuationB: b.continuation, bytes: frame.byteLength,
|
|
137
|
+
leaseWaitMs, elapsedMs: performance.now() - started };
|
|
138
|
+
});
|
|
139
|
+
// Durable storage and remote acknowledgment retain this attempt's parent
|
|
140
|
+
// barrier, but must not hold another conversation's numerical lease.
|
|
141
|
+
await publish(delivery.request, delivery.body, delivery.commits);
|
|
142
|
+
cursor = delivery.transition.successor;
|
|
143
|
+
continuationA = delivery.continuationA; continuationB = delivery.continuationB;
|
|
144
|
+
tokens.push(...delivery.transition.acceptedTokenIds); content += delivery.transition.delta;
|
|
145
|
+
activationBytes += delivery.bytes;
|
|
146
|
+
steps.push({ sequence, step: sequence, tokenPosition: position, inputTokenCount: input.length,
|
|
147
|
+
tokenId: delivery.transition.acceptedTokenIds[0], activationBytes: delivery.bytes, leaseWaitMs: delivery.leaseWaitMs,
|
|
148
|
+
elapsedMs: delivery.elapsedMs, outputDeliveryMs: 0 });
|
|
149
|
+
position = cursor.materializedTokenCount; input = [cursor.pendingTokenId]; stopReason = cursor.stopReason;
|
|
150
|
+
signal.throwIfAborted();
|
|
151
|
+
if (delivery.transition.delta) {
|
|
152
|
+
const started = performance.now();
|
|
153
|
+
try { await onDelta(delivery.transition.delta); } finally { steps.at(-1).outputDeliveryMs = performance.now() - started; }
|
|
154
|
+
}
|
|
155
|
+
signal.throwIfAborted();
|
|
156
|
+
if (cursor.terminal) break;
|
|
157
|
+
}
|
|
158
|
+
assert(cursor?.terminal, 'Canonical generation did not reach its declared stopping outcome');
|
|
159
|
+
}
|
|
160
|
+
return { content, tokenIds: tokens, logits: null, stopReason,
|
|
161
|
+
execution: { schema: 'reploid.mesh.canonical-partition-execution/v1', ...binding, canonicalAttempt: attempt,
|
|
162
|
+
placement: 'two-device-layer-partition', splitLayer: plan.splitLayer, activationBytes, steps, publications, settlement: receipt } };
|
|
163
|
+
} catch (error) {
|
|
164
|
+
const cancellationError = await cancel();
|
|
165
|
+
if (cancellationError) throw new AggregateError([error, cancellationError], 'Canonical execution and publication settlement failed');
|
|
166
|
+
throw error;
|
|
167
|
+
} finally { signal.removeEventListener('abort', cancel); }
|
|
168
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { assertPartition as assert, canonicalPartitionJson } from './partition-contract.js';
|
|
2
|
+
import { validateEntryPublicationContext } from './partition-entry-publication.js';
|
|
3
|
+
|
|
4
|
+
/** Fixed two-stage chat composition. Actual residents supply generation/stages;
|
|
5
|
+
* Doppler and the existing grant owner supply attempt and disclosure identities. */
|
|
6
|
+
export function createCanonicalChatBinding({ runtime, local, remote, authority, model, plan, planId, limits, coordinatorEpoch }) {
|
|
7
|
+
assert(/^[a-f0-9]{32}$/.test(coordinatorEpoch) && ['metadataDigest', 'canonicalGenerationIdentity',
|
|
8
|
+
'validateResidentAttemptIdentity', 'tokenDigest', 'hashLayerPartitionPlan'].every(name => typeof runtime[name] === 'function')
|
|
9
|
+
&& ['canonicalScope', 'issueCanonical'].every(name => typeof authority[name] === 'function')
|
|
10
|
+
&& [local, remote].every(device => ['getCanonicalStage', 'getCanonicalGeneration'].every(name => typeof device[name] === 'function')),
|
|
11
|
+
'Canonical chat requires declared runtime, grant and resident capabilities');
|
|
12
|
+
assert(runtime.hashLayerPartitionPlan(plan) === planId, 'Canonical chat plan mismatch');
|
|
13
|
+
const same = (a, b) => canonicalPartitionJson(a) === canonicalPartitionJson(b);
|
|
14
|
+
const grantLimits = Object.fromEntries(['maxTokens', 'maxPromptTokens', 'maxActivationBytes', 'maxOutputCharacters']
|
|
15
|
+
.map(key => [key, limits[key]]));
|
|
16
|
+
const describe = () => {
|
|
17
|
+
const supplied = local.getCanonicalGeneration(), target = remote.getCanonicalGeneration();
|
|
18
|
+
const stages = [local.getCanonicalStage(), remote.getCanonicalStage()];
|
|
19
|
+
if (!supplied || !target || stages.some(stage => !stage)) return null;
|
|
20
|
+
const generation = runtime.canonicalGenerationIdentity(supplied.policy, supplied.executionIdentity, plan.vocabSize);
|
|
21
|
+
assert(same(generation, supplied) && same(generation, target), 'Canonical stages use different generation contracts');
|
|
22
|
+
assert(generation.policy.maxGeneratedTokens <= limits.maxTokens
|
|
23
|
+
&& generation.policy.maxVisibleOutputUtf16 <= limits.maxOutputCharacters, 'Canonical generation exceeds chat allocation');
|
|
24
|
+
const routeId = runtime.metadataDigest('reploid.canonical-chat-route/v1', { meshId: authority.meshId,
|
|
25
|
+
modelId: model.id, modelIdentity: model.identity, planId, coordinatorEpoch, stages, generationId: generation.generationId });
|
|
26
|
+
return { coordinatorEpoch, routeId, stages, generation, vocabSize: plan.vocabSize };
|
|
27
|
+
};
|
|
28
|
+
const check = (context, binding, publication) => {
|
|
29
|
+
validateEntryPublicationContext(context, binding);
|
|
30
|
+
const current = describe();
|
|
31
|
+
assert(current && Object.keys(current).every(key => same(current[key], context[key])), 'Canonical chat placement or generation changed');
|
|
32
|
+
assert(context.deadlineAt > Date.now() && publication?.requiresCommitEvidence === true
|
|
33
|
+
&& ['reconcile', 'admitAttempt', 'publish', 'cancel'].every(name => typeof publication[name] === 'function'),
|
|
34
|
+
'Canonical requester publication or deadline unavailable');
|
|
35
|
+
return structuredClone(context);
|
|
36
|
+
};
|
|
37
|
+
return Object.freeze({ describe, check,
|
|
38
|
+
attempt({ context, binding, publication, tokenIds }) {
|
|
39
|
+
context = check(context, binding, publication);
|
|
40
|
+
return runtime.validateResidentAttemptIdentity({ schema: 'doppler.resident-attempt/v2', attemptId: binding.attemptId,
|
|
41
|
+
requesterId: binding.requesterId, inputDigest: runtime.tokenDigest(tokenIds, plan.vocabSize, limits.maxPromptTokens),
|
|
42
|
+
authorizationScope: authority.canonicalScope({ identity: binding, limits: grantLimits,
|
|
43
|
+
disclosure: 'partition-activations-and-tokens', generationId: context.generation.generationId }),
|
|
44
|
+
routeId: context.routeId, generationId: context.generation.generationId, coordinatorEpoch, publisherEpoch: context.publisherEpoch,
|
|
45
|
+
routeKind: 'two-stage-layer', stages: context.stages });
|
|
46
|
+
},
|
|
47
|
+
grantLimits: Object.freeze(grantLimits),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { partitionAdapterIdentities, samePartitionAdapters } from './partition-contract.js';
|
|
2
|
+
import { TEXT_GENERATION_CAPABILITY, requireGenerationCapability, boundedGeneration, tokenUsage } from './partition-generation-request.js';
|
|
3
|
+
import { createOrderedPartitionChat } from './partition-ordered-chat.js';
|
|
4
|
+
import { createCanonicalChatBinding } from './partition-chat-canonical.js';
|
|
5
|
+
import { createLayerPartitionRunner } from './partition-runner.js';
|
|
6
|
+
import { assertPartition as assert, canonicalPartitionJson, canonicalPartitionBinding, partitionFingerprint } from './partition-contract.js';
|
|
7
|
+
|
|
8
|
+
/** Conversation adapter for a fixed, explicitly prepared local A and authenticated remote B. */
|
|
9
|
+
export function createPartitionChat({ runtime, local, remote, authority, model, plan, planId, limits, grantTtlMs, canonical = null, ordered = null, authorizeRequester = null, now = Date.now }) {
|
|
10
|
+
if (ordered !== null) {
|
|
11
|
+
assert(canonical === null, 'Ordered chat does not enable canonical decoding; it publishes through the requester-owned writer');
|
|
12
|
+
return createOrderedPartitionChat({ runtime, authority, model, plan, planId, limits, grantTtlMs, ordered, authorizeRequester, now });
|
|
13
|
+
}
|
|
14
|
+
assert(local.index === 0 && local.id === authority.participantId && remote.id !== local.id,
|
|
15
|
+
'Partition chat requires the input owner at A and a distinct authenticated B');
|
|
16
|
+
assert(Number.isSafeInteger(grantTtlMs) && grantTtlMs > 0, 'Explicit partition grant lifetime required');
|
|
17
|
+
// Requesters select a prepared route; opening artifacts and execution policy
|
|
18
|
+
// remain with its contributor. Signed Capsule evidence can exceed the control
|
|
19
|
+
// frame budget and must not be copied into capability advertisements/history.
|
|
20
|
+
assert(canonicalPartitionJson(plan.adapterIdentities || []) === canonicalPartitionJson(partitionAdapterIdentities(model)), 'Partition plan adapter binding mismatch');
|
|
21
|
+
const selection = { id: model.id, name: model.name, identity: model.identity,
|
|
22
|
+
adapters: structuredClone(model.adapters || []), selectionId: model.id + '/partition/' + planId,
|
|
23
|
+
partition: { planId, participantA: local.id, participantB: remote.id } };
|
|
24
|
+
for (const key of ['provider', 'contextLength', 'quantization', 'size', 'recommended']) {
|
|
25
|
+
if (model[key] !== undefined) selection[key] = structuredClone(model[key]);
|
|
26
|
+
}
|
|
27
|
+
const policy = structuredClone(limits);
|
|
28
|
+
const canonicalBinding = canonical === null ? null : createCanonicalChatBinding({ runtime, local, remote, authority,
|
|
29
|
+
model, plan, planId, limits: policy, coordinatorEpoch: canonical.coordinatorEpoch });
|
|
30
|
+
const listeners = new Set();
|
|
31
|
+
let closed = false;
|
|
32
|
+
const models = () => {
|
|
33
|
+
const description = canonicalBinding?.describe() ?? null;
|
|
34
|
+
return [{ ...structuredClone(selection), ...(canonicalBinding ? {} : {textGeneration: TEXT_GENERATION_CAPABILITY}), ...(description ? { canonical: description } : {}),
|
|
35
|
+
availability: closed || canonicalBinding && !description ? 'unavailable' : local.getState().ready && remote.getState().ready ? 'ready'
|
|
36
|
+
: local.getState().phase === 'loading' ? 'loading' : 'unavailable',
|
|
37
|
+
providerIds: [local.id, remote.id], placement: 'two-device-layer-partition' }];
|
|
38
|
+
};
|
|
39
|
+
const notify = () => { for (const listener of listeners) { try { listener(models()); } catch {} } };
|
|
40
|
+
const unsubscribers = [local.subscribe(notify), remote.subscribe(notify)];
|
|
41
|
+
const runner = createLayerPartitionRunner({ runtime, plan, deviceA: local, deviceB: remote, limits: policy, canonical: canonicalBinding !== null,
|
|
42
|
+
authorize: request => (local.canAccept ? local.canAccept(request) : local.getState().ready)
|
|
43
|
+
? authority.verify(request.grant, canonicalBinding ? { identity: canonicalPartitionBinding(request), action: request.action,
|
|
44
|
+
canonicalAttempt: request.canonicalAttempt, generationId: request.generationId, phase: request.phase,
|
|
45
|
+
step: request.step, inputTokenCount: request.inputTokenCount } : { ...request, identity: request }) : Promise.resolve(false) });
|
|
46
|
+
return Object.freeze({
|
|
47
|
+
getModels: models,
|
|
48
|
+
getState: () => runner.getState(),
|
|
49
|
+
subscribe(listener) { listeners.add(listener); listener(models()); return () => listeners.delete(listener); },
|
|
50
|
+
async refresh(options) { await remote.refresh(options); notify(); return models(); },
|
|
51
|
+
async generate(request, controls) {
|
|
52
|
+
// Keep caller-owned request metadata stable through approval and tokenization.
|
|
53
|
+
request = structuredClone(request);
|
|
54
|
+
const requested = requireGenerationCapability(models()[0], request.generationRequest, !!canonicalBinding);
|
|
55
|
+
assert(!requested || requested.maxOutputTokens <= policy.maxTokens, 'Caller token limit exceeds route budget');
|
|
56
|
+
const delegated = request.participantId !== local.id;
|
|
57
|
+
assert(!!canonicalBinding === (request.canonical !== undefined), 'Explicit canonical chat context required');
|
|
58
|
+
assert(!closed && request.meshId === authority.meshId && request.model.id === selection.id
|
|
59
|
+
&& request.model.identity === selection.identity && samePartitionAdapters(request.model, selection)
|
|
60
|
+
&& request.model.partition && canonicalPartitionJson(request.model.partition) === canonicalPartitionJson(selection.partition), 'Partition chat selection mismatch');
|
|
61
|
+
if (delegated) assert(typeof authorizeRequester === 'function'
|
|
62
|
+
&& await authorizeRequester(request, controls.signal) === true
|
|
63
|
+
&& Number.isSafeInteger(request.placementGeneration) && request.placementGeneration >= 0,
|
|
64
|
+
'Remote input owner must authorize this execution placement');
|
|
65
|
+
assert(request.permissions?.sharingScope && request.permissions.sharingScope !== 'local', 'Partition disclosure is disabled');
|
|
66
|
+
controls.signal.throwIfAborted();
|
|
67
|
+
await remote.refresh({ signal: controls.signal });
|
|
68
|
+
assert(models()[0].availability === 'ready', 'No ready contributors for this partition plan');
|
|
69
|
+
const identity = { ...selection.partition, modelId: selection.id, modelIdentity: selection.identity,
|
|
70
|
+
threadId: request.threadId, attemptId: request.attemptId,
|
|
71
|
+
...(delegated || canonicalBinding ? { requesterId: request.participantId, placementGeneration: request.placementGeneration ?? 0 } : {}) };
|
|
72
|
+
const context = canonicalBinding?.check(request.canonical, identity, controls.publication);
|
|
73
|
+
const approved = await controls.requestApproval({ id: crypto.randomUUID(), threadId: request.threadId,
|
|
74
|
+
attemptId: request.attemptId, peerId: remote.id, recipientIdentity: remote.id,
|
|
75
|
+
modelId: selection.id, modelIdentity: selection.identity, adapterIdentities: partitionAdapterIdentities(selection),
|
|
76
|
+
operation: 'generate-partition', disclosure: 'partition-activations-and-tokens', ...selection.partition,
|
|
77
|
+
expiresAt: now() + grantTtlMs,
|
|
78
|
+
input: { messages: structuredClone(request.messages), ...(requested ? {generationRequest: requested} : {}),
|
|
79
|
+
disclosure: 'Intermediate model activations and prompt token context are disclosed to the selected participant for sampling.' } });
|
|
80
|
+
controls.signal.throwIfAborted();
|
|
81
|
+
assert(approved === true, 'Partition disclosure was declined');
|
|
82
|
+
assert(!closed, 'Partition chat closed during approval');
|
|
83
|
+
let grant = null;
|
|
84
|
+
let sequence = 0;
|
|
85
|
+
try {
|
|
86
|
+
const input = await local.tokenize({ messages: request.messages, identity, signal: controls.signal });
|
|
87
|
+
controls.signal.throwIfAborted();
|
|
88
|
+
assert(!closed, 'Partition chat closed during tokenization');
|
|
89
|
+
assert(input.modelIdentity === selection.identity, 'Doppler tokenization model mismatch');
|
|
90
|
+
if (!canonicalBinding) assert(input.generation
|
|
91
|
+
&& Number.isSafeInteger(input.generation.maxTokens) && input.generation.maxTokens > 0
|
|
92
|
+
&& input.generation.maxTokens <= policy.maxTokens, 'Doppler tokenization or generation contract mismatch');
|
|
93
|
+
const generation = boundedGeneration(input.generation, requested);
|
|
94
|
+
if (requested) {
|
|
95
|
+
await controls.onUsage?.({threadId: request.threadId, attemptId: request.attemptId, ...tokenUsage(input.tokenIds.length, 0, requested)});
|
|
96
|
+
controls.signal.throwIfAborted();
|
|
97
|
+
}
|
|
98
|
+
const attempt = canonicalBinding?.attempt({ context, binding: identity, publication: controls.publication, tokenIds: input.tokenIds });
|
|
99
|
+
grant = canonicalBinding
|
|
100
|
+
? await authority.issueCanonical(identity, canonicalBinding.grantLimits, { approved: true, ttlMs: grantTtlMs,
|
|
101
|
+
disclosure: 'partition-activations-and-tokens', generation: context.generation, canonicalAttempt: attempt, vocabSize: plan.vocabSize })
|
|
102
|
+
: await authority.issue(identity, policy, { approved: true, ttlMs: grantTtlMs,
|
|
103
|
+
disclosure: 'partition-activations-and-tokens', generationDigest: await partitionFingerprint(generation) });
|
|
104
|
+
controls.onState({ threadId: request.threadId, attemptId: request.attemptId, status: 'executing',
|
|
105
|
+
execution: { placement: 'two-device-layer-partition', ...selection.partition } });
|
|
106
|
+
const run = { tokenIds: input.tokenIds, identity,
|
|
107
|
+
grants: { executionA: grant, executionB: grant, activation: grant, tokenContext: grant, output: grant }, signal: controls.signal,
|
|
108
|
+
onDelta: text => controls.onDelta({ threadId: request.threadId, attemptId: request.attemptId, sequence: sequence++, text }) };
|
|
109
|
+
const result = canonicalBinding
|
|
110
|
+
? await runner.executeCanonical({ ...run, canonical: { attempt, generation: context.generation,
|
|
111
|
+
publication: controls.publication, deadlineAt: context.deadlineAt } })
|
|
112
|
+
: await runner.execute({ ...run, generation, maxTokens: generation.maxTokens });
|
|
113
|
+
return { threadId: request.threadId, attemptId: request.attemptId, modelId: result.execution.modelId,
|
|
114
|
+
modelIdentity: result.execution.modelIdentity, adapterIdentities: partitionAdapterIdentities(selection), content: result.content,
|
|
115
|
+
...(requested ? {usage: tokenUsage(input.tokenIds.length, result.tokenIds.length, requested)} : {}),
|
|
116
|
+
execution: { ...result.execution, provider: 'peer', transport: remote.getState().receipt } };
|
|
117
|
+
} finally {
|
|
118
|
+
if (grant) authority.revoke(grant);
|
|
119
|
+
// Also settles tokenization failure before the runner acquired an attempt.
|
|
120
|
+
await local.closeAttempt({ identity });
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
async close() { closed = true; unsubscribers.forEach(unsubscribe => unsubscribe()); await runner.close(); listeners.clear(); }
|
|
124
|
+
});
|
|
125
|
+
}
|