@alan-ai-hq/agent-manager-darwin-arm64 0.1.159 → 0.1.160

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/alan-agent.cjs CHANGED
@@ -22501,6 +22501,56 @@ var init_run_log_upload = __esm({
22501
22501
  }
22502
22502
  });
22503
22503
 
22504
+ // ../shared/dist/runtime-v2/run-media.js
22505
+ function runMediaPath(runId) {
22506
+ return `/public/machines/me/runs/${encodeURIComponent(runId)}/media`;
22507
+ }
22508
+ function runMediaCompletePath(runId, mediaId) {
22509
+ return `${runMediaPath(runId)}/${encodeURIComponent(mediaId)}/complete`;
22510
+ }
22511
+ var INT4_MAX, runMediaSourceSchema, runMediaUploadRequestSchema, runMediaUploadTargetSchema, runMediaUploadResponseSchema, runMediaCompleteResponseSchema;
22512
+ var init_run_media = __esm({
22513
+ "../shared/dist/runtime-v2/run-media.js"() {
22514
+ "use strict";
22515
+ init_zod();
22516
+ INT4_MAX = 2147483647;
22517
+ runMediaSourceSchema = external_exports.enum(["generated_image", "session_media"]);
22518
+ runMediaUploadRequestSchema = external_exports.object({
22519
+ /** The `id` the transcript update carries; one upload per id and run. */
22520
+ mediaId: external_exports.string().min(1).max(200),
22521
+ source: runMediaSourceSchema,
22522
+ kind: external_exports.enum(["image", "video"]),
22523
+ mimeType: external_exports.string().min(1).max(200),
22524
+ filename: external_exports.string().min(1).max(500),
22525
+ bytes: external_exports.number().int().positive().max(INT4_MAX),
22526
+ sha256: external_exports.string().regex(/^[0-9a-f]{64}$/),
22527
+ width: external_exports.number().int().min(0).max(INT4_MAX).nullish(),
22528
+ height: external_exports.number().int().min(0).max(INT4_MAX).nullish(),
22529
+ toolId: external_exports.string().max(500).optional(),
22530
+ sourcePath: external_exports.string().max(4096).optional(),
22531
+ ts: external_exports.number().int().positive().optional()
22532
+ });
22533
+ runMediaUploadTargetSchema = external_exports.object({
22534
+ url: external_exports.url(),
22535
+ /** Every header the signed PUT expects, besides the body's `content-length`. */
22536
+ headers: external_exports.record(external_exports.string(), external_exports.string()),
22537
+ expiresAt: external_exports.iso.datetime()
22538
+ });
22539
+ runMediaUploadResponseSchema = external_exports.discriminatedUnion("status", [
22540
+ external_exports.object({
22541
+ status: external_exports.literal("upload"),
22542
+ mediaId: external_exports.string(),
22543
+ upload: runMediaUploadTargetSchema
22544
+ }),
22545
+ external_exports.object({ status: external_exports.literal("ready"), mediaId: external_exports.string() })
22546
+ ]);
22547
+ runMediaCompleteResponseSchema = external_exports.object({
22548
+ status: external_exports.literal("ready"),
22549
+ mediaId: external_exports.string()
22550
+ });
22551
+ }
22552
+ });
22553
+
22504
22554
  // ../shared/dist/runtime-v2/skills.js
22505
22555
  var MACHINE_SKILLS_SYNC_PATH, MAX_MACHINE_SKILLS, installedMachineSkillSchema, MAX_SKILL_UPLOADS, machineSkillScanRepositorySchema, machineSkillScanContextSchema, machineLocalSkillsReportSchema, machineSkillUploadSchema, machineSkillsSyncRequestSchema, desiredMachineSkillSchema, machineSkillDownloadSchema, machineSkillsSyncResponseSchema;
22506
22556
  var init_skills = __esm({
@@ -22624,6 +22674,7 @@ var init_runtime_v2 = __esm({
22624
22674
  init_mcp();
22625
22675
  init_run_log();
22626
22676
  init_run_log_upload();
22677
+ init_run_media();
22627
22678
  init_skills();
22628
22679
  init_workspace();
22629
22680
  }
@@ -26448,17 +26499,20 @@ function stepSummary(node2) {
26448
26499
  const update = node2.event.update;
26449
26500
  const children = node2.children.map(stepSummary);
26450
26501
  if (update.sessionUpdate === "terminal_update") {
26451
- const { output: _output, ...rest2 } = update;
26452
- return { ...node2, event: { ...node2.event, update: rest2 }, children };
26502
+ const { output: output2, ...rest2 } = update;
26503
+ const omitted = output2 === void 0 ? {} : { outputTruncated: true };
26504
+ return { ...node2, event: { ...node2.event, update: { ...rest2, ...omitted } }, children };
26453
26505
  }
26454
26506
  if (update.sessionUpdate !== "tool_call_update")
26455
26507
  return { ...node2, children };
26456
26508
  const inputRecord = toolInputRecord(update.rawInput);
26457
26509
  if (rendersBesideSteps(update, inputRecord))
26458
26510
  return { ...node2, children };
26459
- const { content, rawOutput: _rawOutput, rawInput, ...rest } = update;
26511
+ const { content, rawOutput, rawInput, ...rest } = update;
26460
26512
  const input2 = stepInput(rawInput, inputRecord);
26461
- const diffs = (Array.isArray(content) ? content : []).map(diffWithoutText).filter((block2) => block2 !== null);
26513
+ const blocks = Array.isArray(content) ? content : [];
26514
+ const diffs = blocks.map(diffWithoutText).filter((block2) => block2 !== null);
26515
+ const outputOmitted = rawOutput !== void 0 && rawOutput !== null && rawOutput !== "" || blocks.length > 0;
26462
26516
  return {
26463
26517
  ...node2,
26464
26518
  event: {
@@ -26467,6 +26521,7 @@ function stepSummary(node2) {
26467
26521
  ...rest,
26468
26522
  ...input2.value === void 0 ? {} : { rawInput: input2.value },
26469
26523
  ...input2.truncated ? { inputTruncated: true } : {},
26524
+ ...outputOmitted ? { outputTruncated: true } : {},
26470
26525
  ...diffs.length > 0 ? { content: diffs } : {}
26471
26526
  }
26472
26527
  },
@@ -26783,9 +26838,14 @@ var init_session_activity = __esm({
26783
26838
  });
26784
26839
 
26785
26840
  // ../shared/dist/agent/acp/transcript-byte-decoder.js
26841
+ var MIN_ELIDED_DATA_BYTES, DATA_KEY, MEDIA_MARKERS;
26786
26842
  var init_transcript_byte_decoder = __esm({
26787
26843
  "../shared/dist/agent/acp/transcript-byte-decoder.js"() {
26788
26844
  "use strict";
26845
+ init_types2();
26846
+ MIN_ELIDED_DATA_BYTES = 16 * 1024;
26847
+ DATA_KEY = new TextEncoder().encode('"data":"');
26848
+ MEDIA_MARKERS = [...MEDIA_SESSION_UPDATE_KINDS].map((kind) => new TextEncoder().encode(JSON.stringify(kind)));
26789
26849
  }
26790
26850
  });
26791
26851
 
@@ -28037,7 +28097,7 @@ var init_chunk_ZCTKXKYY = __esm({
28037
28097
  }
28038
28098
  });
28039
28099
 
28040
- // ../agent-core/dist/chunk-FYZKVT3E.js
28100
+ // ../agent-core/dist/chunk-WD7O4DYQ.js
28041
28101
  function detectImageMimeType(buffer) {
28042
28102
  if (buffer.length >= 8 && buffer.subarray(0, 8).equals(PNG_SIGNATURE)) return "image/png";
28043
28103
  if (buffer.length >= 3 && buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255) {
@@ -28173,6 +28233,27 @@ function resultText2(update) {
28173
28233
  if (typeof raw === "string") return raw;
28174
28234
  return raw === void 0 ? "" : JSON.stringify(raw);
28175
28235
  }
28236
+ function mediaUpdate(file2, body) {
28237
+ const fields = {
28238
+ id: file2.mediaId,
28239
+ filename: file2.filename,
28240
+ mimeType: file2.mimeType,
28241
+ size: file2.data.length,
28242
+ ...body,
28243
+ sourcePath: file2.sourcePath,
28244
+ sourceHash: file2.sha256,
28245
+ toolId: file2.toolId,
28246
+ ts: file2.ts,
28247
+ ...file2.width === void 0 ? {} : { width: file2.width },
28248
+ ...file2.height === void 0 ? {} : { height: file2.height }
28249
+ };
28250
+ if (file2.source === "generated_image") {
28251
+ const image = { type: "generated_image", ...fields };
28252
+ return { sessionUpdate: "_alan/generated_image", image };
28253
+ }
28254
+ const media = { type: "session_media", kind: file2.kind, ...fields };
28255
+ return { sessionUpdate: "_alan/session_media", media };
28256
+ }
28176
28257
  function updateRequiredMessage(requirement, found) {
28177
28258
  const { cli, minimumVersion, feature } = requirement;
28178
28259
  const installed = found ? `${cli} ${found}` : `The ${cli} CLI`;
@@ -28457,8 +28538,8 @@ function silentStartError(name, timeoutMs) {
28457
28538
  };
28458
28539
  }
28459
28540
  var import_crypto4, import_fs5, import_path4, PNG_SIGNATURE, IMAGE_MIME_BY_EXT, VIDEO_MIME_BY_EXT, IMAGE_EXTENSIONS, VIDEO_EXTENSIONS, MAX_IMAGE_BYTES, MAX_VIDEO_BYTES, MAX_TURN_MEDIA_DATA_CHARS, MTIME_SLACK_MS, AGENT_BROWSER_MENTION, AGENT_BROWSER_CAPTURE_COMMAND, LocalMediaReader, SessionOpenRefusal, JsonRpcError, ACP_PROTOCOL_VERSION, ACP_ERROR, STDERR_TAIL_LINES, RESULT_EXIT_GRACE_MS, PerTurnSession;
28460
- var init_chunk_FYZKVT3E = __esm({
28461
- "../agent-core/dist/chunk-FYZKVT3E.js"() {
28541
+ var init_chunk_WD7O4DYQ = __esm({
28542
+ "../agent-core/dist/chunk-WD7O4DYQ.js"() {
28462
28543
  "use strict";
28463
28544
  init_chunk_OUEMTEUX();
28464
28545
  init_chunk_ZCTKXKYY();
@@ -28500,8 +28581,12 @@ var init_chunk_FYZKVT3E = __esm({
28500
28581
  this.#cwd = cwd;
28501
28582
  this.#clock = clock;
28502
28583
  }
28503
- /** Updates to record after `update`; nothing for anything but a tool call, which is almost all. */
28584
+ /** Updates to record after `update`, with the bytes inline; nothing for most updates. */
28504
28585
  read(update) {
28586
+ return this.find(update).map((found) => this.inline(found));
28587
+ }
28588
+ /** The media files a completed tool call wrote; nothing for anything but a tool call. */
28589
+ find(update) {
28505
28590
  if (!isUpdate(update, "tool_call_update")) return [];
28506
28591
  const toolCallId = update.toolCallId;
28507
28592
  if (update.name !== void 0 || update.rawInput !== void 0) {
@@ -28547,20 +28632,42 @@ var init_chunk_FYZKVT3E = __esm({
28547
28632
  named: /* @__PURE__ */ new Set([...capturePaths(tool, content, extensions, cwd), ...this.#pathHints])
28548
28633
  });
28549
28634
  }
28550
- #payloadFields(file2, toolId, explicit) {
28551
- const dataChars = base64Length(file2.buffer.length);
28552
- const inline = explicit || this.#mediaDataChars + dataChars <= MAX_TURN_MEDIA_DATA_CHARS;
28635
+ /** The update carrying the file's bytes, unless the turn's budget is spent on media nobody asked for. */
28636
+ inline(found) {
28637
+ const { file: file2 } = found;
28638
+ const dataChars = base64Length(file2.data.length);
28639
+ const inline = found.explicit || this.#mediaDataChars + dataChars <= MAX_TURN_MEDIA_DATA_CHARS;
28553
28640
  if (inline) this.#mediaDataChars += dataChars;
28641
+ return mediaUpdate(
28642
+ file2,
28643
+ inline ? { data: file2.data.toString("base64") } : { inlineDataOmitted: true }
28644
+ );
28645
+ }
28646
+ /** Uploads the file and returns a reference to it; inline as `inline` does when the upload fails. */
28647
+ async publish(found, uploader, signal) {
28648
+ try {
28649
+ await uploader.upload(found.file, signal);
28650
+ return mediaUpdate(found.file, { uploaded: true });
28651
+ } catch {
28652
+ return this.inline(found);
28653
+ }
28654
+ }
28655
+ #found(file2, toolId, source, kind, explicit) {
28554
28656
  return {
28555
- id: (0, import_crypto4.randomUUID)(),
28556
- filename: (0, import_path4.basename)(file2.path),
28557
- mimeType: file2.mimeType,
28558
- size: file2.buffer.length,
28559
- ...inline ? { data: file2.buffer.toString("base64") } : { inlineDataOmitted: true },
28560
- sourcePath: file2.path,
28561
- sourceHash: (0, import_crypto4.createHash)("sha256").update(file2.buffer).digest("hex"),
28562
- toolId,
28563
- ts: this.#clock.now()
28657
+ explicit,
28658
+ file: {
28659
+ mediaId: (0, import_crypto4.randomUUID)(),
28660
+ source,
28661
+ kind,
28662
+ mimeType: file2.mimeType,
28663
+ filename: (0, import_path4.basename)(file2.path),
28664
+ data: file2.buffer,
28665
+ sha256: (0, import_crypto4.createHash)("sha256").update(file2.buffer).digest("hex"),
28666
+ ...kind === "image" ? imageDimensions(file2.buffer, file2.mimeType) : {},
28667
+ toolId,
28668
+ sourcePath: file2.path,
28669
+ ts: this.#clock.now()
28670
+ }
28564
28671
  };
28565
28672
  }
28566
28673
  #generatedImages(toolId, tool, content) {
@@ -28569,14 +28676,7 @@ var init_chunk_FYZKVT3E = __esm({
28569
28676
  mimeByExt: IMAGE_MIME_BY_EXT,
28570
28677
  maxBytes: MAX_IMAGE_BYTES
28571
28678
  });
28572
- return files.map((file2) => {
28573
- const image = {
28574
- type: "generated_image",
28575
- ...this.#payloadFields(file2, toolId, true),
28576
- ...imageDimensions(file2.buffer, file2.mimeType)
28577
- };
28578
- return { sessionUpdate: "_alan/generated_image", image };
28579
- });
28679
+ return files.map((file2) => this.#found(file2, toolId, "generated_image", "image", true));
28580
28680
  }
28581
28681
  #sessionMedia(toolId, tool, content) {
28582
28682
  const isVideo = isAgentBrowserMedia(tool, content, "video");
@@ -28591,13 +28691,7 @@ var init_chunk_FYZKVT3E = __esm({
28591
28691
  );
28592
28692
  return files.map((file2) => {
28593
28693
  this.#pathHints.delete(file2.path);
28594
- const media = {
28595
- type: "session_media",
28596
- kind,
28597
- ...this.#payloadFields(file2, toolId, explicit),
28598
- ...kind === "image" ? imageDimensions(file2.buffer, file2.mimeType) : {}
28599
- };
28600
- return { sessionUpdate: "_alan/session_media", media };
28694
+ return this.#found(file2, toolId, "session_media", kind, explicit);
28601
28695
  });
28602
28696
  }
28603
28697
  };
@@ -31020,7 +31114,7 @@ var init_claude = __esm({
31020
31114
  "../agent-core/dist/providers/claude.js"() {
31021
31115
  "use strict";
31022
31116
  init_chunk_D4TIXPWZ();
31023
- init_chunk_FYZKVT3E();
31117
+ init_chunk_WD7O4DYQ();
31024
31118
  init_chunk_OUEMTEUX();
31025
31119
  init_chunk_ZCTKXKYY();
31026
31120
  init_chunk_6VWVDJ2A();
@@ -33883,7 +33977,7 @@ var init_codex = __esm({
33883
33977
  "../agent-core/dist/providers/codex.js"() {
33884
33978
  "use strict";
33885
33979
  init_chunk_D4TIXPWZ();
33886
- init_chunk_FYZKVT3E();
33980
+ init_chunk_WD7O4DYQ();
33887
33981
  init_chunk_OUEMTEUX();
33888
33982
  init_chunk_ZCTKXKYY();
33889
33983
  init_chunk_6VWVDJ2A();
@@ -45295,7 +45389,7 @@ var require_tar_stream = __commonJS({
45295
45389
  var init_dist = __esm({
45296
45390
  "../agent-core/dist/index.js"() {
45297
45391
  "use strict";
45298
- init_chunk_FYZKVT3E();
45392
+ init_chunk_WD7O4DYQ();
45299
45393
  init_chunk_OUEMTEUX();
45300
45394
  init_chunk_ZCTKXKYY();
45301
45395
  init_chunk_6VWVDJ2A();
@@ -46042,7 +46136,7 @@ var import_promises50, import_path10, import_crypto14, import_promises51, CURSOR
46042
46136
  var init_acp3 = __esm({
46043
46137
  "../agent-core/dist/providers/acp.js"() {
46044
46138
  "use strict";
46045
- init_chunk_FYZKVT3E();
46139
+ init_chunk_WD7O4DYQ();
46046
46140
  init_chunk_OUEMTEUX();
46047
46141
  init_chunk_ZCTKXKYY();
46048
46142
  init_chunk_6VWVDJ2A();
@@ -47080,9 +47174,19 @@ function createPersistentDriver(provider4, options) {
47080
47174
  }
47081
47175
  };
47082
47176
  const media = new LocalMediaReader(spec.projectPath, clock);
47177
+ const uploader = inputs.media;
47178
+ let uploads = Promise.resolve();
47083
47179
  const recordWithMedia = (update) => {
47084
47180
  record2(update);
47085
- for (const found of media.read(update)) record2(found);
47181
+ const found = media.find(update);
47182
+ if (found.length === 0) return;
47183
+ if (uploader === void 0) {
47184
+ for (const item of found) record2(media.inline(item));
47185
+ return;
47186
+ }
47187
+ uploads = uploads.then(async () => {
47188
+ for (const item of found) record2(await media.publish(item, uploader, signal));
47189
+ });
47086
47190
  };
47087
47191
  const forward = (event) => {
47088
47192
  if (event.type === "session_id") {
@@ -47176,6 +47280,7 @@ function createPersistentDriver(provider4, options) {
47176
47280
  } catch (error62) {
47177
47281
  return { outcome: "failed", message: errorMessage(error62) };
47178
47282
  } finally {
47283
+ await uploads;
47179
47284
  signal.removeEventListener("abort", onAbort);
47180
47285
  if (live.turn === turn) live.turn = void 0;
47181
47286
  }
@@ -48010,7 +48115,7 @@ var import_crypto15, import_http10, import_crypto16, import_promises52, import_p
48010
48115
  var init_opencode = __esm({
48011
48116
  "../agent-core/dist/providers/opencode.js"() {
48012
48117
  "use strict";
48013
- init_chunk_FYZKVT3E();
48118
+ init_chunk_WD7O4DYQ();
48014
48119
  init_chunk_OUEMTEUX();
48015
48120
  init_chunk_ZCTKXKYY();
48016
48121
  init_chunk_6VWVDJ2A();
@@ -50061,7 +50166,7 @@ var import_crypto18, import_promises53, FACTORY_API_VERSION, FACTORY_PROTOCOL_VE
50061
50166
  var init_droid = __esm({
50062
50167
  "../agent-core/dist/providers/droid.js"() {
50063
50168
  "use strict";
50064
- init_chunk_FYZKVT3E();
50169
+ init_chunk_WD7O4DYQ();
50065
50170
  init_chunk_OUEMTEUX();
50066
50171
  init_chunk_ZCTKXKYY();
50067
50172
  init_chunk_6VWVDJ2A();
@@ -51171,7 +51276,7 @@ var init_antigravity = __esm({
51171
51276
  "../agent-core/dist/providers/antigravity.js"() {
51172
51277
  "use strict";
51173
51278
  init_chunk_D4TIXPWZ();
51174
- init_chunk_FYZKVT3E();
51279
+ init_chunk_WD7O4DYQ();
51175
51280
  init_chunk_OUEMTEUX();
51176
51281
  init_chunk_ZCTKXKYY();
51177
51282
  init_chunk_6VWVDJ2A();
@@ -51875,7 +51980,7 @@ var import_promises55, import_path16, import_crypto20, COMMAND_CODE_GRAMMAR_NAME
51875
51980
  var init_command_code = __esm({
51876
51981
  "../agent-core/dist/providers/command-code.js"() {
51877
51982
  "use strict";
51878
- init_chunk_FYZKVT3E();
51983
+ init_chunk_WD7O4DYQ();
51879
51984
  init_chunk_OUEMTEUX();
51880
51985
  init_chunk_ZCTKXKYY();
51881
51986
  init_chunk_6VWVDJ2A();
@@ -57278,7 +57383,7 @@ var require_websocket_server = __commonJS({
57278
57383
  // package.json
57279
57384
  var package_default = {
57280
57385
  name: "@alan-ai-hq/agent-manager",
57281
- version: "0.1.159",
57386
+ version: "0.1.160",
57282
57387
  private: true,
57283
57388
  type: "module",
57284
57389
  description: "Alan machine runtime (alan-agent): identity, link, reconciler, session holders, run log, uploader, local API",
@@ -58098,6 +58203,7 @@ function createGitHubProxyForwarder(options) {
58098
58203
  init_runtime_v2();
58099
58204
  init_zod();
58100
58205
  var REQUEST_TIMEOUT_MS3 = 3e4;
58206
+ var MEDIA_PUT_TIMEOUT_MS = 3e5;
58101
58207
  var credentialRefusalSchema = external_exports.object({ message: external_exports.string().trim().min(1) });
58102
58208
  function credentialFailureMessage(response, fallback) {
58103
58209
  if (response.status !== 409) return fallback;
@@ -58166,6 +58272,33 @@ function createHolderApiClient({
58166
58272
  throw new RuntimeFault("io_failed", `MCP credential request failed: ${response.status}`);
58167
58273
  }
58168
58274
  return machineMcpCredentialSchema.parse(jsonBody(response));
58275
+ },
58276
+ uploadRunMedia: async (runId, media, data, signal) => {
58277
+ const reserved = await request2("POST", runMediaPath(runId), signal, media);
58278
+ if (!isOk(reserved)) {
58279
+ throw new RuntimeFault("io_failed", `Media upload request failed: ${reserved.status}`);
58280
+ }
58281
+ const reservation = runMediaUploadResponseSchema.parse(jsonBody(reserved));
58282
+ if (reservation.status === "ready") return;
58283
+ const stored = await transport.send({
58284
+ method: "PUT",
58285
+ url: new URL(reservation.upload.url),
58286
+ headers: {
58287
+ ...reservation.upload.headers,
58288
+ "content-length": String(data.byteLength)
58289
+ },
58290
+ body: data,
58291
+ redirect: "error",
58292
+ signal: AbortSignal.any([signal, AbortSignal.timeout(MEDIA_PUT_TIMEOUT_MS)])
58293
+ });
58294
+ if (!isOk(stored)) {
58295
+ throw new RuntimeFault("io_failed", `Media upload failed: ${stored.status}`);
58296
+ }
58297
+ const completed = await request2("POST", runMediaCompletePath(runId, media.mediaId), signal);
58298
+ if (!isOk(completed)) {
58299
+ throw new RuntimeFault("io_failed", `Media upload completion failed: ${completed.status}`);
58300
+ }
58301
+ runMediaCompleteResponseSchema.parse(jsonBody(completed));
58169
58302
  }
58170
58303
  };
58171
58304
  }
@@ -70831,6 +70964,13 @@ function attachmentPath(spec, attachment, index, runDir) {
70831
70964
  }
70832
70965
  return (0, import_node_path54.join)(runDir, `${index}-${safeFilename(attachment.filename)}`);
70833
70966
  }
70967
+ function runMediaUploader(source, runId) {
70968
+ const upload = source.uploadMedia?.bind(source);
70969
+ if (upload === void 0) return void 0;
70970
+ return {
70971
+ upload: ({ data, ...media }, signal) => upload(runId, { ...media, bytes: data.byteLength }, data, signal)
70972
+ };
70973
+ }
70834
70974
  async function prepareRunInputs(spec, { source, tmpDir, signal, skills = [] }) {
70835
70975
  const dir = (0, import_node_path54.join)(tmpDir, "runs", spec.runId);
70836
70976
  const cleanup = async () => {
@@ -70857,9 +70997,11 @@ async function prepareRunInputs(spec, { source, tmpDir, signal, skills = [] }) {
70857
70997
  ...attachment.height === void 0 ? {} : { height: attachment.height }
70858
70998
  });
70859
70999
  }
71000
+ const media = runMediaUploader(source, spec.runId);
70860
71001
  return {
70861
71002
  attachments,
70862
71003
  providerEnv: credential.env,
71004
+ ...media === void 0 ? {} : { media },
70863
71005
  ...credential.codex === void 0 ? {} : { codex: credential.codex },
70864
71006
  skills,
70865
71007
  [Symbol.asyncDispose]: cleanup
@@ -74515,7 +74657,8 @@ async function machineAccess(paths, log, conversationId, transport) {
74515
74657
  fetchProviderCredential: async (runId, signal) => {
74516
74658
  void managedMcp?.authorization(signal);
74517
74659
  return (await api()).fetchProviderCredential(runId, signal);
74518
- }
74660
+ },
74661
+ uploadMedia: async (runId, media, data, signal) => (await api()).uploadRunMedia(runId, media, data, signal)
74519
74662
  };
74520
74663
  const codexCredentials = {
74521
74664
  refresh: async (runId, rejectedAccessTokenSha256) => (await api()).refreshCodexCredential(
@@ -80646,6 +80789,9 @@ init_zod();
80646
80789
  var RETRY_DELAYS_MS = [250, 500, 1e3, 2e3, 5e3, 1e4, 3e4];
80647
80790
  var PARK_MS = 5 * 6e4;
80648
80791
  var UNAUTHORIZED = 401;
80792
+ var CREDENTIAL_PARK_MS = 5 * 6e4;
80793
+ var CREDENTIAL_PARK_MAX_MS = 60 * 6e4;
80794
+ var UPLOAD_COALESCE_MS = 500;
80649
80795
  var RETRY_JITTER = 0.2;
80650
80796
  var uploadProgressSchema = external_exports.object({
80651
80797
  admittedOffset: external_exports.number().int().nonnegative(),
@@ -80666,43 +80812,78 @@ function startUploader({
80666
80812
  log,
80667
80813
  archive,
80668
80814
  random = Math.random,
80669
- onUnauthorized
80815
+ onUnauthorized,
80816
+ accessToken = () => ""
80670
80817
  }) {
80671
80818
  const controller = new AbortController();
80672
80819
  const active = /* @__PURE__ */ new Map();
80673
80820
  const again = /* @__PURE__ */ new Set();
80821
+ const againNow = /* @__PURE__ */ new Set();
80822
+ const lastSentAt = /* @__PURE__ */ new Map();
80823
+ const coalescing = /* @__PURE__ */ new Map();
80674
80824
  const sealed = /* @__PURE__ */ new Set();
80675
80825
  const receiptBackoff = /* @__PURE__ */ new Map();
80676
80826
  let pendingRuns = /* @__PURE__ */ new Map();
80677
80827
  const retrying = /* @__PURE__ */ new Set();
80678
80828
  let renewing = null;
80679
- const retryDelay = (failures) => {
80680
- const base = RETRY_DELAYS_MS[Math.min(failures, RETRY_DELAYS_MS.length - 1)] ?? 3e4;
80681
- return Math.round(base * (1 - RETRY_JITTER + 2 * RETRY_JITTER * random()));
80682
- };
80829
+ let credentialPark = null;
80830
+ let revoked = false;
80831
+ const jitter = (ms) => Math.round(ms * (1 - RETRY_JITTER + 2 * RETRY_JITTER * random()));
80832
+ const retryDelay = (failures) => jitter(RETRY_DELAYS_MS[Math.min(failures, RETRY_DELAYS_MS.length - 1)] ?? 3e4);
80683
80833
  const renewCredential = () => {
80684
- if (onUnauthorized === void 0) return Promise.resolve();
80685
- renewing ??= onUnauthorized().catch((error62) => log.warn("upload.renew_failed", { error: error62 })).finally(() => {
80834
+ if (onUnauthorized === void 0) return Promise.resolve("unchanged");
80835
+ renewing ??= onUnauthorized().catch((error62) => {
80836
+ log.warn("upload.renew_failed", { error: error62 });
80837
+ return "unchanged";
80838
+ }).finally(() => {
80686
80839
  renewing = null;
80687
80840
  });
80688
80841
  return renewing;
80689
80842
  };
80843
+ const credentialParked = () => {
80844
+ if (credentialPark === null) return false;
80845
+ if (accessToken() !== credentialPark.token) {
80846
+ credentialPark = null;
80847
+ return false;
80848
+ }
80849
+ return credentialPark.until > clock.now();
80850
+ };
80851
+ const parkForCredential = (token) => {
80852
+ if (credentialParked()) return;
80853
+ const failures = (credentialPark?.failures ?? 0) + 1;
80854
+ const delay4 = Math.min(CREDENTIAL_PARK_MS * 2 ** (failures - 1), CREDENTIAL_PARK_MAX_MS);
80855
+ credentialPark = { failures, until: clock.now() + jitter(delay4), token };
80856
+ log.warn("upload.credential_parked", { failures, parkedUntil: credentialPark.until });
80857
+ };
80858
+ const unauthorized = async (runId, tokenAtStart) => {
80859
+ const renewal = await renewCredential();
80860
+ if (renewal === "revoked") {
80861
+ revoked = true;
80862
+ log.error("upload.credential_revoked", { runId });
80863
+ return;
80864
+ }
80865
+ if (renewal === "renewed" || accessToken() !== tokenAtStart) {
80866
+ credentialPark = null;
80867
+ deferReceipt(runId);
80868
+ return;
80869
+ }
80870
+ parkForCredential(tokenAtStart);
80871
+ };
80690
80872
  const deferReceipt = (runId) => {
80691
80873
  const failures = (receiptBackoff.get(runId)?.failures ?? 0) + 1;
80692
80874
  receiptBackoff.set(runId, { failures, notBefore: clock.now() + retryDelay(failures) });
80693
80875
  };
80694
- const reject = async (runId, progressPath, progress, rejection2) => {
80876
+ const reject = async (runId, progressPath, progress, rejection2, tokenAtStart) => {
80695
80877
  log.error("upload.rejected", { runId, status: rejection2.status, message: rejection2.message });
80696
80878
  if (rejection2.status === UNAUTHORIZED) {
80697
- await renewCredential();
80698
- deferReceipt(runId);
80879
+ await unauthorized(runId, tokenAtStart);
80699
80880
  return;
80700
80881
  }
80701
80882
  const parkedUntil = clock.now() + PARK_MS;
80702
80883
  await writeJsonFileAtomic(progressPath, { ...progress, parkedUntil });
80703
80884
  log.warn("upload.parked", { runId, parkedUntil });
80704
80885
  };
80705
- const progressOf = async (runId, target, path4) => {
80886
+ const progressOf = async (runId, target, path4, tokenAtStart) => {
80706
80887
  const stored = await readJsonFile(path4, uploadProgressSchema);
80707
80888
  if (stored.kind === "ok") return stored.value;
80708
80889
  const listed = pendingRuns.get(runId);
@@ -80715,6 +80896,7 @@ function startUploader({
80715
80896
  switch (receipt.kind) {
80716
80897
  case "read": {
80717
80898
  receiptBackoff.delete(runId);
80899
+ credentialPark = null;
80718
80900
  log.debug("upload.resumed", {
80719
80901
  runId,
80720
80902
  admittedOffset: receipt.receipt?.admittedOffset ?? 0
@@ -80724,7 +80906,7 @@ function startUploader({
80724
80906
  return progress;
80725
80907
  }
80726
80908
  case "rejected":
80727
- await reject(runId, path4, progressFromReceipt(null), receipt);
80909
+ await reject(runId, path4, progressFromReceipt(null), receipt, tokenAtStart);
80728
80910
  return null;
80729
80911
  case "retry": {
80730
80912
  deferReceipt(runId);
@@ -80736,6 +80918,7 @@ function startUploader({
80736
80918
  };
80737
80919
  const sendNext = async (upload2, progress) => {
80738
80920
  const ended = (await readLastRecord(upload2.logPath))?.update.sessionUpdate === "_alan/run.ended";
80921
+ const size = await upload2.reader.size();
80739
80922
  const chunk = await upload2.reader.readFrom(
80740
80923
  toByteOffset(progress.admittedOffset),
80741
80924
  MAX_RUN_LOG_CHUNK_BYTES
@@ -80750,14 +80933,14 @@ function startUploader({
80750
80933
  sealed: atEnd || outcome2.receipt.finalOffset !== null
80751
80934
  };
80752
80935
  await writeJsonFileAtomic(upload2.progressPath, next);
80753
- return { kind: "advanced", progress: next };
80936
+ return { kind: "advanced", progress: next, more: ended || chunk.to < size };
80754
80937
  }
80755
80938
  case "offset_conflict": {
80756
80939
  const receipt = await api.readReceipt(upload2.target, controller.signal);
80757
80940
  if (receipt.kind === "read") {
80758
80941
  const next = progressFromReceipt(receipt.receipt);
80759
80942
  await writeJsonFileAtomic(upload2.progressPath, next);
80760
- return { kind: "advanced", progress: next };
80943
+ return { kind: "advanced", progress: next, more: true };
80761
80944
  }
80762
80945
  return receipt.kind === "retry" ? receipt : { kind: "rejected", rejection: receipt };
80763
80946
  }
@@ -80774,7 +80957,18 @@ function startUploader({
80774
80957
  log.warn("upload.retrying", { runId, status, delayMs: delay4 });
80775
80958
  await clock.sleep(delay4, controller.signal);
80776
80959
  };
80777
- const drain = async (runUpload, initial) => {
80960
+ const recordAccepted = (runId, progress) => {
80961
+ receiptBackoff.delete(runId);
80962
+ credentialPark = null;
80963
+ if (!progress.sealed) {
80964
+ lastSentAt.set(runId, clock.monotonic());
80965
+ return;
80966
+ }
80967
+ sealed.add(runId);
80968
+ lastSentAt.delete(runId);
80969
+ log.info("upload.sealed", { runId, bytes: progress.admittedOffset });
80970
+ };
80971
+ const drain = async (runUpload, initial, tokenAtStart) => {
80778
80972
  const { runId } = runUpload.target;
80779
80973
  let progress = initial;
80780
80974
  let failures = 0;
@@ -80782,7 +80976,7 @@ function startUploader({
80782
80976
  const step = await sendNext(runUpload, progress);
80783
80977
  if (step.kind === "caught_up") return "settled";
80784
80978
  if (step.kind === "rejected") {
80785
- await reject(runId, runUpload.progressPath, progress, step.rejection);
80979
+ await reject(runId, runUpload.progressPath, progress, step.rejection, tokenAtStart);
80786
80980
  return "retry_later";
80787
80981
  }
80788
80982
  if (step.kind === "retry") {
@@ -80791,13 +80985,9 @@ function startUploader({
80791
80985
  continue;
80792
80986
  }
80793
80987
  failures = 0;
80794
- receiptBackoff.delete(runId);
80795
80988
  progress = step.progress;
80796
- if (progress.sealed) {
80797
- sealed.add(runId);
80798
- log.info("upload.sealed", { runId, bytes: progress.admittedOffset });
80799
- return "settled";
80800
- }
80989
+ recordAccepted(runId, progress);
80990
+ if (progress.sealed || !step.more) return "settled";
80801
80991
  }
80802
80992
  return "settled";
80803
80993
  };
@@ -80808,9 +80998,11 @@ function startUploader({
80808
80998
  const meta3 = await readRunMeta(dir.meta);
80809
80999
  if (meta3 === null) return "settled";
80810
81000
  const target = { conversationId: meta3.conversationId, runId };
81001
+ if (credentialParked()) return "retry_later";
80811
81002
  const backoff = receiptBackoff.get(runId);
80812
81003
  if (backoff !== void 0 && backoff.notBefore > clock.now()) return "retry_later";
80813
- const progress = await progressOf(runId, target, dir.upload);
81004
+ const tokenAtStart = accessToken();
81005
+ const progress = await progressOf(runId, target, dir.upload, tokenAtStart);
80814
81006
  if (progress === null) return "retry_later";
80815
81007
  if (progress.sealed) {
80816
81008
  sealed.add(runId);
@@ -80820,11 +81012,12 @@ function startUploader({
80820
81012
  return "retry_later";
80821
81013
  }
80822
81014
  const reader = __using(_stack, await openRunLogReader(dir.log), true);
80823
- const attempt2 = await drain(
81015
+ const attempt3 = await drain(
80824
81016
  { target, reader, logPath: dir.log, progressPath: dir.upload },
80825
- progress
81017
+ progress,
81018
+ tokenAtStart
80826
81019
  );
80827
- return attempt2;
81020
+ return attempt3;
80828
81021
  } catch (_) {
80829
81022
  var _error = _, _hasError = true;
80830
81023
  } finally {
@@ -80832,20 +81025,48 @@ function startUploader({
80832
81025
  _promise2 && await _promise2;
80833
81026
  }
80834
81027
  };
80835
- const run2 = (runId) => {
81028
+ const coalesce = async (runId) => {
81029
+ const delay4 = (lastSentAt.get(runId) ?? Number.NEGATIVE_INFINITY) + UPLOAD_COALESCE_MS;
81030
+ const remaining = delay4 - clock.monotonic();
81031
+ if (remaining <= 0) return;
81032
+ const wake = new AbortController();
81033
+ coalescing.set(runId, wake);
81034
+ try {
81035
+ await clock.sleep(remaining, AbortSignal.any([wake.signal, controller.signal]));
81036
+ } catch {
81037
+ } finally {
81038
+ coalescing.delete(runId);
81039
+ }
81040
+ };
81041
+ const attempt2 = async (runId, timing) => {
81042
+ if (timing === "coalesced") await coalesce(runId);
81043
+ again.delete(runId);
81044
+ againNow.delete(runId);
81045
+ if (controller.signal.aborted) return "settled";
81046
+ return upload(runId);
81047
+ };
81048
+ const run2 = (runId, timing = "immediate") => {
81049
+ if (revoked) return;
80836
81050
  if (active.has(runId)) {
80837
81051
  again.add(runId);
81052
+ if (timing === "immediate") {
81053
+ againNow.add(runId);
81054
+ coalescing.get(runId)?.abort();
81055
+ }
80838
81056
  return;
80839
81057
  }
80840
- const task = upload(runId).then((attempt2) => {
80841
- if (attempt2 === "settled") retrying.delete(runId);
81058
+ const task = attempt2(runId, timing).then((attempt3) => {
81059
+ if (attempt3 === "settled") retrying.delete(runId);
80842
81060
  else retrying.add(runId);
80843
81061
  }).catch((error62) => {
80844
81062
  retrying.add(runId);
80845
81063
  if (!controller.signal.aborted) log.warn("upload.failed", { runId, error: error62 });
80846
81064
  }).finally(() => {
80847
81065
  active.delete(runId);
80848
- if (again.delete(runId) && !controller.signal.aborted) run2(runId);
81066
+ const now = againNow.delete(runId);
81067
+ if (again.delete(runId) && !controller.signal.aborted) {
81068
+ run2(runId, now ? "immediate" : "coalesced");
81069
+ }
80849
81070
  });
80850
81071
  active.set(runId, task);
80851
81072
  };
@@ -80892,7 +81113,8 @@ function startUploader({
80892
81113
  return found;
80893
81114
  };
80894
81115
  return {
80895
- notify: run2,
81116
+ notify: (runId) => run2(runId, "coalesced"),
81117
+ uploadNow: (runId) => run2(runId, "immediate"),
80896
81118
  sweep: sweep2,
80897
81119
  pending: (uploads) => {
80898
81120
  pendingRuns = new Map(
@@ -81300,6 +81522,7 @@ async function startMachinePlane(deps) {
81300
81522
  () => identity.renewAfterRejection(stopped.signal)
81301
81523
  );
81302
81524
  if (renewal.kind === "revoked") deps.onRevoked();
81525
+ return renewal;
81303
81526
  };
81304
81527
  const sessionsOpened = Promise.withResolvers();
81305
81528
  const planeOpened = Promise.withResolvers();
@@ -81342,7 +81565,9 @@ async function startMachinePlane(deps) {
81342
81565
  refreshDesired();
81343
81566
  },
81344
81567
  onConnectRefused: (error62) => updates.connectRefused(error62),
81345
- refreshCredential: renewAfterRejection,
81568
+ refreshCredential: async () => {
81569
+ await renewAfterRejection();
81570
+ },
81346
81571
  onStateChange: deps.onStatusChange,
81347
81572
  answerWorkspaceQuery: (request2) => workspaces.answer(request2),
81348
81573
  respond: (request2) => sessions.respond(request2),
@@ -81404,7 +81629,11 @@ async function startMachinePlane(deps) {
81404
81629
  clock,
81405
81630
  log,
81406
81631
  archive,
81407
- onUnauthorized: renewAfterRejection
81632
+ onUnauthorized: async () => {
81633
+ const renewal = await renewAfterRejection();
81634
+ return renewal.kind === "renewed" || renewal.kind === "revoked" ? renewal.kind : "unchanged";
81635
+ },
81636
+ accessToken: identity.accessToken
81408
81637
  })
81409
81638
  );
81410
81639
  const nativeIngest = stack.use(
@@ -81468,7 +81697,7 @@ async function startMachinePlane(deps) {
81468
81697
  onTurnEnded: (runId) => {
81469
81698
  runsShownRunning.delete(runId);
81470
81699
  deps.onStatusChange();
81471
- uploader.notify(runId);
81700
+ uploader.uploadNow(runId);
81472
81701
  appends.notify(runId);
81473
81702
  nativeIngest.runEnded(runId);
81474
81703
  followActiveRuns().catch((error62) => log.warn("power.follow_failed", { error: error62 }));
package/alan-holder.cjs CHANGED
@@ -22443,6 +22443,56 @@ var init_run_log_upload = __esm({
22443
22443
  }
22444
22444
  });
22445
22445
 
22446
+ // ../shared/dist/runtime-v2/run-media.js
22447
+ function runMediaPath(runId) {
22448
+ return `/public/machines/me/runs/${encodeURIComponent(runId)}/media`;
22449
+ }
22450
+ function runMediaCompletePath(runId, mediaId) {
22451
+ return `${runMediaPath(runId)}/${encodeURIComponent(mediaId)}/complete`;
22452
+ }
22453
+ var INT4_MAX, runMediaSourceSchema, runMediaUploadRequestSchema, runMediaUploadTargetSchema, runMediaUploadResponseSchema, runMediaCompleteResponseSchema;
22454
+ var init_run_media = __esm({
22455
+ "../shared/dist/runtime-v2/run-media.js"() {
22456
+ "use strict";
22457
+ init_zod();
22458
+ INT4_MAX = 2147483647;
22459
+ runMediaSourceSchema = external_exports.enum(["generated_image", "session_media"]);
22460
+ runMediaUploadRequestSchema = external_exports.object({
22461
+ /** The `id` the transcript update carries; one upload per id and run. */
22462
+ mediaId: external_exports.string().min(1).max(200),
22463
+ source: runMediaSourceSchema,
22464
+ kind: external_exports.enum(["image", "video"]),
22465
+ mimeType: external_exports.string().min(1).max(200),
22466
+ filename: external_exports.string().min(1).max(500),
22467
+ bytes: external_exports.number().int().positive().max(INT4_MAX),
22468
+ sha256: external_exports.string().regex(/^[0-9a-f]{64}$/),
22469
+ width: external_exports.number().int().min(0).max(INT4_MAX).nullish(),
22470
+ height: external_exports.number().int().min(0).max(INT4_MAX).nullish(),
22471
+ toolId: external_exports.string().max(500).optional(),
22472
+ sourcePath: external_exports.string().max(4096).optional(),
22473
+ ts: external_exports.number().int().positive().optional()
22474
+ });
22475
+ runMediaUploadTargetSchema = external_exports.object({
22476
+ url: external_exports.url(),
22477
+ /** Every header the signed PUT expects, besides the body's `content-length`. */
22478
+ headers: external_exports.record(external_exports.string(), external_exports.string()),
22479
+ expiresAt: external_exports.iso.datetime()
22480
+ });
22481
+ runMediaUploadResponseSchema = external_exports.discriminatedUnion("status", [
22482
+ external_exports.object({
22483
+ status: external_exports.literal("upload"),
22484
+ mediaId: external_exports.string(),
22485
+ upload: runMediaUploadTargetSchema
22486
+ }),
22487
+ external_exports.object({ status: external_exports.literal("ready"), mediaId: external_exports.string() })
22488
+ ]);
22489
+ runMediaCompleteResponseSchema = external_exports.object({
22490
+ status: external_exports.literal("ready"),
22491
+ mediaId: external_exports.string()
22492
+ });
22493
+ }
22494
+ });
22495
+
22446
22496
  // ../shared/dist/runtime-v2/skills.js
22447
22497
  var MAX_MACHINE_SKILLS, installedMachineSkillSchema, MAX_SKILL_UPLOADS, machineSkillScanRepositorySchema, machineSkillScanContextSchema, machineLocalSkillsReportSchema, machineSkillUploadSchema, machineSkillsSyncRequestSchema, desiredMachineSkillSchema, machineSkillDownloadSchema, machineSkillsSyncResponseSchema;
22448
22498
  var init_skills = __esm({
@@ -22565,6 +22615,7 @@ var init_runtime_v2 = __esm({
22565
22615
  init_mcp();
22566
22616
  init_run_log();
22567
22617
  init_run_log_upload();
22618
+ init_run_media();
22568
22619
  init_skills();
22569
22620
  init_workspace();
22570
22621
  }
@@ -25098,11 +25149,15 @@ var init_background_task = __esm({
25098
25149
  function isUpdate(update, kind) {
25099
25150
  return update.sessionUpdate === kind;
25100
25151
  }
25101
- var STEER_ID_META;
25152
+ var STEER_ID_META, MEDIA_SESSION_UPDATE_KINDS;
25102
25153
  var init_types2 = __esm({
25103
25154
  "../shared/dist/agent/acp/types.js"() {
25104
25155
  "use strict";
25105
25156
  STEER_ID_META = "alan.dev/steerId";
25157
+ MEDIA_SESSION_UPDATE_KINDS = /* @__PURE__ */ new Set([
25158
+ "_alan/generated_image",
25159
+ "_alan/session_media"
25160
+ ]);
25106
25161
  }
25107
25162
  });
25108
25163
 
@@ -25210,9 +25265,14 @@ var init_session_activity = __esm({
25210
25265
  });
25211
25266
 
25212
25267
  // ../shared/dist/agent/acp/transcript-byte-decoder.js
25268
+ var MIN_ELIDED_DATA_BYTES, DATA_KEY, MEDIA_MARKERS;
25213
25269
  var init_transcript_byte_decoder = __esm({
25214
25270
  "../shared/dist/agent/acp/transcript-byte-decoder.js"() {
25215
25271
  "use strict";
25272
+ init_types2();
25273
+ MIN_ELIDED_DATA_BYTES = 16 * 1024;
25274
+ DATA_KEY = new TextEncoder().encode('"data":"');
25275
+ MEDIA_MARKERS = [...MEDIA_SESSION_UPDATE_KINDS].map((kind) => new TextEncoder().encode(JSON.stringify(kind)));
25216
25276
  }
25217
25277
  });
25218
25278
 
@@ -26113,7 +26173,7 @@ var init_chunk_ZCTKXKYY = __esm({
26113
26173
  }
26114
26174
  });
26115
26175
 
26116
- // ../agent-core/dist/chunk-FYZKVT3E.js
26176
+ // ../agent-core/dist/chunk-WD7O4DYQ.js
26117
26177
  function detectImageMimeType(buffer) {
26118
26178
  if (buffer.length >= 8 && buffer.subarray(0, 8).equals(PNG_SIGNATURE)) return "image/png";
26119
26179
  if (buffer.length >= 3 && buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255) {
@@ -26249,6 +26309,27 @@ function resultText(update) {
26249
26309
  if (typeof raw === "string") return raw;
26250
26310
  return raw === void 0 ? "" : JSON.stringify(raw);
26251
26311
  }
26312
+ function mediaUpdate(file2, body) {
26313
+ const fields = {
26314
+ id: file2.mediaId,
26315
+ filename: file2.filename,
26316
+ mimeType: file2.mimeType,
26317
+ size: file2.data.length,
26318
+ ...body,
26319
+ sourcePath: file2.sourcePath,
26320
+ sourceHash: file2.sha256,
26321
+ toolId: file2.toolId,
26322
+ ts: file2.ts,
26323
+ ...file2.width === void 0 ? {} : { width: file2.width },
26324
+ ...file2.height === void 0 ? {} : { height: file2.height }
26325
+ };
26326
+ if (file2.source === "generated_image") {
26327
+ const image = { type: "generated_image", ...fields };
26328
+ return { sessionUpdate: "_alan/generated_image", image };
26329
+ }
26330
+ const media = { type: "session_media", kind: file2.kind, ...fields };
26331
+ return { sessionUpdate: "_alan/session_media", media };
26332
+ }
26252
26333
  function updateRequiredMessage(requirement, found) {
26253
26334
  const { cli, minimumVersion, feature } = requirement;
26254
26335
  const installed = found ? `${cli} ${found}` : `The ${cli} CLI`;
@@ -26533,8 +26614,8 @@ function silentStartError(name, timeoutMs) {
26533
26614
  };
26534
26615
  }
26535
26616
  var import_crypto4, import_fs5, import_path4, PNG_SIGNATURE, IMAGE_MIME_BY_EXT, VIDEO_MIME_BY_EXT, IMAGE_EXTENSIONS, VIDEO_EXTENSIONS, MAX_IMAGE_BYTES, MAX_VIDEO_BYTES, MAX_TURN_MEDIA_DATA_CHARS, MTIME_SLACK_MS, AGENT_BROWSER_MENTION, AGENT_BROWSER_CAPTURE_COMMAND, LocalMediaReader, SessionOpenRefusal, JsonRpcError, ACP_PROTOCOL_VERSION, ACP_ERROR, STDERR_TAIL_LINES, RESULT_EXIT_GRACE_MS, PerTurnSession;
26536
- var init_chunk_FYZKVT3E = __esm({
26537
- "../agent-core/dist/chunk-FYZKVT3E.js"() {
26617
+ var init_chunk_WD7O4DYQ = __esm({
26618
+ "../agent-core/dist/chunk-WD7O4DYQ.js"() {
26538
26619
  "use strict";
26539
26620
  init_chunk_OUEMTEUX();
26540
26621
  init_chunk_ZCTKXKYY();
@@ -26576,8 +26657,12 @@ var init_chunk_FYZKVT3E = __esm({
26576
26657
  this.#cwd = cwd;
26577
26658
  this.#clock = clock;
26578
26659
  }
26579
- /** Updates to record after `update`; nothing for anything but a tool call, which is almost all. */
26660
+ /** Updates to record after `update`, with the bytes inline; nothing for most updates. */
26580
26661
  read(update) {
26662
+ return this.find(update).map((found) => this.inline(found));
26663
+ }
26664
+ /** The media files a completed tool call wrote; nothing for anything but a tool call. */
26665
+ find(update) {
26581
26666
  if (!isUpdate(update, "tool_call_update")) return [];
26582
26667
  const toolCallId = update.toolCallId;
26583
26668
  if (update.name !== void 0 || update.rawInput !== void 0) {
@@ -26623,20 +26708,42 @@ var init_chunk_FYZKVT3E = __esm({
26623
26708
  named: /* @__PURE__ */ new Set([...capturePaths(tool, content, extensions, cwd), ...this.#pathHints])
26624
26709
  });
26625
26710
  }
26626
- #payloadFields(file2, toolId, explicit) {
26627
- const dataChars = base64Length(file2.buffer.length);
26628
- const inline = explicit || this.#mediaDataChars + dataChars <= MAX_TURN_MEDIA_DATA_CHARS;
26711
+ /** The update carrying the file's bytes, unless the turn's budget is spent on media nobody asked for. */
26712
+ inline(found) {
26713
+ const { file: file2 } = found;
26714
+ const dataChars = base64Length(file2.data.length);
26715
+ const inline = found.explicit || this.#mediaDataChars + dataChars <= MAX_TURN_MEDIA_DATA_CHARS;
26629
26716
  if (inline) this.#mediaDataChars += dataChars;
26717
+ return mediaUpdate(
26718
+ file2,
26719
+ inline ? { data: file2.data.toString("base64") } : { inlineDataOmitted: true }
26720
+ );
26721
+ }
26722
+ /** Uploads the file and returns a reference to it; inline as `inline` does when the upload fails. */
26723
+ async publish(found, uploader, signal) {
26724
+ try {
26725
+ await uploader.upload(found.file, signal);
26726
+ return mediaUpdate(found.file, { uploaded: true });
26727
+ } catch {
26728
+ return this.inline(found);
26729
+ }
26730
+ }
26731
+ #found(file2, toolId, source, kind, explicit) {
26630
26732
  return {
26631
- id: (0, import_crypto4.randomUUID)(),
26632
- filename: (0, import_path4.basename)(file2.path),
26633
- mimeType: file2.mimeType,
26634
- size: file2.buffer.length,
26635
- ...inline ? { data: file2.buffer.toString("base64") } : { inlineDataOmitted: true },
26636
- sourcePath: file2.path,
26637
- sourceHash: (0, import_crypto4.createHash)("sha256").update(file2.buffer).digest("hex"),
26638
- toolId,
26639
- ts: this.#clock.now()
26733
+ explicit,
26734
+ file: {
26735
+ mediaId: (0, import_crypto4.randomUUID)(),
26736
+ source,
26737
+ kind,
26738
+ mimeType: file2.mimeType,
26739
+ filename: (0, import_path4.basename)(file2.path),
26740
+ data: file2.buffer,
26741
+ sha256: (0, import_crypto4.createHash)("sha256").update(file2.buffer).digest("hex"),
26742
+ ...kind === "image" ? imageDimensions(file2.buffer, file2.mimeType) : {},
26743
+ toolId,
26744
+ sourcePath: file2.path,
26745
+ ts: this.#clock.now()
26746
+ }
26640
26747
  };
26641
26748
  }
26642
26749
  #generatedImages(toolId, tool, content) {
@@ -26645,14 +26752,7 @@ var init_chunk_FYZKVT3E = __esm({
26645
26752
  mimeByExt: IMAGE_MIME_BY_EXT,
26646
26753
  maxBytes: MAX_IMAGE_BYTES
26647
26754
  });
26648
- return files.map((file2) => {
26649
- const image = {
26650
- type: "generated_image",
26651
- ...this.#payloadFields(file2, toolId, true),
26652
- ...imageDimensions(file2.buffer, file2.mimeType)
26653
- };
26654
- return { sessionUpdate: "_alan/generated_image", image };
26655
- });
26755
+ return files.map((file2) => this.#found(file2, toolId, "generated_image", "image", true));
26656
26756
  }
26657
26757
  #sessionMedia(toolId, tool, content) {
26658
26758
  const isVideo = isAgentBrowserMedia(tool, content, "video");
@@ -26667,13 +26767,7 @@ var init_chunk_FYZKVT3E = __esm({
26667
26767
  );
26668
26768
  return files.map((file2) => {
26669
26769
  this.#pathHints.delete(file2.path);
26670
- const media = {
26671
- type: "session_media",
26672
- kind,
26673
- ...this.#payloadFields(file2, toolId, explicit),
26674
- ...kind === "image" ? imageDimensions(file2.buffer, file2.mimeType) : {}
26675
- };
26676
- return { sessionUpdate: "_alan/session_media", media };
26770
+ return this.#found(file2, toolId, "session_media", kind, explicit);
26677
26771
  });
26678
26772
  }
26679
26773
  };
@@ -28902,7 +28996,7 @@ var init_claude = __esm({
28902
28996
  "../agent-core/dist/providers/claude.js"() {
28903
28997
  "use strict";
28904
28998
  init_chunk_D4TIXPWZ();
28905
- init_chunk_FYZKVT3E();
28999
+ init_chunk_WD7O4DYQ();
28906
29000
  init_chunk_OUEMTEUX();
28907
29001
  init_chunk_ZCTKXKYY();
28908
29002
  init_chunk_6VWVDJ2A();
@@ -31121,7 +31215,7 @@ var init_codex = __esm({
31121
31215
  "../agent-core/dist/providers/codex.js"() {
31122
31216
  "use strict";
31123
31217
  init_chunk_D4TIXPWZ();
31124
- init_chunk_FYZKVT3E();
31218
+ init_chunk_WD7O4DYQ();
31125
31219
  init_chunk_OUEMTEUX();
31126
31220
  init_chunk_ZCTKXKYY();
31127
31221
  init_chunk_6VWVDJ2A();
@@ -40032,7 +40126,7 @@ var require_dist = __commonJS({
40032
40126
  var init_dist = __esm({
40033
40127
  "../agent-core/dist/index.js"() {
40034
40128
  "use strict";
40035
- init_chunk_FYZKVT3E();
40129
+ init_chunk_WD7O4DYQ();
40036
40130
  init_chunk_OUEMTEUX();
40037
40131
  init_chunk_ZCTKXKYY();
40038
40132
  init_chunk_6VWVDJ2A();
@@ -40779,7 +40873,7 @@ var import_promises24, import_path10, import_crypto14, import_promises25, CURSOR
40779
40873
  var init_acp3 = __esm({
40780
40874
  "../agent-core/dist/providers/acp.js"() {
40781
40875
  "use strict";
40782
- init_chunk_FYZKVT3E();
40876
+ init_chunk_WD7O4DYQ();
40783
40877
  init_chunk_OUEMTEUX();
40784
40878
  init_chunk_ZCTKXKYY();
40785
40879
  init_chunk_6VWVDJ2A();
@@ -41817,9 +41911,19 @@ function createPersistentDriver(provider4, options) {
41817
41911
  }
41818
41912
  };
41819
41913
  const media = new LocalMediaReader(spec.projectPath, clock);
41914
+ const uploader = inputs.media;
41915
+ let uploads = Promise.resolve();
41820
41916
  const recordWithMedia = (update) => {
41821
41917
  record2(update);
41822
- for (const found of media.read(update)) record2(found);
41918
+ const found = media.find(update);
41919
+ if (found.length === 0) return;
41920
+ if (uploader === void 0) {
41921
+ for (const item of found) record2(media.inline(item));
41922
+ return;
41923
+ }
41924
+ uploads = uploads.then(async () => {
41925
+ for (const item of found) record2(await media.publish(item, uploader, signal));
41926
+ });
41823
41927
  };
41824
41928
  const forward = (event) => {
41825
41929
  if (event.type === "session_id") {
@@ -41913,6 +42017,7 @@ function createPersistentDriver(provider4, options) {
41913
42017
  } catch (error62) {
41914
42018
  return { outcome: "failed", message: errorMessage(error62) };
41915
42019
  } finally {
42020
+ await uploads;
41916
42021
  signal.removeEventListener("abort", onAbort);
41917
42022
  if (live.turn === turn) live.turn = void 0;
41918
42023
  }
@@ -42747,7 +42852,7 @@ var import_crypto15, import_http4, import_crypto16, import_promises26, import_pa
42747
42852
  var init_opencode = __esm({
42748
42853
  "../agent-core/dist/providers/opencode.js"() {
42749
42854
  "use strict";
42750
- init_chunk_FYZKVT3E();
42855
+ init_chunk_WD7O4DYQ();
42751
42856
  init_chunk_OUEMTEUX();
42752
42857
  init_chunk_ZCTKXKYY();
42753
42858
  init_chunk_6VWVDJ2A();
@@ -44798,7 +44903,7 @@ var import_crypto18, import_promises27, FACTORY_API_VERSION, FACTORY_PROTOCOL_VE
44798
44903
  var init_droid = __esm({
44799
44904
  "../agent-core/dist/providers/droid.js"() {
44800
44905
  "use strict";
44801
- init_chunk_FYZKVT3E();
44906
+ init_chunk_WD7O4DYQ();
44802
44907
  init_chunk_OUEMTEUX();
44803
44908
  init_chunk_ZCTKXKYY();
44804
44909
  init_chunk_6VWVDJ2A();
@@ -45908,7 +46013,7 @@ var init_antigravity = __esm({
45908
46013
  "../agent-core/dist/providers/antigravity.js"() {
45909
46014
  "use strict";
45910
46015
  init_chunk_D4TIXPWZ();
45911
- init_chunk_FYZKVT3E();
46016
+ init_chunk_WD7O4DYQ();
45912
46017
  init_chunk_OUEMTEUX();
45913
46018
  init_chunk_ZCTKXKYY();
45914
46019
  init_chunk_6VWVDJ2A();
@@ -46612,7 +46717,7 @@ var import_promises29, import_path16, import_crypto20, COMMAND_CODE_GRAMMAR_NAME
46612
46717
  var init_command_code = __esm({
46613
46718
  "../agent-core/dist/providers/command-code.js"() {
46614
46719
  "use strict";
46615
- init_chunk_FYZKVT3E();
46720
+ init_chunk_WD7O4DYQ();
46616
46721
  init_chunk_OUEMTEUX();
46617
46722
  init_chunk_ZCTKXKYY();
46618
46723
  init_chunk_6VWVDJ2A();
@@ -47577,6 +47682,7 @@ function createHttpTransport() {
47577
47682
  init_runtime_v2();
47578
47683
  init_zod();
47579
47684
  var REQUEST_TIMEOUT_MS = 3e4;
47685
+ var MEDIA_PUT_TIMEOUT_MS = 3e5;
47580
47686
  var credentialRefusalSchema = external_exports.object({ message: external_exports.string().trim().min(1) });
47581
47687
  function credentialFailureMessage(response, fallback) {
47582
47688
  if (response.status !== 409) return fallback;
@@ -47645,6 +47751,33 @@ function createHolderApiClient({
47645
47751
  throw new RuntimeFault("io_failed", `MCP credential request failed: ${response.status}`);
47646
47752
  }
47647
47753
  return machineMcpCredentialSchema.parse(jsonBody(response));
47754
+ },
47755
+ uploadRunMedia: async (runId, media, data, signal) => {
47756
+ const reserved = await request2("POST", runMediaPath(runId), signal, media);
47757
+ if (!isOk(reserved)) {
47758
+ throw new RuntimeFault("io_failed", `Media upload request failed: ${reserved.status}`);
47759
+ }
47760
+ const reservation = runMediaUploadResponseSchema.parse(jsonBody(reserved));
47761
+ if (reservation.status === "ready") return;
47762
+ const stored = await transport.send({
47763
+ method: "PUT",
47764
+ url: new URL(reservation.upload.url),
47765
+ headers: {
47766
+ ...reservation.upload.headers,
47767
+ "content-length": String(data.byteLength)
47768
+ },
47769
+ body: data,
47770
+ redirect: "error",
47771
+ signal: AbortSignal.any([signal, AbortSignal.timeout(MEDIA_PUT_TIMEOUT_MS)])
47772
+ });
47773
+ if (!isOk(stored)) {
47774
+ throw new RuntimeFault("io_failed", `Media upload failed: ${stored.status}`);
47775
+ }
47776
+ const completed = await request2("POST", runMediaCompletePath(runId, media.mediaId), signal);
47777
+ if (!isOk(completed)) {
47778
+ throw new RuntimeFault("io_failed", `Media upload completion failed: ${completed.status}`);
47779
+ }
47780
+ runMediaCompleteResponseSchema.parse(jsonBody(completed));
47648
47781
  }
47649
47782
  };
47650
47783
  }
@@ -49725,6 +49858,13 @@ function attachmentPath(spec, attachment, index, runDir) {
49725
49858
  }
49726
49859
  return (0, import_node_path19.join)(runDir, `${index}-${safeFilename(attachment.filename)}`);
49727
49860
  }
49861
+ function runMediaUploader(source, runId) {
49862
+ const upload = source.uploadMedia?.bind(source);
49863
+ if (upload === void 0) return void 0;
49864
+ return {
49865
+ upload: ({ data, ...media }, signal) => upload(runId, { ...media, bytes: data.byteLength }, data, signal)
49866
+ };
49867
+ }
49728
49868
  async function prepareRunInputs(spec, { source, tmpDir, signal, skills = [] }) {
49729
49869
  const dir = (0, import_node_path19.join)(tmpDir, "runs", spec.runId);
49730
49870
  const cleanup = async () => {
@@ -49751,9 +49891,11 @@ async function prepareRunInputs(spec, { source, tmpDir, signal, skills = [] }) {
49751
49891
  ...attachment.height === void 0 ? {} : { height: attachment.height }
49752
49892
  });
49753
49893
  }
49894
+ const media = runMediaUploader(source, spec.runId);
49754
49895
  return {
49755
49896
  attachments,
49756
49897
  providerEnv: credential.env,
49898
+ ...media === void 0 ? {} : { media },
49757
49899
  ...credential.codex === void 0 ? {} : { codex: credential.codex },
49758
49900
  skills,
49759
49901
  [Symbol.asyncDispose]: cleanup
@@ -51362,7 +51504,8 @@ async function machineAccess(paths, log, conversationId, transport) {
51362
51504
  fetchProviderCredential: async (runId, signal) => {
51363
51505
  void managedMcp?.authorization(signal);
51364
51506
  return (await api()).fetchProviderCredential(runId, signal);
51365
- }
51507
+ },
51508
+ uploadMedia: async (runId, media, data, signal) => (await api()).uploadRunMedia(runId, media, data, signal)
51366
51509
  };
51367
51510
  const codexCredentials = {
51368
51511
  refresh: async (runId, rejectedAccessTokenSha256) => (await api()).refreshCodexCredential(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alan-ai-hq/agent-manager-darwin-arm64",
3
- "version": "0.1.159",
3
+ "version": "0.1.160",
4
4
  "description": "Alan machine runtime (alan-agent) for one platform: the official Node.js binary, the runtime bundle and its launcher. Installed by @alan-ai-hq/agent-manager.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "homepage": "https://tryalan.ai",