@byok-sdk/server 0.6.1 → 0.8.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/hub.d.ts CHANGED
@@ -3,7 +3,7 @@ import { type Envelope, type RuntimeId, type RuntimeInfo, type TaskState, type T
3
3
  import type { DeviceRegistry } from './auth';
4
4
  import { RateLimiter } from './rate-limiter';
5
5
  import type { TaskStore } from './task-store';
6
- import type { ByokServerEvent, AgentContentReadRequest, AgentEgressReceipt, DispatchInput, HubStats, MachineInfo, TaskHandle, TaskSnapshot } from './types';
6
+ import type { ByokServerEvent, AgentContentReadRequest, AgentEgressReceipt, DispatchInput, FreshAgentEgressDispatchInput, HubStats, MachineInfo, TaskHandle, TaskSnapshot } from './types';
7
7
  /**
8
8
  * The connection hub: tracks each device's live transport (WS or long-poll —
9
9
  * never both at once, see {@link takeOverAsLongPoll}), routes `dispatch()`'d
@@ -749,6 +749,8 @@ export declare class ConnectionHub {
749
749
  /** Reap one lease-expired task through the exact same TaskStore/canTransition path — and terminal-event emission — as any other `task.fail` (see {@link applyOrFail}). */
750
750
  private reapTask;
751
751
  dispatch(input: DispatchInput): Promise<TaskHandle>;
752
+ dispatchFreshAgentEgress(input: FreshAgentEgressDispatchInput): Promise<TaskHandle>;
753
+ private dispatchInternal;
752
754
  /** Capability-gated control-plane read request; no request enters the outbox on omission. */
753
755
  requestAgentContentRead(input: AgentContentReadRequest): Promise<void>;
754
756
  private buildTaskHandle;
package/dist/index.d.ts CHANGED
@@ -2,8 +2,8 @@ import type { Server as HttpServer } from 'node:http';
2
2
  import type { Hono } from 'hono';
3
3
  import { type TenantId } from './auth';
4
4
  import { type PairingCodeClaims, type PairingCodeInfo } from './pairing';
5
- import type { ByokServerEvent, AgentContentReadRequest, AgentEgressReceipt, CreateByokServerOptions, DispatchInput, HubStats, MachineInfo, TaskHandle, TaskSnapshot } from './types';
6
- export type { ByokServerEvent, AgentContentReadRequest, AgentEgressReceipt, CreateByokServerOptions, DispatchInput, HubStats, MachineInfo, ServerTaskEvent, TaskHandle, TaskResult, TaskSnapshot, } from './types';
5
+ import type { ByokServerEvent, AgentContentReadRequest, AgentEgressReceipt, CreateByokServerOptions, DispatchInput, FreshAgentEgressDispatchInput, HubStats, MachineInfo, TaskHandle, TaskSnapshot } from './types';
6
+ export type { ByokServerEvent, AgentContentReadRequest, AgentEgressReceipt, CreateByokServerOptions, DispatchInput, FreshAgentEgressDispatchInput, HubStats, MachineInfo, ServerTaskEvent, TaskHandle, TaskResult, TaskSnapshot, } from './types';
7
7
  export type { CreateTaskInput, TaskRecord, TaskStore } from './task-store';
8
8
  export { IllegalTaskTransitionError, InMemoryTaskStore } from './task-store';
9
9
  /**
@@ -60,6 +60,8 @@ export interface ByokServer {
60
60
  createPairingCode(claims: PairingCodeClaims): PairingCodeInfo;
61
61
  };
62
62
  dispatch(input: DispatchInput): Promise<TaskHandle>;
63
+ /** Dispatch a fresh Agent execution whose runtime will mint its session after start. */
64
+ dispatchFreshAgentEgress(input: FreshAgentEgressDispatchInput): Promise<TaskHandle>;
63
65
  /** Enqueue one capability-gated, exact-identity content-read request. */
64
66
  requestAgentContentRead(input: AgentContentReadRequest): Promise<void>;
65
67
  tasks: {
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { mkdir, writeFile, readFile } from 'fs/promises';
5
5
  import { mkdtempSync, mkdirSync, existsSync, chmodSync } from 'fs';
6
6
  import { tmpdir } from 'os';
7
7
  import path, { dirname } from 'path';
8
- import { CAPABILITY_FLAGS, byokBlobContentPath, canTransition, PROTOCOL_VERSION, encodeEnvelope, DAEMON_TO_SERVER_TYPES, AGENT_EGRESS_POLICY_CAPABILITY, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY, AgentRefSchema, AgentEgressPolicySchema, DispatchSelectionSchema, RequiredToolsetsSchema, AgentContentReadPayloadSchema, createEnvelope, TASK_STATES, BYOK_PAIR_PATH, PairRequestSchema, BYOK_CHALLENGE_PATH, ChallengeRequestSchema, BYOK_TOKEN_PATH, TokenRequestSchema, BYOK_BLOBS_PATH, CreateBlobRequestSchema, BYOK_BLOB_FINALIZE_ROUTE, BYOK_BLOB_URL_ROUTE, BYOK_BLOB_CONTENT_ROUTE, BYOK_EVENTS_PATH, BYOK_MESSAGES_PATH, MessagesSendRequestSchema, AGENT_CONTENT_ARTIFACT_READ_CAPABILITY, AGENT_CONTENT_TRANSCRIPT_READ_CAPABILITY, AGENT_CONTENT_WORKSPACE_READ_CAPABILITY, decodeEnvelope, BYOK_WS_PATH } from '@byok-sdk/protocol';
8
+ import { CAPABILITY_FLAGS, byokBlobContentPath, canTransition, PROTOCOL_VERSION, encodeEnvelope, DAEMON_TO_SERVER_TYPES, AGENT_EGRESS_POLICY_CAPABILITY, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY, AgentRefSchema, AgentEgressPolicySchema, DispatchSelectionSchema, RequiredToolsetsSchema, AGENT_EGRESS_FRESH_SESSION_CAPABILITY, AgentContentReadPayloadSchema, createEnvelope, TASK_STATES, BYOK_PAIR_PATH, PairRequestSchema, PairResponseSchema, BYOK_CHALLENGE_PATH, ChallengeRequestSchema, BYOK_TOKEN_PATH, TokenRequestSchema, BYOK_BLOBS_PATH, CreateBlobRequestSchema, BYOK_BLOB_FINALIZE_ROUTE, BYOK_BLOB_URL_ROUTE, BYOK_BLOB_CONTENT_ROUTE, BYOK_EVENTS_PATH, BYOK_MESSAGES_PATH, MessagesSendRequestSchema, AGENT_CONTENT_ARTIFACT_READ_CAPABILITY, AGENT_CONTENT_TRANSCRIPT_READ_CAPABILITY, AGENT_CONTENT_WORKSPACE_READ_CAPABILITY, PairResponseTenantIdSchema, decodeEnvelope, BYOK_WS_PATH } from '@byok-sdk/protocol';
9
9
  import { Hono } from 'hono';
10
10
  import { WebSocketServer } from 'ws';
11
11
  import { createRequire } from 'module';
@@ -266,8 +266,6 @@ function generateDeviceId() {
266
266
  function generateTaskId() {
267
267
  return `task_${randomUUID()}`;
268
268
  }
269
-
270
- // src/pairing.ts
271
269
  var PAIRING_CODE_TTL_MS = 10 * 60 * 1e3;
272
270
  var PairingCodeInvalidError = class extends Error {
273
271
  constructor(reason) {
@@ -320,13 +318,14 @@ function validatePairingCodeClaims(claims) {
320
318
  throw new TypeError("createPairingCode requires { tenantId, productId } claims");
321
319
  }
322
320
  const { tenantId, productId } = claims;
323
- if (typeof tenantId !== "string" || tenantId.length === 0) {
324
- throw new TypeError("createPairingCode requires a non-empty tenantId");
321
+ const tenantResult = PairResponseTenantIdSchema.safeParse(tenantId);
322
+ if (!tenantResult.success) {
323
+ throw new TypeError("createPairingCode requires a valid bounded tenantId");
325
324
  }
326
325
  if (typeof productId !== "string" || productId.length === 0) {
327
326
  throw new TypeError("createPairingCode requires a non-empty productId");
328
327
  }
329
- return { tenantId, productId };
328
+ return { tenantId: tenantResult.data, productId };
330
329
  }
331
330
 
332
331
  // src/http.ts
@@ -366,12 +365,21 @@ function buildHonoApp(deps) {
366
365
  deviceName,
367
366
  devicePublicKey
368
367
  });
368
+ const device = deps.devices.get(claims.tenantId, deviceId);
369
+ if (device === void 0) {
370
+ throw new Error("paired device row was not persisted");
371
+ }
369
372
  const { accessToken, expiresAt } = await mintAccessToken(deps.tokenSigner, {
370
- deviceId,
371
- tenantId: claims.tenantId,
372
- productId: claims.productId
373
+ deviceId: device.deviceId,
374
+ tenantId: device.tenantId,
375
+ productId: device.productId
376
+ });
377
+ const response = PairResponseSchema.parse({
378
+ deviceId: device.deviceId,
379
+ accessToken,
380
+ refreshHint: expiresAt,
381
+ tenantId: device.tenantId
373
382
  });
374
- const response = { deviceId, accessToken, refreshHint: expiresAt };
375
383
  return c.json(response, 200);
376
384
  });
377
385
  app.post(BYOK_CHALLENGE_PATH, async (c) => {
@@ -1849,6 +1857,25 @@ var ConnectionHub = class {
1849
1857
  // dispatch() and the TaskHandle it returns
1850
1858
  // ---------------------------------------------------------------------
1851
1859
  async dispatch(input) {
1860
+ if (input.egressPolicy !== void 0 && input.sessionRef === void 0) {
1861
+ throw new Error("Agent egress resume dispatch requires an exact sessionRef; use dispatchFreshAgentEgress for fresh execution");
1862
+ }
1863
+ return this.dispatchInternal(input, false);
1864
+ }
1865
+ async dispatchFreshAgentEgress(input) {
1866
+ if (Object.prototype.hasOwnProperty.call(input, "sessionRef")) {
1867
+ throw new Error("fresh Agent egress dispatch must not carry sessionRef");
1868
+ }
1869
+ if (typeof input.deviceId !== "string" || input.deviceId.length === 0) {
1870
+ throw new Error("fresh Agent egress dispatch requires an explicit deviceId");
1871
+ }
1872
+ if (input.agentRef === void 0 || input.egressPolicy === void 0) {
1873
+ throw new Error("fresh Agent egress dispatch requires exact AgentRef and egress policy");
1874
+ }
1875
+ return this.dispatchInternal(input, true);
1876
+ }
1877
+ async dispatchInternal(input, freshAgentEgress) {
1878
+ const sessionRef = "sessionRef" in input ? input.sessionRef : void 0;
1852
1879
  const agentRef = input.agentRef === void 0 ? void 0 : AgentRefSchema.parse(input.agentRef);
1853
1880
  const egressPolicy = input.egressPolicy === void 0 ? void 0 : AgentEgressPolicySchema.parse(input.egressPolicy);
1854
1881
  const dispatchSelection = input.dispatchSelection === void 0 ? void 0 : DispatchSelectionSchema.parse(input.dispatchSelection);
@@ -1860,9 +1887,6 @@ var ConnectionHub = class {
1860
1887
  if (egressPolicy !== void 0 && agentRef === void 0) {
1861
1888
  throw new Error("Agent egress policy requires an explicit AgentRef; legacy task dispatch cannot consume it");
1862
1889
  }
1863
- if (egressPolicy !== void 0 && input.sessionRef === void 0) {
1864
- throw new Error("Agent egress policy requires an exact sessionRef");
1865
- }
1866
1890
  if (!deviceId || !this.connections.get(deviceId)?.connected) {
1867
1891
  throw new Error(
1868
1892
  deviceId ? `device ${deviceId} is not connected` : "no connected device to dispatch to (M0 does not queue tasks until a device connects)"
@@ -1873,9 +1897,14 @@ var ConnectionHub = class {
1873
1897
  `device ${deviceId} did not advertise agent-home-contract capability; refusing Agent-bound dispatch`
1874
1898
  );
1875
1899
  }
1876
- if (egressPolicy !== void 0 && !this.hasDeviceCapabilities(deviceId, [AGENT_EGRESS_POLICY_CAPABILITY, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY])) {
1900
+ const requiredEgressCapabilities = freshAgentEgress ? [
1901
+ AGENT_EGRESS_POLICY_CAPABILITY,
1902
+ AGENT_EGRESS_RELIABLE_ACK_CAPABILITY,
1903
+ AGENT_EGRESS_FRESH_SESSION_CAPABILITY
1904
+ ] : [AGENT_EGRESS_POLICY_CAPABILITY, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY];
1905
+ if (egressPolicy !== void 0 && !this.hasDeviceCapabilities(deviceId, requiredEgressCapabilities)) {
1877
1906
  throw new Error(
1878
- `device ${deviceId} did not advertise Agent egress policy and reliable acknowledgement capabilities; refusing before enqueue`
1907
+ freshAgentEgress ? `device ${deviceId} did not advertise Agent egress policy, reliable acknowledgement, and fresh-session capabilities; refusing before enqueue` : `device ${deviceId} did not advertise Agent egress policy and reliable acknowledgement capabilities; refusing before enqueue`
1879
1908
  );
1880
1909
  }
1881
1910
  if (dispatchSelection !== void 0 && !(this.getDeviceCapabilities(deviceId)?.includes("dispatch-selection") ?? false)) {
@@ -1918,7 +1947,7 @@ var ConnectionHub = class {
1918
1947
  policy,
1919
1948
  requiredToolsets,
1920
1949
  deviceId,
1921
- sessionRef: input.sessionRef,
1950
+ sessionRef,
1922
1951
  agentRef
1923
1952
  });
1924
1953
  const queue = new AsyncEventQueue();
@@ -1934,36 +1963,52 @@ var ConnectionHub = class {
1934
1963
  policy,
1935
1964
  runtime,
1936
1965
  dispatchSelection,
1937
- sessionRef: input.sessionRef
1966
+ sessionRef
1938
1967
  };
1939
- if (agentRef !== void 0 && egressPolicy !== void 0) {
1968
+ if (agentRef !== void 0 && egressPolicy !== void 0 && freshAgentEgress) {
1969
+ const freshOffer = {
1970
+ instruction: input.instruction,
1971
+ policy,
1972
+ runtime,
1973
+ dispatchSelection,
1974
+ agentRef,
1975
+ egressPolicy,
1976
+ ...requiredToolsets === void 0 ? {} : { requiredToolsets }
1977
+ };
1978
+ this.sendToDevice(
1979
+ deviceId,
1980
+ "task.offer_for_agent_with_egress_fresh",
1981
+ freshOffer,
1982
+ { taskId }
1983
+ );
1984
+ } else if (agentRef !== void 0 && egressPolicy !== void 0) {
1940
1985
  this.sendToDevice(
1941
1986
  deviceId,
1942
1987
  "task.offer_for_agent_with_egress",
1943
1988
  {
1944
1989
  ...commonOffer,
1945
- sessionRef: input.sessionRef,
1990
+ sessionRef,
1946
1991
  agentRef,
1947
1992
  egressPolicy,
1948
1993
  ...requiredToolsets === void 0 ? {} : { requiredToolsets }
1949
1994
  },
1950
- { taskId, sessionRef: input.sessionRef }
1995
+ { taskId, sessionRef }
1951
1996
  );
1952
1997
  } else if (agentRef !== void 0) {
1953
1998
  this.sendToDevice(
1954
1999
  deviceId,
1955
2000
  "task.offer_for_agent",
1956
2001
  { ...commonOffer, agentRef, ...requiredToolsets === void 0 ? {} : { requiredToolsets } },
1957
- { taskId, sessionRef: input.sessionRef }
2002
+ { taskId, sessionRef }
1958
2003
  );
1959
2004
  } else if (requiredToolsets === void 0) {
1960
- this.sendToDevice(deviceId, "task.offer", commonOffer, { taskId, sessionRef: input.sessionRef });
2005
+ this.sendToDevice(deviceId, "task.offer", commonOffer, { taskId, sessionRef });
1961
2006
  } else {
1962
2007
  this.sendToDevice(
1963
2008
  deviceId,
1964
2009
  "task.offer_with_toolsets",
1965
2010
  { ...commonOffer, requiredToolsets },
1966
- { taskId, sessionRef: input.sessionRef }
2011
+ { taskId, sessionRef }
1967
2012
  );
1968
2013
  }
1969
2014
  return this.buildTaskHandle(taskId);
@@ -3027,6 +3072,7 @@ function createByokServer(opts) {
3027
3072
  createPairingCode: (claims) => pairing.createPairingCode(claims)
3028
3073
  },
3029
3074
  dispatch: (input) => hub.dispatch(input),
3075
+ dispatchFreshAgentEgress: (input) => hub.dispatchFreshAgentEgress(input),
3030
3076
  requestAgentContentRead: (input) => hub.requestAgentContentRead(input),
3031
3077
  tasks: {
3032
3078
  get: (taskId) => hub.getTask(taskId),