@byok-sdk/cloud 0.6.0 → 0.7.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/dist/cloud.d.ts +44 -2
- package/dist/errors.d.ts +10 -0
- package/dist/handlers/messages.d.ts +11 -0
- package/dist/inbound.d.ts +4 -3
- package/dist/index.d.ts +5 -5
- package/dist/index.js +504 -46
- package/dist/index.js.map +1 -1
- package/dist/stores/in-memory/agent-egress.d.ts +12 -0
- package/dist/stores/in-memory/blobs.d.ts +8 -2
- package/dist/stores/in-memory/device-directory.d.ts +4 -0
- package/dist/stores/in-memory/index.d.ts +1 -0
- package/dist/stores/in-memory/task-attempts.d.ts +16 -5
- package/dist/stores/ports.d.ts +86 -3
- package/dist/tenant-stores.d.ts +24 -1
- package/dist/terminal-result.d.ts +5 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BOARD_STATUSES, CapabilityDeclarationSchema, NONCE_SIGNING_DOMAIN, hasCapability, isTenantId, tenantId, principalTenant, parseDeviceProofEnvelope, deviceProofSigningInput, contentHash, parseCapabilityDeclaration, ByokCoreError, tenantKey, PRESENCE_LEVELS, createInMemoryCoreStores, authenticateDeviceAssertion, assertCapability, isCoreConflictError, isCoreError, DEVICE_PROOF_HEADER, TRUTH_RECORD_KINDS, STORAGE_ERROR_CODES, STORAGE_ERROR_HTTP_STATUS } from '@byok-sdk/core';
|
|
2
2
|
export { DEVICE_PROOF_HEADER, NONCE_SIGNING_DOMAIN, isTenantId, tenantId } from '@byok-sdk/core';
|
|
3
|
-
import { AgentEventOrUnknownSchema, DAEMON_TO_SERVER_TYPES, encodeEnvelope, decodeEnvelope, BYOK_PAIR_PATH, BYOK_CHALLENGE_PATH, BYOK_TOKEN_PATH, BYOK_CAPABILITIES_PATH, BYOK_EVENTS_PATH, BYOK_MESSAGES_PATH, BYOK_BOARD_PATH, BYOK_BOARD_CLAIM_ROUTE, BYOK_BOARD_UNCLAIM_ROUTE, BYOK_BOARD_STATUS_ROUTE, BYOK_BOARD_STREAM_PATH, BYOK_PRESENCE_PATH, BYOK_ACTIVITY_PATH, BYOK_RECORDS_PATH, BYOK_RECORD_ROUTE, BYOK_SKILL_PACKS_PATH, BYOK_SKILL_PACK_FILE_ROUTE, BYOK_BLOBS_PATH, BYOK_BLOB_FINALIZE_ROUTE, BYOK_BLOB_URL_ROUTE, BYOK_BLOB_CONTENT_ROUTE, createEnvelope, PairRequestSchema, ChallengeRequestSchema, TokenRequestSchema, MessagesSendRequestSchema, PresencePublishRequestSchema, CreateBlobRequestSchema, byokBlobContentPath } from '@byok-sdk/protocol';
|
|
3
|
+
import { AgentEventOrUnknownSchema, PROTOCOL_VERSION, DAEMON_TO_SERVER_TYPES, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY, encodeEnvelope, decodeEnvelope, BYOK_PAIR_PATH, BYOK_CHALLENGE_PATH, BYOK_TOKEN_PATH, BYOK_CAPABILITIES_PATH, BYOK_EVENTS_PATH, BYOK_MESSAGES_PATH, BYOK_BOARD_PATH, BYOK_BOARD_CLAIM_ROUTE, BYOK_BOARD_UNCLAIM_ROUTE, BYOK_BOARD_STATUS_ROUTE, BYOK_BOARD_STREAM_PATH, BYOK_PRESENCE_PATH, BYOK_ACTIVITY_PATH, BYOK_RECORDS_PATH, BYOK_RECORD_ROUTE, BYOK_SKILL_PACKS_PATH, BYOK_SKILL_PACK_FILE_ROUTE, BYOK_BLOBS_PATH, BYOK_BLOB_FINALIZE_ROUTE, BYOK_BLOB_URL_ROUTE, BYOK_BLOB_CONTENT_ROUTE, createEnvelope, AgentContentReadPayloadSchema, AGENT_EGRESS_POLICY_CAPABILITY, TaskOfferForAgentWithEgressPayloadSchema, TaskOfferForAgentPayloadSchema, AGENT_CONTENT_ARTIFACT_READ_CAPABILITY, AGENT_CONTENT_TRANSCRIPT_READ_CAPABILITY, AGENT_CONTENT_WORKSPACE_READ_CAPABILITY, PairRequestSchema, PairResponseSchema, ChallengeRequestSchema, TokenRequestSchema, MessagesSendRequestSchema, PresencePublishRequestSchema, CreateBlobRequestSchema, byokBlobContentPath, AgentEgressAckPayloadSchema, AgentContentReceiptPayloadSchema } from '@byok-sdk/protocol';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { Hono } from 'hono';
|
|
6
6
|
|
|
@@ -160,8 +160,8 @@ function createHmacTokenSigner(secret, clock) {
|
|
|
160
160
|
}
|
|
161
161
|
};
|
|
162
162
|
}
|
|
163
|
-
function verifyNonceSignature(
|
|
164
|
-
return
|
|
163
|
+
function verifyNonceSignature(crypto2, devicePublicKey, nonce, signature) {
|
|
164
|
+
return crypto2.verifyEd25519(devicePublicKey, NONCE_SIGNING_DOMAIN + nonce, signature);
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
// src/auth/plane.ts
|
|
@@ -170,13 +170,13 @@ var PAIRING_CODE_LENGTH = 8;
|
|
|
170
170
|
var DEVICE_IDENTITY_PROOF_KEY_ID = "identity";
|
|
171
171
|
var DEVICE_IDENTITY_PROOF_KEY_EPOCH = 0;
|
|
172
172
|
function createAuthPlane(deps) {
|
|
173
|
-
const { stores, crypto, clock, tokenSigner } = deps;
|
|
173
|
+
const { stores, crypto: crypto2, clock, tokenSigner } = deps;
|
|
174
174
|
const ttlSeconds = deps.accessTokenTtlSeconds ?? ACCESS_TOKEN_TTL_SECONDS;
|
|
175
175
|
return {
|
|
176
176
|
async createPairingCode(tenant, input) {
|
|
177
177
|
const expiresAt = new Date(clock.now().getTime() + (input.ttlMs ?? PAIRING_CODE_TTL_MS)).toISOString();
|
|
178
178
|
return stores.pairingCodes.issue(tenant, {
|
|
179
|
-
code:
|
|
179
|
+
code: crypto2.randomPairingCode(PAIRING_CODE_LENGTH),
|
|
180
180
|
productId: input.productId,
|
|
181
181
|
expiresAt
|
|
182
182
|
});
|
|
@@ -186,7 +186,7 @@ function createAuthPlane(deps) {
|
|
|
186
186
|
if (claims === void 0) return void 0;
|
|
187
187
|
return stores.devices.register(claims.tenantId, {
|
|
188
188
|
productId: claims.productId,
|
|
189
|
-
deviceId: `dev_${
|
|
189
|
+
deviceId: `dev_${crypto2.randomUuid()}`,
|
|
190
190
|
deviceName: input.deviceName,
|
|
191
191
|
devicePublicKey: input.devicePublicKey,
|
|
192
192
|
proofKeyId: DEVICE_IDENTITY_PROOF_KEY_ID,
|
|
@@ -208,7 +208,7 @@ function createAuthPlane(deps) {
|
|
|
208
208
|
return stores.nonces.markUsed(device.tenantId, nonce);
|
|
209
209
|
},
|
|
210
210
|
verifySignature(device, nonce, signature) {
|
|
211
|
-
return verifyNonceSignature(
|
|
211
|
+
return verifyNonceSignature(crypto2, device.devicePublicKey, nonce, signature);
|
|
212
212
|
},
|
|
213
213
|
async mintAccessToken(device) {
|
|
214
214
|
const accessToken = await tokenSigner.sign(
|
|
@@ -319,7 +319,17 @@ var CLOUD_ERROR_CODES = {
|
|
|
319
319
|
/** A progress/activity batch exceeded the configured event or byte ceiling. */
|
|
320
320
|
activity_batch_too_large: "activity_batch_too_large",
|
|
321
321
|
/** Host control-plane task lookup is tenant-closed and found no task. */
|
|
322
|
-
task_not_found: "task_not_found"
|
|
322
|
+
task_not_found: "task_not_found",
|
|
323
|
+
/** Durable target-device capability is absent, revoked, or unavailable. */
|
|
324
|
+
agent_capability_missing: "agent_capability_missing",
|
|
325
|
+
/** Inbound Agent identity did not exactly match the offered identity. */
|
|
326
|
+
agent_ref_mismatch: "agent_ref_mismatch",
|
|
327
|
+
/** A strict Agent task id already names a durable attempt and cannot be re-enqueued. */
|
|
328
|
+
agent_task_already_exists: "agent_task_already_exists",
|
|
329
|
+
/** A first-write-wins Agent control record was replayed with a different body. */
|
|
330
|
+
agent_content_request_mismatch: "agent_content_request_mismatch",
|
|
331
|
+
/** A durable mailbox receipt id resolved to an envelope other than its exact acknowledgement. */
|
|
332
|
+
mailbox_receipt_mismatch: "mailbox_receipt_mismatch"
|
|
323
333
|
};
|
|
324
334
|
var ByokCloudError = class extends Error {
|
|
325
335
|
code;
|
|
@@ -527,10 +537,15 @@ function tenantStoresFor(principal, root) {
|
|
|
527
537
|
get: (deviceId) => cloud.devices.get(tenant, deviceId),
|
|
528
538
|
list: () => cloud.devices.list(tenant),
|
|
529
539
|
revoke: (deviceId) => cloud.devices.revoke(tenant, deviceId),
|
|
540
|
+
recordCapabilities: (input) => principal.kind === "device" ? cloud.devices.recordCapabilities(tenant, {
|
|
541
|
+
deviceId: principal.deviceId,
|
|
542
|
+
capabilities: input.capabilities
|
|
543
|
+
}) : Promise.resolve(void 0),
|
|
530
544
|
readiness: () => cloud.devices.readiness(tenant, core.presence)
|
|
531
545
|
},
|
|
532
546
|
tasks: {
|
|
533
547
|
open: (input) => cloud.tasks.open(tenant, input),
|
|
548
|
+
reserveAgentOffer: (input) => cloud.tasks.reserveAgentOffer(tenant, input),
|
|
534
549
|
get: (taskId) => cloud.tasks.get(tenant, taskId),
|
|
535
550
|
getMany: (taskIds) => cloud.tasks.getMany(tenant, taskIds),
|
|
536
551
|
claim: (input) => cloud.tasks.claim(tenant, input),
|
|
@@ -546,6 +561,10 @@ function tenantStoresFor(principal, root) {
|
|
|
546
561
|
record: (input) => cloud.receipts.record(tenant, input),
|
|
547
562
|
get: (key) => cloud.receipts.get(tenant, key)
|
|
548
563
|
},
|
|
564
|
+
egress: {
|
|
565
|
+
record: (input) => cloud.egress.record(tenant, input),
|
|
566
|
+
get: (deviceId, eventId) => cloud.egress.get(tenant, deviceId, eventId)
|
|
567
|
+
},
|
|
549
568
|
blobs: {
|
|
550
569
|
createUpload: (reservation) => cloud.blobs.createUpload(tenant, reservation),
|
|
551
570
|
observeUpload: (blobId, reservation) => cloud.blobs.observeUpload(tenant, blobId, reservation),
|
|
@@ -685,11 +704,16 @@ function blobDownloadContentHandler(deps) {
|
|
|
685
704
|
if (!query.success || !await deps.contentProxy.verifySignedUrl(blobId, "get", query.data.sig, query.data.exp)) {
|
|
686
705
|
return c.json({ error: "invalid or expired signature" }, 401);
|
|
687
706
|
}
|
|
688
|
-
const
|
|
689
|
-
if (
|
|
690
|
-
|
|
707
|
+
const result = await deps.contentProxy.readContent(blobId);
|
|
708
|
+
if (result === void 0) return c.json({ error: "blob not found" }, 404);
|
|
709
|
+
if (!result.ok) return c.json({ error: result.code }, BLOB_READ_ERROR_HTTP_STATUS[result.code]);
|
|
710
|
+
return c.body(new Uint8Array(result.content.data), 200, { "content-type": result.content.contentType });
|
|
691
711
|
};
|
|
692
712
|
}
|
|
713
|
+
var BLOB_READ_ERROR_HTTP_STATUS = {
|
|
714
|
+
blob_upstream_unavailable: 502,
|
|
715
|
+
blob_upstream_stream_interrupted: 502
|
|
716
|
+
};
|
|
693
717
|
function idempotencyKey(c) {
|
|
694
718
|
const value = c.req.header("Idempotency-Key");
|
|
695
719
|
if (value === void 0 || value.length === 0 || value.length > 200) return void 0;
|
|
@@ -726,7 +750,12 @@ function pairHandler(deps) {
|
|
|
726
750
|
const device = await deps.auth.redeemAndRegister(parsed.data);
|
|
727
751
|
if (device === void 0) return c.json({ error: "invalid pairing code" }, 401);
|
|
728
752
|
const { accessToken, expiresAt } = await deps.auth.mintAccessToken(device);
|
|
729
|
-
const response = {
|
|
753
|
+
const response = PairResponseSchema.parse({
|
|
754
|
+
deviceId: device.deviceId,
|
|
755
|
+
accessToken,
|
|
756
|
+
refreshHint: expiresAt,
|
|
757
|
+
tenantId: device.tenantId
|
|
758
|
+
});
|
|
730
759
|
return c.json(response, 200);
|
|
731
760
|
};
|
|
732
761
|
}
|
|
@@ -759,7 +788,15 @@ function tokenHandler(deps) {
|
|
|
759
788
|
return c.json(response, 200);
|
|
760
789
|
};
|
|
761
790
|
}
|
|
762
|
-
var CLOUD_PROTOCOL_CAPABILITIES = [
|
|
791
|
+
var CLOUD_PROTOCOL_CAPABILITIES = [
|
|
792
|
+
"result-document",
|
|
793
|
+
"agent-home-contract",
|
|
794
|
+
"agent-egress-policy",
|
|
795
|
+
"agent-egress-reliable-ack",
|
|
796
|
+
"agent-content-workspace-read",
|
|
797
|
+
"agent-content-transcript-read",
|
|
798
|
+
"agent-content-artifact-read"
|
|
799
|
+
];
|
|
763
800
|
function sleep(ms) {
|
|
764
801
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
765
802
|
}
|
|
@@ -791,13 +828,15 @@ function eventsHandler(deps) {
|
|
|
791
828
|
if (page.messages.length === 0) break;
|
|
792
829
|
const decoded = page.messages.map((message) => decodeEnvelope(message.body));
|
|
793
830
|
const offeredTaskIds = decoded.flatMap(
|
|
794
|
-
(event) => (event.type === "task.offer" || event.type === "task.offer_with_toolsets") && event.task_id !== void 0 ? [event.task_id] : []
|
|
831
|
+
(event) => (event.type === "task.offer" || event.type === "task.offer_with_toolsets" || event.type === "task.offer_for_agent" || event.type === "task.offer_for_agent_with_egress") && event.task_id !== void 0 ? [event.task_id] : []
|
|
795
832
|
);
|
|
796
833
|
const attemptsByTaskId = Object.fromEntries(
|
|
797
834
|
(await stores.tasks.getMany(offeredTaskIds)).map((attempt2) => [attempt2.taskId, attempt2])
|
|
798
835
|
);
|
|
799
836
|
const events = decoded.filter((event) => {
|
|
800
|
-
if (event.type !== "task.offer" && event.type !== "task.offer_with_toolsets")
|
|
837
|
+
if (event.type !== "task.offer" && event.type !== "task.offer_with_toolsets" && event.type !== "task.offer_for_agent" && event.type !== "task.offer_for_agent_with_egress") {
|
|
838
|
+
return true;
|
|
839
|
+
}
|
|
801
840
|
return event.task_id === void 0 || attemptsByTaskId[event.task_id]?.cancellation === void 0;
|
|
802
841
|
});
|
|
803
842
|
if (events.length === 0 && page.hasMore) {
|
|
@@ -910,13 +949,103 @@ async function projectTerminalToReview(board, taskId) {
|
|
|
910
949
|
function terminalReceiptKey(taskId) {
|
|
911
950
|
return `task:${taskId}:terminal`;
|
|
912
951
|
}
|
|
952
|
+
function sameAgentRef(expected, actual) {
|
|
953
|
+
return actual?.agentId === expected.agentId && actual.profileRevision === expected.profileRevision;
|
|
954
|
+
}
|
|
955
|
+
function sameReliableEgress(expected, actual) {
|
|
956
|
+
return sameAgentRef(expected.agentRef, actual.agentRef) && expected.sessionRef === actual.sessionRef && expected.policyRevision === actual.policyRevision && expected.eventId === actual.eventId && expected.cursor === actual.cursor && expected.contentHash === actual.contentHash && expected.byteCount === actual.byteCount && JSON.stringify(expected.payload) === JSON.stringify(actual.payload);
|
|
957
|
+
}
|
|
958
|
+
function contentReadCapability(surface) {
|
|
959
|
+
switch (surface) {
|
|
960
|
+
case "workspace":
|
|
961
|
+
return AGENT_CONTENT_WORKSPACE_READ_CAPABILITY;
|
|
962
|
+
case "transcript":
|
|
963
|
+
return AGENT_CONTENT_TRANSCRIPT_READ_CAPABILITY;
|
|
964
|
+
case "artifact":
|
|
965
|
+
return AGENT_CONTENT_ARTIFACT_READ_CAPABILITY;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
function hasCapabilities(capabilities, required) {
|
|
969
|
+
return capabilities !== void 0 && required.every((capability) => capabilities.includes(capability));
|
|
970
|
+
}
|
|
971
|
+
function contentRequestReceiptKey(deviceId, requestId) {
|
|
972
|
+
return `agent-content-request:${deviceId}:${requestId}`;
|
|
973
|
+
}
|
|
974
|
+
function contentReceiptKey(deviceId, requestId) {
|
|
975
|
+
return `agent-content:${deviceId}:${requestId}`;
|
|
976
|
+
}
|
|
977
|
+
function matchesContentReadReceipt(request, receipt) {
|
|
978
|
+
return request.requestId === receipt.requestId && request.surface === receipt.surface && request.actor.kind === receipt.actor.kind && request.actor.id === receipt.actor.id && sameAgentRef(request.agentRef, receipt.agentRef) && request.sessionRef === receipt.sessionRef && request.runtime === receipt.runtime && request.cwd === receipt.cwd && request.policyRevision === receipt.policyRevision && request.target === receipt.target && request.mimeType === receipt.mimeType && request.decodeAs === receipt.decodeAs;
|
|
979
|
+
}
|
|
980
|
+
async function readContentRequest(stores, deviceId, requestId) {
|
|
981
|
+
const stored = await stores.receipts.get(contentRequestReceiptKey(deviceId, requestId));
|
|
982
|
+
if (stored === void 0) return void 0;
|
|
983
|
+
try {
|
|
984
|
+
return AgentContentReadPayloadSchema.parse(JSON.parse(stored.body));
|
|
985
|
+
} catch {
|
|
986
|
+
return void 0;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
function inboundAgentRef(envelope) {
|
|
990
|
+
switch (envelope.type) {
|
|
991
|
+
case "task.claim":
|
|
992
|
+
case "task.decline":
|
|
993
|
+
case "task.complete":
|
|
994
|
+
case "task.fail":
|
|
995
|
+
case "task.cancelled":
|
|
996
|
+
return envelope.payload.agentRef;
|
|
997
|
+
default:
|
|
998
|
+
return void 0;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
function agentRefEchoRequired(envelope) {
|
|
1002
|
+
return envelope.type === "task.claim" || envelope.type === "task.decline" || envelope.type === "task.complete" || envelope.type === "task.fail" || envelope.type === "task.cancelled";
|
|
1003
|
+
}
|
|
913
1004
|
async function handleInboundEnvelope(stores, deviceId, envelope, activityBounds = DEFAULT_ACTIVITY_BOUNDS) {
|
|
914
1005
|
if (!await stores.rateLimiter.consume(deviceId)) return "rate_limited";
|
|
1006
|
+
if (envelope.type === "conn.hello") {
|
|
1007
|
+
if (envelope.payload.deviceId !== deviceId) return "rejected";
|
|
1008
|
+
if (!envelope.payload.protocolVersions.includes(PROTOCOL_VERSION)) return "rejected";
|
|
1009
|
+
const device = await stores.devices.get(deviceId);
|
|
1010
|
+
if (device === void 0 || device.revoked || device.productId !== envelope.payload.productId) {
|
|
1011
|
+
return "rejected";
|
|
1012
|
+
}
|
|
1013
|
+
if (await stores.dedup.checkAndRecord(deviceId, envelope.id)) return "duplicate";
|
|
1014
|
+
return await stores.devices.recordCapabilities({ capabilities: envelope.payload.capabilities }) === void 0 ? "rejected" : "accepted";
|
|
1015
|
+
}
|
|
915
1016
|
if (!DAEMON_TO_SERVER_TYPES.includes(envelope.type)) return "rejected";
|
|
1017
|
+
if (envelope.type === "agent.egress.reliable") {
|
|
1018
|
+
const device = await stores.devices.get(deviceId);
|
|
1019
|
+
if (device === void 0 || device.revoked || !hasCapabilities(device.capabilities, [AGENT_EGRESS_POLICY_CAPABILITY, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY])) {
|
|
1020
|
+
return "rejected";
|
|
1021
|
+
}
|
|
1022
|
+
const outcome = await stores.egress.record({
|
|
1023
|
+
deviceId,
|
|
1024
|
+
payload: envelope.payload,
|
|
1025
|
+
receiptId: crypto.randomUUID()
|
|
1026
|
+
});
|
|
1027
|
+
return outcome.created || sameReliableEgress(outcome.record.payload, envelope.payload) ? outcome.created ? "accepted" : "duplicate" : "rejected";
|
|
1028
|
+
}
|
|
1029
|
+
if (envelope.type === "agent.content.receipt") {
|
|
1030
|
+
const device = await stores.devices.get(deviceId);
|
|
1031
|
+
if (device === void 0 || device.revoked || envelope.payload.eventId !== envelope.payload.requestId || !hasCapabilities(device.capabilities, [contentReadCapability(envelope.payload.surface), AGENT_EGRESS_RELIABLE_ACK_CAPABILITY])) {
|
|
1032
|
+
return "rejected";
|
|
1033
|
+
}
|
|
1034
|
+
const request = await readContentRequest(stores, deviceId, envelope.payload.requestId);
|
|
1035
|
+
if (request === void 0 || !matchesContentReadReceipt(request, envelope.payload)) return "rejected";
|
|
1036
|
+
const key = contentReceiptKey(deviceId, envelope.payload.requestId);
|
|
1037
|
+
const body = JSON.stringify(envelope.payload);
|
|
1038
|
+
const receipt = await stores.receipts.record({ key, body });
|
|
1039
|
+
return receipt.created ? "accepted" : receipt.receipt.body === body ? "duplicate" : "rejected";
|
|
1040
|
+
}
|
|
916
1041
|
const taskId = envelope.task_id;
|
|
917
1042
|
if (taskId === void 0) return "rejected";
|
|
918
1043
|
const attempt = await stores.tasks.get(taskId);
|
|
1044
|
+
if (attempt?.agentRef !== void 0 && attempt.deviceId !== deviceId) return "rejected";
|
|
919
1045
|
if (attempt?.ownerDeviceId !== void 0 && attempt.ownerDeviceId !== deviceId) return "rejected";
|
|
1046
|
+
if (attempt?.agentRef !== void 0 && agentRefEchoRequired(envelope) && !sameAgentRef(attempt.agentRef, inboundAgentRef(envelope))) {
|
|
1047
|
+
return "rejected";
|
|
1048
|
+
}
|
|
920
1049
|
if (envelope.type === "task.progress" && envelope.payload.events.length > 0) {
|
|
921
1050
|
try {
|
|
922
1051
|
validateActivityBatch(
|
|
@@ -946,19 +1075,27 @@ async function handleInboundEnvelope(stores, deviceId, envelope, activityBounds
|
|
|
946
1075
|
}
|
|
947
1076
|
}
|
|
948
1077
|
if (await stores.dedup.checkAndRecord(deviceId, envelope.id)) return "duplicate";
|
|
949
|
-
await applyLifecycle(stores, deviceId, taskId, envelope, activityBounds);
|
|
1078
|
+
await applyLifecycle(stores, deviceId, taskId, envelope, activityBounds, attempt?.agentRef);
|
|
950
1079
|
return "accepted";
|
|
951
1080
|
}
|
|
952
|
-
async function applyLifecycle(stores, deviceId, taskId, envelope, activityBounds) {
|
|
1081
|
+
async function applyLifecycle(stores, deviceId, taskId, envelope, activityBounds, persistedAgentRef) {
|
|
953
1082
|
switch (envelope.type) {
|
|
954
1083
|
case "task.claim":
|
|
955
1084
|
await stores.tasks.claim({ taskId, deviceId });
|
|
956
1085
|
return;
|
|
957
1086
|
case "task.started":
|
|
958
|
-
await stores.tasks.recordStatus({
|
|
1087
|
+
await stores.tasks.recordStatus({
|
|
1088
|
+
taskId,
|
|
1089
|
+
status: "running",
|
|
1090
|
+
...persistedAgentRef === void 0 ? {} : { agentRef: persistedAgentRef }
|
|
1091
|
+
});
|
|
959
1092
|
return;
|
|
960
1093
|
case "task.decline":
|
|
961
|
-
await stores.tasks.recordStatus({
|
|
1094
|
+
await stores.tasks.recordStatus({
|
|
1095
|
+
taskId,
|
|
1096
|
+
status: "failed",
|
|
1097
|
+
...persistedAgentRef === void 0 ? {} : { agentRef: persistedAgentRef }
|
|
1098
|
+
});
|
|
962
1099
|
return;
|
|
963
1100
|
case "task.progress":
|
|
964
1101
|
if (envelope.payload.events.length > 0) {
|
|
@@ -1030,12 +1167,22 @@ async function recordTerminal(stores, taskId, envelope, status) {
|
|
|
1030
1167
|
});
|
|
1031
1168
|
if (attempt?.cancellation !== void 0) {
|
|
1032
1169
|
if (status === "cancelled") {
|
|
1033
|
-
await stores.tasks.recordStatus({
|
|
1170
|
+
await stores.tasks.recordStatus({
|
|
1171
|
+
taskId,
|
|
1172
|
+
status: "cancelled",
|
|
1173
|
+
...attempt.agentRef === void 0 ? {} : { agentRef: attempt.agentRef }
|
|
1174
|
+
});
|
|
1034
1175
|
}
|
|
1035
1176
|
return;
|
|
1036
1177
|
}
|
|
1037
1178
|
if (!created) return;
|
|
1038
|
-
const
|
|
1179
|
+
const cause = envelope.type === "task.fail" || envelope.type === "task.cancelled" ? envelope.payload.reason : void 0;
|
|
1180
|
+
const recordedAttempt = await stores.tasks.recordStatus({
|
|
1181
|
+
taskId,
|
|
1182
|
+
status,
|
|
1183
|
+
...attempt?.agentRef === void 0 ? {} : { agentRef: attempt.agentRef },
|
|
1184
|
+
...cause === void 0 ? {} : { terminalCause: cause }
|
|
1185
|
+
});
|
|
1039
1186
|
if (recordedAttempt?.status !== status || recordedAttempt.cancellation !== void 0) return;
|
|
1040
1187
|
await projectTerminalToReview(stores.board, taskId);
|
|
1041
1188
|
}
|
|
@@ -1058,6 +1205,16 @@ function messagesHandler(deps) {
|
|
|
1058
1205
|
deps.activityBounds
|
|
1059
1206
|
);
|
|
1060
1207
|
if (outcome === "rate_limited") return c.json({ error: "rate limit exceeded" }, 429);
|
|
1208
|
+
if (envelope.type === "agent.egress.reliable" && (outcome === "accepted" || outcome === "duplicate")) {
|
|
1209
|
+
const record = await stores.egress.get(device.deviceId, envelope.payload.eventId);
|
|
1210
|
+
if (record === void 0) {
|
|
1211
|
+
throw new Error(`Accepted reliable egress ${envelope.payload.eventId} has no durable receipt record.`);
|
|
1212
|
+
}
|
|
1213
|
+
await deps.appendReliableEgressAck(stores, record);
|
|
1214
|
+
}
|
|
1215
|
+
if (envelope.type === "agent.content.receipt" && (outcome === "accepted" || outcome === "duplicate")) {
|
|
1216
|
+
await deps.appendContentReceiptAck(stores, device.deviceId, envelope.payload);
|
|
1217
|
+
}
|
|
1061
1218
|
if (outcome === "rejected") rejected += 1;
|
|
1062
1219
|
else accepted += 1;
|
|
1063
1220
|
}
|
|
@@ -1825,6 +1982,7 @@ function projectTerminalResult(taskId, receipt) {
|
|
|
1825
1982
|
return {
|
|
1826
1983
|
taskId,
|
|
1827
1984
|
state: "complete",
|
|
1985
|
+
...envelope.payload.agentRef === void 0 ? {} : { agentRef: envelope.payload.agentRef },
|
|
1828
1986
|
summary: envelope.payload.summary,
|
|
1829
1987
|
sessionRef: envelope.payload.sessionRef,
|
|
1830
1988
|
...envelope.payload.artifactRefs !== void 0 ? { artifactRefs: envelope.payload.artifactRefs } : {},
|
|
@@ -1836,7 +1994,9 @@ function projectTerminalResult(taskId, receipt) {
|
|
|
1836
1994
|
return {
|
|
1837
1995
|
taskId,
|
|
1838
1996
|
state: "failed",
|
|
1997
|
+
...envelope.payload.agentRef === void 0 ? {} : { agentRef: envelope.payload.agentRef },
|
|
1839
1998
|
reason: envelope.payload.reason,
|
|
1999
|
+
terminalCause: envelope.payload.reason,
|
|
1840
2000
|
...envelope.payload.retryable !== void 0 ? { retryable: envelope.payload.retryable } : {},
|
|
1841
2001
|
...envelope.payload.usage !== void 0 ? { usage: envelope.payload.usage } : {},
|
|
1842
2002
|
recordedAt: receipt.recordedAt
|
|
@@ -1845,7 +2005,9 @@ function projectTerminalResult(taskId, receipt) {
|
|
|
1845
2005
|
return {
|
|
1846
2006
|
taskId,
|
|
1847
2007
|
state: "cancelled",
|
|
2008
|
+
...envelope.payload.agentRef === void 0 ? {} : { agentRef: envelope.payload.agentRef },
|
|
1848
2009
|
...envelope.payload.reason !== void 0 ? { reason: envelope.payload.reason } : {},
|
|
2010
|
+
...envelope.payload.reason === void 0 ? {} : { terminalCause: envelope.payload.reason },
|
|
1849
2011
|
...envelope.payload.usage !== void 0 ? { usage: envelope.payload.usage } : {},
|
|
1850
2012
|
recordedAt: receipt.recordedAt
|
|
1851
2013
|
};
|
|
@@ -1862,6 +2024,10 @@ var DEFAULT_MAX_BLOB_SIZE_BYTES = 100 * 1024 * 1024;
|
|
|
1862
2024
|
var DEFAULT_LONG_POLL_HOLD_MS = 5e4;
|
|
1863
2025
|
var DEFAULT_LONG_POLL_INTERVAL_MS = 250;
|
|
1864
2026
|
var DEFAULT_EVENTS_PAGE_LIMIT = 50;
|
|
2027
|
+
var AGENT_HOME_CONTRACT_CAPABILITY = "agent-home-contract";
|
|
2028
|
+
function sameAgentRef2(expected, actual) {
|
|
2029
|
+
return actual?.agentId === expected.agentId && actual.profileRevision === expected.profileRevision;
|
|
2030
|
+
}
|
|
1865
2031
|
function createByokCloud(options) {
|
|
1866
2032
|
const declaration = parseDeclaration(options.capabilities);
|
|
1867
2033
|
assertNoOverDeclaration(
|
|
@@ -1911,7 +2077,12 @@ function createByokCloud(options) {
|
|
|
1911
2077
|
if (declares(declaration, CLOUD_CAPABILITIES.messagesBatch)) {
|
|
1912
2078
|
registry.register(
|
|
1913
2079
|
{ method: "POST", path: BYOK_MESSAGES_PATH, class: "device" },
|
|
1914
|
-
messagesHandler({
|
|
2080
|
+
messagesHandler({
|
|
2081
|
+
...deviceRouteDeps,
|
|
2082
|
+
activityBounds,
|
|
2083
|
+
appendReliableEgressAck: enqueueReliableEgressAck,
|
|
2084
|
+
appendContentReceiptAck: enqueueContentReceiptAck
|
|
2085
|
+
})
|
|
1915
2086
|
);
|
|
1916
2087
|
}
|
|
1917
2088
|
if (declares(declaration, CLOUD_CAPABILITIES.boardCoordination)) {
|
|
@@ -2029,16 +2200,98 @@ function createByokCloud(options) {
|
|
|
2029
2200
|
function controlPlane(tenant) {
|
|
2030
2201
|
return { kind: "control-plane", tenantId: tenant, operatorId };
|
|
2031
2202
|
}
|
|
2032
|
-
async function enqueueTaskEnvelope(tenant, deviceId, requestedTaskId, buildEnvelope) {
|
|
2203
|
+
async function enqueueTaskEnvelope(tenant, deviceId, requestedTaskId, agentRef, buildEnvelope) {
|
|
2033
2204
|
const stores = tenantStoresFor(controlPlane(tenant), root);
|
|
2034
2205
|
const taskId = requestedTaskId ?? `task_${options.crypto.randomUuid()}`;
|
|
2035
2206
|
const messageId = options.crypto.randomUuid();
|
|
2207
|
+
const reservation = agentRef === void 0 ? void 0 : await stores.tasks.reserveAgentOffer({ taskId, deviceId, agentRef });
|
|
2208
|
+
const openedBeforeAppend = reservation?.attempt;
|
|
2209
|
+
if (agentRef !== void 0 && (openedBeforeAppend === void 0 || openedBeforeAppend.deviceId !== deviceId || openedBeforeAppend.agentRef === void 0 || !sameAgentRef2(agentRef, openedBeforeAppend.agentRef))) {
|
|
2210
|
+
throw new ByokCloudError(
|
|
2211
|
+
"agent_ref_mismatch",
|
|
2212
|
+
`Task ${taskId} already has a different durable Agent identity or target device.`
|
|
2213
|
+
);
|
|
2214
|
+
}
|
|
2215
|
+
if (reservation !== void 0 && !reservation.created) {
|
|
2216
|
+
throw new ByokCloudError(
|
|
2217
|
+
"agent_task_already_exists",
|
|
2218
|
+
`Task ${taskId} already has a durable Agent attempt and cannot be enqueued again.`
|
|
2219
|
+
);
|
|
2220
|
+
}
|
|
2221
|
+
let message;
|
|
2222
|
+
try {
|
|
2223
|
+
message = await stores.mailbox.append({
|
|
2224
|
+
deviceId,
|
|
2225
|
+
messageId,
|
|
2226
|
+
materialize: async (seq) => {
|
|
2227
|
+
const envelope2 = buildEnvelope(taskId, seq, messageId);
|
|
2228
|
+
const body = encodeEnvelope(envelope2);
|
|
2229
|
+
const bytes = new TextEncoder().encode(body);
|
|
2230
|
+
return {
|
|
2231
|
+
body,
|
|
2232
|
+
bodyHash: contentHash(await options.crypto.sha256(bytes)),
|
|
2233
|
+
byteSize: BigInt(bytes.length)
|
|
2234
|
+
};
|
|
2235
|
+
}
|
|
2236
|
+
});
|
|
2237
|
+
} catch (error) {
|
|
2238
|
+
if (openedBeforeAppend !== void 0) {
|
|
2239
|
+
try {
|
|
2240
|
+
await stores.tasks.recordStatus({
|
|
2241
|
+
taskId,
|
|
2242
|
+
status: "failed",
|
|
2243
|
+
agentRef,
|
|
2244
|
+
terminalCause: "mailbox append failed before Agent offer delivery"
|
|
2245
|
+
});
|
|
2246
|
+
} catch (cleanupError) {
|
|
2247
|
+
throw new AggregateError(
|
|
2248
|
+
[error, cleanupError],
|
|
2249
|
+
`Agent task ${taskId} could not be delivered or durably closed`
|
|
2250
|
+
);
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
throw error;
|
|
2254
|
+
}
|
|
2255
|
+
const envelope = decodeEnvelope(message.body);
|
|
2256
|
+
if (envelope.seq !== message.seq) {
|
|
2257
|
+
throw new ByokCloudError(
|
|
2258
|
+
"mailbox_seq_mismatch",
|
|
2259
|
+
`Mailbox stored offer seq ${String(envelope.seq)} at row ${message.seq}; the daemon's redelivery cursor would be wrong.`
|
|
2260
|
+
);
|
|
2261
|
+
}
|
|
2262
|
+
const attempt = openedBeforeAppend ?? await stores.tasks.open({
|
|
2263
|
+
taskId,
|
|
2264
|
+
deviceId
|
|
2265
|
+
});
|
|
2266
|
+
return { taskId, seq: message.seq, envelope, attempt };
|
|
2267
|
+
}
|
|
2268
|
+
async function assertAgentCapabilities(tenant, deviceId, required) {
|
|
2269
|
+
const device = await options.cloud.devices.get(tenant, deviceId);
|
|
2270
|
+
if (device === void 0 || device.revoked || !device.capabilities || !required.every((capability) => device.capabilities.includes(capability))) {
|
|
2271
|
+
const missing = required.filter((capability) => !device?.capabilities?.includes(capability));
|
|
2272
|
+
throw new ByokCloudError(
|
|
2273
|
+
"agent_capability_missing",
|
|
2274
|
+
`Device ${deviceId} lacks durable Agent capabilities (${missing.join(", ")}); refusing before mailbox append.`
|
|
2275
|
+
);
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
function contentReadCapability2(surface) {
|
|
2279
|
+
switch (surface) {
|
|
2280
|
+
case "workspace":
|
|
2281
|
+
return AGENT_CONTENT_WORKSPACE_READ_CAPABILITY;
|
|
2282
|
+
case "transcript":
|
|
2283
|
+
return AGENT_CONTENT_TRANSCRIPT_READ_CAPABILITY;
|
|
2284
|
+
case "artifact":
|
|
2285
|
+
return AGENT_CONTENT_ARTIFACT_READ_CAPABILITY;
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
async function enqueueAgentControlEnvelope(tenant, deviceId, messageId, buildEnvelope) {
|
|
2289
|
+
const stores = tenantStoresFor(controlPlane(tenant), root);
|
|
2036
2290
|
const message = await stores.mailbox.append({
|
|
2037
2291
|
deviceId,
|
|
2038
2292
|
messageId,
|
|
2039
2293
|
materialize: async (seq) => {
|
|
2040
|
-
const
|
|
2041
|
-
const body = encodeEnvelope(envelope2);
|
|
2294
|
+
const body = encodeEnvelope(buildEnvelope(seq));
|
|
2042
2295
|
const bytes = new TextEncoder().encode(body);
|
|
2043
2296
|
return {
|
|
2044
2297
|
body,
|
|
@@ -2051,11 +2304,77 @@ function createByokCloud(options) {
|
|
|
2051
2304
|
if (envelope.seq !== message.seq) {
|
|
2052
2305
|
throw new ByokCloudError(
|
|
2053
2306
|
"mailbox_seq_mismatch",
|
|
2054
|
-
`Mailbox stored
|
|
2307
|
+
`Mailbox stored Agent control seq ${String(envelope.seq)} at row ${message.seq}.`
|
|
2308
|
+
);
|
|
2309
|
+
}
|
|
2310
|
+
return { seq: message.seq, envelope };
|
|
2311
|
+
}
|
|
2312
|
+
async function enqueueReliableEgressAck(stores, record) {
|
|
2313
|
+
const payload = AgentEgressAckPayloadSchema.parse({
|
|
2314
|
+
agentRef: record.payload.agentRef,
|
|
2315
|
+
sessionRef: record.payload.sessionRef,
|
|
2316
|
+
policyRevision: record.payload.policyRevision,
|
|
2317
|
+
eventId: record.payload.eventId,
|
|
2318
|
+
cursor: record.payload.cursor,
|
|
2319
|
+
receiptId: record.receiptId
|
|
2320
|
+
});
|
|
2321
|
+
const message = await stores.mailbox.append({
|
|
2322
|
+
deviceId: record.deviceId,
|
|
2323
|
+
messageId: record.receiptId,
|
|
2324
|
+
materialize: async (seq) => {
|
|
2325
|
+
const body = encodeEnvelope(createEnvelope("agent.egress.ack", payload, { id: record.receiptId, seq }));
|
|
2326
|
+
const bytes = new TextEncoder().encode(body);
|
|
2327
|
+
return {
|
|
2328
|
+
body,
|
|
2329
|
+
bodyHash: contentHash(await options.crypto.sha256(bytes)),
|
|
2330
|
+
byteSize: BigInt(bytes.length)
|
|
2331
|
+
};
|
|
2332
|
+
}
|
|
2333
|
+
});
|
|
2334
|
+
const decoded = decodeEnvelope(message.body);
|
|
2335
|
+
if (decoded.type !== "agent.egress.ack" || decoded.seq !== message.seq || JSON.stringify(decoded.payload) !== JSON.stringify(payload)) {
|
|
2336
|
+
throw new ByokCloudError(
|
|
2337
|
+
"mailbox_receipt_mismatch",
|
|
2338
|
+
`Mailbox receipt ${record.receiptId} does not exactly acknowledge Agent egress ${record.payload.eventId}.`
|
|
2339
|
+
);
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
async function enqueueContentReceiptAck(stores, deviceId, receipt) {
|
|
2343
|
+
const exactReceipt = AgentContentReceiptPayloadSchema.parse(receipt);
|
|
2344
|
+
if (exactReceipt.eventId !== exactReceipt.requestId) {
|
|
2345
|
+
throw new ByokCloudError("mailbox_receipt_mismatch", "Content receipt eventId must equal requestId.");
|
|
2346
|
+
}
|
|
2347
|
+
const payload = AgentEgressAckPayloadSchema.parse({
|
|
2348
|
+
agentRef: exactReceipt.agentRef,
|
|
2349
|
+
sessionRef: exactReceipt.sessionRef,
|
|
2350
|
+
policyRevision: exactReceipt.policyRevision,
|
|
2351
|
+
eventId: exactReceipt.eventId,
|
|
2352
|
+
cursor: exactReceipt.cursor,
|
|
2353
|
+
receiptId: exactReceipt.requestId
|
|
2354
|
+
});
|
|
2355
|
+
const message = await stores.mailbox.append({
|
|
2356
|
+
deviceId,
|
|
2357
|
+
// The request itself already occupies its bare request id in this
|
|
2358
|
+
// mailbox. A namespaced producer key keeps the ack idempotent without
|
|
2359
|
+
// returning that control envelope on duplicate receipt delivery.
|
|
2360
|
+
messageId: `agent-content-ack:${exactReceipt.requestId}`,
|
|
2361
|
+
materialize: async (seq) => {
|
|
2362
|
+
const body = encodeEnvelope(createEnvelope("agent.egress.ack", payload, { id: exactReceipt.requestId, seq }));
|
|
2363
|
+
const bytes = new TextEncoder().encode(body);
|
|
2364
|
+
return {
|
|
2365
|
+
body,
|
|
2366
|
+
bodyHash: contentHash(await options.crypto.sha256(bytes)),
|
|
2367
|
+
byteSize: BigInt(bytes.length)
|
|
2368
|
+
};
|
|
2369
|
+
}
|
|
2370
|
+
});
|
|
2371
|
+
const decoded = decodeEnvelope(message.body);
|
|
2372
|
+
if (decoded.type !== "agent.egress.ack" || decoded.seq !== message.seq || JSON.stringify(decoded.payload) !== JSON.stringify(payload)) {
|
|
2373
|
+
throw new ByokCloudError(
|
|
2374
|
+
"mailbox_receipt_mismatch",
|
|
2375
|
+
`Mailbox content receipt ${exactReceipt.requestId} does not exactly acknowledge its durable content fact.`
|
|
2055
2376
|
);
|
|
2056
2377
|
}
|
|
2057
|
-
const attempt = await stores.tasks.open({ taskId, deviceId });
|
|
2058
|
-
return { taskId, seq: message.seq, envelope, attempt };
|
|
2059
2378
|
}
|
|
2060
2379
|
return {
|
|
2061
2380
|
fetch: registry.fetch,
|
|
@@ -2070,6 +2389,7 @@ function createByokCloud(options) {
|
|
|
2070
2389
|
tenant,
|
|
2071
2390
|
deviceId,
|
|
2072
2391
|
input.taskId,
|
|
2392
|
+
void 0,
|
|
2073
2393
|
(taskId, seq, messageId) => createEnvelope("task.offer", input.payload, { id: messageId, taskId, seq })
|
|
2074
2394
|
);
|
|
2075
2395
|
},
|
|
@@ -2078,9 +2398,69 @@ function createByokCloud(options) {
|
|
|
2078
2398
|
tenant,
|
|
2079
2399
|
deviceId,
|
|
2080
2400
|
input.taskId,
|
|
2401
|
+
void 0,
|
|
2081
2402
|
(taskId, seq, messageId) => createEnvelope("task.offer_with_toolsets", input.payload, { id: messageId, taskId, seq })
|
|
2082
2403
|
);
|
|
2083
2404
|
},
|
|
2405
|
+
async enqueueAgentOffer(tenant, deviceId, input) {
|
|
2406
|
+
await assertAgentCapabilities(tenant, deviceId, [AGENT_HOME_CONTRACT_CAPABILITY]);
|
|
2407
|
+
const payload = TaskOfferForAgentPayloadSchema.parse(input.payload);
|
|
2408
|
+
return enqueueTaskEnvelope(
|
|
2409
|
+
tenant,
|
|
2410
|
+
deviceId,
|
|
2411
|
+
input.taskId,
|
|
2412
|
+
payload.agentRef,
|
|
2413
|
+
(taskId, seq, messageId) => createEnvelope("task.offer_for_agent", payload, { id: messageId, taskId, seq })
|
|
2414
|
+
);
|
|
2415
|
+
},
|
|
2416
|
+
async enqueueAgentEgressOffer(tenant, deviceId, input) {
|
|
2417
|
+
await assertAgentCapabilities(tenant, deviceId, [
|
|
2418
|
+
AGENT_HOME_CONTRACT_CAPABILITY,
|
|
2419
|
+
AGENT_EGRESS_POLICY_CAPABILITY,
|
|
2420
|
+
AGENT_EGRESS_RELIABLE_ACK_CAPABILITY
|
|
2421
|
+
]);
|
|
2422
|
+
const payload = TaskOfferForAgentWithEgressPayloadSchema.parse(input.payload);
|
|
2423
|
+
return enqueueTaskEnvelope(
|
|
2424
|
+
tenant,
|
|
2425
|
+
deviceId,
|
|
2426
|
+
input.taskId,
|
|
2427
|
+
payload.agentRef,
|
|
2428
|
+
(taskId, seq, messageId) => createEnvelope("task.offer_for_agent_with_egress", payload, { id: messageId, taskId, seq })
|
|
2429
|
+
);
|
|
2430
|
+
},
|
|
2431
|
+
async enqueueAgentContentRead(tenant, deviceId, input) {
|
|
2432
|
+
const payload = AgentContentReadPayloadSchema.parse(input.payload);
|
|
2433
|
+
await assertAgentCapabilities(tenant, deviceId, [
|
|
2434
|
+
AGENT_HOME_CONTRACT_CAPABILITY,
|
|
2435
|
+
AGENT_EGRESS_POLICY_CAPABILITY,
|
|
2436
|
+
AGENT_EGRESS_RELIABLE_ACK_CAPABILITY,
|
|
2437
|
+
contentReadCapability2(payload.surface)
|
|
2438
|
+
]);
|
|
2439
|
+
const stores = tenantStoresFor(controlPlane(tenant), root);
|
|
2440
|
+
const persisted = await stores.receipts.record({
|
|
2441
|
+
key: `agent-content-request:${deviceId}:${payload.requestId}`,
|
|
2442
|
+
body: JSON.stringify(payload)
|
|
2443
|
+
});
|
|
2444
|
+
if (!persisted.created && persisted.receipt.body !== JSON.stringify(payload)) {
|
|
2445
|
+
throw new ByokCloudError(
|
|
2446
|
+
"agent_content_request_mismatch",
|
|
2447
|
+
`Request ${payload.requestId} already exists with a different immutable content-read body.`
|
|
2448
|
+
);
|
|
2449
|
+
}
|
|
2450
|
+
const control = await enqueueAgentControlEnvelope(
|
|
2451
|
+
tenant,
|
|
2452
|
+
deviceId,
|
|
2453
|
+
payload.requestId,
|
|
2454
|
+
(seq) => createEnvelope("agent.content.read", payload, { id: payload.requestId, seq })
|
|
2455
|
+
);
|
|
2456
|
+
if (control.envelope.type !== "agent.content.read" || JSON.stringify(control.envelope.payload) !== JSON.stringify(payload)) {
|
|
2457
|
+
throw new ByokCloudError(
|
|
2458
|
+
"agent_content_request_mismatch",
|
|
2459
|
+
`Request ${payload.requestId} already exists with a different immutable content-read body.`
|
|
2460
|
+
);
|
|
2461
|
+
}
|
|
2462
|
+
return control;
|
|
2463
|
+
},
|
|
2084
2464
|
async cancelTask(tenant, taskId, reason) {
|
|
2085
2465
|
const stores = tenantStoresFor(controlPlane(tenant), root);
|
|
2086
2466
|
const proposedMessageId = options.crypto.randomUuid();
|
|
@@ -2123,6 +2503,9 @@ function createByokCloud(options) {
|
|
|
2123
2503
|
readTerminalReceipt(tenant, taskId) {
|
|
2124
2504
|
return tenantStoresFor(controlPlane(tenant), root).receipts.get(terminalReceiptKey(taskId));
|
|
2125
2505
|
},
|
|
2506
|
+
readAgentEgress(tenant, deviceId, eventId) {
|
|
2507
|
+
return tenantStoresFor(controlPlane(tenant), root).egress.get(deviceId, eventId);
|
|
2508
|
+
},
|
|
2126
2509
|
async readTaskResult(tenant, taskId) {
|
|
2127
2510
|
const stores = tenantStoresFor(controlPlane(tenant), root);
|
|
2128
2511
|
const attempt = await stores.tasks.get(taskId);
|
|
@@ -2130,7 +2513,9 @@ function createByokCloud(options) {
|
|
|
2130
2513
|
return {
|
|
2131
2514
|
taskId,
|
|
2132
2515
|
state: "cancelled",
|
|
2516
|
+
...attempt.agentRef === void 0 ? {} : { agentRef: attempt.agentRef },
|
|
2133
2517
|
...attempt.cancellation.reason === void 0 ? {} : { reason: attempt.cancellation.reason },
|
|
2518
|
+
...attempt.cancellation.reason === void 0 ? {} : { terminalCause: attempt.cancellation.reason },
|
|
2134
2519
|
recordedAt: attempt.cancellation.requestedAt
|
|
2135
2520
|
};
|
|
2136
2521
|
}
|
|
@@ -2235,9 +2620,9 @@ var InMemoryBlobRegistry = class {
|
|
|
2235
2620
|
crypto;
|
|
2236
2621
|
secret;
|
|
2237
2622
|
urlTtlMs;
|
|
2238
|
-
constructor(clock,
|
|
2623
|
+
constructor(clock, crypto2, options) {
|
|
2239
2624
|
this.clock = clock;
|
|
2240
|
-
this.crypto =
|
|
2625
|
+
this.crypto = crypto2;
|
|
2241
2626
|
this.secret = globalThis.crypto.getRandomValues(new Uint8Array(SIGNING_SECRET_BYTES));
|
|
2242
2627
|
this.urlTtlMs = options.urlTtlMs ?? BLOB_URL_TTL_MS;
|
|
2243
2628
|
}
|
|
@@ -2342,14 +2727,20 @@ var InMemoryBlobContentProxy = class {
|
|
|
2342
2727
|
record.uploaded = true;
|
|
2343
2728
|
return { ok: true };
|
|
2344
2729
|
}
|
|
2730
|
+
/**
|
|
2731
|
+
* Never returns `{ok:false}`: this composition holds the bytes in the same
|
|
2732
|
+
* process, so there is no upstream to be unreachable and no stream to be
|
|
2733
|
+
* interrupted. Both `BlobReadErrorCode`s are structurally unreachable here
|
|
2734
|
+
* — a proxy that fetches from object storage is where they become live.
|
|
2735
|
+
*/
|
|
2345
2736
|
async readContent(blobId) {
|
|
2346
2737
|
const record = this.#registry.blobs.get(blobId);
|
|
2347
2738
|
if (record === void 0 || !record.uploaded || record.data === void 0) return void 0;
|
|
2348
|
-
return { data: record.data, contentType: record.contentType };
|
|
2739
|
+
return { ok: true, content: { data: record.data, contentType: record.contentType } };
|
|
2349
2740
|
}
|
|
2350
2741
|
};
|
|
2351
|
-
function createInMemoryBlobs(clock,
|
|
2352
|
-
const registry = new InMemoryBlobRegistry(clock,
|
|
2742
|
+
function createInMemoryBlobs(clock, crypto2, objects, options = {}) {
|
|
2743
|
+
const registry = new InMemoryBlobRegistry(clock, crypto2, options);
|
|
2353
2744
|
return {
|
|
2354
2745
|
blobs: new InMemoryCloudBlobStore(registry, objects),
|
|
2355
2746
|
contentProxy: new InMemoryBlobContentProxy(registry)
|
|
@@ -2392,6 +2783,17 @@ var InMemoryDeviceDirectory = class {
|
|
|
2392
2783
|
if (record === void 0) return;
|
|
2393
2784
|
this.#byTenant.set(key, { ...record, revoked: true });
|
|
2394
2785
|
}
|
|
2786
|
+
async recordCapabilities(tenant, input) {
|
|
2787
|
+
const key = tenantKey(tenant, input.deviceId);
|
|
2788
|
+
const record = this.#byTenant.get(key);
|
|
2789
|
+
if (record === void 0 || record.revoked) return void 0;
|
|
2790
|
+
const updated = {
|
|
2791
|
+
...record,
|
|
2792
|
+
capabilities: Object.freeze([...input.capabilities])
|
|
2793
|
+
};
|
|
2794
|
+
this.#byTenant.set(key, updated);
|
|
2795
|
+
return updated;
|
|
2796
|
+
}
|
|
2395
2797
|
async list(tenant) {
|
|
2396
2798
|
const prefix = tenantKey(tenant, "");
|
|
2397
2799
|
return [...this.#byTenant.entries()].filter(([key]) => key.startsWith(prefix)).map(([, record]) => record);
|
|
@@ -2477,9 +2879,9 @@ var InMemoryNonceStore = class {
|
|
|
2477
2879
|
#clock;
|
|
2478
2880
|
#crypto;
|
|
2479
2881
|
#ttlMs;
|
|
2480
|
-
constructor(clock,
|
|
2882
|
+
constructor(clock, crypto2, ttlMs = NONCE_TTL_MS) {
|
|
2481
2883
|
this.#clock = clock;
|
|
2482
|
-
this.#crypto =
|
|
2884
|
+
this.#crypto = crypto2;
|
|
2483
2885
|
this.#ttlMs = ttlMs;
|
|
2484
2886
|
}
|
|
2485
2887
|
/** Number of records currently held (post-sweep). Test-facing only. */
|
|
@@ -2583,6 +2985,9 @@ var InMemoryProofRequestReceiptStore = class {
|
|
|
2583
2985
|
return this.#receipts.get(tenantKey(tenant, deviceId, requestId));
|
|
2584
2986
|
}
|
|
2585
2987
|
};
|
|
2988
|
+
function sameAgentRef3(left, right) {
|
|
2989
|
+
return left?.agentId === right?.agentId && left?.profileRevision === right?.profileRevision;
|
|
2990
|
+
}
|
|
2586
2991
|
var InMemoryTaskAttemptStore = class {
|
|
2587
2992
|
#state;
|
|
2588
2993
|
constructor(clock, state = new InMemoryTaskAttemptState(clock)) {
|
|
@@ -2597,6 +3002,7 @@ var InMemoryTaskAttemptStore = class {
|
|
|
2597
3002
|
tenantId: tenant,
|
|
2598
3003
|
taskId: input.taskId,
|
|
2599
3004
|
deviceId: input.deviceId,
|
|
3005
|
+
...input.agentRef === void 0 ? {} : { agentRef: { ...input.agentRef } },
|
|
2600
3006
|
status: "offered",
|
|
2601
3007
|
updatedAt: this.#now()
|
|
2602
3008
|
};
|
|
@@ -2604,6 +3010,23 @@ var InMemoryTaskAttemptStore = class {
|
|
|
2604
3010
|
return attempt;
|
|
2605
3011
|
});
|
|
2606
3012
|
}
|
|
3013
|
+
async reserveAgentOffer(tenant, input) {
|
|
3014
|
+
const key = tenantKey(tenant, input.taskId);
|
|
3015
|
+
return this.#state.mutate(key, () => {
|
|
3016
|
+
const existing = this.#state.attempts.get(key);
|
|
3017
|
+
if (existing !== void 0) return { attempt: existing, created: false };
|
|
3018
|
+
const attempt = {
|
|
3019
|
+
tenantId: tenant,
|
|
3020
|
+
taskId: input.taskId,
|
|
3021
|
+
deviceId: input.deviceId,
|
|
3022
|
+
agentRef: { ...input.agentRef },
|
|
3023
|
+
status: "offered",
|
|
3024
|
+
updatedAt: this.#now()
|
|
3025
|
+
};
|
|
3026
|
+
this.#state.attempts.set(key, attempt);
|
|
3027
|
+
return { attempt, created: true };
|
|
3028
|
+
});
|
|
3029
|
+
}
|
|
2607
3030
|
async get(tenant, taskId) {
|
|
2608
3031
|
return this.#state.attempts.get(tenantKey(tenant, taskId));
|
|
2609
3032
|
}
|
|
@@ -2634,12 +3057,18 @@ var InMemoryTaskAttemptStore = class {
|
|
|
2634
3057
|
return this.#state.mutate(key, () => {
|
|
2635
3058
|
const existing = this.#state.attempts.get(key);
|
|
2636
3059
|
if (existing === void 0) return void 0;
|
|
3060
|
+
if (existing.agentRef === void 0 !== (input.agentRef === void 0) || existing.agentRef !== void 0 && !sameAgentRef3(existing.agentRef, input.agentRef)) return existing;
|
|
2637
3061
|
if (existing.cancellation !== void 0) {
|
|
2638
3062
|
if (input.status !== "cancelled" || existing.status === "cancelled") return existing;
|
|
2639
3063
|
} else if (existing.status === "complete" || existing.status === "failed" || existing.status === "cancelled") {
|
|
2640
3064
|
return existing;
|
|
2641
3065
|
}
|
|
2642
|
-
const updated = {
|
|
3066
|
+
const updated = {
|
|
3067
|
+
...existing,
|
|
3068
|
+
status: input.status,
|
|
3069
|
+
...input.terminalCause === void 0 ? {} : { terminalCause: input.terminalCause },
|
|
3070
|
+
updatedAt: this.#now()
|
|
3071
|
+
};
|
|
2643
3072
|
this.#state.attempts.set(key, updated);
|
|
2644
3073
|
return updated;
|
|
2645
3074
|
});
|
|
@@ -2839,10 +3268,34 @@ var InMemoryApprovalTimelineStore = class {
|
|
|
2839
3268
|
return tail;
|
|
2840
3269
|
}
|
|
2841
3270
|
};
|
|
3271
|
+
var InMemoryAgentEgressStore = class {
|
|
3272
|
+
#records = /* @__PURE__ */ new Map();
|
|
3273
|
+
#clock;
|
|
3274
|
+
constructor(clock) {
|
|
3275
|
+
this.#clock = clock;
|
|
3276
|
+
}
|
|
3277
|
+
async record(tenant, input) {
|
|
3278
|
+
const key = tenantKey(tenant, `${input.deviceId}\0${input.payload.eventId}`);
|
|
3279
|
+
const existing = this.#records.get(key);
|
|
3280
|
+
if (existing !== void 0) return { record: existing, created: false };
|
|
3281
|
+
const record = {
|
|
3282
|
+
tenantId: tenant,
|
|
3283
|
+
deviceId: input.deviceId,
|
|
3284
|
+
payload: input.payload,
|
|
3285
|
+
receiptId: input.receiptId,
|
|
3286
|
+
recordedAt: this.#clock.now().toISOString()
|
|
3287
|
+
};
|
|
3288
|
+
this.#records.set(key, record);
|
|
3289
|
+
return { record, created: true };
|
|
3290
|
+
}
|
|
3291
|
+
async get(tenant, deviceId, eventId) {
|
|
3292
|
+
return this.#records.get(tenantKey(tenant, `${deviceId}\0${eventId}`));
|
|
3293
|
+
}
|
|
3294
|
+
};
|
|
2842
3295
|
|
|
2843
3296
|
// src/stores/in-memory/index.ts
|
|
2844
|
-
function createInMemoryCloudStores(clock,
|
|
2845
|
-
const blobs = createInMemoryBlobs(clock,
|
|
3297
|
+
function createInMemoryCloudStores(clock, crypto2, objects, mailbox) {
|
|
3298
|
+
const blobs = createInMemoryBlobs(clock, crypto2, objects);
|
|
2846
3299
|
const taskState = new InMemoryTaskAttemptState(clock);
|
|
2847
3300
|
const tasks = new InMemoryTaskAttemptStore(clock, taskState);
|
|
2848
3301
|
return {
|
|
@@ -2851,11 +3304,12 @@ function createInMemoryCloudStores(clock, crypto, objects, mailbox) {
|
|
|
2851
3304
|
approvals: new InMemoryApprovalTimelineStore(clock),
|
|
2852
3305
|
devices: new InMemoryDeviceDirectory(),
|
|
2853
3306
|
pairingCodes: new InMemoryPairingCodeStore(clock),
|
|
2854
|
-
nonces: new InMemoryNonceStore(clock,
|
|
3307
|
+
nonces: new InMemoryNonceStore(clock, crypto2),
|
|
2855
3308
|
dedup: new InMemoryInboundDedupStore(),
|
|
2856
3309
|
tasks,
|
|
2857
3310
|
cancellations: new InMemoryTaskCancellationStore(taskState, mailbox),
|
|
2858
3311
|
receipts: new InMemoryRequestReceiptStore(clock),
|
|
3312
|
+
egress: new InMemoryAgentEgressStore(clock),
|
|
2859
3313
|
proofReceipts: new InMemoryProofRequestReceiptStore(clock),
|
|
2860
3314
|
blobs: blobs.blobs,
|
|
2861
3315
|
rateLimiter: new AllowAllRateLimiter()
|
|
@@ -2871,11 +3325,11 @@ function systemClock() {
|
|
|
2871
3325
|
}
|
|
2872
3326
|
function createInMemoryByokCloud(options = {}) {
|
|
2873
3327
|
const clock = options.clock ?? systemClock();
|
|
2874
|
-
const
|
|
3328
|
+
const crypto2 = options.crypto ?? createWebCrypto();
|
|
2875
3329
|
const core = createInMemoryCoreStores({ clock }).stores;
|
|
2876
3330
|
const { stores, blobContentProxy } = createInMemoryCloudStores(
|
|
2877
3331
|
clock,
|
|
2878
|
-
|
|
3332
|
+
crypto2,
|
|
2879
3333
|
core.objects,
|
|
2880
3334
|
core.mailbox
|
|
2881
3335
|
);
|
|
@@ -2888,7 +3342,7 @@ function createInMemoryByokCloud(options = {}) {
|
|
|
2888
3342
|
// pairing is what keeps hosted-in-memory behavior identical to what it was
|
|
2889
3343
|
// before the port narrowed.
|
|
2890
3344
|
blobContentProxy,
|
|
2891
|
-
crypto,
|
|
3345
|
+
crypto: crypto2,
|
|
2892
3346
|
tokenSigner,
|
|
2893
3347
|
clock,
|
|
2894
3348
|
capabilities: options.capabilities ?? fullCapabilityDeclaration(),
|
|
@@ -2917,7 +3371,7 @@ function createInMemoryByokCloud(options = {}) {
|
|
|
2917
3371
|
...options.skillPacks === void 0 ? {} : { skillPacks: options.skillPacks },
|
|
2918
3372
|
...options.skillPackPageLimit === void 0 ? {} : { skillPackPageLimit: options.skillPackPageLimit }
|
|
2919
3373
|
});
|
|
2920
|
-
return { cloud, core, stores, blobContentProxy, clock, crypto };
|
|
3374
|
+
return { cloud, core, stores, blobContentProxy, clock, crypto: crypto2 };
|
|
2921
3375
|
}
|
|
2922
3376
|
function authenticateHostedDeviceAssertion(input, deps) {
|
|
2923
3377
|
return authenticateDeviceAssertion(input, {
|
|
@@ -3085,6 +3539,7 @@ var TASK_ATTEMPT_STATUSES = [
|
|
|
3085
3539
|
"failed",
|
|
3086
3540
|
"cancelled"
|
|
3087
3541
|
];
|
|
3542
|
+
var BLOB_READ_ERROR_CODES = ["blob_upstream_unavailable", "blob_upstream_stream_interrupted"];
|
|
3088
3543
|
var CLOUD_STORE_NAMES = [
|
|
3089
3544
|
"activity",
|
|
3090
3545
|
"approvals",
|
|
@@ -3095,6 +3550,7 @@ var CLOUD_STORE_NAMES = [
|
|
|
3095
3550
|
"tasks",
|
|
3096
3551
|
"cancellations",
|
|
3097
3552
|
"receipts",
|
|
3553
|
+
"egress",
|
|
3098
3554
|
"proofReceipts",
|
|
3099
3555
|
"blobs",
|
|
3100
3556
|
"rateLimiter"
|
|
@@ -3104,13 +3560,14 @@ var CLOUD_STORE_NAMES = [
|
|
|
3104
3560
|
var CLOUD_PORT_METHODS = {
|
|
3105
3561
|
activity: ["append", "read"],
|
|
3106
3562
|
approvals: ["append", "read"],
|
|
3107
|
-
devices: ["register", "get", "revoke", "list", "readiness", "resolveByDeviceId"],
|
|
3563
|
+
devices: ["register", "get", "revoke", "list", "readiness", "recordCapabilities", "resolveByDeviceId"],
|
|
3108
3564
|
pairingCodes: ["issue", "redeem"],
|
|
3109
3565
|
nonces: ["issue", "validate", "markUsed"],
|
|
3110
3566
|
dedup: ["checkAndRecord"],
|
|
3111
|
-
tasks: ["open", "get", "getMany", "claim", "recordStatus"],
|
|
3567
|
+
tasks: ["open", "reserveAgentOffer", "get", "getMany", "claim", "recordStatus"],
|
|
3112
3568
|
cancellations: ["request"],
|
|
3113
3569
|
receipts: ["record", "get"],
|
|
3570
|
+
egress: ["record", "get"],
|
|
3114
3571
|
proofReceipts: ["record", "get"],
|
|
3115
3572
|
// Three methods, not six: the byte-proxy trio moved to `BlobContentProxy`,
|
|
3116
3573
|
// which is a composition input rather than a port and therefore has no row
|
|
@@ -3128,11 +3585,12 @@ var CLOUD_PORT_INTERFACES = {
|
|
|
3128
3585
|
tasks: "TaskAttemptStore",
|
|
3129
3586
|
cancellations: "TaskCancellationStore",
|
|
3130
3587
|
receipts: "RequestReceiptStore",
|
|
3588
|
+
egress: "AgentEgressStore",
|
|
3131
3589
|
proofReceipts: "ProofRequestReceiptStore",
|
|
3132
3590
|
blobs: "CloudBlobStore",
|
|
3133
3591
|
rateLimiter: "InboundRateLimiter"
|
|
3134
3592
|
};
|
|
3135
3593
|
|
|
3136
|
-
export { ACCESS_TOKEN_TTL_SECONDS, APPROVAL_SUMMARY_MAX_BYTES, ActivityAppendRequestSchema, AllowAllRateLimiter, ApprovalObservationSchema, ApprovalTimelineEventSchema, BLOB_URL_TTL_MS, BoardFeedClient, BoardFeedRetryableError, BoardFeedStoppedError, ByokCloudError, CLOUD_CAPABILITIES, CLOUD_ERROR_CODES, CLOUD_PORT_INTERFACES, CLOUD_PORT_METHODS, CLOUD_STORE_NAMES, CapabilitiesResponseSchema, CloudRouteRegistry, DEDUP_RING_CAPACITY, DEFAULT_ACTIVITY_BOUNDS, DEFAULT_ACTIVITY_CAPACITY, DEFAULT_ACTIVITY_MAX_BYTES, DEFAULT_ACTIVITY_MAX_EVENTS, DEFAULT_ACTIVITY_TTL_MS, DEFAULT_APPROVAL_TIMELINE_CAPACITY, DEFAULT_APPROVAL_TIMELINE_TTL_MS, DEFAULT_BOARD_CHANNEL_MAX_BYTES, DEFAULT_BOARD_PAGE_LIMIT, DEFAULT_BOARD_STREAM_HEARTBEAT_INTERVAL_MS, DEFAULT_BOARD_STREAM_QUERY_INTERVAL_MS, DEFAULT_BOARD_STREAM_RECONCILIATION_INTERVAL_MS, DEFAULT_BOARD_TITLE_MAX_BYTES, DEFAULT_DEVICE_PROOF_CLOCK_SKEW_MS, DEFAULT_DEVICE_PROOF_MAX_LIFETIME_MS, DEFAULT_EVENTS_PAGE_LIMIT, DEFAULT_LONG_POLL_HOLD_MS, DEFAULT_LONG_POLL_INTERVAL_MS, DEFAULT_MAX_BLOB_SIZE_BYTES, DEFAULT_MAX_TRUTH_REQUEST_BYTES, DEFAULT_PRESENCE_DETAIL_MAX_BYTES, DEFAULT_PRESENCE_MINIMUM_INTERVAL_MS, DEFAULT_PRESENCE_TTL_MS, DEFAULT_SKILL_PACK_PAGE_LIMIT, DEVICE_IDENTITY_PROOF_KEY_EPOCH, DEVICE_IDENTITY_PROOF_KEY_ID, InMemoryActivityStore, InMemoryBlobContentProxy, InMemoryCloudBlobStore, InMemoryDeviceDirectory, InMemoryInboundDedupStore, InMemoryNonceStore, InMemoryPairingCodeStore, InMemoryProofRequestReceiptStore, InMemoryRequestReceiptStore, InMemoryTaskAttemptStore, InMemoryTaskCancellationStore, MAX_DEVICE_PROOF_CLOCK_SKEW_MS, MAX_DEVICE_PROOF_HEADER_BYTES, MAX_DEVICE_PROOF_MAX_LIFETIME_MS, NONCE_TTL_MS, PAIRING_CODE_TTL_MS, ROUTE_CLASSES, ROUTE_METHODS, TASK_ATTEMPT_STATUSES, TRUTH_BATCH_MAX_RECORDS, TRUTH_INLINE_CONTENT_TYPE, TRUTH_LABEL_MAX_LENGTH, TRUTH_MANIFEST_MAX_LIMIT, TRUTH_RECORD_CAPABILITY, TRUTH_RECORD_KEY_MAX_LENGTH, TRUTH_REQUEST_ID_MAX_LENGTH, TimelineEventSchema, TruthBodyInputSchema, TruthCommitError, TruthCommitResponseSchema, TruthRecordKeySchema, TruthRecordMetadataSchema, TruthWriteRequestSchema, activityCursor, approvalTimelineCursor, authenticateBearer, authenticateDeviceProof, authenticateHostedDeviceAssertion, createAuthPlane, createByokCloud, createHmacTokenSigner, createInMemoryBlobs, createInMemoryByokCloud, createInMemoryCloudStores, createWebCrypto, declares, extractBearerToken, fullCapabilityDeclaration, handleInboundEnvelope, isCloudError, isTruthCommitError, parseApprovalObservations, parseTimelineEvents, projectTerminalResult, projectTimelineEvents, routeKey, tenantStoresFor, terminalReceiptKey, truthManifestMetadata, truthRecordMetadata, validateActivityAppend, validateApprovalTimelineAppend, verifyNonceSignature };
|
|
3594
|
+
export { ACCESS_TOKEN_TTL_SECONDS, AGENT_HOME_CONTRACT_CAPABILITY, APPROVAL_SUMMARY_MAX_BYTES, ActivityAppendRequestSchema, AllowAllRateLimiter, ApprovalObservationSchema, ApprovalTimelineEventSchema, BLOB_READ_ERROR_CODES, BLOB_URL_TTL_MS, BoardFeedClient, BoardFeedRetryableError, BoardFeedStoppedError, ByokCloudError, CLOUD_CAPABILITIES, CLOUD_ERROR_CODES, CLOUD_PORT_INTERFACES, CLOUD_PORT_METHODS, CLOUD_STORE_NAMES, CapabilitiesResponseSchema, CloudRouteRegistry, DEDUP_RING_CAPACITY, DEFAULT_ACTIVITY_BOUNDS, DEFAULT_ACTIVITY_CAPACITY, DEFAULT_ACTIVITY_MAX_BYTES, DEFAULT_ACTIVITY_MAX_EVENTS, DEFAULT_ACTIVITY_TTL_MS, DEFAULT_APPROVAL_TIMELINE_CAPACITY, DEFAULT_APPROVAL_TIMELINE_TTL_MS, DEFAULT_BOARD_CHANNEL_MAX_BYTES, DEFAULT_BOARD_PAGE_LIMIT, DEFAULT_BOARD_STREAM_HEARTBEAT_INTERVAL_MS, DEFAULT_BOARD_STREAM_QUERY_INTERVAL_MS, DEFAULT_BOARD_STREAM_RECONCILIATION_INTERVAL_MS, DEFAULT_BOARD_TITLE_MAX_BYTES, DEFAULT_DEVICE_PROOF_CLOCK_SKEW_MS, DEFAULT_DEVICE_PROOF_MAX_LIFETIME_MS, DEFAULT_EVENTS_PAGE_LIMIT, DEFAULT_LONG_POLL_HOLD_MS, DEFAULT_LONG_POLL_INTERVAL_MS, DEFAULT_MAX_BLOB_SIZE_BYTES, DEFAULT_MAX_TRUTH_REQUEST_BYTES, DEFAULT_PRESENCE_DETAIL_MAX_BYTES, DEFAULT_PRESENCE_MINIMUM_INTERVAL_MS, DEFAULT_PRESENCE_TTL_MS, DEFAULT_SKILL_PACK_PAGE_LIMIT, DEVICE_IDENTITY_PROOF_KEY_EPOCH, DEVICE_IDENTITY_PROOF_KEY_ID, InMemoryActivityStore, InMemoryAgentEgressStore, InMemoryBlobContentProxy, InMemoryCloudBlobStore, InMemoryDeviceDirectory, InMemoryInboundDedupStore, InMemoryNonceStore, InMemoryPairingCodeStore, InMemoryProofRequestReceiptStore, InMemoryRequestReceiptStore, InMemoryTaskAttemptStore, InMemoryTaskCancellationStore, MAX_DEVICE_PROOF_CLOCK_SKEW_MS, MAX_DEVICE_PROOF_HEADER_BYTES, MAX_DEVICE_PROOF_MAX_LIFETIME_MS, NONCE_TTL_MS, PAIRING_CODE_TTL_MS, ROUTE_CLASSES, ROUTE_METHODS, TASK_ATTEMPT_STATUSES, TRUTH_BATCH_MAX_RECORDS, TRUTH_INLINE_CONTENT_TYPE, TRUTH_LABEL_MAX_LENGTH, TRUTH_MANIFEST_MAX_LIMIT, TRUTH_RECORD_CAPABILITY, TRUTH_RECORD_KEY_MAX_LENGTH, TRUTH_REQUEST_ID_MAX_LENGTH, TimelineEventSchema, TruthBodyInputSchema, TruthCommitError, TruthCommitResponseSchema, TruthRecordKeySchema, TruthRecordMetadataSchema, TruthWriteRequestSchema, activityCursor, approvalTimelineCursor, authenticateBearer, authenticateDeviceProof, authenticateHostedDeviceAssertion, createAuthPlane, createByokCloud, createHmacTokenSigner, createInMemoryBlobs, createInMemoryByokCloud, createInMemoryCloudStores, createWebCrypto, declares, extractBearerToken, fullCapabilityDeclaration, handleInboundEnvelope, isCloudError, isTruthCommitError, parseApprovalObservations, parseTimelineEvents, projectTerminalResult, projectTimelineEvents, routeKey, tenantStoresFor, terminalReceiptKey, truthManifestMetadata, truthRecordMetadata, validateActivityAppend, validateApprovalTimelineAppend, verifyNonceSignature };
|
|
3137
3595
|
//# sourceMappingURL=index.js.map
|
|
3138
3596
|
//# sourceMappingURL=index.js.map
|