@agentknight/sdk 0.9.39 → 0.9.41

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
@@ -4,12 +4,12 @@ import {
4
4
  PeerChatRequestSchema,
5
5
  PeerChatResultSchema,
6
6
  validateDataDirectory
7
- } from "./chunks/chunk-UE4QYZCG.js";
7
+ } from "./chunks/chunk-QN3OD5UE.js";
8
8
  import {
9
9
  AgentSelectionSchema,
10
10
  assertSelectionSnapshotFits,
11
11
  supportsAgentSelection
12
- } from "./chunks/chunk-KPRPUIXR.js";
12
+ } from "./chunks/chunk-ASHXZ46V.js";
13
13
  import {
14
14
  ConversationNormalizer,
15
15
  LiveTimelineProjection,
@@ -31,25 +31,26 @@ import {
31
31
  resolveGitProjectIdentity,
32
32
  sessionRestoreFailure,
33
33
  validateOperationResponse
34
- } from "./chunks/chunk-QGPX4UDW.js";
34
+ } from "./chunks/chunk-SHOE7YAU.js";
35
35
  import {
36
36
  GROUP_CHAT_MAX_TURNS,
37
37
  GroupChatError
38
- } from "./chunks/chunk-VCNYBWYE.js";
38
+ } from "./chunks/chunk-VDC4G7ZG.js";
39
39
  import {
40
40
  assistantPreview,
41
41
  isContentfulAssistant,
42
42
  userPreview
43
- } from "./chunks/chunk-N4MN54CD.js";
43
+ } from "./chunks/chunk-RBULXS7T.js";
44
44
  import {
45
45
  AgentModelListingError,
46
46
  AgentSessionRenameError,
47
47
  SessionOperationError,
48
48
  SessionOperations,
49
+ TimelinePageBudgetError,
49
50
  UnsupportedAgentOperationError,
50
51
  captureResearchAccess,
51
52
  captureWorkbenchAccess
52
- } from "./chunks/chunk-BM6T2DLH.js";
53
+ } from "./chunks/chunk-LQIW4ARE.js";
53
54
  import {
54
55
  A2aRelayRequestSchema,
55
56
  A2aRelayResponseSchema,
@@ -85,6 +86,7 @@ import {
85
86
  PC_PEER_CHAT_CAPABILITY,
86
87
  PROTOCOL_VERSION,
87
88
  PairingCreateResultSchema,
89
+ PairingStatusResultSchema,
88
90
  PeerDeliverySchema,
89
91
  PeerMessageSchema,
90
92
  PermissionRequestPayloadSchema,
@@ -95,6 +97,7 @@ import {
95
97
  SECURE_MESSAGE_MAX_CIPHERTEXT_LENGTH,
96
98
  SECURE_SOCKET_IO_NAMESPACE,
97
99
  SESSION_ASSISTANT_PREVIEW_CAPABILITY,
100
+ SESSION_AVATAR_PERSONA_CAPABILITY,
98
101
  SESSION_COMMUNICATION_CAPABILITY,
99
102
  SESSION_DELETE_CAPABILITY,
100
103
  SESSION_DIRECTORY_LIST_OPERATION,
@@ -124,6 +127,7 @@ import {
124
127
  SESSION_IMAGE_MAX_PIXELS,
125
128
  SESSION_LIST_UPDATES_CAPABILITY,
126
129
  SESSION_OPTIONS_PARTIAL_CAPABILITY,
130
+ SESSION_OPTIONS_PROGRESSIVE_CAPABILITY,
127
131
  SESSION_PROJECT_IDENTITY_OPERATION,
128
132
  SESSION_PROJECT_IDENTITY_VERSION,
129
133
  SESSION_PROMPT_SUBMISSION_TIME_CAPABILITY,
@@ -223,7 +227,7 @@ import {
223
227
  sessionCommunicationError,
224
228
  sessionCommunicationOperationCapability,
225
229
  workbenchCapability
226
- } from "./chunks/chunk-E3XCZWRK.js";
230
+ } from "./chunks/chunk-QTBB2U7G.js";
227
231
 
228
232
  // src/initialize.ts
229
233
  import { createHash as createHash16 } from "node:crypto";
@@ -301,7 +305,7 @@ async function createCodingAgentAdapter(config, onDiagnostic, owner) {
301
305
  switch (engine.kind) {
302
306
  case "managed": {
303
307
  if (owner === void 0) throw new Error("Managed coding agents require the PC owner identity");
304
- const { ManagedCodingAgentAdapter } = await import("./chunks/managed-agent-adapter-T3FVUJHA.js");
308
+ const { ManagedCodingAgentAdapter } = await import("./chunks/managed-agent-adapter-LMHQX6IH.js");
305
309
  return new ManagedCodingAgentAdapter({
306
310
  dataDirectory: config.dataDirectory,
307
311
  owner,
@@ -340,7 +344,7 @@ async function createCodingAgentAdapter(config, onDiagnostic, owner) {
340
344
  });
341
345
  }
342
346
  case "copilot": {
343
- const { GithubCopilotAdapter } = await import("./chunks/copilot-adapter-N5B7BNWO.js");
347
+ const { GithubCopilotAdapter } = await import("./chunks/copilot-adapter-FY75OLIU.js");
344
348
  if (owner !== void 0) {
345
349
  return new GithubCopilotAdapter(void 0, void 0, void 0, {
346
350
  dataDirectory: config.dataDirectory,
@@ -360,13 +364,13 @@ async function createCodingAgentAdapter(config, onDiagnostic, owner) {
360
364
  }
361
365
  case "pi": {
362
366
  assertPiRuntimeSupported();
363
- const { PiCodingAgentAdapter } = await import("./chunks/pi-adapter-PHEFFJVF.js");
367
+ const { PiCodingAgentAdapter } = await import("./chunks/pi-adapter-NWQWUNXO.js");
364
368
  return new PiCodingAgentAdapter(
365
369
  engine.agentDirectory === void 0 ? {} : { agentDirectory: resolve(engine.agentDirectory) }
366
370
  );
367
371
  }
368
372
  case "acp": {
369
- const { AcpCodingAgentAdapter } = await import("./chunks/acp-adapter-BWVM6WIF.js");
373
+ const { AcpCodingAgentAdapter } = await import("./chunks/acp-adapter-SPIMGGL2.js");
370
374
  return new AcpCodingAgentAdapter({
371
375
  command: engine.command,
372
376
  args: engine.args,
@@ -747,43 +751,47 @@ var DeviceIdentitySchema = z3.object({
747
751
 
748
752
  // src/pairing.ts
749
753
  var CachedPairingProvider = class {
754
+ constructor(requestPairing, minimumValidityMs = 15e3, requestStatus) {
755
+ this.requestStatus = requestStatus;
756
+ this.#requestPairing = requestPairing;
757
+ this.#minimumValidityMs = minimumValidityMs;
758
+ }
759
+ requestStatus;
750
760
  #requestPairing;
751
761
  #minimumValidityMs;
752
762
  #current;
753
763
  #pending;
754
- #requestSequence = 0;
755
- #committedSequence = 0;
756
- constructor(requestPairing, minimumValidityMs = 15e3) {
757
- this.#requestPairing = requestPairing;
758
- this.#minimumValidityMs = minimumValidityMs;
759
- }
760
764
  async getPairing(options = {}) {
761
765
  const force = options.force ?? false;
762
766
  if (this.#pending !== void 0) {
763
767
  return this.#pending;
764
768
  }
765
- if (!force && this.#current !== void 0 && this.#current.expiresAt > Date.now() + this.#minimumValidityMs) {
766
- return this.#current;
767
- }
768
- const sequence = ++this.#requestSequence;
769
- const pending = this.#requestPairing().then((pairing) => {
770
- if (pairing.expiresAt <= Date.now()) {
771
- throw new Error("Relay returned an expired pairing ticket");
772
- }
773
- if (sequence >= this.#committedSequence) {
774
- this.#committedSequence = sequence;
775
- this.#current = pairing;
776
- }
777
- return pairing;
778
- });
769
+ const pending = this.#getPairing(force);
779
770
  this.#pending = pending;
780
771
  try {
781
772
  return await pending;
782
773
  } finally {
783
- if (this.#pending === pending) {
784
- this.#pending = void 0;
785
- }
774
+ if (this.#pending === pending) this.#pending = void 0;
775
+ }
776
+ }
777
+ async getPairingStatus(statusId) {
778
+ const state = await this.requestStatus?.(statusId) ?? "unavailable";
779
+ if (state !== "pending" && this.#current?.statusId === statusId) {
780
+ this.#current = void 0;
781
+ }
782
+ return state;
783
+ }
784
+ async #getPairing(force) {
785
+ const current = this.#current;
786
+ if (!force && current !== void 0 && current.expiresAt > Date.now() + this.#minimumValidityMs && (current.statusId === void 0 || this.requestStatus === void 0 || await this.getPairingStatus(current.statusId) === "pending")) {
787
+ return current;
788
+ }
789
+ const pairing = await this.#requestPairing();
790
+ if (pairing.expiresAt <= Date.now()) {
791
+ throw new Error("Relay returned an expired pairing ticket");
786
792
  }
793
+ this.#current = pairing;
794
+ return pairing;
787
795
  }
788
796
  };
789
797
  function buildPairingUri(relayUrl, code, machineId, contentKey) {
@@ -827,9 +835,26 @@ async function requestPairingUri(config, identity2, contentKey) {
827
835
  identity2.machineId,
828
836
  contentKey.encoded
829
837
  ),
830
- expiresAt: result.expiresAt
838
+ expiresAt: result.expiresAt,
839
+ ...result.statusId === void 0 ? {} : { statusId: result.statusId }
831
840
  };
832
841
  }
842
+ async function requestPairingStatus(config, identity2, statusId) {
843
+ const response = await fetch(`${config.relayUrl.replace(/\/+$/, "")}/auth/pairing/status`, {
844
+ method: "POST",
845
+ headers: {
846
+ authorization: `Bearer ${config.relayToken}`,
847
+ "content-type": "application/json"
848
+ },
849
+ body: JSON.stringify({ userId: config.userId, machineId: identity2.machineId, statusId }),
850
+ signal: AbortSignal.timeout(1e4)
851
+ });
852
+ const result = PairingStatusResultSchema.parse(await response.json());
853
+ if (!response.ok || !result.ok) {
854
+ throw new Error(result.ok ? `Relay pairing status failed with HTTP ${response.status}` : `${result.error.code}: ${result.error.message}`);
855
+ }
856
+ return result.state;
857
+ }
833
858
 
834
859
  // src/pc-agent.ts
835
860
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
@@ -2324,11 +2349,21 @@ function researchAwareCodingAgentAdapter(inner, research) {
2324
2349
  },
2325
2350
  readSessionTimelinePage: (id, options) => route(id, () => research.timeline(id, options), () => inner.readSessionTimelinePage(id, options)),
2326
2351
  watchSession: (id, watched) => route(id, () => research.watch(id, watched), () => inner.watchSession(id, watched)),
2327
- sendPrompt: (id, prompt, mode, attachments, persist, files, operationId) => route(id, () => {
2352
+ sendPrompt: (id, prompt, mode, attachments, persist, files, operationId, avatarPersona) => route(id, () => {
2353
+ if (avatarPersona !== void 0) return deny();
2328
2354
  if (attachments?.length || files?.length) return deny();
2329
2355
  if (operationId === void 0) throw new SessionOperationError("OPERATION_ID_REQUIRED", "A stable operation ID is required");
2330
2356
  return research.sendPrompt(id, prompt, mode, operationId);
2331
- }, () => inner.sendPrompt(id, prompt, mode, attachments, persist, files, operationId)),
2357
+ }, () => inner.sendPrompt(
2358
+ id,
2359
+ prompt,
2360
+ mode,
2361
+ attachments,
2362
+ persist,
2363
+ files,
2364
+ operationId,
2365
+ ...avatarPersona === void 0 ? [] : [avatarPersona]
2366
+ )),
2332
2367
  abortSession: (id) => route(id, () => research.abort(id), () => inner.abortSession(id)),
2333
2368
  getSessionConfiguration: (id) => route(id, () => research.configuration(id), () => inner.getSessionConfiguration(id)),
2334
2369
  getSessionCapabilities: (id) => id !== void 0 && owned(id) ? { agentModes: ["interactive"], supportsReasoningEffort: false, supportsFileAttachments: false, supportsPlanRead: false, agentName: "Side chat" } : inner.getSessionCapabilities?.(id) ?? inner,
@@ -2403,8 +2438,25 @@ function toErrorDetails(error) {
2403
2438
  };
2404
2439
  }
2405
2440
 
2406
- // src/pc-agent.ts
2441
+ // src/service/transport/relay-socket.ts
2407
2442
  import { io } from "socket.io-client";
2443
+ function createRelaySocket(uri, options) {
2444
+ const socket = io(uri, { ...options, autoConnect: false });
2445
+ socket.on("connect_error", (error) => {
2446
+ const manager = socket.io;
2447
+ const transports = manager.opts.transports;
2448
+ if (error.message !== "timeout" || manager.engine.readyState !== "opening" || !manager.opts.tryAllTransports || transports === void 0 || transports.length < 2 || !transports.every((transport) => typeof transport === "string")) return;
2449
+ const failedTransport = manager.engine.transport.name;
2450
+ const failedIndex = transports.findIndex((transport) => transport === failedTransport);
2451
+ if (failedIndex < 0) return;
2452
+ manager.opts.transports = [
2453
+ ...transports.slice(failedIndex + 1),
2454
+ ...transports.slice(0, failedIndex + 1)
2455
+ ];
2456
+ });
2457
+ if (options.autoConnect !== false) socket.connect();
2458
+ return socket;
2459
+ }
2408
2460
 
2409
2461
  // src/service/requests/session-communication.ts
2410
2462
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -2793,7 +2845,7 @@ var Work = class {
2793
2845
  GIT_DIR: join6(cwd, "no-repository"),
2794
2846
  GIT_CONFIG_NOSYSTEM: "1",
2795
2847
  GIT_ATTR_NOSYSTEM: "1",
2796
- GIT_CONFIG_GLOBAL: process.platform === "win32" ? "NUL" : "/dev/null"
2848
+ GIT_CONFIG_GLOBAL: join6(cwd, "gitconfig")
2797
2849
  } : {}
2798
2850
  }
2799
2851
  }, (error, output2, stderr) => {
@@ -3122,6 +3174,7 @@ async function patch(context, change, work, scratchDirectory) {
3122
3174
  await writeFile2(file, content, { flag: "wx", mode: 384 });
3123
3175
  if (process.platform !== "win32") await chmod(file, mode === "100755" ? 448 : 384);
3124
3176
  }
3177
+ await writeFile2(join6(scratch, "gitconfig"), "", { flag: "wx", mode: 384 });
3125
3178
  text = decode(await work.git(scratch, [
3126
3179
  "-c",
3127
3180
  "core.quotePath=false",
@@ -3302,10 +3355,10 @@ var TimelineImageCache = class {
3302
3355
  get bytes() {
3303
3356
  return this.#bytes;
3304
3357
  }
3305
- referenceItem(sessionId, item) {
3358
+ referenceItem = (sessionId, item) => {
3306
3359
  if (!("attachments" in item) || item.attachments === void 0) return item;
3307
3360
  return { ...item, attachments: item.attachments.map((attachment) => this.#reference(sessionId, attachment)) };
3308
- }
3361
+ };
3309
3362
  read(sessionId, request) {
3310
3363
  const key = JSON.stringify([sessionId, request.sha256]);
3311
3364
  const asset = this.#assets.get(key);
@@ -3632,6 +3685,9 @@ var SessionImageUploader = class {
3632
3685
  headers: { ...this.#headers(), "content-type": "application/json" },
3633
3686
  body: JSON.stringify(body)
3634
3687
  }, stage, signal, async (response, requestSignal) => {
3688
+ if (stage === "reserve" && response.status === 404) {
3689
+ throw new SessionImageUploadError("IMAGE_STORAGE_UNAVAILABLE", stage, response.status);
3690
+ }
3635
3691
  if (response.status !== status) throw new SessionImageUploadError("IMAGE_HTTP_ERROR", stage, response.status);
3636
3692
  const contentLength = response.headers.get("content-length");
3637
3693
  assert(
@@ -4576,14 +4632,14 @@ var SessionOptionsHandler = class {
4576
4632
  ]));
4577
4633
  if (modelResult.status === "fulfilled" && modelResult.value.length > 0) availableModels = modelResult.value;
4578
4634
  if (configurationResult.status === "fulfilled") configuration = configurationResult.value;
4579
- for (const [stage, result] of [
4635
+ for (const [stage, result2] of [
4580
4636
  ["configuration", configurationResult],
4581
4637
  ["models", modelResult],
4582
4638
  ["workspaces", workspaceResult]
4583
4639
  ]) {
4584
- if (result.status === "rejected" && isSessionRestoreFailure(result.reason)) {
4640
+ if (result2.status === "rejected" && isSessionRestoreFailure(result2.reason)) {
4585
4641
  failureStage = stage;
4586
- throw result.reason;
4642
+ throw result2.reason;
4587
4643
  }
4588
4644
  }
4589
4645
  if (configurationResult.status === "rejected") {
@@ -4605,7 +4661,8 @@ var SessionOptionsHandler = class {
4605
4661
  failureStage = "models";
4606
4662
  throw modelFailure ?? new Error("No coding-agent models are available. Select an authenticated coding agent on the PC.");
4607
4663
  }
4608
- const environment2 = await sessionEnvironment;
4664
+ const progressive = request.sessionId !== void 0 && request.capabilities?.includes(SESSION_OPTIONS_PROGRESSIVE_CAPABILITY) === true;
4665
+ const environment2 = progressive ? void 0 : await sessionEnvironment;
4609
4666
  const worktreeCreationSupported = request.sessionId === void 0 && request.capabilities?.includes(SESSION_WORKTREE_CREATION_CAPABILITY) === true;
4610
4667
  let worktreeChoices;
4611
4668
  if (worktreeCreationSupported && request.workspaceId !== void 0) {
@@ -4617,7 +4674,7 @@ var SessionOptionsHandler = class {
4617
4674
  }
4618
4675
  const capabilities = adapter.getSessionCapabilities?.(request.sessionId) ?? adapter;
4619
4676
  this.#errors.recovered(errorKey);
4620
- emit("session.options.result", {
4677
+ const result = {
4621
4678
  ok: true,
4622
4679
  requestId: request.requestId,
4623
4680
  machineId,
@@ -4639,7 +4696,21 @@ var SessionOptionsHandler = class {
4639
4696
  ...environment2 === void 0 ? {} : { environment: environment2 },
4640
4697
  agentName: "agentName" in capabilities && typeof capabilities.agentName === "string" ? capabilities.agentName : codingAgentPresentation(adapter.agentId).name,
4641
4698
  ...current?.configOptions === void 0 ? {} : { configOptions: current.configOptions }
4699
+ };
4700
+ if (!scope.isCurrent()) return;
4701
+ emit("session.options.result", {
4702
+ ...result,
4703
+ ...progressive ? { environmentPending: true } : {}
4642
4704
  });
4705
+ if (progressive) {
4706
+ const environment3 = await sessionEnvironment;
4707
+ if (!scope.isCurrent()) return;
4708
+ adapter.getSessionCapabilities?.(request.sessionId);
4709
+ emit("session.options.result", {
4710
+ ...result,
4711
+ ...environment3 === void 0 ? {} : { environment: environment3 }
4712
+ });
4713
+ }
4643
4714
  const plan = await sessionPlan;
4644
4715
  if (plan !== void 0 && scope.isCurrent()) {
4645
4716
  emit("conversation.item.upsert", plan);
@@ -5023,11 +5094,15 @@ var SessionCommandsHandler = class {
5023
5094
  // src/service/requests/session-prompt.ts
5024
5095
  import { createHash as createHash10 } from "node:crypto";
5025
5096
  function promptOperationFingerprint(request) {
5026
- return createHash10("sha256").update(request.sessionId).update("\0").update(request.mode).update("\0").update(request.prompt).update("\0").update(request.attachments?.map((attachment) => attachment.sha256).join(",") ?? "").update("\0").update(JSON.stringify(request.fileAttachments?.map(({ name, mimeType, sha256 }) => ({
5097
+ const fingerprint = createHash10("sha256").update(request.sessionId).update("\0").update(request.mode).update("\0").update(request.prompt).update("\0").update(request.attachments?.map((attachment) => attachment.sha256).join(",") ?? "").update("\0").update(JSON.stringify(request.fileAttachments?.map(({ name, mimeType, sha256 }) => ({
5027
5098
  name,
5028
5099
  mimeType,
5029
5100
  sha256
5030
- })) ?? [])).digest("base64url");
5101
+ })) ?? []));
5102
+ if (request.avatarPersona !== void 0) {
5103
+ fingerprint.update("\0").update(JSON.stringify(request.avatarPersona));
5104
+ }
5105
+ return fingerprint.digest("base64url");
5031
5106
  }
5032
5107
  var SessionPromptHandler = class {
5033
5108
  constructor(options) {
@@ -5049,6 +5124,9 @@ var SessionPromptHandler = class {
5049
5124
  if (adapter.isSessionVisible?.(request.sessionId) === false) {
5050
5125
  throw new Error("This session's coding agent is not shared or is unavailable on the PC");
5051
5126
  }
5127
+ if (request.avatarPersona !== void 0 && adapter.agentId !== "copilot" && adapter.agentId !== "managed") {
5128
+ throw new Error("Avatar personas require Copilot; nothing was submitted");
5129
+ }
5052
5130
  const accepted = await diagnostics.run(() => this.#operations.run({
5053
5131
  operationId: request.operationId,
5054
5132
  fingerprint: promptOperationFingerprint(request),
@@ -5067,7 +5145,8 @@ var SessionPromptHandler = class {
5067
5145
  request.attachments,
5068
5146
  this.options.supportsPersistentInteractions(context.clientId),
5069
5147
  request.fileAttachments,
5070
- request.operationId
5148
+ request.operationId,
5149
+ ...request.avatarPersona === void 0 ? [] : [request.avatarPersona]
5071
5150
  )
5072
5151
  }));
5073
5152
  emit("session.prompt.result", {
@@ -5186,63 +5265,95 @@ var SessionTimelinePageHandler = class {
5186
5265
  if (request.metadataOnly === true && request.assistantPreview !== true && adapter.supportsSessionListUpdates !== true) {
5187
5266
  throw new Error("Passive session metadata is not supported by this runtime");
5188
5267
  }
5189
- const page = await diagnostics.run(() => measureOperationPhase("read", () => adapter.readSessionTimelinePage(
5190
- request.sessionId,
5191
- request.metadataOnly === true ? {
5192
- pageSize: request.pageSize,
5193
- metadataOnly: true,
5194
- ...request.assistantPreview === true ? { assistantPreview: true } : {},
5195
- ...request.cursor === void 0 ? {} : { cursor: request.cursor }
5196
- } : request.cursor === void 0 ? { pageSize: request.pageSize } : { cursor: request.cursor, pageSize: request.pageSize }
5197
- )));
5198
- if (diagnostics.activeMs >= 1e3) {
5199
- logger.info({
5200
- ...diagnosticRequest(request),
5201
- ...diagnostics.details(),
5202
- metadataOnly: request.metadataOnly === true
5203
- }, "session.timeline.page.read-slow");
5204
- }
5205
- if (!publications.isCurrent(request.sessionId, publication)) throw new SessionNotSharedError();
5206
- const latestAssistant = request.assistantPreview === true ? [...page.items].reverse().find(isContentfulAssistant) : void 0;
5207
- const preview = latestAssistant === void 0 ? void 0 : assistantPreview(
5208
- latestAssistant,
5209
- (item) => this.options.referenceItem(request.sessionId, item)
5210
- );
5211
- const latestUser = request.assistantPreview === true ? [...page.items].reverse().find((item) => item.kind === "human-message" && item.actor === "human") : void 0;
5212
- const humanPreview = latestUser === void 0 ? void 0 : userPreview(latestUser);
5213
- const responsePage = {
5214
- ...page,
5215
- ...preview === void 0 ? {} : { assistantPreview: preview },
5216
- ...humanPreview === void 0 ? {} : { userPreview: humanPreview },
5217
- ...request.assistantPreview === true ? { previewsComplete: !page.hasMore } : {},
5218
- items: request.metadataOnly === true && request.assistantPreview === true ? page.items.map((item) => item.kind === "assistant-message" || item.kind === "human-message" ? { ...item, content: "", attachments: [] } : item) : page.items
5219
- };
5220
- const result = {
5221
- ok: true,
5222
- requestId: request.requestId,
5223
- machineId,
5224
- sessionId: request.sessionId,
5225
- page: request.imageReferences === true && config.timelineIncrementalEnabled !== false && this.options.imageReferencesEnabled() ? { ...responsePage, items: responsePage.items.map((item) => this.options.referenceItem(request.sessionId, item)) } : responsePage
5226
- };
5227
- logger.debug({
5228
- requestId: request.requestId,
5229
- sessionId: request.sessionId,
5230
- itemCount: page.items.length
5231
- }, "session.timeline.page.ready");
5232
- phase = "encode";
5233
- const { message, metrics } = await this.options.encoder.seal(result, request, {
5234
- enabled: config.timelineCompressionEnabled === true,
5235
- ...scope.clientId === void 0 ? {} : { recipientClientId: scope.clientId },
5236
- ...config.secureMessagePacketBudget === void 0 ? {} : { packetBudget: config.secureMessagePacketBudget }
5237
- });
5238
- if (!scope.isCurrent()) return;
5239
- if (!publications.isCurrent(request.sessionId, publication)) throw new SessionNotSharedError();
5240
- phase = "emit";
5241
- this.options.sendSealed(message);
5242
- this.options.trafficMetrics.record(message, metrics.plaintextBytes, metrics.sealDurationMs);
5243
- this.#errors.recovered(errorKey);
5244
- const timingLevel = metrics.encodeDurationMs + metrics.sealDurationMs >= 1e3 ? "info" : "debug";
5245
- logger[timingLevel](metrics, "transport.timeline.encoding");
5268
+ const references = request.imageReferences === true && config.timelineIncrementalEnabled !== false && this.options.imageReferencesEnabled();
5269
+ let pageSize = request.pageSize;
5270
+ while (true) {
5271
+ let itemCount;
5272
+ try {
5273
+ phase = "read";
5274
+ const page = await diagnostics.run(() => measureOperationPhase("read", () => adapter.readSessionTimelinePage(
5275
+ request.sessionId,
5276
+ {
5277
+ pageSize,
5278
+ ...request.cursor === void 0 ? {} : { cursor: request.cursor },
5279
+ ...request.metadataOnly === true ? {
5280
+ metadataOnly: true,
5281
+ ...request.assistantPreview === true ? { assistantPreview: true } : {}
5282
+ } : {
5283
+ ...references || request.cursor !== void 0 || pageSize !== request.pageSize ? { readOnly: true } : {},
5284
+ ...references ? {
5285
+ imageProjection: { sessionId: request.sessionId, referenceItem: this.options.referenceItem }
5286
+ } : {}
5287
+ }
5288
+ }
5289
+ )));
5290
+ itemCount = page.items.length;
5291
+ if (diagnostics.activeMs >= 1e3) {
5292
+ logger.info({
5293
+ ...diagnosticRequest(request),
5294
+ ...diagnostics.details(),
5295
+ metadataOnly: request.metadataOnly === true
5296
+ }, "session.timeline.page.read-slow");
5297
+ }
5298
+ if (!publications.isCurrent(request.sessionId, publication)) throw new SessionNotSharedError();
5299
+ const latestAssistant = request.assistantPreview === true ? [...page.items].reverse().find(isContentfulAssistant) : void 0;
5300
+ const preview = latestAssistant === void 0 ? void 0 : assistantPreview(
5301
+ latestAssistant,
5302
+ (item) => this.options.referenceItem(request.sessionId, item)
5303
+ );
5304
+ const latestUser = request.assistantPreview === true ? [...page.items].reverse().find((item) => item.kind === "human-message" && item.actor === "human") : void 0;
5305
+ const humanPreview = latestUser === void 0 ? void 0 : userPreview(latestUser);
5306
+ const responsePage = {
5307
+ ...page,
5308
+ ...preview === void 0 ? {} : { assistantPreview: preview },
5309
+ ...humanPreview === void 0 ? {} : { userPreview: humanPreview },
5310
+ ...request.assistantPreview === true ? { previewsComplete: !page.hasMore } : {},
5311
+ items: request.metadataOnly === true && request.assistantPreview === true ? page.items.map((item) => {
5312
+ if (item.kind === "assistant-message" || item.kind === "human-message") {
5313
+ return { ...item, content: "", attachments: [] };
5314
+ }
5315
+ return isContentfulAssistant(item) ? { ...item, content: "" } : item;
5316
+ }) : page.items
5317
+ };
5318
+ const result = {
5319
+ ok: true,
5320
+ requestId: request.requestId,
5321
+ machineId,
5322
+ sessionId: request.sessionId,
5323
+ page: references ? { ...responsePage, items: responsePage.items.map((item) => this.options.referenceItem(request.sessionId, item)) } : responsePage
5324
+ };
5325
+ logger.debug({
5326
+ requestId: request.requestId,
5327
+ sessionId: request.sessionId,
5328
+ itemCount: page.items.length
5329
+ }, "session.timeline.page.ready");
5330
+ phase = "encode";
5331
+ const { message, metrics } = await this.options.encoder.seal(result, request, {
5332
+ enabled: config.timelineCompressionEnabled === true,
5333
+ ...scope.clientId === void 0 ? {} : { recipientClientId: scope.clientId },
5334
+ ...config.secureMessagePacketBudget === void 0 ? {} : { packetBudget: config.secureMessagePacketBudget }
5335
+ });
5336
+ if (!scope.isCurrent()) return;
5337
+ if (!publications.isCurrent(request.sessionId, publication)) throw new SessionNotSharedError();
5338
+ phase = "emit";
5339
+ this.options.sendSealed(message);
5340
+ this.options.trafficMetrics.record(message, metrics.plaintextBytes, metrics.sealDurationMs);
5341
+ this.#errors.recovered(errorKey);
5342
+ const timingLevel = metrics.encodeDurationMs + metrics.sealDurationMs >= 1e3 ? "info" : "debug";
5343
+ logger[timingLevel](metrics, "transport.timeline.encoding");
5344
+ return;
5345
+ } catch (error) {
5346
+ if (!scope.isCurrent()) return;
5347
+ if (!publications.isCurrent(request.sessionId, publication)) throw new SessionNotSharedError();
5348
+ if (phase === "emit" || request.metadataOnly === true || request.assistantPreview === true || pageSize <= 25 || !(error instanceof TimelinePageBudgetError || error instanceof SecureMessageBudgetError) || itemCount !== void 0 && itemCount <= 1) throw error;
5349
+ const nextPageSize = Math.max(25, Math.floor(pageSize / 2));
5350
+ logger.info(
5351
+ { ...diagnosticRequest(request), pageSize, nextPageSize, phase },
5352
+ "session.timeline.page.resized"
5353
+ );
5354
+ pageSize = nextPageSize;
5355
+ }
5356
+ }
5246
5357
  } catch (error) {
5247
5358
  if (!scope.isCurrent()) return;
5248
5359
  this.#errors.failure(errorKey, error, {
@@ -5256,7 +5367,7 @@ var SessionTimelinePageHandler = class {
5256
5367
  machineId,
5257
5368
  sessionId: request.sessionId,
5258
5369
  error: sessionRestoreFailure(error) ?? {
5259
- code: error instanceof SecureMessageBudgetError ? "TRANSPORT_BUDGET_EXCEEDED" : operationErrorCode(adapter.agentId, "TIMELINE_PAGE", error),
5370
+ code: error instanceof SecureMessageBudgetError || error instanceof TimelinePageBudgetError ? "TRANSPORT_BUDGET_EXCEEDED" : operationErrorCode(adapter.agentId, "TIMELINE_PAGE", error),
5260
5371
  message: toErrorDetails(error).message
5261
5372
  }
5262
5373
  });
@@ -7786,7 +7897,7 @@ var INVENTORY_REFRESH_DEBOUNCE_MS = 100;
7786
7897
  var SESSION_LIST_REFRESH_RETRIES = 2;
7787
7898
  var TRAFFIC_METRICS_INTERVAL_MS = 6e4;
7788
7899
  var PcAgent = class {
7789
- constructor(config, identity2, appVersion, adapter, logger, pairingProvider, contentCipher, research, createSocket = (uri, options) => io(uri, options), onPairing) {
7900
+ constructor(config, identity2, appVersion, adapter, logger, pairingProvider, contentCipher, research, createSocket = createRelaySocket, onPairing) {
7790
7901
  this.config = config;
7791
7902
  this.identity = identity2;
7792
7903
  this.appVersion = appVersion;
@@ -7832,7 +7943,10 @@ var PcAgent = class {
7832
7943
  stopSynchronizing: (clientId, sessionId) => this.#conversationAudience.stopSynchronizing(clientId, sessionId)
7833
7944
  });
7834
7945
  this.#timelineIncremental = new TimelineIncrementalTransport({
7835
- readHead: (sessionId) => this.adapter.readSessionTimelinePage(sessionId, { pageSize: 100 })
7946
+ readHead: (sessionId) => this.adapter.readSessionTimelinePage(sessionId, {
7947
+ pageSize: 100,
7948
+ imageProjection: { sessionId, referenceItem: this.#timelineIncremental.images.referenceItem }
7949
+ })
7836
7950
  });
7837
7951
  const imageSettings = config.sessionImages === void 0 ? void 0 : SessionImagesConfigSchema.parse(config.sessionImages);
7838
7952
  this.#imageBlob = imageSettings === void 0 ? void 0 : new TimelineImageBlobPublisher(this.#timelineIncremental.images, new SessionImageUploader({
@@ -7902,7 +8016,7 @@ var PcAgent = class {
7902
8016
  trafficMetrics: this.#trafficMetrics,
7903
8017
  sendSealed: (message) => this.#socket.emit("secure.message", message),
7904
8018
  imageReferencesEnabled: () => this.#communicationNegotiated && this.#conversationAudience.confirmed,
7905
- referenceItem: (sessionId, item) => this.#timelineIncremental.images.referenceItem(sessionId, item)
8019
+ referenceItem: this.#timelineIncremental.images.referenceItem
7906
8020
  });
7907
8021
  this.#secureRequestRouter = createPcSecureRequestRouter({
7908
8022
  configuredMachineId: identity2.machineId,
@@ -8828,6 +8942,7 @@ var PcAgent = class {
8828
8942
  }
8829
8943
  #machineCapabilities() {
8830
8944
  return [
8945
+ ...this.adapter.agentId === "copilot" || this.adapter.agentId === "managed" ? [SESSION_AVATAR_PERSONA_CAPABILITY] : [],
8831
8946
  SESSION_COMMUNICATION_CAPABILITY,
8832
8947
  ...this.#peerChatEnabled && this.adapter.runPeerTurn !== void 0 ? [PC_PEER_CHAT_CAPABILITY] : [],
8833
8948
  ...this.adapter.runPeerTurn !== void 0 ? [PC_A2A_CAPABILITY] : [],
@@ -10564,7 +10679,11 @@ async function initialize(options) {
10564
10679
  );
10565
10680
  const contentKey = await loadOrCreateContentKey(dataDirectory);
10566
10681
  const cipher = await createPersistentContentCipher(dataDirectory, contentKey);
10567
- const pairingProvider = new CachedPairingProvider(() => requestPairingUri(config, identity2, contentKey));
10682
+ const pairingProvider = new CachedPairingProvider(
10683
+ () => requestPairingUri(config, identity2, contentKey),
10684
+ void 0,
10685
+ (statusId) => requestPairingStatus(config, identity2, statusId)
10686
+ );
10568
10687
  const sourceAdapter = adapter;
10569
10688
  const sourceMetadata = async (sessionId) => {
10570
10689
  const access2 = captureResearchAccess(sourceAdapter, sessionId);
@@ -10680,6 +10799,7 @@ export {
10680
10799
  SessionImageUploadError,
10681
10800
  SessionImageUploader,
10682
10801
  SessionImagesConfigSchema,
10802
+ TimelinePageBudgetError,
10683
10803
  assertPiRuntimeSupported,
10684
10804
  buildPairingUri,
10685
10805
  codingAgentPresentation,
package/dist/runtime.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  PEER_CHAT_TIMEOUT_MS,
4
4
  PeerChatRequestSchema,
5
5
  PeerChatResultSchema
6
- } from "./chunks/chunk-UE4QYZCG.js";
7
- import "./chunks/chunk-E3XCZWRK.js";
6
+ } from "./chunks/chunk-QN3OD5UE.js";
7
+ import "./chunks/chunk-QTBB2U7G.js";
8
8
  export {
9
9
  DataDirectoryLease,
10
10
  PEER_CHAT_TIMEOUT_MS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentknight/sdk",
3
- "version": "0.9.39",
3
+ "version": "0.9.41",
4
4
  "description": "AgentKnight runtime SDK for local and remote coding sessions",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -49,8 +49,8 @@
49
49
  "esbuild": "0.28.2",
50
50
  "rollup": "4.63.1",
51
51
  "rollup-plugin-dts": "6.3.0",
52
- "@agentknight/shared": "0.1.0",
53
- "@agentknight/protocol": "0.1.0"
52
+ "@agentknight/protocol": "0.1.0",
53
+ "@agentknight/shared": "0.1.0"
54
54
  },
55
55
  "optionalDependencies": {
56
56
  "@earendil-works/pi-ai": "0.85.1",