@byok-sdk/cloud 0.5.0 → 0.6.1

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/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { BOARD_STATUSES, PRESENCE_LEVELS, CapabilityDeclarationSchema, NONCE_SIGNING_DOMAIN, hasCapability, isTenantId, tenantId, principalTenant, parseDeviceProofEnvelope, deviceProofSigningInput, parseCapabilityDeclaration, ByokCoreError, tenantKey, createInMemoryCoreStores, authenticateDeviceAssertion, assertCapability, contentHash, isCoreConflictError, isCoreError, DEVICE_PROOF_HEADER, TRUTH_RECORD_KINDS, STORAGE_ERROR_CODES, STORAGE_ERROR_HTTP_STATUS } from '@byok-sdk/core';
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, ConfiguredToolsetsSchema, 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, 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, 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(crypto, devicePublicKey, nonce, signature) {
164
- return crypto.verifyEd25519(devicePublicKey, NONCE_SIGNING_DOMAIN + nonce, signature);
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: crypto.randomPairingCode(PAIRING_CODE_LENGTH),
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_${crypto.randomUuid()}`,
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(crypto, device.devicePublicKey, nonce, signature);
211
+ return verifyNonceSignature(crypto2, device.devicePublicKey, nonce, signature);
212
212
  },
213
213
  async mintAccessToken(device) {
214
214
  const accessToken = await tokenSigner.sign(
@@ -317,7 +317,19 @@ var CLOUD_ERROR_CODES = {
317
317
  */
318
318
  terminal_receipt_unreadable: "terminal_receipt_unreadable",
319
319
  /** A progress/activity batch exceeded the configured event or byte ceiling. */
320
- activity_batch_too_large: "activity_batch_too_large"
320
+ activity_batch_too_large: "activity_batch_too_large",
321
+ /** Host control-plane task lookup is tenant-closed and found no task. */
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"
321
333
  };
322
334
  var ByokCloudError = class extends Error {
323
335
  code;
@@ -524,14 +536,24 @@ function tenantStoresFor(principal, root) {
524
536
  devices: {
525
537
  get: (deviceId) => cloud.devices.get(tenant, deviceId),
526
538
  list: () => cloud.devices.list(tenant),
527
- revoke: (deviceId) => cloud.devices.revoke(tenant, deviceId)
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),
544
+ readiness: () => cloud.devices.readiness(tenant, core.presence)
528
545
  },
529
546
  tasks: {
530
547
  open: (input) => cloud.tasks.open(tenant, input),
548
+ reserveAgentOffer: (input) => cloud.tasks.reserveAgentOffer(tenant, input),
531
549
  get: (taskId) => cloud.tasks.get(tenant, taskId),
550
+ getMany: (taskIds) => cloud.tasks.getMany(tenant, taskIds),
532
551
  claim: (input) => cloud.tasks.claim(tenant, input),
533
552
  recordStatus: (input) => cloud.tasks.recordStatus(tenant, input)
534
553
  },
554
+ cancellations: {
555
+ request: (input) => cloud.cancellations.request(tenant, input)
556
+ },
535
557
  dedup: {
536
558
  checkAndRecord: (deviceId, envelopeId) => cloud.dedup.checkAndRecord(tenant, deviceId, envelopeId)
537
559
  },
@@ -539,6 +561,10 @@ function tenantStoresFor(principal, root) {
539
561
  record: (input) => cloud.receipts.record(tenant, input),
540
562
  get: (key) => cloud.receipts.get(tenant, key)
541
563
  },
564
+ egress: {
565
+ record: (input) => cloud.egress.record(tenant, input),
566
+ get: (deviceId, eventId) => cloud.egress.get(tenant, deviceId, eventId)
567
+ },
542
568
  blobs: {
543
569
  createUpload: (reservation) => cloud.blobs.createUpload(tenant, reservation),
544
570
  observeUpload: (blobId, reservation) => cloud.blobs.observeUpload(tenant, blobId, reservation),
@@ -678,11 +704,16 @@ function blobDownloadContentHandler(deps) {
678
704
  if (!query.success || !await deps.contentProxy.verifySignedUrl(blobId, "get", query.data.sig, query.data.exp)) {
679
705
  return c.json({ error: "invalid or expired signature" }, 401);
680
706
  }
681
- const content = await deps.contentProxy.readContent(blobId);
682
- if (content === void 0) return c.json({ error: "blob not found" }, 404);
683
- return c.body(new Uint8Array(content.data), 200, { "content-type": content.contentType });
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 });
684
711
  };
685
712
  }
713
+ var BLOB_READ_ERROR_HTTP_STATUS = {
714
+ blob_upstream_unavailable: 502,
715
+ blob_upstream_stream_interrupted: 502
716
+ };
686
717
  function idempotencyKey(c) {
687
718
  const value = c.req.header("Idempotency-Key");
688
719
  if (value === void 0 || value.length === 0 || value.length > 200) return void 0;
@@ -752,7 +783,15 @@ function tokenHandler(deps) {
752
783
  return c.json(response, 200);
753
784
  };
754
785
  }
755
- var CLOUD_PROTOCOL_CAPABILITIES = ["result-document"];
786
+ var CLOUD_PROTOCOL_CAPABILITIES = [
787
+ "result-document",
788
+ "agent-home-contract",
789
+ "agent-egress-policy",
790
+ "agent-egress-reliable-ack",
791
+ "agent-content-workspace-read",
792
+ "agent-content-transcript-read",
793
+ "agent-content-artifact-read"
794
+ ];
756
795
  function sleep(ms) {
757
796
  return new Promise((resolve) => setTimeout(resolve, ms));
758
797
  }
@@ -774,13 +813,32 @@ function eventsHandler(deps) {
774
813
  }
775
814
  const attempts = Math.max(1, Math.ceil(deps.longPollHoldMs / deps.longPollIntervalMs));
776
815
  for (let attempt = 0; attempt < attempts; attempt += 1) {
777
- const page = await stores.mailbox.readAfter({
778
- deviceId: device.deviceId,
779
- afterSeq: cursor,
780
- limit: deps.pageLimit
781
- });
782
- if (page.messages.length > 0) {
783
- const events = page.messages.map((message) => decodeEnvelope(message.body));
816
+ let scanCursor = cursor;
817
+ while (true) {
818
+ const page = await stores.mailbox.readAfter({
819
+ deviceId: device.deviceId,
820
+ afterSeq: scanCursor,
821
+ limit: deps.pageLimit
822
+ });
823
+ if (page.messages.length === 0) break;
824
+ const decoded = page.messages.map((message) => decodeEnvelope(message.body));
825
+ const offeredTaskIds = decoded.flatMap(
826
+ (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] : []
827
+ );
828
+ const attemptsByTaskId = Object.fromEntries(
829
+ (await stores.tasks.getMany(offeredTaskIds)).map((attempt2) => [attempt2.taskId, attempt2])
830
+ );
831
+ const events = decoded.filter((event) => {
832
+ 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") {
833
+ return true;
834
+ }
835
+ return event.task_id === void 0 || attemptsByTaskId[event.task_id]?.cancellation === void 0;
836
+ });
837
+ if (events.length === 0 && page.hasMore) {
838
+ scanCursor = page.nextSeq;
839
+ continue;
840
+ }
841
+ if (events.length === 0) break;
784
842
  const response2 = {
785
843
  events,
786
844
  cursor: page.nextSeq,
@@ -886,13 +944,103 @@ async function projectTerminalToReview(board, taskId) {
886
944
  function terminalReceiptKey(taskId) {
887
945
  return `task:${taskId}:terminal`;
888
946
  }
947
+ function sameAgentRef(expected, actual) {
948
+ return actual?.agentId === expected.agentId && actual.profileRevision === expected.profileRevision;
949
+ }
950
+ function sameReliableEgress(expected, actual) {
951
+ 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);
952
+ }
953
+ function contentReadCapability(surface) {
954
+ switch (surface) {
955
+ case "workspace":
956
+ return AGENT_CONTENT_WORKSPACE_READ_CAPABILITY;
957
+ case "transcript":
958
+ return AGENT_CONTENT_TRANSCRIPT_READ_CAPABILITY;
959
+ case "artifact":
960
+ return AGENT_CONTENT_ARTIFACT_READ_CAPABILITY;
961
+ }
962
+ }
963
+ function hasCapabilities(capabilities, required) {
964
+ return capabilities !== void 0 && required.every((capability) => capabilities.includes(capability));
965
+ }
966
+ function contentRequestReceiptKey(deviceId, requestId) {
967
+ return `agent-content-request:${deviceId}:${requestId}`;
968
+ }
969
+ function contentReceiptKey(deviceId, requestId) {
970
+ return `agent-content:${deviceId}:${requestId}`;
971
+ }
972
+ function matchesContentReadReceipt(request, receipt) {
973
+ 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;
974
+ }
975
+ async function readContentRequest(stores, deviceId, requestId) {
976
+ const stored = await stores.receipts.get(contentRequestReceiptKey(deviceId, requestId));
977
+ if (stored === void 0) return void 0;
978
+ try {
979
+ return AgentContentReadPayloadSchema.parse(JSON.parse(stored.body));
980
+ } catch {
981
+ return void 0;
982
+ }
983
+ }
984
+ function inboundAgentRef(envelope) {
985
+ switch (envelope.type) {
986
+ case "task.claim":
987
+ case "task.decline":
988
+ case "task.complete":
989
+ case "task.fail":
990
+ case "task.cancelled":
991
+ return envelope.payload.agentRef;
992
+ default:
993
+ return void 0;
994
+ }
995
+ }
996
+ function agentRefEchoRequired(envelope) {
997
+ return envelope.type === "task.claim" || envelope.type === "task.decline" || envelope.type === "task.complete" || envelope.type === "task.fail" || envelope.type === "task.cancelled";
998
+ }
889
999
  async function handleInboundEnvelope(stores, deviceId, envelope, activityBounds = DEFAULT_ACTIVITY_BOUNDS) {
890
1000
  if (!await stores.rateLimiter.consume(deviceId)) return "rate_limited";
1001
+ if (envelope.type === "conn.hello") {
1002
+ if (envelope.payload.deviceId !== deviceId) return "rejected";
1003
+ if (!envelope.payload.protocolVersions.includes(PROTOCOL_VERSION)) return "rejected";
1004
+ const device = await stores.devices.get(deviceId);
1005
+ if (device === void 0 || device.revoked || device.productId !== envelope.payload.productId) {
1006
+ return "rejected";
1007
+ }
1008
+ if (await stores.dedup.checkAndRecord(deviceId, envelope.id)) return "duplicate";
1009
+ return await stores.devices.recordCapabilities({ capabilities: envelope.payload.capabilities }) === void 0 ? "rejected" : "accepted";
1010
+ }
891
1011
  if (!DAEMON_TO_SERVER_TYPES.includes(envelope.type)) return "rejected";
1012
+ if (envelope.type === "agent.egress.reliable") {
1013
+ const device = await stores.devices.get(deviceId);
1014
+ if (device === void 0 || device.revoked || !hasCapabilities(device.capabilities, [AGENT_EGRESS_POLICY_CAPABILITY, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY])) {
1015
+ return "rejected";
1016
+ }
1017
+ const outcome = await stores.egress.record({
1018
+ deviceId,
1019
+ payload: envelope.payload,
1020
+ receiptId: crypto.randomUUID()
1021
+ });
1022
+ return outcome.created || sameReliableEgress(outcome.record.payload, envelope.payload) ? outcome.created ? "accepted" : "duplicate" : "rejected";
1023
+ }
1024
+ if (envelope.type === "agent.content.receipt") {
1025
+ const device = await stores.devices.get(deviceId);
1026
+ if (device === void 0 || device.revoked || envelope.payload.eventId !== envelope.payload.requestId || !hasCapabilities(device.capabilities, [contentReadCapability(envelope.payload.surface), AGENT_EGRESS_RELIABLE_ACK_CAPABILITY])) {
1027
+ return "rejected";
1028
+ }
1029
+ const request = await readContentRequest(stores, deviceId, envelope.payload.requestId);
1030
+ if (request === void 0 || !matchesContentReadReceipt(request, envelope.payload)) return "rejected";
1031
+ const key = contentReceiptKey(deviceId, envelope.payload.requestId);
1032
+ const body = JSON.stringify(envelope.payload);
1033
+ const receipt = await stores.receipts.record({ key, body });
1034
+ return receipt.created ? "accepted" : receipt.receipt.body === body ? "duplicate" : "rejected";
1035
+ }
892
1036
  const taskId = envelope.task_id;
893
1037
  if (taskId === void 0) return "rejected";
894
1038
  const attempt = await stores.tasks.get(taskId);
1039
+ if (attempt?.agentRef !== void 0 && attempt.deviceId !== deviceId) return "rejected";
895
1040
  if (attempt?.ownerDeviceId !== void 0 && attempt.ownerDeviceId !== deviceId) return "rejected";
1041
+ if (attempt?.agentRef !== void 0 && agentRefEchoRequired(envelope) && !sameAgentRef(attempt.agentRef, inboundAgentRef(envelope))) {
1042
+ return "rejected";
1043
+ }
896
1044
  if (envelope.type === "task.progress" && envelope.payload.events.length > 0) {
897
1045
  try {
898
1046
  validateActivityBatch(
@@ -922,19 +1070,27 @@ async function handleInboundEnvelope(stores, deviceId, envelope, activityBounds
922
1070
  }
923
1071
  }
924
1072
  if (await stores.dedup.checkAndRecord(deviceId, envelope.id)) return "duplicate";
925
- await applyLifecycle(stores, deviceId, taskId, envelope, activityBounds);
1073
+ await applyLifecycle(stores, deviceId, taskId, envelope, activityBounds, attempt?.agentRef);
926
1074
  return "accepted";
927
1075
  }
928
- async function applyLifecycle(stores, deviceId, taskId, envelope, activityBounds) {
1076
+ async function applyLifecycle(stores, deviceId, taskId, envelope, activityBounds, persistedAgentRef) {
929
1077
  switch (envelope.type) {
930
1078
  case "task.claim":
931
1079
  await stores.tasks.claim({ taskId, deviceId });
932
1080
  return;
933
1081
  case "task.started":
934
- await stores.tasks.recordStatus({ taskId, status: "running" });
1082
+ await stores.tasks.recordStatus({
1083
+ taskId,
1084
+ status: "running",
1085
+ ...persistedAgentRef === void 0 ? {} : { agentRef: persistedAgentRef }
1086
+ });
935
1087
  return;
936
1088
  case "task.decline":
937
- await stores.tasks.recordStatus({ taskId, status: "failed" });
1089
+ await stores.tasks.recordStatus({
1090
+ taskId,
1091
+ status: "failed",
1092
+ ...persistedAgentRef === void 0 ? {} : { agentRef: persistedAgentRef }
1093
+ });
938
1094
  return;
939
1095
  case "task.progress":
940
1096
  if (envelope.payload.events.length > 0) {
@@ -999,12 +1155,30 @@ function approvalTimelineAppendInput(taskId, envelope) {
999
1155
  }
1000
1156
  }
1001
1157
  async function recordTerminal(stores, taskId, envelope, status) {
1158
+ const attempt = await stores.tasks.get(taskId);
1002
1159
  const { created } = await stores.receipts.record({
1003
1160
  key: terminalReceiptKey(taskId),
1004
1161
  body: encodeEnvelope(envelope)
1005
1162
  });
1163
+ if (attempt?.cancellation !== void 0) {
1164
+ if (status === "cancelled") {
1165
+ await stores.tasks.recordStatus({
1166
+ taskId,
1167
+ status: "cancelled",
1168
+ ...attempt.agentRef === void 0 ? {} : { agentRef: attempt.agentRef }
1169
+ });
1170
+ }
1171
+ return;
1172
+ }
1006
1173
  if (!created) return;
1007
- await stores.tasks.recordStatus({ taskId, status });
1174
+ const cause = envelope.type === "task.fail" || envelope.type === "task.cancelled" ? envelope.payload.reason : void 0;
1175
+ const recordedAttempt = await stores.tasks.recordStatus({
1176
+ taskId,
1177
+ status,
1178
+ ...attempt?.agentRef === void 0 ? {} : { agentRef: attempt.agentRef },
1179
+ ...cause === void 0 ? {} : { terminalCause: cause }
1180
+ });
1181
+ if (recordedAttempt?.status !== status || recordedAttempt.cancellation !== void 0) return;
1008
1182
  await projectTerminalToReview(stores.board, taskId);
1009
1183
  }
1010
1184
 
@@ -1026,6 +1200,16 @@ function messagesHandler(deps) {
1026
1200
  deps.activityBounds
1027
1201
  );
1028
1202
  if (outcome === "rate_limited") return c.json({ error: "rate limit exceeded" }, 429);
1203
+ if (envelope.type === "agent.egress.reliable" && (outcome === "accepted" || outcome === "duplicate")) {
1204
+ const record = await stores.egress.get(device.deviceId, envelope.payload.eventId);
1205
+ if (record === void 0) {
1206
+ throw new Error(`Accepted reliable egress ${envelope.payload.eventId} has no durable receipt record.`);
1207
+ }
1208
+ await deps.appendReliableEgressAck(stores, record);
1209
+ }
1210
+ if (envelope.type === "agent.content.receipt" && (outcome === "accepted" || outcome === "duplicate")) {
1211
+ await deps.appendContentReceiptAck(stores, device.deviceId, envelope.payload);
1212
+ }
1029
1213
  if (outcome === "rejected") rejected += 1;
1030
1214
  else accepted += 1;
1031
1215
  }
@@ -1271,11 +1455,7 @@ function boardFailure(c, caught) {
1271
1455
  if (isCoreError(caught, "board_not_held")) return c.json({ error: caught.code }, 409);
1272
1456
  throw caught;
1273
1457
  }
1274
- var PresenceBodySchema = z.object({
1275
- level: z.enum(PRESENCE_LEVELS),
1276
- detail: z.string().optional(),
1277
- configuredToolsets: ConfiguredToolsetsSchema.optional()
1278
- });
1458
+ var PresenceBodySchema = PresencePublishRequestSchema;
1279
1459
  function presencePublishHandler(deps) {
1280
1460
  return async (c) => {
1281
1461
  const authenticated = await authenticateDevice(c, deps);
@@ -1292,6 +1472,15 @@ function presencePublishHandler(deps) {
1292
1472
  level: parsed.data.level,
1293
1473
  ...parsed.data.detail === void 0 ? {} : { detail: parsed.data.detail },
1294
1474
  ...parsed.data.configuredToolsets === void 0 ? {} : { configuredToolsets: parsed.data.configuredToolsets },
1475
+ ...parsed.data.clientVersion === void 0 ? {} : { clientVersion: parsed.data.clientVersion },
1476
+ ...parsed.data.protocolVersions === void 0 ? {} : { protocolVersions: parsed.data.protocolVersions },
1477
+ ...parsed.data.runtimes === void 0 ? {} : {
1478
+ runtimes: parsed.data.runtimes.map(({ id, version, authPresent }) => ({
1479
+ id,
1480
+ ...version === void 0 ? {} : { version },
1481
+ ...authPresent === void 0 ? {} : { authPresent }
1482
+ }))
1483
+ },
1295
1484
  ttlMs: deps.ttlMs,
1296
1485
  minimumIntervalMs: deps.minimumIntervalMs
1297
1486
  }),
@@ -1788,25 +1977,33 @@ function projectTerminalResult(taskId, receipt) {
1788
1977
  return {
1789
1978
  taskId,
1790
1979
  state: "complete",
1980
+ ...envelope.payload.agentRef === void 0 ? {} : { agentRef: envelope.payload.agentRef },
1791
1981
  summary: envelope.payload.summary,
1792
1982
  sessionRef: envelope.payload.sessionRef,
1793
1983
  ...envelope.payload.artifactRefs !== void 0 ? { artifactRefs: envelope.payload.artifactRefs } : {},
1794
1984
  ...envelope.payload.document !== void 0 ? { document: envelope.payload.document } : {},
1985
+ ...envelope.payload.usage !== void 0 ? { usage: envelope.payload.usage } : {},
1795
1986
  recordedAt: receipt.recordedAt
1796
1987
  };
1797
1988
  case "task.fail":
1798
1989
  return {
1799
1990
  taskId,
1800
1991
  state: "failed",
1992
+ ...envelope.payload.agentRef === void 0 ? {} : { agentRef: envelope.payload.agentRef },
1801
1993
  reason: envelope.payload.reason,
1994
+ terminalCause: envelope.payload.reason,
1802
1995
  ...envelope.payload.retryable !== void 0 ? { retryable: envelope.payload.retryable } : {},
1996
+ ...envelope.payload.usage !== void 0 ? { usage: envelope.payload.usage } : {},
1803
1997
  recordedAt: receipt.recordedAt
1804
1998
  };
1805
1999
  case "task.cancelled":
1806
2000
  return {
1807
2001
  taskId,
1808
2002
  state: "cancelled",
2003
+ ...envelope.payload.agentRef === void 0 ? {} : { agentRef: envelope.payload.agentRef },
1809
2004
  ...envelope.payload.reason !== void 0 ? { reason: envelope.payload.reason } : {},
2005
+ ...envelope.payload.reason === void 0 ? {} : { terminalCause: envelope.payload.reason },
2006
+ ...envelope.payload.usage !== void 0 ? { usage: envelope.payload.usage } : {},
1810
2007
  recordedAt: receipt.recordedAt
1811
2008
  };
1812
2009
  default:
@@ -1822,6 +2019,10 @@ var DEFAULT_MAX_BLOB_SIZE_BYTES = 100 * 1024 * 1024;
1822
2019
  var DEFAULT_LONG_POLL_HOLD_MS = 5e4;
1823
2020
  var DEFAULT_LONG_POLL_INTERVAL_MS = 250;
1824
2021
  var DEFAULT_EVENTS_PAGE_LIMIT = 50;
2022
+ var AGENT_HOME_CONTRACT_CAPABILITY = "agent-home-contract";
2023
+ function sameAgentRef2(expected, actual) {
2024
+ return actual?.agentId === expected.agentId && actual.profileRevision === expected.profileRevision;
2025
+ }
1825
2026
  function createByokCloud(options) {
1826
2027
  const declaration = parseDeclaration(options.capabilities);
1827
2028
  assertNoOverDeclaration(
@@ -1871,7 +2072,12 @@ function createByokCloud(options) {
1871
2072
  if (declares(declaration, CLOUD_CAPABILITIES.messagesBatch)) {
1872
2073
  registry.register(
1873
2074
  { method: "POST", path: BYOK_MESSAGES_PATH, class: "device" },
1874
- messagesHandler({ ...deviceRouteDeps, activityBounds })
2075
+ messagesHandler({
2076
+ ...deviceRouteDeps,
2077
+ activityBounds,
2078
+ appendReliableEgressAck: enqueueReliableEgressAck,
2079
+ appendContentReceiptAck: enqueueContentReceiptAck
2080
+ })
1875
2081
  );
1876
2082
  }
1877
2083
  if (declares(declaration, CLOUD_CAPABILITIES.boardCoordination)) {
@@ -1989,16 +2195,98 @@ function createByokCloud(options) {
1989
2195
  function controlPlane(tenant) {
1990
2196
  return { kind: "control-plane", tenantId: tenant, operatorId };
1991
2197
  }
1992
- async function enqueueTaskEnvelope(tenant, deviceId, requestedTaskId, buildEnvelope) {
2198
+ async function enqueueTaskEnvelope(tenant, deviceId, requestedTaskId, agentRef, buildEnvelope) {
1993
2199
  const stores = tenantStoresFor(controlPlane(tenant), root);
1994
2200
  const taskId = requestedTaskId ?? `task_${options.crypto.randomUuid()}`;
1995
2201
  const messageId = options.crypto.randomUuid();
2202
+ const reservation = agentRef === void 0 ? void 0 : await stores.tasks.reserveAgentOffer({ taskId, deviceId, agentRef });
2203
+ const openedBeforeAppend = reservation?.attempt;
2204
+ if (agentRef !== void 0 && (openedBeforeAppend === void 0 || openedBeforeAppend.deviceId !== deviceId || openedBeforeAppend.agentRef === void 0 || !sameAgentRef2(agentRef, openedBeforeAppend.agentRef))) {
2205
+ throw new ByokCloudError(
2206
+ "agent_ref_mismatch",
2207
+ `Task ${taskId} already has a different durable Agent identity or target device.`
2208
+ );
2209
+ }
2210
+ if (reservation !== void 0 && !reservation.created) {
2211
+ throw new ByokCloudError(
2212
+ "agent_task_already_exists",
2213
+ `Task ${taskId} already has a durable Agent attempt and cannot be enqueued again.`
2214
+ );
2215
+ }
2216
+ let message;
2217
+ try {
2218
+ message = await stores.mailbox.append({
2219
+ deviceId,
2220
+ messageId,
2221
+ materialize: async (seq) => {
2222
+ const envelope2 = buildEnvelope(taskId, seq, messageId);
2223
+ const body = encodeEnvelope(envelope2);
2224
+ const bytes = new TextEncoder().encode(body);
2225
+ return {
2226
+ body,
2227
+ bodyHash: contentHash(await options.crypto.sha256(bytes)),
2228
+ byteSize: BigInt(bytes.length)
2229
+ };
2230
+ }
2231
+ });
2232
+ } catch (error) {
2233
+ if (openedBeforeAppend !== void 0) {
2234
+ try {
2235
+ await stores.tasks.recordStatus({
2236
+ taskId,
2237
+ status: "failed",
2238
+ agentRef,
2239
+ terminalCause: "mailbox append failed before Agent offer delivery"
2240
+ });
2241
+ } catch (cleanupError) {
2242
+ throw new AggregateError(
2243
+ [error, cleanupError],
2244
+ `Agent task ${taskId} could not be delivered or durably closed`
2245
+ );
2246
+ }
2247
+ }
2248
+ throw error;
2249
+ }
2250
+ const envelope = decodeEnvelope(message.body);
2251
+ if (envelope.seq !== message.seq) {
2252
+ throw new ByokCloudError(
2253
+ "mailbox_seq_mismatch",
2254
+ `Mailbox stored offer seq ${String(envelope.seq)} at row ${message.seq}; the daemon's redelivery cursor would be wrong.`
2255
+ );
2256
+ }
2257
+ const attempt = openedBeforeAppend ?? await stores.tasks.open({
2258
+ taskId,
2259
+ deviceId
2260
+ });
2261
+ return { taskId, seq: message.seq, envelope, attempt };
2262
+ }
2263
+ async function assertAgentCapabilities(tenant, deviceId, required) {
2264
+ const device = await options.cloud.devices.get(tenant, deviceId);
2265
+ if (device === void 0 || device.revoked || !device.capabilities || !required.every((capability) => device.capabilities.includes(capability))) {
2266
+ const missing = required.filter((capability) => !device?.capabilities?.includes(capability));
2267
+ throw new ByokCloudError(
2268
+ "agent_capability_missing",
2269
+ `Device ${deviceId} lacks durable Agent capabilities (${missing.join(", ")}); refusing before mailbox append.`
2270
+ );
2271
+ }
2272
+ }
2273
+ function contentReadCapability2(surface) {
2274
+ switch (surface) {
2275
+ case "workspace":
2276
+ return AGENT_CONTENT_WORKSPACE_READ_CAPABILITY;
2277
+ case "transcript":
2278
+ return AGENT_CONTENT_TRANSCRIPT_READ_CAPABILITY;
2279
+ case "artifact":
2280
+ return AGENT_CONTENT_ARTIFACT_READ_CAPABILITY;
2281
+ }
2282
+ }
2283
+ async function enqueueAgentControlEnvelope(tenant, deviceId, messageId, buildEnvelope) {
2284
+ const stores = tenantStoresFor(controlPlane(tenant), root);
1996
2285
  const message = await stores.mailbox.append({
1997
2286
  deviceId,
1998
2287
  messageId,
1999
2288
  materialize: async (seq) => {
2000
- const envelope2 = buildEnvelope(taskId, seq, messageId);
2001
- const body = encodeEnvelope(envelope2);
2289
+ const body = encodeEnvelope(buildEnvelope(seq));
2002
2290
  const bytes = new TextEncoder().encode(body);
2003
2291
  return {
2004
2292
  body,
@@ -2011,11 +2299,77 @@ function createByokCloud(options) {
2011
2299
  if (envelope.seq !== message.seq) {
2012
2300
  throw new ByokCloudError(
2013
2301
  "mailbox_seq_mismatch",
2014
- `Mailbox stored offer seq ${String(envelope.seq)} at row ${message.seq}; the daemon's redelivery cursor would be wrong.`
2302
+ `Mailbox stored Agent control seq ${String(envelope.seq)} at row ${message.seq}.`
2303
+ );
2304
+ }
2305
+ return { seq: message.seq, envelope };
2306
+ }
2307
+ async function enqueueReliableEgressAck(stores, record) {
2308
+ const payload = AgentEgressAckPayloadSchema.parse({
2309
+ agentRef: record.payload.agentRef,
2310
+ sessionRef: record.payload.sessionRef,
2311
+ policyRevision: record.payload.policyRevision,
2312
+ eventId: record.payload.eventId,
2313
+ cursor: record.payload.cursor,
2314
+ receiptId: record.receiptId
2315
+ });
2316
+ const message = await stores.mailbox.append({
2317
+ deviceId: record.deviceId,
2318
+ messageId: record.receiptId,
2319
+ materialize: async (seq) => {
2320
+ const body = encodeEnvelope(createEnvelope("agent.egress.ack", payload, { id: record.receiptId, seq }));
2321
+ const bytes = new TextEncoder().encode(body);
2322
+ return {
2323
+ body,
2324
+ bodyHash: contentHash(await options.crypto.sha256(bytes)),
2325
+ byteSize: BigInt(bytes.length)
2326
+ };
2327
+ }
2328
+ });
2329
+ const decoded = decodeEnvelope(message.body);
2330
+ if (decoded.type !== "agent.egress.ack" || decoded.seq !== message.seq || JSON.stringify(decoded.payload) !== JSON.stringify(payload)) {
2331
+ throw new ByokCloudError(
2332
+ "mailbox_receipt_mismatch",
2333
+ `Mailbox receipt ${record.receiptId} does not exactly acknowledge Agent egress ${record.payload.eventId}.`
2334
+ );
2335
+ }
2336
+ }
2337
+ async function enqueueContentReceiptAck(stores, deviceId, receipt) {
2338
+ const exactReceipt = AgentContentReceiptPayloadSchema.parse(receipt);
2339
+ if (exactReceipt.eventId !== exactReceipt.requestId) {
2340
+ throw new ByokCloudError("mailbox_receipt_mismatch", "Content receipt eventId must equal requestId.");
2341
+ }
2342
+ const payload = AgentEgressAckPayloadSchema.parse({
2343
+ agentRef: exactReceipt.agentRef,
2344
+ sessionRef: exactReceipt.sessionRef,
2345
+ policyRevision: exactReceipt.policyRevision,
2346
+ eventId: exactReceipt.eventId,
2347
+ cursor: exactReceipt.cursor,
2348
+ receiptId: exactReceipt.requestId
2349
+ });
2350
+ const message = await stores.mailbox.append({
2351
+ deviceId,
2352
+ // The request itself already occupies its bare request id in this
2353
+ // mailbox. A namespaced producer key keeps the ack idempotent without
2354
+ // returning that control envelope on duplicate receipt delivery.
2355
+ messageId: `agent-content-ack:${exactReceipt.requestId}`,
2356
+ materialize: async (seq) => {
2357
+ const body = encodeEnvelope(createEnvelope("agent.egress.ack", payload, { id: exactReceipt.requestId, seq }));
2358
+ const bytes = new TextEncoder().encode(body);
2359
+ return {
2360
+ body,
2361
+ bodyHash: contentHash(await options.crypto.sha256(bytes)),
2362
+ byteSize: BigInt(bytes.length)
2363
+ };
2364
+ }
2365
+ });
2366
+ const decoded = decodeEnvelope(message.body);
2367
+ if (decoded.type !== "agent.egress.ack" || decoded.seq !== message.seq || JSON.stringify(decoded.payload) !== JSON.stringify(payload)) {
2368
+ throw new ByokCloudError(
2369
+ "mailbox_receipt_mismatch",
2370
+ `Mailbox content receipt ${exactReceipt.requestId} does not exactly acknowledge its durable content fact.`
2015
2371
  );
2016
2372
  }
2017
- const attempt = await stores.tasks.open({ taskId, deviceId });
2018
- return { taskId, seq: message.seq, envelope, attempt };
2019
2373
  }
2020
2374
  return {
2021
2375
  fetch: registry.fetch,
@@ -2030,6 +2384,7 @@ function createByokCloud(options) {
2030
2384
  tenant,
2031
2385
  deviceId,
2032
2386
  input.taskId,
2387
+ void 0,
2033
2388
  (taskId, seq, messageId) => createEnvelope("task.offer", input.payload, { id: messageId, taskId, seq })
2034
2389
  );
2035
2390
  },
@@ -2038,17 +2393,128 @@ function createByokCloud(options) {
2038
2393
  tenant,
2039
2394
  deviceId,
2040
2395
  input.taskId,
2396
+ void 0,
2041
2397
  (taskId, seq, messageId) => createEnvelope("task.offer_with_toolsets", input.payload, { id: messageId, taskId, seq })
2042
2398
  );
2043
2399
  },
2400
+ async enqueueAgentOffer(tenant, deviceId, input) {
2401
+ await assertAgentCapabilities(tenant, deviceId, [AGENT_HOME_CONTRACT_CAPABILITY]);
2402
+ const payload = TaskOfferForAgentPayloadSchema.parse(input.payload);
2403
+ return enqueueTaskEnvelope(
2404
+ tenant,
2405
+ deviceId,
2406
+ input.taskId,
2407
+ payload.agentRef,
2408
+ (taskId, seq, messageId) => createEnvelope("task.offer_for_agent", payload, { id: messageId, taskId, seq })
2409
+ );
2410
+ },
2411
+ async enqueueAgentEgressOffer(tenant, deviceId, input) {
2412
+ await assertAgentCapabilities(tenant, deviceId, [
2413
+ AGENT_HOME_CONTRACT_CAPABILITY,
2414
+ AGENT_EGRESS_POLICY_CAPABILITY,
2415
+ AGENT_EGRESS_RELIABLE_ACK_CAPABILITY
2416
+ ]);
2417
+ const payload = TaskOfferForAgentWithEgressPayloadSchema.parse(input.payload);
2418
+ return enqueueTaskEnvelope(
2419
+ tenant,
2420
+ deviceId,
2421
+ input.taskId,
2422
+ payload.agentRef,
2423
+ (taskId, seq, messageId) => createEnvelope("task.offer_for_agent_with_egress", payload, { id: messageId, taskId, seq })
2424
+ );
2425
+ },
2426
+ async enqueueAgentContentRead(tenant, deviceId, input) {
2427
+ const payload = AgentContentReadPayloadSchema.parse(input.payload);
2428
+ await assertAgentCapabilities(tenant, deviceId, [
2429
+ AGENT_HOME_CONTRACT_CAPABILITY,
2430
+ AGENT_EGRESS_POLICY_CAPABILITY,
2431
+ AGENT_EGRESS_RELIABLE_ACK_CAPABILITY,
2432
+ contentReadCapability2(payload.surface)
2433
+ ]);
2434
+ const stores = tenantStoresFor(controlPlane(tenant), root);
2435
+ const persisted = await stores.receipts.record({
2436
+ key: `agent-content-request:${deviceId}:${payload.requestId}`,
2437
+ body: JSON.stringify(payload)
2438
+ });
2439
+ if (!persisted.created && persisted.receipt.body !== JSON.stringify(payload)) {
2440
+ throw new ByokCloudError(
2441
+ "agent_content_request_mismatch",
2442
+ `Request ${payload.requestId} already exists with a different immutable content-read body.`
2443
+ );
2444
+ }
2445
+ const control = await enqueueAgentControlEnvelope(
2446
+ tenant,
2447
+ deviceId,
2448
+ payload.requestId,
2449
+ (seq) => createEnvelope("agent.content.read", payload, { id: payload.requestId, seq })
2450
+ );
2451
+ if (control.envelope.type !== "agent.content.read" || JSON.stringify(control.envelope.payload) !== JSON.stringify(payload)) {
2452
+ throw new ByokCloudError(
2453
+ "agent_content_request_mismatch",
2454
+ `Request ${payload.requestId} already exists with a different immutable content-read body.`
2455
+ );
2456
+ }
2457
+ return control;
2458
+ },
2459
+ async cancelTask(tenant, taskId, reason) {
2460
+ const stores = tenantStoresFor(controlPlane(tenant), root);
2461
+ const proposedMessageId = options.crypto.randomUuid();
2462
+ const mutation = await stores.cancellations.request({
2463
+ taskId,
2464
+ proposedMessageId,
2465
+ ...reason === void 0 ? {} : { reason },
2466
+ materialize: async (seq, messageId) => {
2467
+ const envelope = createEnvelope("task.cancel", reason === void 0 ? {} : { reason }, {
2468
+ id: messageId,
2469
+ taskId,
2470
+ seq
2471
+ });
2472
+ const body = encodeEnvelope(envelope);
2473
+ const bytes = new TextEncoder().encode(body);
2474
+ return {
2475
+ body,
2476
+ bodyHash: contentHash(await options.crypto.sha256(bytes)),
2477
+ byteSize: BigInt(bytes.length)
2478
+ };
2479
+ }
2480
+ });
2481
+ if (mutation === void 0) {
2482
+ throw new ByokCloudError("task_not_found", `Task ${taskId} was not found for this tenant.`);
2483
+ }
2484
+ if (mutation.message !== void 0) {
2485
+ const envelope = decodeEnvelope(mutation.message.body);
2486
+ if (envelope.seq !== mutation.message.seq || envelope.type !== "task.cancel") {
2487
+ throw new ByokCloudError(
2488
+ "mailbox_seq_mismatch",
2489
+ `Mailbox stored cancellation seq ${String(envelope.seq)} at row ${mutation.message.seq}.`
2490
+ );
2491
+ }
2492
+ }
2493
+ return mutation.attempt;
2494
+ },
2044
2495
  readTaskAttempt(tenant, taskId) {
2045
2496
  return tenantStoresFor(controlPlane(tenant), root).tasks.get(taskId);
2046
2497
  },
2047
2498
  readTerminalReceipt(tenant, taskId) {
2048
2499
  return tenantStoresFor(controlPlane(tenant), root).receipts.get(terminalReceiptKey(taskId));
2049
2500
  },
2501
+ readAgentEgress(tenant, deviceId, eventId) {
2502
+ return tenantStoresFor(controlPlane(tenant), root).egress.get(deviceId, eventId);
2503
+ },
2050
2504
  async readTaskResult(tenant, taskId) {
2051
- const receipt = await tenantStoresFor(controlPlane(tenant), root).receipts.get(
2505
+ const stores = tenantStoresFor(controlPlane(tenant), root);
2506
+ const attempt = await stores.tasks.get(taskId);
2507
+ if (attempt?.cancellation !== void 0) {
2508
+ return {
2509
+ taskId,
2510
+ state: "cancelled",
2511
+ ...attempt.agentRef === void 0 ? {} : { agentRef: attempt.agentRef },
2512
+ ...attempt.cancellation.reason === void 0 ? {} : { reason: attempt.cancellation.reason },
2513
+ ...attempt.cancellation.reason === void 0 ? {} : { terminalCause: attempt.cancellation.reason },
2514
+ recordedAt: attempt.cancellation.requestedAt
2515
+ };
2516
+ }
2517
+ const receipt = await stores.receipts.get(
2052
2518
  terminalReceiptKey(taskId)
2053
2519
  );
2054
2520
  return receipt === void 0 ? void 0 : projectTerminalResult(taskId, receipt);
@@ -2079,6 +2545,9 @@ function createByokCloud(options) {
2079
2545
  listPresence(tenant) {
2080
2546
  return tenantStoresFor(controlPlane(tenant), root).presence.list();
2081
2547
  },
2548
+ readTenantReadiness(tenant) {
2549
+ return tenantStoresFor(controlPlane(tenant), root).devices.readiness();
2550
+ },
2082
2551
  readActivity(tenant, taskId) {
2083
2552
  return tenantStoresFor(controlPlane(tenant), root).activity.read(taskId);
2084
2553
  },
@@ -2146,9 +2615,9 @@ var InMemoryBlobRegistry = class {
2146
2615
  crypto;
2147
2616
  secret;
2148
2617
  urlTtlMs;
2149
- constructor(clock, crypto, options) {
2618
+ constructor(clock, crypto2, options) {
2150
2619
  this.clock = clock;
2151
- this.crypto = crypto;
2620
+ this.crypto = crypto2;
2152
2621
  this.secret = globalThis.crypto.getRandomValues(new Uint8Array(SIGNING_SECRET_BYTES));
2153
2622
  this.urlTtlMs = options.urlTtlMs ?? BLOB_URL_TTL_MS;
2154
2623
  }
@@ -2253,14 +2722,20 @@ var InMemoryBlobContentProxy = class {
2253
2722
  record.uploaded = true;
2254
2723
  return { ok: true };
2255
2724
  }
2725
+ /**
2726
+ * Never returns `{ok:false}`: this composition holds the bytes in the same
2727
+ * process, so there is no upstream to be unreachable and no stream to be
2728
+ * interrupted. Both `BlobReadErrorCode`s are structurally unreachable here
2729
+ * — a proxy that fetches from object storage is where they become live.
2730
+ */
2256
2731
  async readContent(blobId) {
2257
2732
  const record = this.#registry.blobs.get(blobId);
2258
2733
  if (record === void 0 || !record.uploaded || record.data === void 0) return void 0;
2259
- return { data: record.data, contentType: record.contentType };
2734
+ return { ok: true, content: { data: record.data, contentType: record.contentType } };
2260
2735
  }
2261
2736
  };
2262
- function createInMemoryBlobs(clock, crypto, objects, options = {}) {
2263
- const registry = new InMemoryBlobRegistry(clock, crypto, options);
2737
+ function createInMemoryBlobs(clock, crypto2, objects, options = {}) {
2738
+ const registry = new InMemoryBlobRegistry(clock, crypto2, options);
2264
2739
  return {
2265
2740
  blobs: new InMemoryCloudBlobStore(registry, objects),
2266
2741
  contentProxy: new InMemoryBlobContentProxy(registry)
@@ -2303,10 +2778,67 @@ var InMemoryDeviceDirectory = class {
2303
2778
  if (record === void 0) return;
2304
2779
  this.#byTenant.set(key, { ...record, revoked: true });
2305
2780
  }
2781
+ async recordCapabilities(tenant, input) {
2782
+ const key = tenantKey(tenant, input.deviceId);
2783
+ const record = this.#byTenant.get(key);
2784
+ if (record === void 0 || record.revoked) return void 0;
2785
+ const updated = {
2786
+ ...record,
2787
+ capabilities: Object.freeze([...input.capabilities])
2788
+ };
2789
+ this.#byTenant.set(key, updated);
2790
+ return updated;
2791
+ }
2306
2792
  async list(tenant) {
2307
2793
  const prefix = tenantKey(tenant, "");
2308
2794
  return [...this.#byTenant.entries()].filter(([key]) => key.startsWith(prefix)).map(([, record]) => record);
2309
2795
  }
2796
+ async readiness(tenant, presence) {
2797
+ const devices = await this.list(tenant);
2798
+ const livePresence = await presence.list(tenant);
2799
+ const presenceByDevice = new Map(livePresence.map((hint) => [hint.deviceId, hint]));
2800
+ const activeDeviceIds = new Set(
2801
+ devices.filter((device) => !device.revoked).map((device) => device.deviceId)
2802
+ );
2803
+ const observedPresenceByLevel = Object.fromEntries(
2804
+ PRESENCE_LEVELS.map((level) => [level, 0])
2805
+ );
2806
+ for (const hint of livePresence) {
2807
+ if (!activeDeviceIds.has(hint.deviceId)) continue;
2808
+ observedPresenceByLevel[hint.level] += 1;
2809
+ }
2810
+ return {
2811
+ tenantId: tenant,
2812
+ activePairedDeviceCount: devices.filter((device) => !device.revoked).length,
2813
+ revokedDeviceCount: devices.filter((device) => device.revoked).length,
2814
+ observedPresenceCount: Object.values(observedPresenceByLevel).reduce(
2815
+ (total, count) => total + count,
2816
+ 0
2817
+ ),
2818
+ observedPresenceByLevel,
2819
+ devices: [...devices].sort((left, right) => left.deviceId.localeCompare(right.deviceId)).map((device) => {
2820
+ const hint = device.revoked ? void 0 : presenceByDevice.get(device.deviceId);
2821
+ return {
2822
+ deviceId: device.deviceId,
2823
+ productId: device.productId,
2824
+ deviceName: device.deviceName,
2825
+ revoked: device.revoked,
2826
+ ...hint === void 0 ? {} : {
2827
+ presence: {
2828
+ level: hint.level,
2829
+ ...hint.detail === void 0 ? {} : { detail: hint.detail },
2830
+ ...hint.configuredToolsets === void 0 ? {} : { configuredToolsets: hint.configuredToolsets },
2831
+ ...hint.clientVersion === void 0 ? {} : { clientVersion: hint.clientVersion },
2832
+ ...hint.protocolVersions === void 0 ? {} : { protocolVersions: hint.protocolVersions },
2833
+ ...hint.runtimes === void 0 ? {} : { runtimes: hint.runtimes },
2834
+ observedAt: hint.observedAt,
2835
+ expiresAt: hint.expiresAt
2836
+ }
2837
+ }
2838
+ };
2839
+ })
2840
+ };
2841
+ }
2310
2842
  async resolveByDeviceId(deviceId) {
2311
2843
  const key = this.#byDeviceId.get(deviceId);
2312
2844
  return key === void 0 ? void 0 : this.#byTenant.get(key);
@@ -2342,9 +2874,9 @@ var InMemoryNonceStore = class {
2342
2874
  #clock;
2343
2875
  #crypto;
2344
2876
  #ttlMs;
2345
- constructor(clock, crypto, ttlMs = NONCE_TTL_MS) {
2877
+ constructor(clock, crypto2, ttlMs = NONCE_TTL_MS) {
2346
2878
  this.#clock = clock;
2347
- this.#crypto = crypto;
2879
+ this.#crypto = crypto2;
2348
2880
  this.#ttlMs = ttlMs;
2349
2881
  }
2350
2882
  /** Number of records currently held (post-sweep). Test-facing only. */
@@ -2448,54 +2980,171 @@ var InMemoryProofRequestReceiptStore = class {
2448
2980
  return this.#receipts.get(tenantKey(tenant, deviceId, requestId));
2449
2981
  }
2450
2982
  };
2983
+ function sameAgentRef3(left, right) {
2984
+ return left?.agentId === right?.agentId && left?.profileRevision === right?.profileRevision;
2985
+ }
2451
2986
  var InMemoryTaskAttemptStore = class {
2452
- #attempts = /* @__PURE__ */ new Map();
2453
- #clock;
2454
- constructor(clock) {
2455
- this.#clock = clock;
2987
+ #state;
2988
+ constructor(clock, state = new InMemoryTaskAttemptState(clock)) {
2989
+ this.#state = state;
2456
2990
  }
2457
2991
  async open(tenant, input) {
2458
2992
  const key = tenantKey(tenant, input.taskId);
2459
- const existing = this.#attempts.get(key);
2460
- if (existing !== void 0) return existing;
2461
- const attempt = {
2462
- tenantId: tenant,
2463
- taskId: input.taskId,
2464
- deviceId: input.deviceId,
2465
- status: "offered",
2466
- updatedAt: this.#now()
2467
- };
2468
- this.#attempts.set(key, attempt);
2469
- return attempt;
2993
+ return this.#state.mutate(key, () => {
2994
+ const existing = this.#state.attempts.get(key);
2995
+ if (existing !== void 0) return existing;
2996
+ const attempt = {
2997
+ tenantId: tenant,
2998
+ taskId: input.taskId,
2999
+ deviceId: input.deviceId,
3000
+ ...input.agentRef === void 0 ? {} : { agentRef: { ...input.agentRef } },
3001
+ status: "offered",
3002
+ updatedAt: this.#now()
3003
+ };
3004
+ this.#state.attempts.set(key, attempt);
3005
+ return attempt;
3006
+ });
3007
+ }
3008
+ async reserveAgentOffer(tenant, input) {
3009
+ const key = tenantKey(tenant, input.taskId);
3010
+ return this.#state.mutate(key, () => {
3011
+ const existing = this.#state.attempts.get(key);
3012
+ if (existing !== void 0) return { attempt: existing, created: false };
3013
+ const attempt = {
3014
+ tenantId: tenant,
3015
+ taskId: input.taskId,
3016
+ deviceId: input.deviceId,
3017
+ agentRef: { ...input.agentRef },
3018
+ status: "offered",
3019
+ updatedAt: this.#now()
3020
+ };
3021
+ this.#state.attempts.set(key, attempt);
3022
+ return { attempt, created: true };
3023
+ });
2470
3024
  }
2471
3025
  async get(tenant, taskId) {
2472
- return this.#attempts.get(tenantKey(tenant, taskId));
3026
+ return this.#state.attempts.get(tenantKey(tenant, taskId));
3027
+ }
3028
+ async getMany(tenant, taskIds) {
3029
+ return taskIds.flatMap((taskId) => {
3030
+ const attempt = this.#state.attempts.get(tenantKey(tenant, taskId));
3031
+ return attempt === void 0 ? [] : [attempt];
3032
+ });
2473
3033
  }
2474
3034
  async claim(tenant, input) {
2475
3035
  const key = tenantKey(tenant, input.taskId);
2476
- const existing = this.#attempts.get(key);
2477
- if (existing === void 0) return void 0;
2478
- if (existing.ownerDeviceId !== void 0) return existing;
2479
- const claimed = {
2480
- ...existing,
2481
- ownerDeviceId: input.deviceId,
2482
- status: "claimed",
2483
- updatedAt: this.#now()
2484
- };
2485
- this.#attempts.set(key, claimed);
2486
- return claimed;
3036
+ return this.#state.mutate(key, () => {
3037
+ const existing = this.#state.attempts.get(key);
3038
+ if (existing === void 0) return void 0;
3039
+ if (existing.ownerDeviceId !== void 0 || existing.cancellation !== void 0 || existing.status !== "offered") return existing;
3040
+ const claimed = {
3041
+ ...existing,
3042
+ ownerDeviceId: input.deviceId,
3043
+ status: "claimed",
3044
+ updatedAt: this.#now()
3045
+ };
3046
+ this.#state.attempts.set(key, claimed);
3047
+ return claimed;
3048
+ });
2487
3049
  }
2488
3050
  async recordStatus(tenant, input) {
2489
3051
  const key = tenantKey(tenant, input.taskId);
2490
- const existing = this.#attempts.get(key);
2491
- if (existing === void 0) return void 0;
2492
- const updated = { ...existing, status: input.status, updatedAt: this.#now() };
2493
- this.#attempts.set(key, updated);
2494
- return updated;
3052
+ return this.#state.mutate(key, () => {
3053
+ const existing = this.#state.attempts.get(key);
3054
+ if (existing === void 0) return void 0;
3055
+ if (existing.agentRef === void 0 !== (input.agentRef === void 0) || existing.agentRef !== void 0 && !sameAgentRef3(existing.agentRef, input.agentRef)) return existing;
3056
+ if (existing.cancellation !== void 0) {
3057
+ if (input.status !== "cancelled" || existing.status === "cancelled") return existing;
3058
+ } else if (existing.status === "complete" || existing.status === "failed" || existing.status === "cancelled") {
3059
+ return existing;
3060
+ }
3061
+ const updated = {
3062
+ ...existing,
3063
+ status: input.status,
3064
+ ...input.terminalCause === void 0 ? {} : { terminalCause: input.terminalCause },
3065
+ updatedAt: this.#now()
3066
+ };
3067
+ this.#state.attempts.set(key, updated);
3068
+ return updated;
3069
+ });
2495
3070
  }
2496
3071
  #now() {
3072
+ return this.#state.now();
3073
+ }
3074
+ };
3075
+ var InMemoryTaskAttemptState = class {
3076
+ attempts = /* @__PURE__ */ new Map();
3077
+ #clock;
3078
+ #mutationTails = /* @__PURE__ */ new Map();
3079
+ constructor(clock) {
3080
+ this.#clock = clock;
3081
+ }
3082
+ now() {
2497
3083
  return this.#clock.now().toISOString();
2498
3084
  }
3085
+ /** Serialize every state-changing operation for one tenant/task key. */
3086
+ async mutate(key, operation) {
3087
+ const previous = this.#mutationTails.get(key) ?? Promise.resolve();
3088
+ const result = previous.then(operation);
3089
+ const tail = result.then(
3090
+ () => void 0,
3091
+ () => void 0
3092
+ );
3093
+ this.#mutationTails.set(key, tail);
3094
+ try {
3095
+ return await result;
3096
+ } finally {
3097
+ if (this.#mutationTails.get(key) === tail) this.#mutationTails.delete(key);
3098
+ }
3099
+ }
3100
+ };
3101
+ var InMemoryTaskCancellationStore = class {
3102
+ #state;
3103
+ #mailbox;
3104
+ #messageIds = /* @__PURE__ */ new Map();
3105
+ #inFlight = /* @__PURE__ */ new Map();
3106
+ constructor(state, mailbox) {
3107
+ this.#state = state;
3108
+ this.#mailbox = mailbox;
3109
+ }
3110
+ request(tenant, input) {
3111
+ const key = tenantKey(tenant, input.taskId);
3112
+ const running = this.#inFlight.get(key);
3113
+ if (running !== void 0) return running;
3114
+ const operation = this.#request(tenant, key, input).finally(() => {
3115
+ this.#inFlight.delete(key);
3116
+ });
3117
+ this.#inFlight.set(key, operation);
3118
+ return operation;
3119
+ }
3120
+ async #request(tenant, key, input) {
3121
+ return this.#state.mutate(key, async () => {
3122
+ const existing = this.#state.attempts.get(key);
3123
+ if (existing === void 0) return void 0;
3124
+ if (existing.cancellation === void 0 && (existing.status === "complete" || existing.status === "failed" || existing.status === "cancelled")) {
3125
+ return { attempt: existing };
3126
+ }
3127
+ const messageId = this.#messageIds.get(key) ?? input.proposedMessageId;
3128
+ const message = await this.#mailbox.append(tenant, {
3129
+ deviceId: existing.deviceId,
3130
+ messageId,
3131
+ materialize: (seq) => input.materialize(seq, messageId)
3132
+ });
3133
+ const requestedAt = this.#state.now();
3134
+ const attempt = existing.cancellation === void 0 ? {
3135
+ ...existing,
3136
+ status: existing.ownerDeviceId === void 0 ? "cancelled" : "cancel_requested",
3137
+ cancellation: {
3138
+ requestedAt,
3139
+ ...input.reason === void 0 ? {} : { reason: input.reason }
3140
+ },
3141
+ updatedAt: requestedAt
3142
+ } : existing;
3143
+ this.#state.attempts.set(key, attempt);
3144
+ this.#messageIds.set(key, messageId);
3145
+ return { attempt, message };
3146
+ });
3147
+ }
2499
3148
  };
2500
3149
 
2501
3150
  // src/stores/in-memory/activity.ts
@@ -2614,20 +3263,48 @@ var InMemoryApprovalTimelineStore = class {
2614
3263
  return tail;
2615
3264
  }
2616
3265
  };
3266
+ var InMemoryAgentEgressStore = class {
3267
+ #records = /* @__PURE__ */ new Map();
3268
+ #clock;
3269
+ constructor(clock) {
3270
+ this.#clock = clock;
3271
+ }
3272
+ async record(tenant, input) {
3273
+ const key = tenantKey(tenant, `${input.deviceId}\0${input.payload.eventId}`);
3274
+ const existing = this.#records.get(key);
3275
+ if (existing !== void 0) return { record: existing, created: false };
3276
+ const record = {
3277
+ tenantId: tenant,
3278
+ deviceId: input.deviceId,
3279
+ payload: input.payload,
3280
+ receiptId: input.receiptId,
3281
+ recordedAt: this.#clock.now().toISOString()
3282
+ };
3283
+ this.#records.set(key, record);
3284
+ return { record, created: true };
3285
+ }
3286
+ async get(tenant, deviceId, eventId) {
3287
+ return this.#records.get(tenantKey(tenant, `${deviceId}\0${eventId}`));
3288
+ }
3289
+ };
2617
3290
 
2618
3291
  // src/stores/in-memory/index.ts
2619
- function createInMemoryCloudStores(clock, crypto, objects) {
2620
- const blobs = createInMemoryBlobs(clock, crypto, objects);
3292
+ function createInMemoryCloudStores(clock, crypto2, objects, mailbox) {
3293
+ const blobs = createInMemoryBlobs(clock, crypto2, objects);
3294
+ const taskState = new InMemoryTaskAttemptState(clock);
3295
+ const tasks = new InMemoryTaskAttemptStore(clock, taskState);
2621
3296
  return {
2622
3297
  stores: {
2623
3298
  activity: new InMemoryActivityStore(clock),
2624
3299
  approvals: new InMemoryApprovalTimelineStore(clock),
2625
3300
  devices: new InMemoryDeviceDirectory(),
2626
3301
  pairingCodes: new InMemoryPairingCodeStore(clock),
2627
- nonces: new InMemoryNonceStore(clock, crypto),
3302
+ nonces: new InMemoryNonceStore(clock, crypto2),
2628
3303
  dedup: new InMemoryInboundDedupStore(),
2629
- tasks: new InMemoryTaskAttemptStore(clock),
3304
+ tasks,
3305
+ cancellations: new InMemoryTaskCancellationStore(taskState, mailbox),
2630
3306
  receipts: new InMemoryRequestReceiptStore(clock),
3307
+ egress: new InMemoryAgentEgressStore(clock),
2631
3308
  proofReceipts: new InMemoryProofRequestReceiptStore(clock),
2632
3309
  blobs: blobs.blobs,
2633
3310
  rateLimiter: new AllowAllRateLimiter()
@@ -2643,9 +3320,14 @@ function systemClock() {
2643
3320
  }
2644
3321
  function createInMemoryByokCloud(options = {}) {
2645
3322
  const clock = options.clock ?? systemClock();
2646
- const crypto = options.crypto ?? createWebCrypto();
3323
+ const crypto2 = options.crypto ?? createWebCrypto();
2647
3324
  const core = createInMemoryCoreStores({ clock }).stores;
2648
- const { stores, blobContentProxy } = createInMemoryCloudStores(clock, crypto, core.objects);
3325
+ const { stores, blobContentProxy } = createInMemoryCloudStores(
3326
+ clock,
3327
+ crypto2,
3328
+ core.objects,
3329
+ core.mailbox
3330
+ );
2649
3331
  const tokenSigner = options.tokenSigner ?? createHmacTokenSigner(globalThis.crypto.getRandomValues(new Uint8Array(TOKEN_SECRET_BYTES)), clock);
2650
3332
  const cloud = createByokCloud({
2651
3333
  core,
@@ -2655,7 +3337,7 @@ function createInMemoryByokCloud(options = {}) {
2655
3337
  // pairing is what keeps hosted-in-memory behavior identical to what it was
2656
3338
  // before the port narrowed.
2657
3339
  blobContentProxy,
2658
- crypto,
3340
+ crypto: crypto2,
2659
3341
  tokenSigner,
2660
3342
  clock,
2661
3343
  capabilities: options.capabilities ?? fullCapabilityDeclaration(),
@@ -2684,7 +3366,7 @@ function createInMemoryByokCloud(options = {}) {
2684
3366
  ...options.skillPacks === void 0 ? {} : { skillPacks: options.skillPacks },
2685
3367
  ...options.skillPackPageLimit === void 0 ? {} : { skillPackPageLimit: options.skillPackPageLimit }
2686
3368
  });
2687
- return { cloud, core, stores, blobContentProxy, clock, crypto };
3369
+ return { cloud, core, stores, blobContentProxy, clock, crypto: crypto2 };
2688
3370
  }
2689
3371
  function authenticateHostedDeviceAssertion(input, deps) {
2690
3372
  return authenticateDeviceAssertion(input, {
@@ -2847,10 +3529,12 @@ var TASK_ATTEMPT_STATUSES = [
2847
3529
  "offered",
2848
3530
  "claimed",
2849
3531
  "running",
3532
+ "cancel_requested",
2850
3533
  "complete",
2851
3534
  "failed",
2852
3535
  "cancelled"
2853
3536
  ];
3537
+ var BLOB_READ_ERROR_CODES = ["blob_upstream_unavailable", "blob_upstream_stream_interrupted"];
2854
3538
  var CLOUD_STORE_NAMES = [
2855
3539
  "activity",
2856
3540
  "approvals",
@@ -2859,7 +3543,9 @@ var CLOUD_STORE_NAMES = [
2859
3543
  "nonces",
2860
3544
  "dedup",
2861
3545
  "tasks",
3546
+ "cancellations",
2862
3547
  "receipts",
3548
+ "egress",
2863
3549
  "proofReceipts",
2864
3550
  "blobs",
2865
3551
  "rateLimiter"
@@ -2869,12 +3555,14 @@ var CLOUD_STORE_NAMES = [
2869
3555
  var CLOUD_PORT_METHODS = {
2870
3556
  activity: ["append", "read"],
2871
3557
  approvals: ["append", "read"],
2872
- devices: ["register", "get", "revoke", "list", "resolveByDeviceId"],
3558
+ devices: ["register", "get", "revoke", "list", "readiness", "recordCapabilities", "resolveByDeviceId"],
2873
3559
  pairingCodes: ["issue", "redeem"],
2874
3560
  nonces: ["issue", "validate", "markUsed"],
2875
3561
  dedup: ["checkAndRecord"],
2876
- tasks: ["open", "get", "claim", "recordStatus"],
3562
+ tasks: ["open", "reserveAgentOffer", "get", "getMany", "claim", "recordStatus"],
3563
+ cancellations: ["request"],
2877
3564
  receipts: ["record", "get"],
3565
+ egress: ["record", "get"],
2878
3566
  proofReceipts: ["record", "get"],
2879
3567
  // Three methods, not six: the byte-proxy trio moved to `BlobContentProxy`,
2880
3568
  // which is a composition input rather than a port and therefore has no row
@@ -2890,12 +3578,14 @@ var CLOUD_PORT_INTERFACES = {
2890
3578
  nonces: "NonceStore",
2891
3579
  dedup: "InboundDedupStore",
2892
3580
  tasks: "TaskAttemptStore",
3581
+ cancellations: "TaskCancellationStore",
2893
3582
  receipts: "RequestReceiptStore",
3583
+ egress: "AgentEgressStore",
2894
3584
  proofReceipts: "ProofRequestReceiptStore",
2895
3585
  blobs: "CloudBlobStore",
2896
3586
  rateLimiter: "InboundRateLimiter"
2897
3587
  };
2898
3588
 
2899
- 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, 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 };
3589
+ 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 };
2900
3590
  //# sourceMappingURL=index.js.map
2901
3591
  //# sourceMappingURL=index.js.map