newmark-agent 0.4.7 → 0.4.8

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.
@@ -327556,6 +327556,7 @@ var NATIVE_TOOL_CATALOG = [
327556
327556
  { name: "browser_reload", label: "Browser reload", description: "Reload the built-in browser.", category: "browser", defaultEnabled: true },
327557
327557
  { name: "browser_cdp", label: "Browser CDP", description: "Run an advanced Chrome DevTools Protocol command.", category: "browser", defaultEnabled: true },
327558
327558
  { name: "browser_use", label: "Browser Use", description: "Observe and control the built-in browser through scoped opaque element refs and structured receipts.", category: "browser", defaultEnabled: true },
327559
+ { name: "screen_capture", label: "Active screenshot", description: "Capture the Windows desktop or one visible application without starting the full Computer Use control surface.", category: "desktop", defaultEnabled: true, protected: true, availability: "mode-scoped" },
327559
327560
  { name: "computer_use", label: "Computer Use", description: "Observe and control Windows desktop UI with screenshots and semantic objects.", category: "desktop", defaultEnabled: true },
327560
327561
  { name: "image_inspect", label: "Image inspect", description: "Crop and magnify images submitted in the current conversation for closer visual inspection.", category: "core", defaultEnabled: true, protected: true, availability: "mode-scoped" },
327561
327562
  { name: "image_display", label: "Image display", description: "Present a workspace PNG/JPEG inside the current Build Block.", category: "core", defaultEnabled: true, protected: true, availability: "mode-scoped" },
@@ -335746,6 +335747,7 @@ var import_crypto6 = require("crypto");
335746
335747
  // src/core/toolPolicy.ts
335747
335748
  var REQUIRED_TOOLS = /* @__PURE__ */ new Set(["pwd", "read", "glob", "grep"]);
335748
335749
  var MODE_SCOPED_TOOLS = /* @__PURE__ */ new Set([
335750
+ "screen_capture",
335749
335751
  "image_inspect",
335750
335752
  "image_display",
335751
335753
  "ocr_read",
@@ -335778,6 +335780,7 @@ var MODE_SCOPED_TOOLS = /* @__PURE__ */ new Set([
335778
335780
  "branch_create"
335779
335781
  ]);
335780
335782
  var PLAN_READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
335783
+ "screen_capture",
335781
335784
  "task_read",
335782
335785
  "pwd",
335783
335786
  "read",
@@ -335825,6 +335828,7 @@ var CONCURRENCY_SAFE_TOOLS = /* @__PURE__ */ new Set([
335825
335828
  "git_status",
335826
335829
  "file_audit",
335827
335830
  "repo_security_audit",
335831
+ "screen_capture",
335828
335832
  "SubAgent"
335829
335833
  ]);
335830
335834
  function isConcurrencySafeTool(name50, riskLevel) {
@@ -336908,6 +336912,13 @@ var ToolExecutor = class {
336908
336912
  max_refs: { type: "number" },
336909
336913
  attribute: { type: "string" }
336910
336914
  }, ["action"]),
336915
+ t3("screen_capture", "Read-only active Windows screenshot available without provisioning or starting full Computer Use. Capture the whole desktop or one visible application. The image is a one-use model input and is deleted immediately; semantic Windows UI objects are returned alongside it.", {
336916
+ target: { type: "string", enum: ["desktop", "application"], description: "Capture the whole desktop or one visible application. Defaults to desktop." },
336917
+ app_target: { type: "string", description: "For target=application: application title, process name, process id, or window handle." },
336918
+ capture_max_width: { type: "number", minimum: 320, maximum: 2048, description: "Maximum ephemeral screenshot width; defaults to 1280. Aspect ratio is preserved and the source is never enlarged." },
336919
+ capture_max_height: { type: "number", minimum: 240, maximum: 2048, description: "Maximum ephemeral screenshot height; defaults to 960. Aspect ratio is preserved and the source is never enlarged." },
336920
+ max_chars: { type: "number", minimum: 1e3, maximum: 1e5, description: "Maximum returned semantic UI text characters." }
336921
+ }, []),
336911
336922
  t3("computer_use", "Native Windows desktop control with persistent observation/action helpers. Use observe/app_observe before acting. sequence may perform up to three stable low-risk move/click/scroll/wait/app_activate steps and stops when focus, window, menu, dialog, scene, or risk changes. Vision screenshots remain one-time inputs and are deleted immediately.", {
336912
336923
  action: { type: "string", enum: ["observe", "app_list", "app_observe", "sequence", "takeover_start", "takeover_stop", "move", "click", "scroll", "type", "key", "wait", "app_activate", "app_click", "app_scroll", "app_type", "app_key"] },
336913
336924
  capture_max_width: { type: "number", minimum: 320, maximum: 2048, description: "For observe/app_observe only. Maximum ephemeral screenshot width; defaults to 1280. Aspect ratio is preserved and the source is never enlarged." },
@@ -337398,6 +337409,44 @@ var ToolExecutor = class {
337398
337409
  result: parsed
337399
337410
  }, null, 2);
337400
337411
  }
337412
+ case "screen_capture": {
337413
+ const target = g2("target").toLowerCase() === "application" ? "application" : "desktop";
337414
+ if (process.env.NEWMARK_WSL_DISTRO) {
337415
+ const result = await requestWindowsHostTool("screen_capture", args, {
337416
+ conversationId: context.conversationId || "default",
337417
+ workspaceId: context.workspaceId || terminalTakeoverWorkspaceId(context.workspacePath || wsPath),
337418
+ actorId: context.actorId || ROOT_TERMINAL_ACTOR_ID,
337419
+ runtimeKey: browserUseScope(context, wsPath).runtimeKey,
337420
+ allowEphemeralVisionImage: context.allowEphemeralVisionImage === true,
337421
+ mode: context.mode || "build"
337422
+ }, 12e4, context.signal);
337423
+ return typeof result === "string" ? result : JSON.stringify(result);
337424
+ }
337425
+ if (process.env.NEWMARK_ISOLATED_RUNTIME === "1") {
337426
+ const result = await requestUtilityHostTool("screen_capture", args, {
337427
+ conversationId: context.conversationId || "default",
337428
+ workspaceId: context.workspaceId || terminalTakeoverWorkspaceId(context.workspacePath || wsPath),
337429
+ actorId: context.actorId || ROOT_TERMINAL_ACTOR_ID,
337430
+ workspacePath: context.workspacePath || wsPath,
337431
+ backend: "utility",
337432
+ mode: context.mode || "build",
337433
+ allowEphemeralVisionImage: context.allowEphemeralVisionImage === true
337434
+ }, 12e4, context.signal);
337435
+ return typeof result === "string" ? result : JSON.stringify(result);
337436
+ }
337437
+ return await runComputerUse({
337438
+ action: target === "application" ? "app_observe" : "observe",
337439
+ appTarget: g2("app_target"),
337440
+ windowHandle: target === "application" ? g2("app_target") : "",
337441
+ maxChars: Number(args.max_chars || 3e4),
337442
+ workspacePath: wsPath,
337443
+ allowEphemeralVisionImage: context.allowEphemeralVisionImage === true,
337444
+ captureMaxWidth: Number(args.capture_max_width),
337445
+ captureMaxHeight: Number(args.capture_max_height),
337446
+ invocation: context.invocation,
337447
+ ownerId: `screen-capture:${computerUseOwner(context, wsPath)}:${String(context.actorId || "root")}`
337448
+ });
337449
+ }
337401
337450
  case "computer_use": {
337402
337451
  const action = normalizeComputerUseAction(g2("action"));
337403
337452
  const owner = `${computerUseOwner(context, wsPath)}:${String(context.actorId || "root")}`;
@@ -337604,7 +337653,7 @@ var ToolExecutor = class {
337604
337653
  }
337605
337654
  hostSupportsTool(name50) {
337606
337655
  if (name50.startsWith("browser_") && !this.hostProfile.electronBrowser) return false;
337607
- if (name50 === "computer_use" && !this.hostProfile.windowsComputerUse) return false;
337656
+ if ((name50 === "computer_use" || name50 === "screen_capture") && !this.hostProfile.windowsComputerUse) return false;
337608
337657
  return true;
337609
337658
  }
337610
337659
  async decorateBrowserUseReceipt(input, context, runtimeKey) {
@@ -341504,10 +341553,12 @@ function toKernelTools(agent, definitions, provisioning) {
341504
341553
  throw new Error(rawText);
341505
341554
  }
341506
341555
  const visionImage = visualFallbackImageInput(agent, name50, rawText);
341556
+ const capturedInput = name50 === "screen_capture" ? agent.registerCapturedImageInput(visionImage.image || "", "active-screenshot.jpg") : null;
341507
341557
  const directImage = imageInspectDataUrl(name50, rawText);
341508
- const text = spillOversizedToolResult(agent, name50, sanitizeVisualToolText(name50, rawText));
341558
+ const text = spillOversizedToolResult(agent, name50, capturedImageToolText(name50, sanitizeVisualToolText(name50, rawText), capturedInput?.id));
341509
341559
  const content = [{ type: "text", text }];
341510
- if (visionImage.imagePath) content.push({ type: "image", imagePath: visionImage.imagePath, mimeType: imageMimeForPath(visionImage.imagePath) });
341560
+ if (name50 === "screen_capture" && capturedInput?.dataUrl) content.push({ type: "image", image: capturedInput.dataUrl, mimeType: capturedInput.mimeType });
341561
+ else if (visionImage.imagePath) content.push({ type: "image", imagePath: visionImage.imagePath, mimeType: imageMimeForPath(visionImage.imagePath) });
341511
341562
  else if (visionImage.image) content.push({ type: "image", image: visionImage.image, mimeType: visionImage.mimeType });
341512
341563
  if (directImage) content.push({ type: "image", image: directImage, mimeType: "image/png" });
341513
341564
  const terminate = shouldTerminateAfterToolResult(name50) && (name50 !== "question" || agent.pendingOptions.length > 0);
@@ -341520,7 +341571,7 @@ function toKernelTools(agent, definitions, provisioning) {
341520
341571
  } catch {
341521
341572
  }
341522
341573
  }
341523
- return { content, details: { tool: name50, ok: true, terminate, ...launchReceipt ? { launchReceipt } : {}, visionImagePath: visionImage.imagePath || void 0, ephemeralVisionImage: !!visionImage.image, displayImage }, terminate };
341574
+ return { content, details: { tool: name50, ok: true, terminate, ...launchReceipt ? { launchReceipt } : {}, visionImagePath: visionImage.imagePath || void 0, ephemeralVisionImage: !!visionImage.image, capturedAttachmentId: capturedInput?.id, displayImage }, terminate };
341524
341575
  }
341525
341576
  };
341526
341577
  }).filter((tool) => !!tool.name);
@@ -341544,7 +341595,7 @@ var INLINE_TOOL_RESULT_MAX_CHARS = 24e3;
341544
341595
  function spillOversizedToolResult(agent, name50, text) {
341545
341596
  const value = String(text || "");
341546
341597
  if (value.length <= INLINE_TOOL_RESULT_MAX_CHARS) return value;
341547
- if (["computer_use", "browser_use", "pdf_read", "image_inspect", "image_display", "task", "subagent_create", "SubAgent", "subagent_send", "subagent_result", "subagent_read", "linked_plan", "question"].includes(name50)) {
341598
+ if (["screen_capture", "computer_use", "browser_use", "pdf_read", "image_inspect", "image_display", "task", "subagent_create", "SubAgent", "subagent_send", "subagent_result", "subagent_read", "linked_plan", "question"].includes(name50)) {
341548
341599
  return value;
341549
341600
  }
341550
341601
  const artifactId = agent.storeToolResultArtifact(name50, value);
@@ -341559,10 +341610,10 @@ function spillOversizedToolResult(agent, name50, text) {
341559
341610
  ].join("\n");
341560
341611
  }
341561
341612
  function sanitizeVisualToolText(name50, text) {
341562
- if (name50 !== "computer_use" && name50 !== "browser_use" && name50 !== "pdf_read" && name50 !== "image_inspect") return text;
341613
+ if (name50 !== "screen_capture" && name50 !== "computer_use" && name50 !== "browser_use" && name50 !== "pdf_read" && name50 !== "image_inspect") return text;
341563
341614
  try {
341564
341615
  const parsed = JSON.parse(text);
341565
- if (name50 === "computer_use" || name50 === "browser_use" || name50 === "pdf_read") {
341616
+ if (name50 === "screen_capture" || name50 === "computer_use" || name50 === "browser_use" || name50 === "pdf_read") {
341566
341617
  delete parsed.vision_image_path;
341567
341618
  delete parsed.vision_image_data_url;
341568
341619
  if (name50 === "pdf_read" && parsed.result && typeof parsed.result === "object") {
@@ -341578,7 +341629,7 @@ function sanitizeVisualToolText(name50, text) {
341578
341629
  }
341579
341630
  }
341580
341631
  function discardComputerUseVisionImage(name50, text) {
341581
- if (name50 !== "computer_use") return;
341632
+ if (name50 !== "screen_capture" && name50 !== "computer_use") return;
341582
341633
  try {
341583
341634
  const parsed = JSON.parse(text);
341584
341635
  const screenshotPath = String(parsed.vision_image_path || "");
@@ -341596,8 +341647,20 @@ function imageInspectDataUrl(name50, text) {
341596
341647
  return "";
341597
341648
  }
341598
341649
  }
341650
+ function capturedImageToolText(name50, text, attachmentId) {
341651
+ if (name50 !== "screen_capture" || !attachmentId) return text;
341652
+ try {
341653
+ const parsed = JSON.parse(text);
341654
+ parsed.attachment_id = attachmentId;
341655
+ parsed.image_input_channel = "user-image";
341656
+ parsed.inspect_next = { tool: "image_inspect", actions: ["source_info", "crop"], max_scale: 4 };
341657
+ return JSON.stringify(parsed, null, 2);
341658
+ } catch {
341659
+ return text;
341660
+ }
341661
+ }
341599
341662
  function visualFallbackImageInput(agent, name50, text) {
341600
- if (name50 !== "computer_use" && name50 !== "browser_use" && name50 !== "pdf_read") return {};
341663
+ if (name50 !== "screen_capture" && name50 !== "computer_use" && name50 !== "browser_use" && name50 !== "pdf_read") return {};
341601
341664
  const model = agent.activeModelConfig();
341602
341665
  if (!model?.vision) return {};
341603
341666
  try {
@@ -341723,7 +341786,7 @@ async function executeNewmarkTool(agent, name50, args, inputSchema, signal) {
341723
341786
  actorId: agent.runtimeActorId,
341724
341787
  workspaceId: terminalTakeoverWorkspaceId(wsDir),
341725
341788
  backend: process.env.NEWMARK_WSL_DISTRO ? "wsl" : process.platform === "win32" ? "windows" : process.platform,
341726
- allowEphemeralVisionImage: (name50 === "computer_use" || name50 === "browser_use" || name50 === "pdf_read" || name50 === "ocr_read") && !!agent.activeModelConfig()?.vision,
341789
+ allowEphemeralVisionImage: (name50 === "screen_capture" || name50 === "computer_use" || name50 === "browser_use" || name50 === "pdf_read" || name50 === "ocr_read") && !!agent.activeModelConfig()?.vision,
341727
341790
  signal
341728
341791
  });
341729
341792
  if (signal?.aborted) throw abortError4();
@@ -344866,6 +344929,7 @@ var Agent4 = class _Agent {
344866
344929
  memoryLabRebuildState = "idle";
344867
344930
  memoryLabRebuildError = "";
344868
344931
  displayImageDescriptionCache = /* @__PURE__ */ new Map();
344932
+ latestCapturedImageInputs = [];
344869
344933
  activeProcessAbortController = null;
344870
344934
  automationManager = null;
344871
344935
  activeAgentKernelRuntime = null;
@@ -347063,6 +347127,13 @@ ${String(event.toolArgs || "")}`;
347063
347127
  listConversationStates() {
347064
347128
  return this.listWorkspaceConversationStates(this.workspace.current);
347065
347129
  }
347130
+ registerCapturedImageInput(dataUrl, name50 = "active-screenshot.jpg") {
347131
+ if (!String(dataUrl || "").startsWith("data:image/")) return null;
347132
+ const prepared = this.prepareSubmittedConversationImages([{ dataUrl, name: name50, type: dataUrl.slice(5, dataUrl.indexOf(";")) }]);
347133
+ const attachment = prepared.attachments[0] || null;
347134
+ this.latestCapturedImageInputs = attachment ? [attachment] : [];
347135
+ return attachment;
347136
+ }
347066
347137
  subagentConcurrencyLimit() {
347067
347138
  return this.intelligence === "ultra" ? 16 : 4;
347068
347139
  }
@@ -351980,6 +352051,13 @@ ${items.map((item) => this.formatAutomation(item)).join("\n")}`;
351980
352051
  }
351981
352052
  latestSubmittedImages(attachmentId = "") {
351982
352053
  const normalizedId = String(attachmentId || "").trim();
352054
+ const captured = hydrateConversationImageAttachments(this.rootPath, this.latestCapturedImageInputs).flatMap((attachment) => attachment.dataUrl ? [{ id: attachment.id, dataUrl: attachment.dataUrl }] : []);
352055
+ if (normalizedId) {
352056
+ const capturedMatch = captured.find((item) => item.id === normalizedId);
352057
+ if (capturedMatch) return [capturedMatch];
352058
+ } else if (captured.length) {
352059
+ return captured;
352060
+ }
351983
352061
  for (let index = this.chatMessages.length - 1; index >= 0; index -= 1) {
351984
352062
  const message = this.chatMessages[index];
351985
352063
  if (message?.role !== "user") continue;
@@ -353164,6 +353242,155 @@ var ConversationKernel = class {
353164
353242
  followUp: queued?.followUp.slice() || []
353165
353243
  };
353166
353244
  }
353245
+ queueItems(target) {
353246
+ const runtime = this.findRuntime(target);
353247
+ if (!runtime) return [];
353248
+ return runtime.pendingNextTurn.flatMap((item) => {
353249
+ if (item.queueMode !== "followUp") return [];
353250
+ if (typeof item.message === "string") return [];
353251
+ const id = String(item.message.clientMessageId || "");
353252
+ if (!id) return [];
353253
+ return [{
353254
+ id,
353255
+ text: String(item.message.visibleUserInput || item.message.text || "").replace(/^\[Next queued while current turn is running\]\n/, ""),
353256
+ queueMode: item.queueMode,
353257
+ requestedMode: item.message.visibleMode,
353258
+ goalObjective: item.message.goalObjective,
353259
+ runId: item.message.runId,
353260
+ createdAt: String(item.message.createdAt || "")
353261
+ }];
353262
+ });
353263
+ }
353264
+ enqueueNext(target, input) {
353265
+ const runtime = this.findRuntime(target);
353266
+ if (!runtime?.activePromise || !runtime.runId) throw new Error("Target conversation is not running");
353267
+ const id = String(input.id || "").trim().slice(0, 200);
353268
+ const text = String(input.text || "").trim();
353269
+ if (!id || !text) throw new Error("Queue item id and text are required");
353270
+ const existing = this.queueItems(runtime.target).find((item) => item.id === id);
353271
+ if (existing) return existing;
353272
+ const prompt = `[Next queued while current turn is running]
353273
+ ${text}`;
353274
+ const createdAt = String(input.createdAt || (/* @__PURE__ */ new Date()).toISOString());
353275
+ runtime.pendingNextTurn.push({
353276
+ message: {
353277
+ text: prompt,
353278
+ visibleUserInput: text,
353279
+ visibleMode: String(input.requestedMode || "build"),
353280
+ goalObjective: String(input.goalObjective || "") || void 0,
353281
+ clientMessageId: id,
353282
+ runId: runtime.runId,
353283
+ createdAt
353284
+ },
353285
+ queueMode: "followUp"
353286
+ });
353287
+ runtime.runner.retainConversationContinuations([{
353288
+ content: prompt,
353289
+ queueMode: "followUp",
353290
+ clientMessageId: id,
353291
+ runId: runtime.runId,
353292
+ createdAt
353293
+ }]);
353294
+ this.trackQueuedMessage(runtime, prompt, "followUp");
353295
+ this.emitQueueUpdate(runtime);
353296
+ return this.queueItems(runtime.target).find((item) => item.id === id);
353297
+ }
353298
+ updateQueueItem(target, idInput, textInput) {
353299
+ const runtime = this.findRuntime(target);
353300
+ if (!runtime) throw new Error("Target conversation runtime is unavailable");
353301
+ const id = String(idInput || "").trim();
353302
+ const text = String(textInput || "").trim();
353303
+ if (!id || !text) throw new Error("Queue item id and text are required");
353304
+ const pending3 = runtime.pendingNextTurn.find((item) => typeof item.message !== "string" && item.message.clientMessageId === id);
353305
+ if (!pending3 || typeof pending3.message === "string") throw new Error("Queue item is no longer editable");
353306
+ const oldPrompt = pending3.message.text;
353307
+ pending3.message.text = `[Next queued while current turn is running]
353308
+ ${text}`;
353309
+ pending3.message.visibleUserInput = text;
353310
+ runtime.runner.consumeConversationContinuation({ content: oldPrompt, queueMode: pending3.queueMode, clientMessageId: id });
353311
+ runtime.runner.retainConversationContinuations([{
353312
+ content: pending3.message.text,
353313
+ queueMode: pending3.queueMode,
353314
+ clientMessageId: id,
353315
+ runId: pending3.message.runId
353316
+ }]);
353317
+ this.replaceTrackedQueuedMessage(runtime, oldPrompt, pending3.message.text, pending3.queueMode);
353318
+ this.emitQueueUpdate(runtime);
353319
+ return this.queueItems(runtime.target).find((item) => item.id === id);
353320
+ }
353321
+ deleteQueueItem(target, idInput) {
353322
+ const runtime = this.findRuntime(target);
353323
+ if (!runtime) return false;
353324
+ const id = String(idInput || "").trim();
353325
+ const index = runtime.pendingNextTurn.findIndex((item) => typeof item.message !== "string" && item.message.clientMessageId === id);
353326
+ if (index < 0) return false;
353327
+ const [removed] = runtime.pendingNextTurn.splice(index, 1);
353328
+ if (typeof removed.message !== "string") {
353329
+ runtime.runner.consumeConversationContinuation({ content: removed.message.text, queueMode: removed.queueMode, clientMessageId: id });
353330
+ this.consumeQueuedMessage(runtime, removed.message.text);
353331
+ }
353332
+ this.emitQueueUpdate(runtime);
353333
+ return true;
353334
+ }
353335
+ setQueuePaused(target, paused) {
353336
+ const runtime = this.findRuntime(target);
353337
+ if (!runtime) throw new Error("Target conversation runtime is unavailable");
353338
+ runtime.queuePaused = paused;
353339
+ this.emitQueueUpdate(runtime);
353340
+ if (!paused && !runtime.activePromise && runtime.pendingNextTurn.length) {
353341
+ this.schedulePendingRuntimeContinuation(runtime, runtime.runId);
353342
+ }
353343
+ return runtime.queuePaused;
353344
+ }
353345
+ queueAction(target, action, input = {}) {
353346
+ const runtime = this.findRuntime(target);
353347
+ if (!runtime) throw new Error("Target conversation runtime is unavailable");
353348
+ let receipt;
353349
+ if (action === "enqueue") {
353350
+ this.enqueueNext(runtime.target, {
353351
+ id: String(input.id || ""),
353352
+ text: String(input.text || ""),
353353
+ requestedMode: input.requestedMode,
353354
+ goalObjective: input.goalObjective,
353355
+ createdAt: input.createdAt
353356
+ });
353357
+ } else if (action === "update") {
353358
+ this.updateQueueItem(runtime.target, String(input.id || ""), String(input.text || ""));
353359
+ } else if (action === "delete") {
353360
+ if (!this.deleteQueueItem(runtime.target, String(input.id || ""))) throw new Error("Queue item was not found");
353361
+ } else if (action === "toggle_pause") {
353362
+ this.setQueuePaused(runtime.target, !runtime.queuePaused);
353363
+ } else if (action === "guide") {
353364
+ const item = this.queueItems(runtime.target).find((entry) => entry.id === String(input.id || ""));
353365
+ if (!item) throw new Error("Queue item was not found");
353366
+ receipt = this.enqueueGuide({
353367
+ clientMessageId: item.id,
353368
+ guideId: (0, import_crypto16.randomUUID)(),
353369
+ target: runtime.target,
353370
+ runId: runtime.runId,
353371
+ deliveryMode: "steer",
353372
+ text: item.goalObjective ? `Goal for the current Build:
353373
+ ${item.goalObjective}` : item.text,
353374
+ goalObjective: item.goalObjective,
353375
+ createdAt: item.createdAt || (/* @__PURE__ */ new Date()).toISOString()
353376
+ });
353377
+ if (receipt.status === "rejected") return {
353378
+ ok: false,
353379
+ queueItems: this.queueItems(runtime.target),
353380
+ queuePaused: runtime.queuePaused,
353381
+ queued: this.queued(runtime.target),
353382
+ receipt
353383
+ };
353384
+ this.deleteQueueItem(runtime.target, item.id);
353385
+ }
353386
+ return {
353387
+ ok: true,
353388
+ queueItems: this.queueItems(runtime.target),
353389
+ queuePaused: runtime.queuePaused,
353390
+ queued: this.queued(runtime.target),
353391
+ receipt
353392
+ };
353393
+ }
353167
353394
  events(target) {
353168
353395
  return this.findRuntime(target)?.events.slice() || [];
353169
353396
  }
@@ -353192,6 +353419,8 @@ var ConversationKernel = class {
353192
353419
  workRuns: this.bindWorkRunsToRuntimeTarget(conversationSnapshot.workRuns, normalized),
353193
353420
  target: normalized,
353194
353421
  queued: this.queued(normalized),
353422
+ queueItems: this.queueItems(normalized),
353423
+ queuePaused: runtime?.queuePaused === true,
353195
353424
  workEvents: this.events(normalized),
353196
353425
  runtime: this.runtimeState(normalized),
353197
353426
  mode: runner.mode,
@@ -353627,7 +353856,7 @@ var ConversationKernel = class {
353627
353856
  if (runtime.stopRequestedRunId === runId) {
353628
353857
  stopped = true;
353629
353858
  this.settleCooperativeStop(runtime, runId);
353630
- } else if (runtime.pendingNextTurn.length > 0) {
353859
+ } else if (!runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
353631
353860
  this.schedulePendingRuntimeContinuation(runtime, runId);
353632
353861
  }
353633
353862
  }
@@ -353662,7 +353891,7 @@ var ConversationKernel = class {
353662
353891
  return this.result(runtime, lastTokens);
353663
353892
  }
353664
353893
  for (; ; ) {
353665
- while (runtime.pendingNextTurn.length > 0) {
353894
+ while (!runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
353666
353895
  if (runtime.stopRequestedRunId === runtime.runId) return this.result(runtime, lastTokens);
353667
353896
  const next = runtime.pendingNextTurn.shift();
353668
353897
  if (next.queueMode === "steer" && typeof next.message !== "string" && !!next.message.clientMessageId) {
@@ -353704,11 +353933,11 @@ ${batchText}`,
353704
353933
  this.mirrorHostIfTargetActive(runtime);
353705
353934
  return this.result(runtime, lastTokens);
353706
353935
  }
353707
- this.clearQueued(runtime);
353936
+ if (!runtime.pendingNextTurn.length) this.clearQueued(runtime);
353708
353937
  const completedRunId = runtime.runId;
353709
353938
  runtime.runner.finishConversationWorkRun(completedRunId, "completed");
353710
353939
  await new Promise((resolve16) => setImmediate(resolve16));
353711
- if (runtime.runId === completedRunId && runtime.stopRequestedRunId !== completedRunId && runtime.pendingNextTurn.length > 0) {
353940
+ if (runtime.runId === completedRunId && runtime.stopRequestedRunId !== completedRunId && !runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
353712
353941
  runtime.guideAcceptanceClosedRunId = "";
353713
353942
  if (!runtime.runner.resumeConversationWorkRun(completedRunId)) {
353714
353943
  throw new Error(`Unable to resume deferred Guide work run ${completedRunId}`);
@@ -353799,6 +354028,7 @@ Review this persisted peer result and summarize or continue the parent task as n
353799
354028
  events: [],
353800
354029
  pendingNextTurn: [],
353801
354030
  queued: { steering: [], followUp: [] },
354031
+ queuePaused: false,
353802
354032
  runId: "",
353803
354033
  generation: this.generations.get(target.runtimeKey) || 0,
353804
354034
  stopRequestedRunId: "",
@@ -353894,7 +354124,7 @@ Review this persisted peer result and summarize or continue the parent task as n
353894
354124
  }
353895
354125
  setImmediate(() => {
353896
354126
  runtime.pendingContinuationRunId = void 0;
353897
- if (runtime.runId !== runId || runtime.activePromise || runtime.stopRequestedRunId === runId) return;
354127
+ if (runtime.runId !== runId || runtime.activePromise || runtime.stopRequestedRunId === runId || runtime.queuePaused) return;
353898
354128
  const next = runtime.pendingNextTurn.shift();
353899
354129
  if (!next) return;
353900
354130
  const message = typeof next.message === "string" ? { text: next.message, runId } : { ...next.message, runId: next.message.runId || runId };
@@ -354045,7 +354275,36 @@ Review this persisted peer result and summarize or continue the parent task as n
354045
354275
  const text = typeof message === "string" ? message : message.text;
354046
354276
  const prompt = isSteer ? text : `[Next queued while current turn is running]
354047
354277
  ${text}`;
354048
- if (!isSteer) this.trackQueuedMessage(runtime, prompt, queueMode);
354278
+ if (!isSteer) {
354279
+ const structured = typeof message === "string" ? null : message;
354280
+ const clientMessageId = String(structured?.clientMessageId || (0, import_crypto16.randomUUID)());
354281
+ const queuedMessage = {
354282
+ ...structured || {},
354283
+ text: prompt,
354284
+ visibleUserInput: structured?.visibleUserInput || text,
354285
+ visibleMode: structured?.visibleMode || runtime.options.mode,
354286
+ clientMessageId,
354287
+ runId: structured?.runId || runtime.runId,
354288
+ createdAt: String(structured?.createdAt || (/* @__PURE__ */ new Date()).toISOString())
354289
+ };
354290
+ if (!runtime.pendingNextTurn.some((item) => typeof item.message !== "string" && item.message.clientMessageId === clientMessageId)) {
354291
+ runtime.pendingNextTurn.push({ message: queuedMessage, queueMode: "followUp" });
354292
+ }
354293
+ runtime.runner.retainConversationContinuations([{
354294
+ content: prompt,
354295
+ queueMode: "followUp",
354296
+ clientMessageId,
354297
+ runId: queuedMessage.runId,
354298
+ images: queuedMessage.images?.map((image) => ({ ...image })),
354299
+ attachments: queuedMessage.attachments?.map((attachment) => ({ ...attachment })),
354300
+ createdAt: queuedMessage.createdAt
354301
+ }]);
354302
+ this.trackQueuedMessage(runtime, prompt, "followUp");
354303
+ runtime.runner.recordWorkStatus(runtime.stopRequestedRunId === runtime.runId ? "Next message retained while stopping." : "Next message queued.");
354304
+ if (runtime.stopRequestedRunId === runtime.runId) runtime.forceStopArmedRunId = "";
354305
+ this.emitQueueUpdate(runtime);
354306
+ return;
354307
+ }
354049
354308
  if (runtime.stopRequestedRunId === runtime.runId) {
354050
354309
  runtime.forceStopArmedRunId = "";
354051
354310
  const structured = typeof message === "string" ? void 0 : message;
@@ -354091,6 +354350,12 @@ ${text}`;
354091
354350
  }
354092
354351
  if (changed) this.emitQueueUpdate(runtime);
354093
354352
  }
354353
+ replaceTrackedQueuedMessage(runtime, oldMessage, nextMessage, queueMode) {
354354
+ this.queueState(runtime);
354355
+ const list = queueMode === "steer" ? runtime.queued.steering : runtime.queued.followUp;
354356
+ const index = list.indexOf(oldMessage);
354357
+ if (index >= 0) list[index] = nextMessage;
354358
+ }
354094
354359
  emitQueueUpdate(runtime) {
354095
354360
  this.queueState(runtime);
354096
354361
  runtime.runner.emitWorkEvent({
@@ -354212,9 +354477,10 @@ ${text}`;
354212
354477
  const runId = runtime.runId;
354213
354478
  await Promise.resolve();
354214
354479
  if (runtime.runId !== runId || runtime.stopRequestedRunId === runId) return true;
354215
- if (runtime.pendingNextTurn.length > 0 || runtime.runner.subagents.readRootInbox().length > 0) return false;
354480
+ const hasSteering = runtime.pendingNextTurn.some((item) => item.queueMode === "steer");
354481
+ if (hasSteering || runtime.runner.subagents.readRootInbox().length > 0) return false;
354216
354482
  runtime.guideAcceptanceClosedRunId = runId;
354217
- if (runtime.pendingNextTurn.length > 0 || runtime.runner.subagents.readRootInbox().length > 0) {
354483
+ if (runtime.pendingNextTurn.some((item) => item.queueMode === "steer") || runtime.runner.subagents.readRootInbox().length > 0) {
354218
354484
  runtime.guideAcceptanceClosedRunId = "";
354219
354485
  return false;
354220
354486
  }
@@ -354367,6 +354633,9 @@ async function handle(request) {
354367
354633
  target
354368
354634
  });
354369
354635
  }
354636
+ if (request.method === "queue_action") {
354637
+ return kernel.queueAction(checkedTarget(request.params.target), request.params.action, request.params.input);
354638
+ }
354370
354639
  if (request.method === "checkpoint") return kernel.checkpoint(checkedTarget(request.params.target));
354371
354640
  if (request.method === "context_compress") {
354372
354641
  return kernel.compressContext(checkedTarget(request.params.target), request.params.options);
@@ -79,6 +79,9 @@ async function handle(request) {
79
79
  target,
80
80
  });
81
81
  }
82
+ if (request.method === 'queue_action') {
83
+ return kernel.queueAction(checkedTarget(request.params.target), request.params.action, request.params.input);
84
+ }
82
85
  if (request.method === 'checkpoint')
83
86
  return kernel.checkpoint(checkedTarget(request.params.target));
84
87
  if (request.method === 'context_compress') {
@@ -346,6 +346,7 @@ export declare class Agent {
346
346
  private memoryLabRebuildState;
347
347
  private memoryLabRebuildError;
348
348
  private displayImageDescriptionCache;
349
+ private latestCapturedImageInputs;
349
350
  private activeProcessAbortController;
350
351
  private automationManager;
351
352
  private activeAgentKernelRuntime;
@@ -622,6 +623,7 @@ export declare class Agent {
622
623
  order: number;
623
624
  branchCommunication: boolean;
624
625
  }>;
626
+ registerCapturedImageInput(dataUrl: string, name?: string): ConversationImageAttachment | null;
625
627
  private subagentConcurrencyLimit;
626
628
  /** 当前工作区使用内存中的前台选择;后台工作区从各自持久化状态读取 active id。 */
627
629
  activeConversationIdForWorkspace(ws: WorkspaceInfo | null): string;
@@ -241,6 +241,7 @@ class Agent {
241
241
  memoryLabRebuildState = 'idle';
242
242
  memoryLabRebuildError = '';
243
243
  displayImageDescriptionCache = new Map();
244
+ latestCapturedImageInputs = [];
244
245
  activeProcessAbortController = null;
245
246
  automationManager = null;
246
247
  activeAgentKernelRuntime = null;
@@ -2859,6 +2860,14 @@ class Agent {
2859
2860
  listConversationStates() {
2860
2861
  return this.listWorkspaceConversationStates(this.workspace.current);
2861
2862
  }
2863
+ registerCapturedImageInput(dataUrl, name = 'active-screenshot.jpg') {
2864
+ if (!String(dataUrl || '').startsWith('data:image/'))
2865
+ return null;
2866
+ const prepared = this.prepareSubmittedConversationImages([{ dataUrl, name, type: dataUrl.slice(5, dataUrl.indexOf(';')) }]);
2867
+ const attachment = prepared.attachments[0] || null;
2868
+ this.latestCapturedImageInputs = attachment ? [attachment] : [];
2869
+ return attachment;
2870
+ }
2862
2871
  subagentConcurrencyLimit() {
2863
2872
  return this.intelligence === 'ultra' ? 16 : 4;
2864
2873
  }
@@ -8382,6 +8391,17 @@ class Agent {
8382
8391
  }
8383
8392
  latestSubmittedImages(attachmentId = '') {
8384
8393
  const normalizedId = String(attachmentId || '').trim();
8394
+ const captured = (0, conversationAttachments_1.hydrateConversationImageAttachments)(this.rootPath, this.latestCapturedImageInputs).flatMap(attachment => attachment.dataUrl
8395
+ ? [{ id: attachment.id, dataUrl: attachment.dataUrl }]
8396
+ : []);
8397
+ if (normalizedId) {
8398
+ const capturedMatch = captured.find(item => item.id === normalizedId);
8399
+ if (capturedMatch)
8400
+ return [capturedMatch];
8401
+ }
8402
+ else if (captured.length) {
8403
+ return captured;
8404
+ }
8385
8405
  for (let index = this.chatMessages.length - 1; index >= 0; index -= 1) {
8386
8406
  const message = this.chatMessages[index];
8387
8407
  if (message?.role !== 'user')