@moxt-ai/mobius 0.0.322 → 0.0.324

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.
Files changed (88) hide show
  1. package/dist/cli.js +445 -284
  2. package/dist/cli.js.map +4 -4
  3. package/dist/runtime/command/dispatcher.d.ts +1 -0
  4. package/dist/runtime/command/dispatcher.d.ts.map +1 -1
  5. package/dist/runtime/command/dispatcher.js.map +1 -1
  6. package/dist/runtime/command/registry/content-write/index.d.ts +10 -0
  7. package/dist/runtime/command/registry/content-write/index.d.ts.map +1 -0
  8. package/dist/runtime/command/registry/content-write/index.js +125 -0
  9. package/dist/runtime/command/registry/content-write/index.js.map +1 -0
  10. package/dist/runtime/command/registry/file-read/index.d.ts.map +1 -1
  11. package/dist/runtime/command/registry/file-read/index.js +2 -2
  12. package/dist/runtime/command/registry/file-read/index.js.map +1 -1
  13. package/dist/runtime/command/registry/index.d.ts +2 -1
  14. package/dist/runtime/command/registry/index.d.ts.map +1 -1
  15. package/dist/runtime/command/registry/index.js +9 -1
  16. package/dist/runtime/command/registry/index.js.map +1 -1
  17. package/dist/runtime/command/registry/prompt.d.ts.map +1 -1
  18. package/dist/runtime/command/registry/prompt.js +7 -2
  19. package/dist/runtime/command/registry/prompt.js.map +1 -1
  20. package/dist/runtime/command/registry/session.d.ts.map +1 -1
  21. package/dist/runtime/command/registry/session.js +10 -5
  22. package/dist/runtime/command/registry/session.js.map +1 -1
  23. package/dist/runtime/command/transport.d.ts +1 -0
  24. package/dist/runtime/command/transport.d.ts.map +1 -1
  25. package/dist/runtime/command/transport.js +7 -1
  26. package/dist/runtime/command/transport.js.map +1 -1
  27. package/dist/runtime/relay/connect.d.ts.map +1 -1
  28. package/dist/runtime/relay/connect.js +1 -0
  29. package/dist/runtime/relay/connect.js.map +1 -1
  30. package/dist/runtime/relay/run-relay-connection.d.ts.map +1 -1
  31. package/dist/runtime/relay/run-relay-connection.js +6 -1
  32. package/dist/runtime/relay/run-relay-connection.js.map +1 -1
  33. package/dist/runtime.js +418 -266
  34. package/dist/runtime.js.map +4 -4
  35. package/dist/session/api/session-api.d.ts +11 -4
  36. package/dist/session/api/session-api.d.ts.map +1 -1
  37. package/dist/session/api/session-api.js +3 -1
  38. package/dist/session/api/session-api.js.map +1 -1
  39. package/dist/session/content/external-content-store.d.ts +2 -0
  40. package/dist/session/content/external-content-store.d.ts.map +1 -1
  41. package/dist/session/content/external-content-store.js +5 -0
  42. package/dist/session/content/external-content-store.js.map +1 -1
  43. package/dist/session/content/session-files.d.ts +1 -1
  44. package/dist/session/content/session-files.d.ts.map +1 -1
  45. package/dist/session/content/session-files.js +4 -11
  46. package/dist/session/content/session-files.js.map +1 -1
  47. package/dist/session/live/agent-session.d.ts +2 -2
  48. package/dist/session/live/agent-session.d.ts.map +1 -1
  49. package/dist/session/live/agent-session.js +45 -13
  50. package/dist/session/live/agent-session.js.map +1 -1
  51. package/dist/session/manager/session-manager.d.ts +3 -3
  52. package/dist/session/manager/session-manager.d.ts.map +1 -1
  53. package/dist/session/manager/session-manager.js +2 -2
  54. package/dist/session/manager/session-manager.js.map +1 -1
  55. package/dist/session/prompt/apply-session-configuration.d.ts.map +1 -1
  56. package/dist/session/prompt/apply-session-configuration.js +2 -2
  57. package/dist/session/prompt/apply-session-configuration.js.map +1 -1
  58. package/dist/session/prompt/execute-prompt.d.ts +3 -3
  59. package/dist/session/prompt/execute-prompt.d.ts.map +1 -1
  60. package/dist/session/prompt/execute-prompt.js +2 -2
  61. package/dist/session/prompt/execute-prompt.js.map +1 -1
  62. package/dist/session/prompt/prompt-artifacts.d.ts +7 -22
  63. package/dist/session/prompt/prompt-artifacts.d.ts.map +1 -1
  64. package/dist/session/prompt/prompt-artifacts.js +22 -76
  65. package/dist/session/prompt/prompt-artifacts.js.map +1 -1
  66. package/dist/session/prompt/prompt-lifecycle.d.ts.map +1 -1
  67. package/dist/session/prompt/prompt-lifecycle.js +15 -12
  68. package/dist/session/prompt/prompt-lifecycle.js.map +1 -1
  69. package/dist/session/turn/session-turns.d.ts +5 -9
  70. package/dist/session/turn/session-turns.d.ts.map +1 -1
  71. package/dist/session/turn/session-turns.js +1 -2
  72. package/dist/session/turn/session-turns.js.map +1 -1
  73. package/dist/storage/files/scratch-directory.d.ts +2 -0
  74. package/dist/storage/files/scratch-directory.d.ts.map +1 -1
  75. package/dist/storage/files/scratch-directory.js +7 -1
  76. package/dist/storage/files/scratch-directory.js.map +1 -1
  77. package/dist/util/filesystem/private-path.js +2 -3
  78. package/dist/util/filesystem/private-path.js.map +2 -2
  79. package/dist/util/platform/windows.d.ts.map +1 -1
  80. package/dist/util/platform/windows.js +3 -5
  81. package/dist/util/platform/windows.js.map +1 -1
  82. package/dist/util/process/executable.js +2 -3
  83. package/dist/util/process/executable.js.map +2 -2
  84. package/package.json +2 -2
  85. package/dist/runtime/relay/artifact-download.d.ts +0 -5
  86. package/dist/runtime/relay/artifact-download.d.ts.map +0 -1
  87. package/dist/runtime/relay/artifact-download.js +0 -105
  88. package/dist/runtime/relay/artifact-download.js.map +0 -1
package/dist/cli.js CHANGED
@@ -2086,7 +2086,7 @@ var init_package = __esm({
2086
2086
  "package.json"() {
2087
2087
  package_default = {
2088
2088
  name: "@moxt-ai/mobius",
2089
- version: "0.0.322",
2089
+ version: "0.0.324",
2090
2090
  description: "Mobius CLI for pairing and running local AI agent services.",
2091
2091
  type: "module",
2092
2092
  bin: {
@@ -70855,11 +70855,10 @@ var init_windows = __esm({
70855
70855
  windowsPermissions = `
70856
70856
  $ErrorActionPreference = 'Stop'
70857
70857
  $ProgressPreference = 'SilentlyContinue'
70858
- Import-Module (Join-Path $PSHOME 'Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1')
70859
70858
  $item = Get-Item -LiteralPath $env:MOBIUS_PERMISSION_PATH -Force
70860
70859
  if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) { throw 'Unsafe path' }
70861
70860
  $sid = [Security.Principal.WindowsIdentity]::GetCurrent().User
70862
- $acl = Get-Acl -LiteralPath $item.FullName
70861
+ $acl = $item.GetAccessControl()
70863
70862
  $owner = $acl.GetOwner([Security.Principal.SecurityIdentifier])
70864
70863
  if ($owner -ne $sid -and -not ($owner.Value -eq 'S-1-5-32-544' -and ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))) { throw 'Path is not user-owned' }
70865
70864
  if ($env:MOBIUS_PERMISSION_PRIVATE -eq '1') {
@@ -70873,7 +70872,7 @@ if ($env:MOBIUS_PERMISSION_PRIVATE -eq '1') {
70873
70872
  $private.SetOwner($sid)
70874
70873
  $private.SetAccessRuleProtection($true, $false)
70875
70874
  $private.AddAccessRule($rule)
70876
- Set-Acl -LiteralPath $item.FullName -AclObject $private
70875
+ $item.SetAccessControl($private)
70877
70876
  }
70878
70877
  `;
70879
70878
  windowsPermissionsTimeoutMs = 3e4;
@@ -74107,6 +74106,8 @@ var init_configuration = __esm({
74107
74106
  ...sessionIdentityFields,
74108
74107
  booleanValue: external_exports.boolean(),
74109
74108
  configId: external_exports.string().min(1).max(128),
74109
+ // Omitted by legacy clients: explicit edits retain last-write-wins behavior.
74110
+ expectedConfigurationRevision: identifierStringSchema.optional(),
74110
74111
  kind: external_exports.literal(SESSION_CONFIGURE_KIND),
74111
74112
  requestId: identifierStringSchema,
74112
74113
  value: external_exports.string().max(500),
@@ -74114,6 +74115,8 @@ var init_configuration = __esm({
74114
74115
  }).readonly();
74115
74116
  sessionConfigUpdatedEventSchema = external_exports.object({
74116
74117
  configOptions: sessionConfigOptionsSchema,
74118
+ // An opaque Runtime generation token; absent on older Runtimes.
74119
+ configurationRevision: identifierStringSchema.optional(),
74117
74120
  kind: external_exports.literal(SESSION_CONFIG_UPDATED_KIND),
74118
74121
  requestId: identifierStringSchema,
74119
74122
  sessionId: identifierStringSchema
@@ -74132,6 +74135,8 @@ var init_configuration = __esm({
74132
74135
  }).readonly();
74133
74136
  sessionConfigReadResultSchema = external_exports.object({
74134
74137
  configOptions: sessionConfigOptionsSchema,
74138
+ // An opaque Runtime generation token; absent on older Runtimes.
74139
+ configurationRevision: identifierStringSchema.optional(),
74135
74140
  kind: external_exports.literal(SESSION_CONFIG_READ_RESULT_KIND),
74136
74141
  requestId: identifierStringSchema,
74137
74142
  sessionId: identifierStringSchema
@@ -74174,7 +74179,60 @@ var init_title = __esm({
74174
74179
  });
74175
74180
 
74176
74181
  // ../mobius-sdk/src/protocol/session/files/index.ts
74177
- var FILE_READ_KIND, FILE_BEGIN_KIND, FILE_CHUNK_KIND, FILE_END_KIND, FILE_FAILED_KIND, fileReadCommandSchema, fileBeginEventSchema, fileChunkEventSchema, fileEndEventSchema, fileFailedEventSchema, decodeFileReadCommand, encodeFileReadCommand, decodeFileBeginEvent, encodeFileBeginEvent, decodeFileChunkEvent, encodeFileChunkEvent, decodeFileEndEvent, encodeFileEndEvent, decodeFileFailedEvent, encodeFileFailedEvent;
74182
+ function binaryBytes(value) {
74183
+ if (value instanceof ArrayBuffer) {
74184
+ return new Uint8Array(value);
74185
+ }
74186
+ if (ArrayBuffer.isView(value)) {
74187
+ return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
74188
+ }
74189
+ throw new Error("Content chunk must be a binary WebSocket frame");
74190
+ }
74191
+ function encodeContentChunkFrame(frame) {
74192
+ if (!isIdentifier(frame.requestId)) {
74193
+ throw new Error("Content chunk request identifier is invalid");
74194
+ }
74195
+ if (!Number.isSafeInteger(frame.sequence) || frame.sequence < 0 || frame.sequence > 4294967295) {
74196
+ throw new Error("Content chunk sequence is invalid");
74197
+ }
74198
+ if (frame.bytes.byteLength < 1 || frame.bytes.byteLength > CONTENT_CHUNK_MAX_BYTES) {
74199
+ throw new Error("Content chunk size is invalid");
74200
+ }
74201
+ const requestId = new TextEncoder().encode(frame.requestId);
74202
+ if (requestId.byteLength > 255) {
74203
+ throw new Error("Content chunk request identifier is too long");
74204
+ }
74205
+ const encoded = new Uint8Array(CONTENT_CHUNK_HEADER_BYTES + requestId.byteLength + frame.bytes.byteLength);
74206
+ encoded.set(CONTENT_CHUNK_MAGIC, 0);
74207
+ encoded[CONTENT_CHUNK_MAGIC.byteLength] = requestId.byteLength;
74208
+ new DataView(encoded.buffer).setUint32(CONTENT_CHUNK_MAGIC.byteLength + 1, frame.sequence);
74209
+ encoded.set(requestId, CONTENT_CHUNK_HEADER_BYTES);
74210
+ encoded.set(frame.bytes, CONTENT_CHUNK_HEADER_BYTES + requestId.byteLength);
74211
+ return encoded;
74212
+ }
74213
+ function decodeContentChunkFrame(value) {
74214
+ const encoded = binaryBytes(value);
74215
+ if (encoded.byteLength <= CONTENT_CHUNK_HEADER_BYTES || !CONTENT_CHUNK_MAGIC.every((byte, index2) => encoded[index2] === byte)) {
74216
+ throw new Error("Content chunk frame header is invalid");
74217
+ }
74218
+ const requestIdLength = encoded[CONTENT_CHUNK_MAGIC.byteLength] ?? 0;
74219
+ const payloadOffset = CONTENT_CHUNK_HEADER_BYTES + requestIdLength;
74220
+ if (requestIdLength < 1 || payloadOffset >= encoded.byteLength) {
74221
+ throw new Error("Content chunk frame length is invalid");
74222
+ }
74223
+ const requestId = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(
74224
+ encoded.subarray(CONTENT_CHUNK_HEADER_BYTES, payloadOffset)
74225
+ );
74226
+ const bytes = encoded.slice(payloadOffset);
74227
+ const sequence = new DataView(encoded.buffer, encoded.byteOffset, encoded.byteLength).getUint32(
74228
+ CONTENT_CHUNK_MAGIC.byteLength + 1
74229
+ );
74230
+ if (!isIdentifier(requestId) || bytes.byteLength > CONTENT_CHUNK_MAX_BYTES) {
74231
+ throw new Error("Content chunk frame is invalid");
74232
+ }
74233
+ return { bytes, requestId, sequence };
74234
+ }
74235
+ var FILE_READ_KIND, FILE_BEGIN_KIND, FILE_END_KIND, FILE_FAILED_KIND, CONTENT_WRITE_KIND, CONTENT_COMMIT_KIND, CONTENT_READY_KIND, CONTENT_AVAILABLE_KIND, CONTENT_CHUNK_MAX_BYTES, CONTENT_WRITE_MAX_BYTES, PROMPT_IMAGE_MAX_BYTES, CONTENT_CHUNK_MAGIC, CONTENT_CHUNK_HEADER_BYTES, fileReadCommandSchema, fileBeginEventSchema, contentWriteCommandSchema, contentCommitCommandSchema, contentReadyEventSchema, contentAvailableEventSchema, fileEndEventSchema, fileFailedEventSchema, decodeFileReadCommand, encodeFileReadCommand, decodeFileBeginEvent, encodeFileBeginEvent, decodeFileEndEvent, encodeFileEndEvent, decodeFileFailedEvent, encodeFileFailedEvent, decodeContentWriteCommand, encodeContentWriteCommand, decodeContentCommitCommand, encodeContentCommitCommand, decodeContentReadyEvent, encodeContentReadyEvent, decodeContentAvailableEvent, encodeContentAvailableEvent;
74178
74236
  var init_files = __esm({
74179
74237
  "../mobius-sdk/src/protocol/session/files/index.ts"() {
74180
74238
  "use strict";
@@ -74183,9 +74241,17 @@ var init_files = __esm({
74183
74241
  init_message_codec();
74184
74242
  FILE_READ_KIND = "file.read";
74185
74243
  FILE_BEGIN_KIND = "file.begin";
74186
- FILE_CHUNK_KIND = "file.chunk";
74187
74244
  FILE_END_KIND = "file.end";
74188
74245
  FILE_FAILED_KIND = "file.failed";
74246
+ CONTENT_WRITE_KIND = "content.write";
74247
+ CONTENT_COMMIT_KIND = "content.commit";
74248
+ CONTENT_READY_KIND = "content.ready";
74249
+ CONTENT_AVAILABLE_KIND = "content.available";
74250
+ CONTENT_CHUNK_MAX_BYTES = 192 * 1024;
74251
+ CONTENT_WRITE_MAX_BYTES = 32 * 1024 * 1024;
74252
+ PROMPT_IMAGE_MAX_BYTES = 5e6;
74253
+ CONTENT_CHUNK_MAGIC = new Uint8Array([77, 66, 67, 49]);
74254
+ CONTENT_CHUNK_HEADER_BYTES = CONTENT_CHUNK_MAGIC.byteLength + 1 + 4;
74189
74255
  fileReadCommandSchema = external_exports.object({
74190
74256
  kind: external_exports.literal(FILE_READ_KIND),
74191
74257
  maxBytes: external_exports.number().int().positive().max(128 * 1024 * 1024),
@@ -74202,11 +74268,31 @@ var init_files = __esm({
74202
74268
  requestId: identifierStringSchema,
74203
74269
  sessionId: identifierStringSchema
74204
74270
  }).readonly();
74205
- fileChunkEventSchema = external_exports.object({
74206
- data: external_exports.string().min(1).max(4e5),
74207
- kind: external_exports.literal(FILE_CHUNK_KIND),
74271
+ contentWriteCommandSchema = external_exports.object({
74272
+ byteLength: external_exports.number().int().positive().max(CONTENT_WRITE_MAX_BYTES),
74273
+ contentKey: external_exports.string().regex(/^[a-f0-9]{64}$/u),
74274
+ contentKind: external_exports.enum(["image", "resource"]),
74275
+ kind: external_exports.literal(CONTENT_WRITE_KIND),
74276
+ mediaType: external_exports.string().min(1).max(255),
74277
+ name: external_exports.string().min(1).max(500),
74278
+ requestId: identifierStringSchema,
74279
+ sessionId: identifierStringSchema
74280
+ }).readonly();
74281
+ contentCommitCommandSchema = external_exports.object({
74282
+ kind: external_exports.literal(CONTENT_COMMIT_KIND),
74283
+ requestId: identifierStringSchema,
74284
+ sessionId: identifierStringSchema
74285
+ }).readonly();
74286
+ contentReadyEventSchema = external_exports.object({
74287
+ kind: external_exports.literal(CONTENT_READY_KIND),
74288
+ requestId: identifierStringSchema,
74289
+ sessionId: identifierStringSchema
74290
+ }).readonly();
74291
+ contentAvailableEventSchema = external_exports.object({
74292
+ byteLength: external_exports.number().int().positive().max(CONTENT_WRITE_MAX_BYTES),
74293
+ contentKey: external_exports.string().regex(/^[a-f0-9]{64}$/u),
74294
+ kind: external_exports.literal(CONTENT_AVAILABLE_KIND),
74208
74295
  requestId: identifierStringSchema,
74209
- sequence: external_exports.number().int().nonnegative().max(1024),
74210
74296
  sessionId: identifierStringSchema
74211
74297
  }).readonly();
74212
74298
  fileEndEventSchema = external_exports.object({
@@ -74225,12 +74311,18 @@ var init_files = __esm({
74225
74311
  encodeFileReadCommand = (message) => encodeZodMessage(message, fileReadCommandSchema);
74226
74312
  decodeFileBeginEvent = (encoded) => decodeZodMessage(encoded, fileBeginEventSchema);
74227
74313
  encodeFileBeginEvent = (message) => encodeZodMessage(message, fileBeginEventSchema);
74228
- decodeFileChunkEvent = (encoded) => decodeZodMessage(encoded, fileChunkEventSchema);
74229
- encodeFileChunkEvent = (message) => encodeZodMessage(message, fileChunkEventSchema);
74230
74314
  decodeFileEndEvent = (encoded) => decodeZodMessage(encoded, fileEndEventSchema);
74231
74315
  encodeFileEndEvent = (message) => encodeZodMessage(message, fileEndEventSchema);
74232
74316
  decodeFileFailedEvent = (encoded) => decodeZodMessage(encoded, fileFailedEventSchema);
74233
74317
  encodeFileFailedEvent = (message) => encodeZodMessage(message, fileFailedEventSchema);
74318
+ decodeContentWriteCommand = (encoded) => decodeZodMessage(encoded, contentWriteCommandSchema);
74319
+ encodeContentWriteCommand = (message) => encodeZodMessage(message, contentWriteCommandSchema);
74320
+ decodeContentCommitCommand = (encoded) => decodeZodMessage(encoded, contentCommitCommandSchema);
74321
+ encodeContentCommitCommand = (message) => encodeZodMessage(message, contentCommitCommandSchema);
74322
+ decodeContentReadyEvent = (encoded) => decodeZodMessage(encoded, contentReadyEventSchema);
74323
+ encodeContentReadyEvent = (message) => encodeZodMessage(message, contentReadyEventSchema);
74324
+ decodeContentAvailableEvent = (encoded) => decodeZodMessage(encoded, contentAvailableEventSchema);
74325
+ encodeContentAvailableEvent = (message) => encodeZodMessage(message, contentAvailableEventSchema);
74234
74326
  }
74235
74327
  });
74236
74328
 
@@ -74584,6 +74676,7 @@ var init_lifecycle = __esm({
74584
74676
  capabilities: sessionCapabilitiesSchema,
74585
74677
  commands: external_exports.array(sessionCommandSchema).max(500).readonly(),
74586
74678
  configOptions: sessionConfigOptionsSchema,
74679
+ configurationRevision: identifierStringSchema.optional(),
74587
74680
  directoryId: DIRECTORY_IDENTIFIER,
74588
74681
  directoryLabel: external_exports.string().min(1).max(MAX_WORKSPACE_PATH_LENGTH),
74589
74682
  kind: external_exports.literal(SESSION_READY_KIND),
@@ -74678,13 +74771,12 @@ function decodeSessionPromptCommand(encoded) {
74678
74771
  const hasSessionConfigurations = Object.hasOwn(value, "sessionConfigurations");
74679
74772
  assertKind(value, SESSION_PROMPT_KIND);
74680
74773
  const prompt = readText(value, "prompt", MAX_PROMPT_LENGTH);
74681
- const images = decodePromptImagesValue(value["images"]);
74682
- const resources = decodePromptResourcesValue(value["resources"]);
74683
- const attachmentLength = images.reduce((total, image) => total + image.data.length, 0) + resources.reduce((total, resource) => total + resource.text.length, 0);
74684
- if (attachmentLength > MAX_PROMPT_ATTACHMENT_LENGTH) {
74774
+ const attachments = !Object.hasOwn(value, "attachments") && Array.isArray(value["images"]) && Array.isArray(value["resources"]) ? [] : decodePromptAttachmentsValue(value["attachments"]);
74775
+ const attachmentBytes = attachments.reduce((total, attachment) => total + attachment.byteLength, 0);
74776
+ if (attachmentBytes > MAX_PROMPT_ATTACHMENT_BYTES) {
74685
74777
  throw new ProtocolMessageError("Prompt attachments are too large");
74686
74778
  }
74687
- if (prompt.trim().length === 0 && images.length === 0 && resources.length === 0) {
74779
+ if (prompt.trim().length === 0 && attachments.length === 0) {
74688
74780
  throw new ProtocolMessageError("Prompt must contain content");
74689
74781
  }
74690
74782
  const disposition = readPromptDisposition(value);
@@ -74704,13 +74796,12 @@ function decodeSessionPromptCommand(encoded) {
74704
74796
  commandId: readIdentifier(value, "commandId"),
74705
74797
  directoryId: readDirectoryIdentifier(value, "directoryId"),
74706
74798
  disposition,
74707
- images,
74799
+ attachments,
74708
74800
  ...value["historyPolicy"] === void 0 ? {} : {
74709
74801
  historyPolicy: readHistoryPolicy(value)
74710
74802
  },
74711
74803
  kind: SESSION_PROMPT_KIND,
74712
74804
  prompt,
74713
- resources,
74714
74805
  ...hasSessionConfigurations ? { sessionConfigurations } : {},
74715
74806
  sessionId: readIdentifier(value, "sessionId"),
74716
74807
  targetCommandId
@@ -74746,7 +74837,15 @@ function decodeSessionPromptDispositionCommand(encoded) {
74746
74837
  };
74747
74838
  }
74748
74839
  function encodeSessionPromptCommand(message) {
74749
- return JSON.stringify(decodeSessionPromptCommand(JSON.stringify(message)));
74840
+ const command = decodeSessionPromptCommand(JSON.stringify(message));
74841
+ return JSON.stringify({
74842
+ ...command,
74843
+ // Keep text prompts compatible with the previous Runtime release while
74844
+ // attachments move to the content-key protocol. Older Runtimes ignore
74845
+ // `attachments` and require both legacy arrays to be present.
74846
+ images: [],
74847
+ resources: []
74848
+ });
74750
74849
  }
74751
74850
  function encodeSessionCancelCommand(message) {
74752
74851
  return JSON.stringify(decodeSessionCancelCommand(JSON.stringify(message)));
@@ -74754,7 +74853,7 @@ function encodeSessionCancelCommand(message) {
74754
74853
  function encodeSessionPromptDispositionCommand(message) {
74755
74854
  return JSON.stringify(decodeSessionPromptDispositionCommand(JSON.stringify(message)));
74756
74855
  }
74757
- var SESSION_PROMPT_KIND, SESSION_PROMPT_DISPOSITION_KIND, SESSION_CANCEL_KIND, SessionPromptDisposition, SessionHistoryPolicy, MAX_PROMPT_LENGTH, MAX_PROMPT_ATTACHMENT_LENGTH, promptImageSchema, promptResourceSchema, decodePromptImagesValue, decodePromptResourcesValue;
74856
+ var SESSION_PROMPT_KIND, SESSION_PROMPT_DISPOSITION_KIND, SESSION_CANCEL_KIND, SessionPromptDisposition, SessionHistoryPolicy, MAX_PROMPT_LENGTH, MAX_PROMPT_ATTACHMENT_BYTES, promptAttachmentSchema, decodePromptAttachmentsValue;
74758
74857
  var init_commands = __esm({
74759
74858
  "../mobius-sdk/src/protocol/session/prompt/commands.ts"() {
74760
74859
  "use strict";
@@ -74775,21 +74874,16 @@ var init_commands = __esm({
74775
74874
  ExecutionOnly: "execution-only"
74776
74875
  });
74777
74876
  MAX_PROMPT_LENGTH = 1e5;
74778
- MAX_PROMPT_ATTACHMENT_LENGTH = 6e6;
74779
- promptImageSchema = external_exports.object({
74780
- data: external_exports.string().min(1).max(4e6),
74877
+ MAX_PROMPT_ATTACHMENT_BYTES = 32 * 1024 * 1024;
74878
+ promptAttachmentSchema = external_exports.object({
74879
+ byteLength: external_exports.number().int().positive().max(MAX_PROMPT_ATTACHMENT_BYTES),
74880
+ contentKey: external_exports.string().regex(/^[a-f0-9]{64}$/u),
74881
+ kind: external_exports.enum(["image", "resource"]),
74781
74882
  mimeType: external_exports.string().min(1).max(255),
74782
- name: external_exports.string().min(1).max(500)
74783
- }).readonly();
74784
- promptResourceSchema = external_exports.object({
74785
- mimeType: external_exports.string().max(255),
74786
74883
  name: external_exports.string().min(1).max(500),
74787
- text: external_exports.string().max(1e6),
74788
- type: external_exports.enum(["embedded", "link"]),
74789
74884
  uri: external_exports.string().min(1).max(4096)
74790
74885
  }).readonly();
74791
- decodePromptImagesValue = (value) => decodeZodValue(value, external_exports.array(promptImageSchema).max(8).readonly());
74792
- decodePromptResourcesValue = (value) => decodeZodValue(value, external_exports.array(promptResourceSchema).max(16).readonly());
74886
+ decodePromptAttachmentsValue = (value) => decodeZodValue(value, external_exports.array(promptAttachmentSchema).max(16).readonly());
74793
74887
  }
74794
74888
  });
74795
74889
 
@@ -74889,9 +74983,7 @@ var init_native = __esm({
74889
74983
  external_exports.object({
74890
74984
  commandId: identifierStringSchema,
74891
74985
  prompt: external_exports.string().max(1e5),
74892
- images: external_exports.array(promptImageSchema).max(8).readonly(),
74893
- // Absent from daemons that predate it; a client then cannot restore the prompt's files.
74894
- resources: external_exports.array(promptResourceSchema).max(16).readonly().optional()
74986
+ attachments: external_exports.array(promptAttachmentSchema).max(16).readonly()
74895
74987
  }).readonly()
74896
74988
  ).readonly(),
74897
74989
  turn: activeTurnSnapshotSchema.nullable()
@@ -75468,8 +75560,15 @@ var init_usage = __esm({
75468
75560
  }
75469
75561
  });
75470
75562
 
75563
+ // ../mobius-sdk/src/protocol/session/recording/recorded-lifecycle-status.ts
75564
+ var init_recorded_lifecycle_status = __esm({
75565
+ "../mobius-sdk/src/protocol/session/recording/recorded-lifecycle-status.ts"() {
75566
+ "use strict";
75567
+ }
75568
+ });
75569
+
75471
75570
  // ../mobius-sdk/src/protocol/session/recording/recording.ts
75472
- var sessionRecordingWriteSchema, sessionRecordingHistorySchema, sessionRecordingStatusSchema, recordingCursorSchema, sessionRecordingHistoryPageSchema, sessionRecordingSummarySchema, sessionRecordingDirectorySchema;
75571
+ var sessionRecordingWriteSchema, sessionRecordingHistorySchema, sessionRecordingStatusSchema, recordingCursorSchema, sessionRecordingHistoryPageSchema, sessionRecordingSummaryFields, sessionRecordingSummaryV2Schema, sessionRecordingDirectoryV2Schema, sessionRecordingSummarySchema, sessionRecordingDirectorySchema;
75473
75572
  var init_recording = __esm({
75474
75573
  "../mobius-sdk/src/protocol/session/recording/recording.ts"() {
75475
75574
  "use strict";
@@ -75501,16 +75600,18 @@ var init_recording = __esm({
75501
75600
  truncated: external_exports.boolean(),
75502
75601
  version: external_exports.literal(2)
75503
75602
  }).readonly();
75504
- sessionRecordingSummarySchema = external_exports.object({
75603
+ sessionRecordingSummaryFields = {
75505
75604
  additionalDirectoryIds: external_exports.array(DIRECTORY_IDENTIFIER).max(16).readonly(),
75506
75605
  agentId: identifierStringSchema,
75507
75606
  directoryId: DIRECTORY_IDENTIFIER,
75508
75607
  runtimeId: identifierStringSchema,
75509
75608
  sessionId: identifierStringSchema,
75510
- status: sessionRecordingStatusSchema,
75511
75609
  title: external_exports.string().max(1e3),
75512
75610
  updatedAt: external_exports.iso.datetime({ offset: true })
75513
- }).readonly();
75611
+ };
75612
+ sessionRecordingSummaryV2Schema = external_exports.object(sessionRecordingSummaryFields).readonly();
75613
+ sessionRecordingDirectoryV2Schema = external_exports.object({ sessions: external_exports.array(sessionRecordingSummaryV2Schema).max(1e5).readonly() }).readonly();
75614
+ sessionRecordingSummarySchema = external_exports.object({ ...sessionRecordingSummaryFields, status: sessionRecordingStatusSchema }).readonly();
75514
75615
  sessionRecordingDirectorySchema = external_exports.object({
75515
75616
  sessions: external_exports.array(sessionRecordingSummarySchema).max(1e5).readonly()
75516
75617
  }).readonly();
@@ -75887,6 +75988,16 @@ var init_daemon_transport = __esm({
75887
75988
  decodeAgentCatalogDiscoverCommand
75888
75989
  ),
75889
75990
  [FILE_READ_KIND]: defineMessageSignature(FILE_READ_KIND, encodeFileReadCommand, decodeFileReadCommand),
75991
+ [CONTENT_WRITE_KIND]: defineMessageSignature(
75992
+ CONTENT_WRITE_KIND,
75993
+ encodeContentWriteCommand,
75994
+ decodeContentWriteCommand
75995
+ ),
75996
+ [CONTENT_COMMIT_KIND]: defineMessageSignature(
75997
+ CONTENT_COMMIT_KIND,
75998
+ encodeContentCommitCommand,
75999
+ decodeContentCommitCommand
76000
+ ),
75890
76001
  [SESSION_LIST_KIND]: defineMessageSignature(SESSION_LIST_KIND, encodeSessionListCommand, decodeSessionListCommand),
75891
76002
  [SESSION_QUERY_KIND]: defineMessageSignature(
75892
76003
  SESSION_QUERY_KIND,
@@ -76038,9 +76149,14 @@ var init_daemon_transport = __esm({
76038
76149
  decodeAgentCatalogDiscoveryFailedEvent
76039
76150
  ),
76040
76151
  [FILE_BEGIN_KIND]: defineMessageSignature(FILE_BEGIN_KIND, encodeFileBeginEvent, decodeFileBeginEvent),
76041
- [FILE_CHUNK_KIND]: defineMessageSignature(FILE_CHUNK_KIND, encodeFileChunkEvent, decodeFileChunkEvent),
76042
76152
  [FILE_END_KIND]: defineMessageSignature(FILE_END_KIND, encodeFileEndEvent, decodeFileEndEvent),
76043
76153
  [FILE_FAILED_KIND]: defineMessageSignature(FILE_FAILED_KIND, encodeFileFailedEvent, decodeFileFailedEvent),
76154
+ [CONTENT_READY_KIND]: defineMessageSignature(CONTENT_READY_KIND, encodeContentReadyEvent, decodeContentReadyEvent),
76155
+ [CONTENT_AVAILABLE_KIND]: defineMessageSignature(
76156
+ CONTENT_AVAILABLE_KIND,
76157
+ encodeContentAvailableEvent,
76158
+ decodeContentAvailableEvent
76159
+ ),
76044
76160
  [SESSION_LISTED_KIND]: defineMessageSignature(
76045
76161
  SESSION_LISTED_KIND,
76046
76162
  encodeSessionsListedEvent,
@@ -76135,6 +76251,7 @@ var init_protocol = __esm({
76135
76251
  init_history2();
76136
76252
  init_commands();
76137
76253
  init_usage();
76254
+ init_recorded_lifecycle_status();
76138
76255
  init_turn_history();
76139
76256
  init_webhooks();
76140
76257
  init_turn();
@@ -93491,7 +93608,8 @@ var init_session_api = __esm({
93491
93608
  configOptions;
93492
93609
  prompted;
93493
93610
  restored;
93494
- constructor(agentName, agentVersion, capabilities, commands, configOptions, prompted, restored) {
93611
+ configurationRevision;
93612
+ constructor(agentName, agentVersion, capabilities, commands, configOptions, prompted, restored, configurationRevision) {
93495
93613
  this.agentName = agentName;
93496
93614
  this.agentVersion = agentVersion;
93497
93615
  this.capabilities = capabilities;
@@ -93499,6 +93617,7 @@ var init_session_api = __esm({
93499
93617
  this.configOptions = configOptions;
93500
93618
  this.prompted = prompted;
93501
93619
  this.restored = restored;
93620
+ this.configurationRevision = configurationRevision;
93502
93621
  }
93503
93622
  };
93504
93623
  AgentSettingsSnapshot = class {
@@ -94563,6 +94682,7 @@ var init_agent_session = __esm({
94563
94682
  init_prompt_content();
94564
94683
  init_session_capabilities();
94565
94684
  init_session_config_protocol();
94685
+ init_serial_task_queue();
94566
94686
  init_value_utils();
94567
94687
  init_session_api();
94568
94688
  init_session_history();
@@ -94622,7 +94742,8 @@ var init_agent_session = __esm({
94622
94742
  #agentVersion = "";
94623
94743
  #capabilities = unsupportedSessionCapabilities();
94624
94744
  #commands = [];
94625
- #configRevision = 0;
94745
+ #configRevision = crypto.randomUUID();
94746
+ #configurationChanges = new SerialTaskQueue();
94626
94747
  #configOptions = [];
94627
94748
  #sessionConfigurations = new SessionConfigurations();
94628
94749
  #nativeHistoryOwnership = { kind: "unbound" };
@@ -94791,7 +94912,8 @@ var init_agent_session = __esm({
94791
94912
  this.#commands,
94792
94913
  this.#configOptions,
94793
94914
  this.#prompted,
94794
- this.#restored
94915
+ this.#restored,
94916
+ this.#configRevision
94795
94917
  );
94796
94918
  ensureHistoryLoaded = async (signal) => {
94797
94919
  if (!this.#capabilities.loadSession) {
@@ -94921,12 +95043,23 @@ var init_agent_session = __esm({
94921
95043
  const configured = await this.#adapter.configureSession(this.#target(), selection, signal);
94922
95044
  if (this.#configRevision === configRevision) {
94923
95045
  this.#configOptions = configured;
95046
+ this.#configRevision = crypto.randomUUID();
95047
+ await this.#publishConfiguration();
94924
95048
  }
94925
95049
  };
94926
- configure = async (options) => {
95050
+ // The revision check and Agent mutation share one queue, including legacy callers.
95051
+ // A lost response may have committed: reread after a conflict, never replay an edit blindly.
95052
+ configure = async (options) => this.#configurationChanges.run(async (signal) => {
95053
+ if (options.expectedConfigurationRevision !== void 0 && options.expectedConfigurationRevision !== this.#configRevision) {
95054
+ throw new AcpExecutionError(
95055
+ "Session settings changed. Review the current settings before applying your selection again.",
95056
+ {},
95057
+ "session_configuration_conflict"
95058
+ );
95059
+ }
94927
95060
  await this.#applyConfiguration(
94928
95061
  options.valueType === "boolean" ? { type: "boolean", configId: options.configId, booleanValue: options.booleanValue } : { type: "select", configId: options.configId, value: options.value },
94929
- options.signal
95062
+ signal
94930
95063
  );
94931
95064
  const applied = this.#configOptions.find((option) => option.id === options.configId);
94932
95065
  if (applied === void 0) {
@@ -94934,7 +95067,24 @@ var init_agent_session = __esm({
94934
95067
  }
94935
95068
  this.#sessionConfigurations.select(applied);
94936
95069
  this.writeStoredSession((/* @__PURE__ */ new Date()).toISOString());
94937
- return this.#configOptions;
95070
+ return { configOptions: this.#configOptions, configurationRevision: this.#configRevision };
95071
+ }, options.signal);
95072
+ #publishConfiguration = async () => {
95073
+ const event = this.#store.events.append(this.#mobiusSessionId, {
95074
+ type: "acp",
95075
+ payload: {
95076
+ sessionUpdate: "config_option_update",
95077
+ configOptions: this.#configOptions.map((option) => ({
95078
+ category: option.category,
95079
+ description: option.description,
95080
+ id: option.id,
95081
+ name: option.name,
95082
+ ...option.type === "boolean" ? { type: "boolean", currentValue: option.booleanValue } : { type: "select", currentValue: option.currentValue, options: option.values }
95083
+ }))
95084
+ }
95085
+ });
95086
+ await this.#getObserver().onSessionEvent?.(event);
95087
+ await this.emitConfigUpdate();
94938
95088
  };
94939
95089
  #target = () => ({
94940
95090
  nativeSessionId: this.#updates.sessionId(),
@@ -95112,6 +95262,13 @@ var init_agent_session = __esm({
95112
95262
  this.#nativeHistoryOwnership = { kind: "agent-owned" };
95113
95263
  };
95114
95264
  #processEvent = async (event) => {
95265
+ if (event.kind === "configuration" || event.kind === "mode") {
95266
+ this.#configOptions = event.kind === "configuration" ? event.configOptions : this.#configOptions.map(
95267
+ (option) => option.category === "mode" ? { ...option, currentValue: event.modeId } : option
95268
+ );
95269
+ this.#configRevision = crypto.randomUUID();
95270
+ this.#captureSelectedConfigurationValues();
95271
+ }
95115
95272
  if (this.#sessionLoad.kind === "capturing") {
95116
95273
  await this.#sessionLoad.history.record(event.payload);
95117
95274
  } else if (this.#sessionLoad.kind === "loaded" || this.#sessionLoad.kind === "execution-only") {
@@ -95132,17 +95289,7 @@ var init_agent_session = __esm({
95132
95289
  });
95133
95290
  return;
95134
95291
  case "configuration":
95135
- this.#configOptions = event.configOptions;
95136
- this.#configRevision += 1;
95137
- this.#captureSelectedConfigurationValues();
95138
- await this.emitConfigUpdate();
95139
- return;
95140
95292
  case "mode":
95141
- this.#configOptions = this.#configOptions.map(
95142
- (option) => option.category === "mode" ? { ...option, currentValue: event.modeId } : option
95143
- );
95144
- this.#configRevision += 1;
95145
- this.#captureSelectedConfigurationValues();
95146
95293
  await this.emitConfigUpdate();
95147
95294
  return;
95148
95295
  case "info":
@@ -95205,6 +95352,7 @@ var init_agent_session = __esm({
95205
95352
  }
95206
95353
  setConfigOptions(options) {
95207
95354
  this.#configOptions = options;
95355
+ this.#configRevision = crypto.randomUUID();
95208
95356
  }
95209
95357
  setNativeHistoryOwnership(ownership) {
95210
95358
  this.#nativeHistoryOwnership = ownership;
@@ -95226,6 +95374,7 @@ var init_agent_session = __esm({
95226
95374
  emitConfigUpdate = async () => {
95227
95375
  await this.#getObserver().onConfig({
95228
95376
  configOptions: this.#configOptions,
95377
+ configurationRevision: this.#configRevision,
95229
95378
  kind: SESSION_CONFIG_UPDATED_KIND,
95230
95379
  requestId: `agent-update-${crypto.randomUUID()}`,
95231
95380
  sessionId: this.#mobiusSessionId
@@ -95653,7 +95802,7 @@ var init_session_manager = __esm({
95653
95802
  (option) => option.id === "model" || option.category === "model"
95654
95803
  );
95655
95804
  const modelIsFixed = modelOption2?.type === "select" && modelOption2.values.length < 2 && modelOption2.currentValue === model;
95656
- const configOptions = model === void 0 || modelIsFixed ? prepared.configOptions : await runtime.configure({
95805
+ const configOptions = model === void 0 || modelIsFixed ? prepared.configOptions : (await runtime.configure({
95657
95806
  ...options2,
95658
95807
  booleanValue: false,
95659
95808
  configId: modelOption2?.id ?? "model",
@@ -95661,7 +95810,7 @@ var init_session_manager = __esm({
95661
95810
  sessionId: `agent-settings-${crypto.randomUUID()}`,
95662
95811
  value: model,
95663
95812
  valueType: "select"
95664
- });
95813
+ })).configOptions;
95665
95814
  return new AgentSettingsSnapshot(
95666
95815
  prepared.agentName,
95667
95816
  prepared.agentVersion,
@@ -96515,19 +96664,22 @@ function promptContent(command) {
96515
96664
  if (command.prompt.length > 0) {
96516
96665
  content.push({ text: command.prompt, type: "text" });
96517
96666
  }
96518
- for (const image of command.images) {
96519
- content.push({
96520
- data: image.data,
96521
- mimeType: image.mimeType,
96522
- type: "image"
96523
- });
96524
- }
96525
- for (const resource of command.resources) {
96667
+ for (const attachment of command.attachments) {
96526
96668
  content.push(
96527
- resource.type === "embedded" ? {
96528
- resource: { mimeType: resource.mimeType, text: resource.text, uri: resource.uri },
96529
- type: "resource"
96530
- } : { mimeType: resource.mimeType, name: resource.name, type: "resource_link", uri: resource.uri }
96669
+ attachment.kind === "image" ? {
96670
+ byteLength: attachment.byteLength,
96671
+ imageKey: attachment.contentKey,
96672
+ mimeType: attachment.mimeType,
96673
+ type: "external_image",
96674
+ uri: attachment.uri
96675
+ } : {
96676
+ byteLength: attachment.byteLength,
96677
+ encoding: "text",
96678
+ mimeType: attachment.mimeType,
96679
+ resourceKey: attachment.contentKey,
96680
+ type: "external_resource",
96681
+ uri: attachment.uri
96682
+ }
96531
96683
  );
96532
96684
  }
96533
96685
  return content;
@@ -97248,8 +97400,7 @@ var init_session_turns = __esm({
97248
97400
  queued.push({
97249
97401
  commandId: candidate.command.commandId,
97250
97402
  prompt: candidate.command.prompt,
97251
- images: candidate.command.images,
97252
- resources: candidate.command.resources
97403
+ attachments: candidate.command.attachments
97253
97404
  });
97254
97405
  }
97255
97406
  return { turn: turnSnapshot ?? null, queued };
@@ -97574,7 +97725,7 @@ var init_session_layer = __esm({
97574
97725
 
97575
97726
  // src/storage/files/scratch-directory.ts
97576
97727
  import { randomUUID as randomUUID16 } from "node:crypto";
97577
- import { lstat as lstat6, mkdir as mkdir5, readdir as readdir7, realpath as realpath9, rename as rename5, rm as rm4, stat as stat8, utimes, writeFile as writeFile5 } from "node:fs/promises";
97728
+ import { lstat as lstat6, mkdir as mkdir5, readdir as readdir7, readFile as readFile12, realpath as realpath9, rename as rename5, rm as rm4, stat as stat8, utimes, writeFile as writeFile5 } from "node:fs/promises";
97578
97729
  import { dirname as dirname12, join as join34 } from "node:path";
97579
97730
  async function atomicWrite(path8, bytes, signal) {
97580
97731
  const temporary = `${path8}.${randomUUID16()}.tmp`;
@@ -97642,6 +97793,12 @@ var init_scratch_directory = __esm({
97642
97793
  return null;
97643
97794
  }
97644
97795
  };
97796
+ /** Reads a regular file owned by this scratch directory after validating its canonical path. */
97797
+ read = async (path8, signal) => {
97798
+ const resolved = await this.resolveFile(path8);
97799
+ signal.throwIfAborted();
97800
+ return resolved === null ? null : new Uint8Array(await readFile12(resolved, { signal }));
97801
+ };
97645
97802
  removeAll = async () => {
97646
97803
  await rm4(this.#root, { force: true, recursive: true });
97647
97804
  };
@@ -97753,6 +97910,11 @@ var init_external_content_store = __esm({
97753
97910
  signal.throwIfAborted();
97754
97911
  return resolvedPath === null ? null : { mediaType: entry.mediaType, name: entry.name, path: resolvedPath };
97755
97912
  };
97913
+ read = (sessionId, request, signal) => this.#track(async () => {
97914
+ const active = AbortSignal.any([signal, this.#lifetime.signal]);
97915
+ const resolved = await this.#resolve(sessionId, request, active);
97916
+ return resolved === null ? null : this.#scratch.read(resolved.path, active);
97917
+ });
97756
97918
  [Symbol.asyncDispose] = async () => {
97757
97919
  clearInterval(this.#expirationTimer);
97758
97920
  this.#lifetime.abort();
@@ -98361,6 +98523,12 @@ function send(socket, message) {
98361
98523
  }
98362
98524
  socket.send(encodeDaemonToServiceMessage(message));
98363
98525
  }
98526
+ function sendContentChunk(socket, requestId, sequence, bytes) {
98527
+ if (socket.readyState !== WebSocket2.OPEN) {
98528
+ throw new Error("Relay connection is not open");
98529
+ }
98530
+ socket.send(encodeContentChunkFrame({ bytes, requestId, sequence }));
98531
+ }
98364
98532
  function reportOperationFailure(socket, requestId, sessionId, error62, runtimeTimings = []) {
98365
98533
  if (socket.readyState !== WebSocket2.OPEN) {
98366
98534
  return;
@@ -99047,6 +99215,134 @@ var init_agent_settings = __esm({
99047
99215
  }
99048
99216
  });
99049
99217
 
99218
+ // src/runtime/command/registry/content-write/index.ts
99219
+ import { createHash as createHash10 } from "node:crypto";
99220
+ function createContentWriteCommands(context) {
99221
+ const pending = /* @__PURE__ */ new Map();
99222
+ const operations = /* @__PURE__ */ new Set();
99223
+ const fail = (command, error62) => {
99224
+ pending.delete(command.requestId);
99225
+ send(context.socket, {
99226
+ code: "content_write_failed",
99227
+ kind: FILE_FAILED_KIND,
99228
+ message: error62 instanceof Error ? error62.message : "The content could not be stored",
99229
+ requestId: command.requestId,
99230
+ sessionId: command.sessionId
99231
+ });
99232
+ };
99233
+ const write = {
99234
+ kind: CONTENT_WRITE_KIND,
99235
+ handle: (_commandContext, message) => {
99236
+ if (message.kind !== CONTENT_WRITE_KIND) {
99237
+ throw new Error("Command kind mismatch");
99238
+ }
99239
+ const existing = pending.get(message.requestId);
99240
+ if (existing !== void 0) {
99241
+ if (JSON.stringify(existing.command) !== JSON.stringify(message)) {
99242
+ fail(message, new Error("The content request identifier is already in use"));
99243
+ return;
99244
+ }
99245
+ } else {
99246
+ pending.set(message.requestId, {
99247
+ bytes: new Uint8Array(message.byteLength),
99248
+ command: message,
99249
+ hash: createHash10("sha256"),
99250
+ receivedBytes: 0,
99251
+ sequence: 0
99252
+ });
99253
+ }
99254
+ send(context.socket, {
99255
+ kind: CONTENT_READY_KIND,
99256
+ requestId: message.requestId,
99257
+ sessionId: message.sessionId
99258
+ });
99259
+ }
99260
+ };
99261
+ const commit = {
99262
+ kind: CONTENT_COMMIT_KIND,
99263
+ handle: (_commandContext, message) => {
99264
+ if (message.kind !== CONTENT_COMMIT_KIND) {
99265
+ throw new Error("Command kind mismatch");
99266
+ }
99267
+ const state = pending.get(message.requestId);
99268
+ if (state === void 0 || state.command.sessionId !== message.sessionId) {
99269
+ fail(message, new Error("The content upload is unavailable"));
99270
+ return;
99271
+ }
99272
+ pending.delete(message.requestId);
99273
+ const operation = (async () => {
99274
+ try {
99275
+ if (state.receivedBytes !== state.command.byteLength) {
99276
+ throw new Error("The content upload ended at an unexpected length");
99277
+ }
99278
+ if (state.hash.digest("hex") !== state.command.contentKey) {
99279
+ throw new Error("The content upload failed integrity validation");
99280
+ }
99281
+ const stored = await context.externalContent.put({
99282
+ bytes: state.bytes,
99283
+ kind: state.command.contentKind,
99284
+ mediaType: state.command.mediaType,
99285
+ name: state.command.name,
99286
+ sessionId: state.command.sessionId,
99287
+ signal: context.signal
99288
+ });
99289
+ if (stored.key !== state.command.contentKey || stored.byteLength !== state.command.byteLength) {
99290
+ throw new Error("Stored content did not match the upload");
99291
+ }
99292
+ send(context.socket, {
99293
+ byteLength: stored.byteLength,
99294
+ contentKey: stored.key,
99295
+ kind: CONTENT_AVAILABLE_KIND,
99296
+ requestId: message.requestId,
99297
+ sessionId: message.sessionId
99298
+ });
99299
+ } catch (error62) {
99300
+ if (!context.signal.aborted) {
99301
+ fail(message, error62);
99302
+ }
99303
+ }
99304
+ })();
99305
+ operations.add(operation);
99306
+ void operation.finally(() => operations.delete(operation));
99307
+ }
99308
+ };
99309
+ return {
99310
+ commands: [write, commit],
99311
+ receiveChunk: (frame) => {
99312
+ const state = pending.get(frame.requestId);
99313
+ if (state === void 0) {
99314
+ context.diagnostics.daemonDiagnostic("content_chunk_discarded", frame.requestId, {
99315
+ reason: "upload_unavailable",
99316
+ sequence: frame.sequence.toString()
99317
+ });
99318
+ return;
99319
+ }
99320
+ if (frame.sequence !== state.sequence || state.receivedBytes + frame.bytes.byteLength > state.command.byteLength) {
99321
+ fail(state.command, new Error("The content upload contains invalid chunks"));
99322
+ return;
99323
+ }
99324
+ state.bytes.set(frame.bytes, state.receivedBytes);
99325
+ state.hash.update(frame.bytes);
99326
+ pending.set(frame.requestId, {
99327
+ ...state,
99328
+ receivedBytes: state.receivedBytes + frame.bytes.byteLength,
99329
+ sequence: state.sequence + 1
99330
+ });
99331
+ },
99332
+ settle: async () => {
99333
+ pending.clear();
99334
+ await Promise.allSettled([...operations]);
99335
+ }
99336
+ };
99337
+ }
99338
+ var init_content_write = __esm({
99339
+ "src/runtime/command/registry/content-write/index.ts"() {
99340
+ "use strict";
99341
+ init_protocol();
99342
+ init_transport();
99343
+ }
99344
+ });
99345
+
99050
99346
  // src/session/content/session-files.ts
99051
99347
  import { basename as basename9, extname as extname2, isAbsolute as isAbsolute18, join as join37, normalize as normalize3, resolve as resolve18 } from "node:path";
99052
99348
  import { fileURLToPath as fileURLToPath2 } from "node:url";
@@ -99089,7 +99385,7 @@ async function resolveFile(value, workingDirectory, signal) {
99089
99385
  }
99090
99386
  return null;
99091
99387
  }
99092
- async function streamLocalFile(command, send2, signal, workingDirectory, externalContent) {
99388
+ async function streamLocalFile(command, send2, sendChunk, signal, workingDirectory, externalContent) {
99093
99389
  const external = await externalContent.resolve(command.sessionId, command.path, signal);
99094
99390
  const target = external?.path ?? await resolveFile(command.path, workingDirectory, signal);
99095
99391
  if (target === null) {
@@ -99111,14 +99407,8 @@ async function streamLocalFile(command, send2, signal, workingDirectory, externa
99111
99407
  sessionId: command.sessionId
99112
99408
  });
99113
99409
  let sequence = 0;
99114
- for await (const bytes of readFileChunks(target, CHUNK_BYTES, signal)) {
99115
- send2({
99116
- data: Buffer.from(bytes).toString("base64"),
99117
- kind: FILE_CHUNK_KIND,
99118
- requestId: command.requestId,
99119
- sequence,
99120
- sessionId: command.sessionId
99121
- });
99410
+ for await (const bytes of readFileChunks(target, CONTENT_CHUNK_MAX_BYTES, signal)) {
99411
+ sendChunk(command.requestId, sequence, bytes);
99122
99412
  sequence += 1;
99123
99413
  }
99124
99414
  const after = await readPathMetadata(target);
@@ -99132,14 +99422,12 @@ async function streamLocalFile(command, send2, signal, workingDirectory, externa
99132
99422
  sessionId: command.sessionId
99133
99423
  });
99134
99424
  }
99135
- var CHUNK_BYTES;
99136
99425
  var init_session_files = __esm({
99137
99426
  "src/session/content/session-files.ts"() {
99138
99427
  "use strict";
99139
99428
  init_protocol();
99140
99429
  init_raster();
99141
99430
  init_local_files();
99142
- CHUNK_BYTES = 192 * 1024;
99143
99431
  }
99144
99432
  });
99145
99433
 
@@ -99161,6 +99449,7 @@ var init_file_read = __esm({
99161
99449
  void streamLocalFile(
99162
99450
  message,
99163
99451
  (response) => send(socket, response),
99452
+ (requestId, sequence, bytes) => sendContentChunk(socket, requestId, sequence, bytes),
99164
99453
  signal,
99165
99454
  sessions.findSessions([message.sessionId])[0]?.cwd ?? null,
99166
99455
  externalContent
@@ -99803,7 +100092,7 @@ async function applySessionConfigurationSelection(sessions, options, selection,
99803
100092
  if (sessionConfigurationMatches(option, selection)) {
99804
100093
  return options;
99805
100094
  }
99806
- return await sessions.configureSession({
100095
+ return (await sessions.configureSession({
99807
100096
  adapter,
99808
100097
  additionalDirectories,
99809
100098
  agent,
@@ -99815,7 +100104,7 @@ async function applySessionConfigurationSelection(sessions, options, selection,
99815
100104
  signal,
99816
100105
  value: selection.value,
99817
100106
  valueType: selection.valueType
99818
- });
100107
+ })).configOptions;
99819
100108
  }
99820
100109
  async function applyCompleteSessionConfiguration(sessions, initialOptions, selections, agent, adapter, cwd, additionalDirectories, commandId, sessionId, signal) {
99821
100110
  let options = initialOptions;
@@ -99859,98 +100148,70 @@ var init_apply_session_configuration = __esm({
99859
100148
  });
99860
100149
 
99861
100150
  // src/session/prompt/prompt-artifacts.ts
99862
- function parseReference(resource) {
99863
- let url2;
99864
- try {
99865
- url2 = new URL(resource.uri);
99866
- } catch (cause) {
99867
- throw new PromptArtifactError("artifact_reference_invalid", "The prompt artifact reference is invalid", {
99868
- cause
99869
- });
99870
- }
99871
- const keys = [...url2.searchParams.keys()].sort();
99872
- const artifactId = url2.pathname;
99873
- const encodedByteLength = url2.searchParams.get("byteLength") ?? "";
99874
- const sha256 = url2.searchParams.get("sha256") ?? "";
99875
- const byteLength = Number(encodedByteLength);
99876
- if (url2.protocol !== ARTIFACT_SCHEME || url2.hash.length > 0 || resource.type !== "link" || resource.text.length > 0 || !isIdentifier(artifactId) || keys.length !== 2 || keys[0] !== "byteLength" || keys[1] !== "sha256" || !/^[1-9][0-9]*$/.test(encodedByteLength) || !Number.isSafeInteger(byteLength) || !/^[a-f0-9]{64}$/.test(sha256)) {
99877
- throw new PromptArtifactError("artifact_reference_invalid", "The prompt artifact reference is invalid");
99878
- }
99879
- return new PromptArtifactReference(artifactId, byteLength, sha256, resource);
99880
- }
100151
+ import { createHash as createHash11 } from "node:crypto";
99881
100152
  function isTextMediaType(mediaType) {
99882
100153
  return mediaType.startsWith("text/") || mediaType === "application/json" || mediaType.endsWith("+json") || mediaType === "application/xml" || mediaType.endsWith("+xml");
99883
100154
  }
99884
- async function resolvePromptArtifacts(download, command, signal) {
99885
- const images = [...command.images];
100155
+ async function resolvePromptArtifacts(read, attachments, signal) {
100156
+ const images = [];
99886
100157
  const resources = [];
99887
- for (const resource of command.resources) {
100158
+ for (const attachment of attachments) {
99888
100159
  signal.throwIfAborted();
99889
- if (!resource.uri.startsWith(ARTIFACT_SCHEME)) {
99890
- resources.push(resource);
99891
- continue;
100160
+ const bytes = await read(attachment, signal);
100161
+ if (bytes.byteLength !== attachment.byteLength || createHash11("sha256").update(bytes).digest("hex") !== attachment.contentKey) {
100162
+ throw new PromptArtifactError(
100163
+ "artifact_integrity_failed",
100164
+ "The prompt attachment failed integrity validation"
100165
+ );
99892
100166
  }
99893
- const reference = parseReference(resource);
99894
- const bytes = await download(
99895
- {
99896
- artifactId: reference.artifactId,
99897
- byteLength: reference.byteLength,
99898
- commandId: command.commandId,
99899
- mimeType: reference.resource.mimeType,
99900
- sessionId: command.sessionId,
99901
- sha256: reference.sha256
99902
- },
99903
- signal
99904
- );
99905
- if (resource.mimeType.startsWith("image/")) {
99906
- const data = Buffer.from(bytes).toString("base64");
99907
- if (data.length > MAX_AGENT_IMAGE_BASE64_LENGTH || images.length >= 8) {
100167
+ if (attachment.kind === "image") {
100168
+ if (bytes.byteLength > PROMPT_IMAGE_MAX_BYTES || images.length >= 8) {
99908
100169
  throw new PromptArtifactError(
99909
100170
  "artifact_too_large_for_agent",
99910
- "The prompt artifact exceeds the Agent image limit"
100171
+ "The prompt attachment exceeds the Agent image limit"
99911
100172
  );
99912
100173
  }
99913
- images.push({ data, mimeType: resource.mimeType, name: resource.name });
100174
+ images.push({
100175
+ data: Buffer.from(bytes).toString("base64"),
100176
+ mimeType: attachment.mimeType,
100177
+ name: attachment.name
100178
+ });
99914
100179
  continue;
99915
100180
  }
99916
- if (!isTextMediaType(resource.mimeType)) {
100181
+ if (!isTextMediaType(attachment.mimeType)) {
99917
100182
  throw new PromptArtifactError(
99918
100183
  "artifact_media_type_unsupported",
99919
- "The Agent cannot consume this prompt artifact media type"
100184
+ "The Agent cannot consume this prompt attachment media type"
99920
100185
  );
99921
100186
  }
99922
100187
  if (bytes.byteLength > MAX_AGENT_RESOURCE_BYTE_LENGTH || resources.length >= 16) {
99923
100188
  throw new PromptArtifactError(
99924
100189
  "artifact_too_large_for_agent",
99925
- "The prompt artifact exceeds the Agent resource limit"
100190
+ "The prompt attachment exceeds the Agent resource limit"
99926
100191
  );
99927
100192
  }
99928
100193
  let text2;
99929
100194
  try {
99930
100195
  text2 = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
99931
100196
  } catch (cause) {
99932
- throw new PromptArtifactError("artifact_encoding_invalid", "The prompt artifact is not valid UTF-8 text", {
99933
- cause
99934
- });
100197
+ throw new PromptArtifactError(
100198
+ "artifact_encoding_invalid",
100199
+ "The prompt attachment is not valid UTF-8 text",
100200
+ {
100201
+ cause
100202
+ }
100203
+ );
99935
100204
  }
99936
- resources.push({
99937
- mimeType: resource.mimeType,
99938
- name: resource.name,
99939
- text: text2,
99940
- type: "embedded",
99941
- uri: resource.uri
99942
- });
100205
+ resources.push({ mimeType: attachment.mimeType, text: text2, type: "embedded", uri: attachment.uri });
99943
100206
  }
99944
100207
  return new ResolvedPromptArtifacts(images, resources);
99945
100208
  }
99946
- var ARTIFACT_SCHEME, MAX_AGENT_IMAGE_BASE64_LENGTH, MAX_AGENT_RESOURCE_BYTE_LENGTH, PromptArtifactError, ResolvedPromptArtifacts, PromptArtifactReference;
100209
+ var MAX_AGENT_RESOURCE_BYTE_LENGTH, PromptArtifactError, ResolvedPromptArtifacts;
99947
100210
  var init_prompt_artifacts = __esm({
99948
100211
  "src/session/prompt/prompt-artifacts.ts"() {
99949
100212
  "use strict";
99950
100213
  init_protocol();
99951
100214
  init_operation_error();
99952
- ARTIFACT_SCHEME = "mobius-artifact:";
99953
- MAX_AGENT_IMAGE_BASE64_LENGTH = 4e6;
99954
100215
  MAX_AGENT_RESOURCE_BYTE_LENGTH = 1e6;
99955
100216
  PromptArtifactError = class extends OperationError {
99956
100217
  constructor(code, message, options = {}) {
@@ -99966,18 +100227,6 @@ var init_prompt_artifacts = __esm({
99966
100227
  this.resources = resources;
99967
100228
  }
99968
100229
  };
99969
- PromptArtifactReference = class {
99970
- artifactId;
99971
- byteLength;
99972
- resource;
99973
- sha256;
99974
- constructor(artifactId, byteLength, sha256, resource) {
99975
- this.artifactId = artifactId;
99976
- this.byteLength = byteLength;
99977
- this.resource = resource;
99978
- this.sha256 = sha256;
99979
- }
99980
- };
99981
100230
  }
99982
100231
  });
99983
100232
 
@@ -99987,7 +100236,7 @@ async function executePrompt({
99987
100236
  eventProjection,
99988
100237
  command,
99989
100238
  resolveAgent,
99990
- downloadArtifact,
100239
+ readArtifact,
99991
100240
  reportFailure,
99992
100241
  directories,
99993
100242
  sessions,
@@ -100069,7 +100318,7 @@ async function executePrompt({
100069
100318
  stream.epoch,
100070
100319
  availability.disposition
100071
100320
  );
100072
- const attachments = await resolvePromptArtifacts(downloadArtifact, command, signal);
100321
+ const attachments = await resolvePromptArtifacts(readArtifact, command.attachments, signal);
100073
100322
  let stopReason;
100074
100323
  if (availability.disposition === SessionPromptDisposition.Steer) {
100075
100324
  await sessions.steerPrompt({
@@ -100140,124 +100389,6 @@ var init_execute_prompt = __esm({
100140
100389
  }
100141
100390
  });
100142
100391
 
100143
- // src/runtime/relay/artifact-download.ts
100144
- import { createHash as createHash10 } from "node:crypto";
100145
- import { fetch as fetch4 } from "undici";
100146
- function downloadUrl(config2, artifact) {
100147
- const url2 = relayHttpEndpoint(config2.relayUrl);
100148
- let channelPath = "";
100149
- if (url2.pathname.endsWith("/daemon")) {
100150
- channelPath = url2.pathname.slice(0, -"/daemon".length);
100151
- } else {
100152
- const runtimePath = "/v1/runtimes/connect";
100153
- if (!url2.pathname.endsWith(runtimePath)) {
100154
- throw new PromptArtifactError("artifact_endpoint_invalid", "The Relay artifact endpoint is invalid");
100155
- }
100156
- channelPath = `${url2.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
100157
- }
100158
- url2.pathname = `${channelPath}/sessions/${encodeURIComponent(artifact.sessionId)}/commands/${encodeURIComponent(artifact.commandId)}/artifacts/${encodeURIComponent(artifact.artifactId)}/content`;
100159
- return url2;
100160
- }
100161
- async function responseBytes(response, expectedByteLength, signal) {
100162
- const declaredLength = response.headers.get("content-length") ?? "";
100163
- if (!/^(0|[1-9][0-9]*)$/.test(declaredLength) || Number(declaredLength) !== expectedByteLength || response.body === null) {
100164
- throw new PromptArtifactError("artifact_integrity_failed", "The prompt artifact failed integrity validation");
100165
- }
100166
- const reader = response.body.getReader();
100167
- const chunks = [];
100168
- let byteLength = 0;
100169
- try {
100170
- while (true) {
100171
- signal.throwIfAborted();
100172
- const chunk = await reader.read();
100173
- signal.throwIfAborted();
100174
- if (chunk.done) {
100175
- break;
100176
- }
100177
- byteLength += chunk.value.byteLength;
100178
- if (byteLength > expectedByteLength) {
100179
- await reader.cancel("Artifact response exceeded its authorization");
100180
- throw new PromptArtifactError(
100181
- "artifact_integrity_failed",
100182
- "The prompt artifact failed integrity validation"
100183
- );
100184
- }
100185
- chunks.push(chunk.value);
100186
- }
100187
- } finally {
100188
- reader.releaseLock();
100189
- }
100190
- if (byteLength !== expectedByteLength) {
100191
- throw new PromptArtifactError("artifact_integrity_failed", "The prompt artifact failed integrity validation");
100192
- }
100193
- const bytes = new Uint8Array(byteLength);
100194
- let offset = 0;
100195
- for (const chunk of chunks) {
100196
- bytes.set(chunk, offset);
100197
- offset += chunk.byteLength;
100198
- }
100199
- return bytes;
100200
- }
100201
- async function downloadPromptArtifact(config2, artifact, signal) {
100202
- signal.throwIfAborted();
100203
- const timeoutSignal = AbortSignal.timeout(ARTIFACT_DOWNLOAD_TIMEOUT_MILLISECONDS);
100204
- const requestSignal = AbortSignal.any([signal, timeoutSignal]);
100205
- let response;
100206
- try {
100207
- response = await fetch4(downloadUrl(config2, artifact), {
100208
- dispatcher: environmentProxyDispatcher,
100209
- headers: {
100210
- accept: artifact.mimeType,
100211
- "accept-encoding": "identity",
100212
- ...relayAuthorization(config2.relayUrl)
100213
- },
100214
- signal: requestSignal
100215
- });
100216
- if (!response.ok) {
100217
- await response.body?.cancel();
100218
- throw new PromptArtifactError(
100219
- "artifact_download_rejected",
100220
- "The Relay rejected the prompt artifact download"
100221
- );
100222
- }
100223
- if (response.headers.get("content-type") !== artifact.mimeType || response.headers.get("x-mobius-artifact-id") !== artifact.artifactId || response.headers.get("x-mobius-sha256") !== artifact.sha256) {
100224
- await response.body?.cancel();
100225
- throw new PromptArtifactError(
100226
- "artifact_integrity_failed",
100227
- "The prompt artifact failed integrity validation"
100228
- );
100229
- }
100230
- const bytes = await responseBytes(response, artifact.byteLength, requestSignal);
100231
- if (createHash10("sha256").update(bytes).digest("hex") !== artifact.sha256) {
100232
- throw new PromptArtifactError(
100233
- "artifact_integrity_failed",
100234
- "The prompt artifact failed integrity validation"
100235
- );
100236
- }
100237
- return bytes;
100238
- } catch (error62) {
100239
- signal.throwIfAborted();
100240
- if (error62 instanceof PromptArtifactError) {
100241
- throw error62;
100242
- }
100243
- throw new PromptArtifactError(
100244
- timeoutSignal.aborted ? "artifact_download_timeout" : "artifact_download_failed",
100245
- timeoutSignal.aborted ? "The prompt artifact download timed out" : "The prompt artifact could not be downloaded",
100246
- { cause: error62 }
100247
- );
100248
- }
100249
- }
100250
- var ARTIFACT_DOWNLOAD_TIMEOUT_MILLISECONDS;
100251
- var init_artifact_download = __esm({
100252
- "src/runtime/relay/artifact-download.ts"() {
100253
- "use strict";
100254
- init_prompt_artifacts();
100255
- init_environment_proxy();
100256
- init_relay_authentication();
100257
- ARTIFACT_DOWNLOAD_TIMEOUT_MILLISECONDS = 2e4;
100258
- }
100259
- });
100260
-
100261
100392
  // src/runtime/command/registry/prompt.ts
100262
100393
  var sessionPromptCommand;
100263
100394
  var init_prompt2 = __esm({
@@ -100265,7 +100396,6 @@ var init_prompt2 = __esm({
100265
100396
  "use strict";
100266
100397
  init_protocol();
100267
100398
  init_execute_prompt();
100268
- init_artifact_download();
100269
100399
  init_transport();
100270
100400
  sessionPromptCommand = {
100271
100401
  kind: SESSION_PROMPT_KIND,
@@ -100319,7 +100449,17 @@ var init_prompt2 = __esm({
100319
100449
  eventProjection: context.eventProjection,
100320
100450
  command: message,
100321
100451
  resolveAgent: context.resolveAgent,
100322
- downloadArtifact: (artifact, signal) => downloadPromptArtifact(context.config, artifact, signal),
100452
+ readArtifact: async (artifact, signal) => {
100453
+ const bytes = await context.externalContent.read(
100454
+ message.sessionId,
100455
+ `mobius-content:${artifact.kind}:${artifact.contentKey}`,
100456
+ signal
100457
+ );
100458
+ if (bytes === null) {
100459
+ throw new Error("The prompt attachment is unavailable");
100460
+ }
100461
+ return bytes;
100462
+ },
100323
100463
  reportFailure: context.diagnostics.daemonDiagnostic,
100324
100464
  directories: context.directories,
100325
100465
  sessions: context.sessions,
@@ -100412,7 +100552,7 @@ async function prepareSession(command, recovery, closed, config2, resolveAgent,
100412
100552
  };
100413
100553
  const prepared = command.transient === true ? await sessions.inspectSession(preparation, metrics) : recovery.kind === "history-required" ? await sessions.restoreSession(preparation, metrics, closed) : await sessions.prepareSession(preparation, metrics, closed);
100414
100554
  const configuration = command.configuration;
100415
- const configOptions = configuration === void 0 ? prepared.configOptions : await metrics.measure(
100555
+ const snapshot = configuration === void 0 ? prepared : await metrics.measure(
100416
100556
  "configuration",
100417
100557
  async () => await sessions.configureSession({
100418
100558
  ...preparation,
@@ -100430,7 +100570,8 @@ async function prepareSession(command, recovery, closed, config2, resolveAgent,
100430
100570
  agentVersion: prepared.agentVersion,
100431
100571
  capabilities: prepared.capabilities,
100432
100572
  commands: prepared.commands,
100433
- configOptions,
100573
+ configOptions: snapshot.configOptions,
100574
+ configurationRevision: snapshot.configurationRevision,
100434
100575
  directoryId: command.directoryId,
100435
100576
  directoryLabel: resolved.directoryLabel,
100436
100577
  kind: "session.ready",
@@ -100563,11 +100704,12 @@ async function executeSessionConfigure(socket, command, config2, resolveAgent, d
100563
100704
  command.additionalDirectoryIds,
100564
100705
  signal
100565
100706
  );
100566
- const configOptions = await sessions.configureSession({
100707
+ const snapshot = await sessions.configureSession({
100567
100708
  additionalDirectories: resolved.additionalDirectories,
100568
100709
  ...await resolveAgent(command.agentId, signal, command.sessionId),
100569
100710
  booleanValue: command.booleanValue,
100570
100711
  configId: command.configId,
100712
+ ...command.expectedConfigurationRevision === void 0 ? {} : { expectedConfigurationRevision: command.expectedConfigurationRevision },
100571
100713
  cwd: resolved.cwd,
100572
100714
  requestId: command.requestId,
100573
100715
  sessionId: command.sessionId,
@@ -100576,7 +100718,7 @@ async function executeSessionConfigure(socket, command, config2, resolveAgent, d
100576
100718
  valueType: command.valueType
100577
100719
  });
100578
100720
  send(socket, {
100579
- configOptions,
100721
+ ...snapshot,
100580
100722
  kind: "session.config.updated",
100581
100723
  requestId: command.requestId,
100582
100724
  sessionId: command.sessionId
@@ -100624,6 +100766,7 @@ async function executeSessionConfigRead(socket, command, config2, resolveAgent,
100624
100766
  );
100625
100767
  send(socket, {
100626
100768
  configOptions: ready.configOptions,
100769
+ configurationRevision: ready.configurationRevision,
100627
100770
  kind: SESSION_CONFIG_READ_RESULT_KIND,
100628
100771
  requestId: command.requestId,
100629
100772
  sessionId: command.sessionId
@@ -100747,6 +100890,7 @@ var init_session5 = __esm({
100747
100890
 
100748
100891
  // src/runtime/command/registry/index.ts
100749
100892
  function createCommandRegistry(context) {
100893
+ const contentWrites = createContentWriteCommands(context);
100750
100894
  const commands = [
100751
100895
  runtimeDiagnosticsCommand,
100752
100896
  runtimePingCommand,
@@ -100755,6 +100899,7 @@ function createCommandRegistry(context) {
100755
100899
  ...createNativeSessionCommands(context),
100756
100900
  ...createAgentCatalogCommands(context),
100757
100901
  ...createAgentSettingsCommands(context),
100902
+ ...contentWrites.commands,
100758
100903
  fileReadCommand,
100759
100904
  sessionCancelCommand,
100760
100905
  sessionCloseCommand,
@@ -100777,16 +100922,22 @@ function createCommandRegistry(context) {
100777
100922
  }
100778
100923
  command.handle(context, message);
100779
100924
  },
100925
+ dispatchChunk: (message) => contentWrites.receiveChunk(decodeContentChunkFrame(message)),
100780
100926
  settle: async () => {
100781
- await Promise.all(commands.flatMap((command) => command.settle === void 0 ? [] : [command.settle()]));
100927
+ await Promise.all([
100928
+ contentWrites.settle(),
100929
+ ...commands.flatMap((command) => command.settle === void 0 ? [] : [command.settle()])
100930
+ ]);
100782
100931
  }
100783
100932
  };
100784
100933
  }
100785
100934
  var init_registry2 = __esm({
100786
100935
  "src/runtime/command/registry/index.ts"() {
100787
100936
  "use strict";
100937
+ init_protocol();
100788
100938
  init_agent_catalog();
100789
100939
  init_agent_settings();
100940
+ init_content_write();
100790
100941
  init_file_read();
100791
100942
  init_history3();
100792
100943
  init_interactions2();
@@ -100853,6 +101004,7 @@ function connectRelay(url2, signal) {
100853
101004
  dispatcher,
100854
101005
  headers
100855
101006
  });
101007
+ socket.binaryType = "arraybuffer";
100856
101008
  let released = false;
100857
101009
  const release = (reason) => {
100858
101010
  if (released) {
@@ -101244,7 +101396,16 @@ async function runRelayConnection({
101244
101396
  const handleMessage = (event) => {
101245
101397
  const encoded = event.data;
101246
101398
  if (typeof encoded !== "string") {
101247
- failAndClose(new Error("Relay sent a non-text message"), 4003, "Text message required", "protocol");
101399
+ try {
101400
+ commands.dispatchChunk(encoded);
101401
+ } catch (error62) {
101402
+ failAndClose(
101403
+ new Error("Relay sent an invalid content chunk", { cause: error62 }),
101404
+ 4008,
101405
+ "Invalid content chunk",
101406
+ "protocol"
101407
+ );
101408
+ }
101248
101409
  return;
101249
101410
  }
101250
101411
  try {