@byok-sdk/cloud 0.8.0-beta.0 → 0.8.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.
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Durable task-free Agent-home projection facts.
3
+ *
4
+ * Desired projection and completion are deliberately two immutable request
5
+ * receipts. The receipt store is tenant-scoped and first-write-wins, so the
6
+ * composition does not need a second mutable projection authority merely to
7
+ * survive a process restart.
8
+ */
9
+ import { type AgentHomeProjectionPayload, type AgentHomeProjectionCompletionRequest, type AgentHomeProjectionReadback } from '@byok-sdk/protocol';
10
+ import type { TenantId } from '@byok-sdk/core';
11
+ import type { TenantBoundReceipts } from './tenant-stores';
12
+ export interface AgentHomeProjectionReceiptInput {
13
+ readonly requestId: string;
14
+ readonly agentRef: AgentHomeProjectionPayload['agentRef'];
15
+ readonly projectionHash: AgentHomeProjectionPayload['projectionHash'];
16
+ }
17
+ export declare function agentHomeProjectionRequestKey(deviceId: string, requestId: string): string;
18
+ export declare function agentHomeProjectionCompletionKey(deviceId: string, requestId: string): string;
19
+ export declare function sameAgentHomeProjectionRequest(expected: AgentHomeProjectionPayload, actual: AgentHomeProjectionPayload): boolean;
20
+ export declare function receiptMatchesAgentHomeProjection(request: AgentHomeProjectionPayload, receipt: AgentHomeProjectionCompletionRequest): boolean;
21
+ export declare function statusInputMatchesAgentHomeProjection(request: AgentHomeProjectionPayload, input: AgentHomeProjectionReceiptInput): boolean;
22
+ export declare function readAgentHomeProjectionStatus(receipts: TenantBoundReceipts, tenant: TenantId, deviceId: string, input: AgentHomeProjectionReceiptInput): Promise<AgentHomeProjectionReadback | undefined>;
23
+ export declare function recordAgentHomeProjectionCompletion(receipts: TenantBoundReceipts, tenant: TenantId, deviceId: string, receiptInput: AgentHomeProjectionCompletionRequest): Promise<AgentHomeProjectionReadback>;
package/dist/cloud.d.ts CHANGED
@@ -17,10 +17,11 @@
17
17
  import { type BoardItem, type BoardItemInput, type BoardListQuery, type BoardPage, type CapabilityDeclaration, type Clock, type CoreStores, type PresenceHint, type SkillPackStore, type TenantId, type TenantReadiness } from '@byok-sdk/core';
18
18
  import type { ActivityTail } from './activity';
19
19
  import type { ApprovalTimelineTail } from './approval-timeline';
20
- import { type Envelope, type AgentContentReadPayload, type TaskOfferPayload, type TaskOfferForAgentPayload, type TaskOfferForAgentWithEgressPayload, type TaskOfferForAgentWithEgressFreshPayload, type TaskOfferWithToolsetsPayload } from '@byok-sdk/protocol';
20
+ import { type Envelope, type AgentContentReadPayload, type AgentHomeProjectionCompletionRequest, type AgentHomeProjectionPayload, type AgentHomeProjectionReadback, type TaskOfferPayload, type TaskOfferForAgentPayload, type TaskOfferForAgentWithEgressPayload, type TaskOfferForAgentWithEgressFreshPayload, type TaskOfferWithToolsetsPayload } from '@byok-sdk/protocol';
21
21
  import type { TokenSigner } from './auth/tokens';
22
22
  import type { CloudCrypto } from './crypto/port';
23
23
  import { type RouteDescriptor } from './router/registry';
24
+ import { type AgentHomeProjectionReceiptInput } from './agent-home-projections';
24
25
  import type { BlobContentProxy, CloudStores, DeviceRecord, AgentEgressRecord, PairingCodeInfo, RequestReceipt, TaskAttempt } from './stores/ports';
25
26
  import { type TerminalResult } from './terminal-result';
26
27
  import type { TruthCommitter, TruthObjectDownloads } from './truth/contract';
@@ -125,10 +126,17 @@ export interface AgentEgressFreshSessionDispatchInput {
125
126
  export interface AgentContentReadInput {
126
127
  readonly payload: AgentContentReadPayload;
127
128
  }
129
+ /** Task-free exact-device projection desired state, intentionally unrelated to TaskAttempt. */
130
+ export type AgentHomeProjectionInput = AgentHomeProjectionPayload;
131
+ /** Exact request identity a host must echo to read back durable projection status. */
132
+ export type AgentHomeProjectionStatusInput = AgentHomeProjectionReceiptInput;
128
133
  export interface EnqueuedAgentControl {
129
134
  readonly seq: number;
130
135
  readonly envelope: Envelope;
131
136
  }
137
+ export interface EnqueuedAgentHomeProjection extends EnqueuedAgentControl {
138
+ readonly status: AgentHomeProjectionReadback;
139
+ }
132
140
  export interface EnqueuedOffer {
133
141
  readonly taskId: string;
134
142
  /** The per-(tenant, device) delivery seq — the daemon's redelivery cursor position for this envelope. */
@@ -180,6 +188,12 @@ export interface ByokCloud {
180
188
  enqueueFreshAgentEgressOffer(tenant: TenantId, deviceId: string, input: AgentEgressFreshSessionDispatchInput): Promise<EnqueuedOffer>;
181
189
  /** Host control plane: request one policy-bound content read without a task fallback. */
182
190
  enqueueAgentContentRead(tenant: TenantId, deviceId: string, input: AgentContentReadInput): Promise<EnqueuedAgentControl>;
191
+ /** Durable, task-free projection request for precisely one admitted device. */
192
+ enqueueAgentHomeProjection(tenant: TenantId, deviceId: string, input: AgentHomeProjectionInput): Promise<EnqueuedAgentHomeProjection>;
193
+ /** Tenant/device/request-bound durable desired-state and terminal-outcome readback. */
194
+ getAgentHomeProjectionStatus(tenant: TenantId, deviceId: string, input: AgentHomeProjectionStatusInput): Promise<AgentHomeProjectionReadback | undefined>;
195
+ /** Direct device completion endpoint authority; first exact terminal receipt wins. */
196
+ completeAgentHomeProjection(tenant: TenantId, deviceId: string, receipt: AgentHomeProjectionCompletionRequest): Promise<AgentHomeProjectionReadback>;
183
197
  /** Host control plane: durably request cancellation by tenant/task id. Idempotent. */
184
198
  cancelTask(tenant: TenantId, taskId: string, reason?: string): Promise<TaskAttempt>;
185
199
  readTaskAttempt(tenant: TenantId, taskId: string): Promise<TaskAttempt | undefined>;
package/dist/errors.d.ts CHANGED
@@ -53,6 +53,16 @@ export declare const CLOUD_ERROR_CODES: {
53
53
  readonly agent_content_request_mismatch: 'agent_content_request_mismatch';
54
54
  /** A durable mailbox receipt id resolved to an envelope other than its exact acknowledgement. */
55
55
  readonly mailbox_receipt_mismatch: 'mailbox_receipt_mismatch';
56
+ /** A task-free Agent-home request id already names a different immutable desired projection. */
57
+ readonly agent_home_projection_request_conflict: 'agent_home_projection_request_conflict';
58
+ /** A direct Agent-home completion did not identify a stored desired request for this exact device. */
59
+ readonly agent_home_projection_request_not_found: 'agent_home_projection_request_not_found';
60
+ /** A direct Agent-home completion changed the first durable terminal outcome. */
61
+ readonly agent_home_projection_completion_conflict: 'agent_home_projection_completion_conflict';
62
+ /** A task-free completion did not exactly echo its immutable desired projection binding. */
63
+ readonly agent_home_projection_receipt_mismatch: 'agent_home_projection_receipt_mismatch';
64
+ /** A receipt-store row at the projection namespace violated the frozen projection schema. */
65
+ readonly agent_home_projection_receipt_invalid: 'agent_home_projection_receipt_invalid';
56
66
  };
57
67
  export type CloudErrorCode = (typeof CLOUD_ERROR_CODES)[keyof typeof CLOUD_ERROR_CODES];
58
68
  export declare class ByokCloudError extends Error {
@@ -0,0 +1,9 @@
1
+ /** Device-authenticated exact completion readback for task-free Agent-home projections. */
2
+ import type { Context } from 'hono';
3
+ import { type AgentHomeProjectionCompletionRequest, type AgentHomeProjectionReadback } from '@byok-sdk/protocol';
4
+ import { type DeviceRouteDeps } from './shared';
5
+ import type { TenantStores } from '../tenant-stores';
6
+ export interface AgentHomeProjectionRouteDeps extends DeviceRouteDeps {
7
+ readonly complete: (stores: TenantStores, deviceId: string, receipt: AgentHomeProjectionCompletionRequest) => Promise<AgentHomeProjectionReadback>;
8
+ }
9
+ export declare function agentHomeProjectionCompletionHandler(deps: AgentHomeProjectionRouteDeps): (c: Context) => Promise<Response>;
package/dist/index.d.ts CHANGED
@@ -15,7 +15,9 @@
15
15
  export { isTenantId, tenantId } from '@byok-sdk/core';
16
16
  export type { TenantId } from '@byok-sdk/core';
17
17
  export { createByokCloud } from './cloud';
18
- export type { ByokCloud, ByokCloudOptions, AgentDispatchInput, AgentEgressDispatchInput, AgentEgressFreshSessionDispatchInput, AgentContentReadInput, EnqueueOfferInput, EnqueueToolsetOfferInput, EnqueuedAgentControl, EnqueuedOffer, } from './cloud';
18
+ export type { ByokCloud, ByokCloudOptions, AgentDispatchInput, AgentEgressDispatchInput, AgentEgressFreshSessionDispatchInput, AgentContentReadInput, AgentHomeProjectionInput, AgentHomeProjectionStatusInput, EnqueueOfferInput, EnqueueToolsetOfferInput, EnqueuedAgentControl, EnqueuedAgentHomeProjection, EnqueuedOffer, } from './cloud';
19
+ export { agentHomeProjectionCompletionKey, agentHomeProjectionRequestKey, readAgentHomeProjectionStatus, recordAgentHomeProjectionCompletion, } from './agent-home-projections';
20
+ export type { AgentHomeProjectionReceiptInput } from './agent-home-projections';
19
21
  export { AGENT_HOME_CONTRACT_CAPABILITY, DEFAULT_EVENTS_PAGE_LIMIT, DEFAULT_LONG_POLL_HOLD_MS, DEFAULT_LONG_POLL_INTERVAL_MS, DEFAULT_MAX_BLOB_SIZE_BYTES, } from './cloud';
20
22
  export { DEFAULT_BOARD_PAGE_LIMIT, DEFAULT_BOARD_STREAM_HEARTBEAT_INTERVAL_MS, DEFAULT_BOARD_STREAM_QUERY_INTERVAL_MS, DEFAULT_BOARD_STREAM_RECONCILIATION_INTERVAL_MS, } from './handlers/board';
21
23
  export { DEFAULT_SKILL_PACK_PAGE_LIMIT } from './handlers/skill-packs';
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, 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, TaskOfferForAgentWithEgressFreshPayloadSchema, TaskOfferForAgentWithEgressPayloadSchema, TaskOfferForAgentPayloadSchema, AGENT_CONTENT_ARTIFACT_READ_CAPABILITY, AGENT_CONTENT_TRANSCRIPT_READ_CAPABILITY, AGENT_CONTENT_WORKSPACE_READ_CAPABILITY, AGENT_EGRESS_FRESH_SESSION_CAPABILITY, PairRequestSchema, PairResponseSchema, ChallengeRequestSchema, TokenRequestSchema, MessagesSendRequestSchema, PresencePublishRequestSchema, CreateBlobRequestSchema, byokBlobContentPath, AgentEgressAckPayloadSchema, AgentContentReceiptPayloadSchema } from '@byok-sdk/protocol';
3
+ import { AgentEventOrUnknownSchema, PROTOCOL_VERSION, DAEMON_TO_SERVER_TYPES, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY, encodeEnvelope, AgentHomeProjectionCompletionRequestSchema, decodeEnvelope, BYOK_PAIR_PATH, BYOK_CHALLENGE_PATH, BYOK_TOKEN_PATH, BYOK_CAPABILITIES_PATH, BYOK_EVENTS_PATH, BYOK_MESSAGES_PATH, BYOK_AGENT_HOME_PROJECTION_COMPLETION_ROUTE, 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, AgentHomeProjectionPayloadSchema, AgentContentReadPayloadSchema, AGENT_EGRESS_POLICY_CAPABILITY, TaskOfferForAgentWithEgressFreshPayloadSchema, TaskOfferForAgentWithEgressPayloadSchema, TaskOfferForAgentPayloadSchema, STRICT_AGENT_ONLY_CAPABILITY, AGENT_CONTENT_ARTIFACT_READ_CAPABILITY, AGENT_CONTENT_TRANSCRIPT_READ_CAPABILITY, AGENT_CONTENT_WORKSPACE_READ_CAPABILITY, AGENT_HOME_PROJECTION_CAPABILITY, AGENT_EGRESS_FRESH_SESSION_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
 
@@ -329,7 +329,17 @@ var CLOUD_ERROR_CODES = {
329
329
  /** A first-write-wins Agent control record was replayed with a different body. */
330
330
  agent_content_request_mismatch: "agent_content_request_mismatch",
331
331
  /** A durable mailbox receipt id resolved to an envelope other than its exact acknowledgement. */
332
- mailbox_receipt_mismatch: "mailbox_receipt_mismatch"
332
+ mailbox_receipt_mismatch: "mailbox_receipt_mismatch",
333
+ /** A task-free Agent-home request id already names a different immutable desired projection. */
334
+ agent_home_projection_request_conflict: "agent_home_projection_request_conflict",
335
+ /** A direct Agent-home completion did not identify a stored desired request for this exact device. */
336
+ agent_home_projection_request_not_found: "agent_home_projection_request_not_found",
337
+ /** A direct Agent-home completion changed the first durable terminal outcome. */
338
+ agent_home_projection_completion_conflict: "agent_home_projection_completion_conflict",
339
+ /** A task-free completion did not exactly echo its immutable desired projection binding. */
340
+ agent_home_projection_receipt_mismatch: "agent_home_projection_receipt_mismatch",
341
+ /** A receipt-store row at the projection namespace violated the frozen projection schema. */
342
+ agent_home_projection_receipt_invalid: "agent_home_projection_receipt_invalid"
333
343
  };
334
344
  var ByokCloudError = class extends Error {
335
345
  code;
@@ -791,6 +801,7 @@ function tokenHandler(deps) {
791
801
  var CLOUD_PROTOCOL_CAPABILITIES = [
792
802
  "result-document",
793
803
  "agent-home-contract",
804
+ "agent-home-projection",
794
805
  "agent-egress-policy",
795
806
  "agent-egress-reliable-ack",
796
807
  "agent-egress-fresh-session",
@@ -1223,6 +1234,35 @@ function messagesHandler(deps) {
1223
1234
  return c.json(response, 200);
1224
1235
  };
1225
1236
  }
1237
+ function agentHomeProjectionCompletionHandler(deps) {
1238
+ return async (c) => {
1239
+ const authenticated = await authenticateDevice(c, deps);
1240
+ if (authenticated === void 0) return c.json({ error: "unauthorized" }, 401);
1241
+ const parsed = AgentHomeProjectionCompletionRequestSchema.safeParse(await readJsonBody(c));
1242
+ if (!parsed.success) return c.json({ error: "invalid Agent-home projection completion" }, 422);
1243
+ const requestId = c.req.param("requestId");
1244
+ if (requestId === void 0 || requestId !== parsed.data.requestId) {
1245
+ return c.json({ error: "agent_home_projection_receipt_mismatch" }, 422);
1246
+ }
1247
+ try {
1248
+ return c.json(
1249
+ await deps.complete(authenticated.stores, authenticated.device.deviceId, parsed.data),
1250
+ 200
1251
+ );
1252
+ } catch (error) {
1253
+ if (isCloudError(error, "agent_home_projection_request_not_found")) {
1254
+ return c.json({ error: error.code }, 404);
1255
+ }
1256
+ if (isCloudError(error, "agent_home_projection_receipt_mismatch") || isCloudError(error, "agent_home_projection_receipt_invalid")) {
1257
+ return c.json({ error: error.code }, 422);
1258
+ }
1259
+ if (isCloudError(error, "agent_home_projection_request_conflict") || isCloudError(error, "agent_home_projection_completion_conflict") || isCloudError(error, "agent_capability_missing")) {
1260
+ return c.json({ error: error.code }, 409);
1261
+ }
1262
+ throw error;
1263
+ }
1264
+ };
1265
+ }
1226
1266
  var DEFAULT_BOARD_PAGE_LIMIT = 50;
1227
1267
  var DEFAULT_BOARD_STREAM_QUERY_INTERVAL_MS = 5e3;
1228
1268
  var DEFAULT_BOARD_STREAM_HEARTBEAT_INTERVAL_MS = 15e3;
@@ -1967,6 +2007,118 @@ var CloudRouteRegistry = class {
1967
2007
  return this.#app.fetch;
1968
2008
  }
1969
2009
  };
2010
+ function agentHomeProjectionRequestKey(deviceId, requestId) {
2011
+ return `agent-home-projection:v1:${deviceId}:${requestId}:request`;
2012
+ }
2013
+ function agentHomeProjectionCompletionKey(deviceId, requestId) {
2014
+ return `agent-home-projection:v1:${deviceId}:${requestId}:completion`;
2015
+ }
2016
+ function sameAgentHomeProjectionRequest(expected, actual) {
2017
+ return expected.requestId === actual.requestId && expected.agentRef.agentId === actual.agentRef.agentId && expected.agentRef.profileRevision === actual.agentRef.profileRevision && expected.projectionHash === actual.projectionHash && JSON.stringify(expected.projection) === JSON.stringify(actual.projection);
2018
+ }
2019
+ function receiptMatchesAgentHomeProjection(request, receipt) {
2020
+ return receipt.requestId === request.requestId && receipt.agentRef.agentId === request.agentRef.agentId && receipt.agentRef.profileRevision === request.agentRef.profileRevision && receipt.projectionHash === request.projectionHash;
2021
+ }
2022
+ function statusInputMatchesAgentHomeProjection(request, input) {
2023
+ return input.requestId === request.requestId && input.agentRef.agentId === request.agentRef.agentId && input.agentRef.profileRevision === request.agentRef.profileRevision && input.projectionHash === request.projectionHash;
2024
+ }
2025
+ function parseRequestBody(body) {
2026
+ try {
2027
+ return AgentHomeProjectionPayloadSchema.parse(JSON.parse(body));
2028
+ } catch (error) {
2029
+ throw new ByokCloudError(
2030
+ "agent_home_projection_receipt_invalid",
2031
+ "Stored Agent-home projection request is not a valid immutable projection fact.",
2032
+ { cause: error }
2033
+ );
2034
+ }
2035
+ }
2036
+ function parseCompletionBody(body) {
2037
+ try {
2038
+ return AgentHomeProjectionCompletionRequestSchema.parse(JSON.parse(body));
2039
+ } catch (error) {
2040
+ throw new ByokCloudError(
2041
+ "agent_home_projection_receipt_invalid",
2042
+ "Stored Agent-home projection completion is not a valid immutable receipt fact.",
2043
+ { cause: error }
2044
+ );
2045
+ }
2046
+ }
2047
+ async function readAgentHomeProjectionStatus(receipts, tenant, deviceId, input) {
2048
+ const storedRequest = await receipts.get(agentHomeProjectionRequestKey(deviceId, input.requestId));
2049
+ if (storedRequest === void 0) return void 0;
2050
+ const request = parseRequestBody(storedRequest.body);
2051
+ if (!statusInputMatchesAgentHomeProjection(request, input)) {
2052
+ throw new ByokCloudError(
2053
+ "agent_home_projection_request_conflict",
2054
+ `Agent-home projection request ${input.requestId} does not match its immutable desired fact.`
2055
+ );
2056
+ }
2057
+ const storedCompletion = await receipts.get(agentHomeProjectionCompletionKey(deviceId, input.requestId));
2058
+ if (storedCompletion === void 0) {
2059
+ return {
2060
+ tenantId: tenant,
2061
+ deviceId,
2062
+ requestId: request.requestId,
2063
+ agentRef: request.agentRef,
2064
+ projectionHash: request.projectionHash,
2065
+ status: "pending"
2066
+ };
2067
+ }
2068
+ const completion = parseCompletionBody(storedCompletion.body);
2069
+ if (!receiptMatchesAgentHomeProjection(request, completion)) {
2070
+ throw new ByokCloudError(
2071
+ "agent_home_projection_receipt_mismatch",
2072
+ `Agent-home projection completion ${input.requestId} does not match its immutable desired fact.`
2073
+ );
2074
+ }
2075
+ return {
2076
+ tenantId: tenant,
2077
+ deviceId,
2078
+ requestId: request.requestId,
2079
+ agentRef: request.agentRef,
2080
+ projectionHash: request.projectionHash,
2081
+ status: completion.outcome,
2082
+ completedAt: storedCompletion.recordedAt
2083
+ };
2084
+ }
2085
+ async function recordAgentHomeProjectionCompletion(receipts, tenant, deviceId, receiptInput) {
2086
+ const receipt = AgentHomeProjectionCompletionRequestSchema.parse(receiptInput);
2087
+ const storedRequest = await receipts.get(agentHomeProjectionRequestKey(deviceId, receipt.requestId));
2088
+ if (storedRequest === void 0) {
2089
+ throw new ByokCloudError(
2090
+ "agent_home_projection_request_not_found",
2091
+ `Agent-home projection request ${receipt.requestId} was not found for this device.`
2092
+ );
2093
+ }
2094
+ const request = parseRequestBody(storedRequest.body);
2095
+ if (!receiptMatchesAgentHomeProjection(request, receipt)) {
2096
+ throw new ByokCloudError(
2097
+ "agent_home_projection_receipt_mismatch",
2098
+ `Agent-home projection completion ${receipt.requestId} does not exactly match its desired fact.`
2099
+ );
2100
+ }
2101
+ const body = JSON.stringify(receipt);
2102
+ const storedCompletion = await receipts.record({
2103
+ key: agentHomeProjectionCompletionKey(deviceId, receipt.requestId),
2104
+ body
2105
+ });
2106
+ if (!storedCompletion.created && storedCompletion.receipt.body !== body) {
2107
+ throw new ByokCloudError(
2108
+ "agent_home_projection_completion_conflict",
2109
+ `Agent-home projection request ${receipt.requestId} already has a different terminal completion.`
2110
+ );
2111
+ }
2112
+ return {
2113
+ tenantId: tenant,
2114
+ deviceId,
2115
+ requestId: request.requestId,
2116
+ agentRef: request.agentRef,
2117
+ projectionHash: request.projectionHash,
2118
+ status: receipt.outcome,
2119
+ completedAt: storedCompletion.receipt.recordedAt
2120
+ };
2121
+ }
1970
2122
  function projectTerminalResult(taskId, receipt) {
1971
2123
  let envelope;
1972
2124
  try {
@@ -2086,6 +2238,13 @@ function createByokCloud(options) {
2086
2238
  })
2087
2239
  );
2088
2240
  }
2241
+ registry.register(
2242
+ { method: "PUT", path: BYOK_AGENT_HOME_PROJECTION_COMPLETION_ROUTE, class: "device" },
2243
+ agentHomeProjectionCompletionHandler({
2244
+ ...deviceRouteDeps,
2245
+ complete: (stores, deviceId, receipt) => completeAgentHomeProjectionFromStores(stores, deviceId, receipt)
2246
+ })
2247
+ );
2089
2248
  if (declares(declaration, CLOUD_CAPABILITIES.boardCoordination)) {
2090
2249
  const boardDeps = {
2091
2250
  ...deviceRouteDeps,
@@ -2276,6 +2435,15 @@ function createByokCloud(options) {
2276
2435
  );
2277
2436
  }
2278
2437
  }
2438
+ async function assertLegacyAdmission(tenant, deviceId) {
2439
+ const device = await options.cloud.devices.get(tenant, deviceId);
2440
+ if (device?.capabilities?.includes(STRICT_AGENT_ONLY_CAPABILITY) === true) {
2441
+ throw new ByokCloudError(
2442
+ "agent_capability_missing",
2443
+ `Device ${deviceId} advertises strict-agent-only; refusing legacy offer before mailbox append.`
2444
+ );
2445
+ }
2446
+ }
2279
2447
  function contentReadCapability2(surface) {
2280
2448
  switch (surface) {
2281
2449
  case "workspace":
@@ -2310,6 +2478,34 @@ function createByokCloud(options) {
2310
2478
  }
2311
2479
  return { seq: message.seq, envelope };
2312
2480
  }
2481
+ async function getAgentHomeProjectionStatus(tenant, deviceId, input) {
2482
+ return readAgentHomeProjectionStatus(
2483
+ tenantStoresFor(controlPlane(tenant), root).receipts,
2484
+ tenant,
2485
+ deviceId,
2486
+ input
2487
+ );
2488
+ }
2489
+ async function completeAgentHomeProjection(tenant, deviceId, receiptInput) {
2490
+ return completeAgentHomeProjectionFromStores(
2491
+ tenantStoresFor(controlPlane(tenant), root),
2492
+ deviceId,
2493
+ receiptInput
2494
+ );
2495
+ }
2496
+ async function completeAgentHomeProjectionFromStores(stores, deviceId, receiptInput) {
2497
+ const receipt = AgentHomeProjectionCompletionRequestSchema.parse(receiptInput);
2498
+ await assertAgentCapabilities(stores.tenant, deviceId, [
2499
+ AGENT_HOME_CONTRACT_CAPABILITY,
2500
+ AGENT_HOME_PROJECTION_CAPABILITY
2501
+ ]);
2502
+ return recordAgentHomeProjectionCompletion(
2503
+ stores.receipts,
2504
+ stores.tenant,
2505
+ deviceId,
2506
+ receipt
2507
+ );
2508
+ }
2313
2509
  async function enqueueReliableEgressAck(stores, record) {
2314
2510
  const payload = AgentEgressAckPayloadSchema.parse({
2315
2511
  agentRef: record.payload.agentRef,
@@ -2386,6 +2582,7 @@ function createByokCloud(options) {
2386
2582
  return auth.createPairingCode(tenant, input);
2387
2583
  },
2388
2584
  async enqueueOffer(tenant, deviceId, input) {
2585
+ await assertLegacyAdmission(tenant, deviceId);
2389
2586
  return enqueueTaskEnvelope(
2390
2587
  tenant,
2391
2588
  deviceId,
@@ -2395,6 +2592,7 @@ function createByokCloud(options) {
2395
2592
  );
2396
2593
  },
2397
2594
  async enqueueToolsetOffer(tenant, deviceId, input) {
2595
+ await assertLegacyAdmission(tenant, deviceId);
2398
2596
  return enqueueTaskEnvelope(
2399
2597
  tenant,
2400
2598
  deviceId,
@@ -2478,6 +2676,52 @@ function createByokCloud(options) {
2478
2676
  }
2479
2677
  return control;
2480
2678
  },
2679
+ async enqueueAgentHomeProjection(tenant, deviceId, input) {
2680
+ const payload = AgentHomeProjectionPayloadSchema.parse(input);
2681
+ await assertAgentCapabilities(tenant, deviceId, [
2682
+ AGENT_HOME_CONTRACT_CAPABILITY,
2683
+ AGENT_HOME_PROJECTION_CAPABILITY
2684
+ ]);
2685
+ const stores = tenantStoresFor(controlPlane(tenant), root);
2686
+ const requestBody = JSON.stringify(payload);
2687
+ const persisted = await stores.receipts.record({
2688
+ key: agentHomeProjectionRequestKey(deviceId, payload.requestId),
2689
+ body: requestBody
2690
+ });
2691
+ const persistedPayload = AgentHomeProjectionPayloadSchema.parse(JSON.parse(persisted.receipt.body));
2692
+ if (!sameAgentHomeProjectionRequest(payload, persistedPayload)) {
2693
+ throw new ByokCloudError(
2694
+ "agent_home_projection_request_conflict",
2695
+ `Agent-home projection request ${payload.requestId} already exists with a different immutable desired body.`
2696
+ );
2697
+ }
2698
+ const control = await enqueueAgentControlEnvelope(
2699
+ tenant,
2700
+ deviceId,
2701
+ payload.requestId,
2702
+ (seq) => createEnvelope("agent.home.projection", payload, { id: payload.requestId, seq })
2703
+ );
2704
+ if (control.envelope.type !== "agent.home.projection" || !sameAgentHomeProjectionRequest(payload, control.envelope.payload)) {
2705
+ throw new ByokCloudError(
2706
+ "agent_home_projection_request_conflict",
2707
+ `Mailbox request ${payload.requestId} does not match its immutable Agent-home projection fact.`
2708
+ );
2709
+ }
2710
+ const status = await getAgentHomeProjectionStatus(tenant, deviceId, {
2711
+ requestId: payload.requestId,
2712
+ agentRef: payload.agentRef,
2713
+ projectionHash: payload.projectionHash
2714
+ });
2715
+ if (status === void 0) {
2716
+ throw new ByokCloudError(
2717
+ "agent_home_projection_receipt_invalid",
2718
+ `Agent-home projection request ${payload.requestId} disappeared after durable allocation.`
2719
+ );
2720
+ }
2721
+ return { ...control, status };
2722
+ },
2723
+ getAgentHomeProjectionStatus,
2724
+ completeAgentHomeProjection,
2481
2725
  async cancelTask(tenant, taskId, reason) {
2482
2726
  const stores = tenantStoresFor(controlPlane(tenant), root);
2483
2727
  const proposedMessageId = options.crypto.randomUuid();
@@ -3608,6 +3852,6 @@ var CLOUD_PORT_INTERFACES = {
3608
3852
  rateLimiter: "InboundRateLimiter"
3609
3853
  };
3610
3854
 
3611
- 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 };
3855
+ 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, agentHomeProjectionCompletionKey, agentHomeProjectionRequestKey, approvalTimelineCursor, authenticateBearer, authenticateDeviceProof, authenticateHostedDeviceAssertion, createAuthPlane, createByokCloud, createHmacTokenSigner, createInMemoryBlobs, createInMemoryByokCloud, createInMemoryCloudStores, createWebCrypto, declares, extractBearerToken, fullCapabilityDeclaration, handleInboundEnvelope, isCloudError, isTruthCommitError, parseApprovalObservations, parseTimelineEvents, projectTerminalResult, projectTimelineEvents, readAgentHomeProjectionStatus, recordAgentHomeProjectionCompletion, routeKey, tenantStoresFor, terminalReceiptKey, truthManifestMetadata, truthRecordMetadata, validateActivityAppend, validateApprovalTimelineAppend, verifyNonceSignature };
3612
3856
  //# sourceMappingURL=index.js.map
3613
3857
  //# sourceMappingURL=index.js.map