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.
@@ -327560,6 +327560,7 @@ var NATIVE_TOOL_CATALOG = [
327560
327560
  { name: "browser_reload", label: "Browser reload", description: "Reload the built-in browser.", category: "browser", defaultEnabled: true },
327561
327561
  { name: "browser_cdp", label: "Browser CDP", description: "Run an advanced Chrome DevTools Protocol command.", category: "browser", defaultEnabled: true },
327562
327562
  { 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 },
327563
+ { 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" },
327563
327564
  { name: "computer_use", label: "Computer Use", description: "Observe and control Windows desktop UI with screenshots and semantic objects.", category: "desktop", defaultEnabled: true },
327564
327565
  { 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" },
327565
327566
  { 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" },
@@ -335754,6 +335755,7 @@ var import_crypto6 = require("crypto");
335754
335755
  // src/core/toolPolicy.ts
335755
335756
  var REQUIRED_TOOLS = /* @__PURE__ */ new Set(["pwd", "read", "glob", "grep"]);
335756
335757
  var MODE_SCOPED_TOOLS = /* @__PURE__ */ new Set([
335758
+ "screen_capture",
335757
335759
  "image_inspect",
335758
335760
  "image_display",
335759
335761
  "ocr_read",
@@ -335786,6 +335788,7 @@ var MODE_SCOPED_TOOLS = /* @__PURE__ */ new Set([
335786
335788
  "branch_create"
335787
335789
  ]);
335788
335790
  var PLAN_READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
335791
+ "screen_capture",
335789
335792
  "task_read",
335790
335793
  "pwd",
335791
335794
  "read",
@@ -335833,6 +335836,7 @@ var CONCURRENCY_SAFE_TOOLS = /* @__PURE__ */ new Set([
335833
335836
  "git_status",
335834
335837
  "file_audit",
335835
335838
  "repo_security_audit",
335839
+ "screen_capture",
335836
335840
  "SubAgent"
335837
335841
  ]);
335838
335842
  function isConcurrencySafeTool(name50, riskLevel) {
@@ -336912,6 +336916,13 @@ var ToolExecutor = class {
336912
336916
  max_refs: { type: "number" },
336913
336917
  attribute: { type: "string" }
336914
336918
  }, ["action"]),
336919
+ 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.", {
336920
+ target: { type: "string", enum: ["desktop", "application"], description: "Capture the whole desktop or one visible application. Defaults to desktop." },
336921
+ app_target: { type: "string", description: "For target=application: application title, process name, process id, or window handle." },
336922
+ 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." },
336923
+ 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." },
336924
+ max_chars: { type: "number", minimum: 1e3, maximum: 1e5, description: "Maximum returned semantic UI text characters." }
336925
+ }, []),
336915
336926
  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.", {
336916
336927
  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"] },
336917
336928
  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." },
@@ -337402,6 +337413,44 @@ var ToolExecutor = class {
337402
337413
  result: parsed
337403
337414
  }, null, 2);
337404
337415
  }
337416
+ case "screen_capture": {
337417
+ const target = g2("target").toLowerCase() === "application" ? "application" : "desktop";
337418
+ if (process.env.NEWMARK_WSL_DISTRO) {
337419
+ const result = await requestWindowsHostTool("screen_capture", args, {
337420
+ conversationId: context.conversationId || "default",
337421
+ workspaceId: context.workspaceId || terminalTakeoverWorkspaceId(context.workspacePath || wsPath),
337422
+ actorId: context.actorId || ROOT_TERMINAL_ACTOR_ID,
337423
+ runtimeKey: browserUseScope(context, wsPath).runtimeKey,
337424
+ allowEphemeralVisionImage: context.allowEphemeralVisionImage === true,
337425
+ mode: context.mode || "build"
337426
+ }, 12e4, context.signal);
337427
+ return typeof result === "string" ? result : JSON.stringify(result);
337428
+ }
337429
+ if (process.env.NEWMARK_ISOLATED_RUNTIME === "1") {
337430
+ const result = await requestUtilityHostTool("screen_capture", args, {
337431
+ conversationId: context.conversationId || "default",
337432
+ workspaceId: context.workspaceId || terminalTakeoverWorkspaceId(context.workspacePath || wsPath),
337433
+ actorId: context.actorId || ROOT_TERMINAL_ACTOR_ID,
337434
+ workspacePath: context.workspacePath || wsPath,
337435
+ backend: "utility",
337436
+ mode: context.mode || "build",
337437
+ allowEphemeralVisionImage: context.allowEphemeralVisionImage === true
337438
+ }, 12e4, context.signal);
337439
+ return typeof result === "string" ? result : JSON.stringify(result);
337440
+ }
337441
+ return await runComputerUse({
337442
+ action: target === "application" ? "app_observe" : "observe",
337443
+ appTarget: g2("app_target"),
337444
+ windowHandle: target === "application" ? g2("app_target") : "",
337445
+ maxChars: Number(args.max_chars || 3e4),
337446
+ workspacePath: wsPath,
337447
+ allowEphemeralVisionImage: context.allowEphemeralVisionImage === true,
337448
+ captureMaxWidth: Number(args.capture_max_width),
337449
+ captureMaxHeight: Number(args.capture_max_height),
337450
+ invocation: context.invocation,
337451
+ ownerId: `screen-capture:${computerUseOwner(context, wsPath)}:${String(context.actorId || "root")}`
337452
+ });
337453
+ }
337405
337454
  case "computer_use": {
337406
337455
  const action = normalizeComputerUseAction(g2("action"));
337407
337456
  const owner = `${computerUseOwner(context, wsPath)}:${String(context.actorId || "root")}`;
@@ -337608,7 +337657,7 @@ var ToolExecutor = class {
337608
337657
  }
337609
337658
  hostSupportsTool(name50) {
337610
337659
  if (name50.startsWith("browser_") && !this.hostProfile.electronBrowser) return false;
337611
- if (name50 === "computer_use" && !this.hostProfile.windowsComputerUse) return false;
337660
+ if ((name50 === "computer_use" || name50 === "screen_capture") && !this.hostProfile.windowsComputerUse) return false;
337612
337661
  return true;
337613
337662
  }
337614
337663
  async decorateBrowserUseReceipt(input2, context, runtimeKey) {
@@ -341508,10 +341557,12 @@ function toKernelTools(agent, definitions, provisioning) {
341508
341557
  throw new Error(rawText);
341509
341558
  }
341510
341559
  const visionImage = visualFallbackImageInput(agent, name50, rawText);
341560
+ const capturedInput = name50 === "screen_capture" ? agent.registerCapturedImageInput(visionImage.image || "", "active-screenshot.jpg") : null;
341511
341561
  const directImage = imageInspectDataUrl(name50, rawText);
341512
- const text = spillOversizedToolResult(agent, name50, sanitizeVisualToolText(name50, rawText));
341562
+ const text = spillOversizedToolResult(agent, name50, capturedImageToolText(name50, sanitizeVisualToolText(name50, rawText), capturedInput?.id));
341513
341563
  const content = [{ type: "text", text }];
341514
- if (visionImage.imagePath) content.push({ type: "image", imagePath: visionImage.imagePath, mimeType: imageMimeForPath(visionImage.imagePath) });
341564
+ if (name50 === "screen_capture" && capturedInput?.dataUrl) content.push({ type: "image", image: capturedInput.dataUrl, mimeType: capturedInput.mimeType });
341565
+ else if (visionImage.imagePath) content.push({ type: "image", imagePath: visionImage.imagePath, mimeType: imageMimeForPath(visionImage.imagePath) });
341515
341566
  else if (visionImage.image) content.push({ type: "image", image: visionImage.image, mimeType: visionImage.mimeType });
341516
341567
  if (directImage) content.push({ type: "image", image: directImage, mimeType: "image/png" });
341517
341568
  const terminate = shouldTerminateAfterToolResult(name50) && (name50 !== "question" || agent.pendingOptions.length > 0);
@@ -341524,7 +341575,7 @@ function toKernelTools(agent, definitions, provisioning) {
341524
341575
  } catch {
341525
341576
  }
341526
341577
  }
341527
- return { content, details: { tool: name50, ok: true, terminate, ...launchReceipt ? { launchReceipt } : {}, visionImagePath: visionImage.imagePath || void 0, ephemeralVisionImage: !!visionImage.image, displayImage }, terminate };
341578
+ return { content, details: { tool: name50, ok: true, terminate, ...launchReceipt ? { launchReceipt } : {}, visionImagePath: visionImage.imagePath || void 0, ephemeralVisionImage: !!visionImage.image, capturedAttachmentId: capturedInput?.id, displayImage }, terminate };
341528
341579
  }
341529
341580
  };
341530
341581
  }).filter((tool) => !!tool.name);
@@ -341548,7 +341599,7 @@ var INLINE_TOOL_RESULT_MAX_CHARS = 24e3;
341548
341599
  function spillOversizedToolResult(agent, name50, text) {
341549
341600
  const value = String(text || "");
341550
341601
  if (value.length <= INLINE_TOOL_RESULT_MAX_CHARS) return value;
341551
- 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)) {
341602
+ 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)) {
341552
341603
  return value;
341553
341604
  }
341554
341605
  const artifactId = agent.storeToolResultArtifact(name50, value);
@@ -341563,10 +341614,10 @@ function spillOversizedToolResult(agent, name50, text) {
341563
341614
  ].join("\n");
341564
341615
  }
341565
341616
  function sanitizeVisualToolText(name50, text) {
341566
- if (name50 !== "computer_use" && name50 !== "browser_use" && name50 !== "pdf_read" && name50 !== "image_inspect") return text;
341617
+ if (name50 !== "screen_capture" && name50 !== "computer_use" && name50 !== "browser_use" && name50 !== "pdf_read" && name50 !== "image_inspect") return text;
341567
341618
  try {
341568
341619
  const parsed = JSON.parse(text);
341569
- if (name50 === "computer_use" || name50 === "browser_use" || name50 === "pdf_read") {
341620
+ if (name50 === "screen_capture" || name50 === "computer_use" || name50 === "browser_use" || name50 === "pdf_read") {
341570
341621
  delete parsed.vision_image_path;
341571
341622
  delete parsed.vision_image_data_url;
341572
341623
  if (name50 === "pdf_read" && parsed.result && typeof parsed.result === "object") {
@@ -341582,7 +341633,7 @@ function sanitizeVisualToolText(name50, text) {
341582
341633
  }
341583
341634
  }
341584
341635
  function discardComputerUseVisionImage(name50, text) {
341585
- if (name50 !== "computer_use") return;
341636
+ if (name50 !== "screen_capture" && name50 !== "computer_use") return;
341586
341637
  try {
341587
341638
  const parsed = JSON.parse(text);
341588
341639
  const screenshotPath = String(parsed.vision_image_path || "");
@@ -341600,8 +341651,20 @@ function imageInspectDataUrl(name50, text) {
341600
341651
  return "";
341601
341652
  }
341602
341653
  }
341654
+ function capturedImageToolText(name50, text, attachmentId) {
341655
+ if (name50 !== "screen_capture" || !attachmentId) return text;
341656
+ try {
341657
+ const parsed = JSON.parse(text);
341658
+ parsed.attachment_id = attachmentId;
341659
+ parsed.image_input_channel = "user-image";
341660
+ parsed.inspect_next = { tool: "image_inspect", actions: ["source_info", "crop"], max_scale: 4 };
341661
+ return JSON.stringify(parsed, null, 2);
341662
+ } catch {
341663
+ return text;
341664
+ }
341665
+ }
341603
341666
  function visualFallbackImageInput(agent, name50, text) {
341604
- if (name50 !== "computer_use" && name50 !== "browser_use" && name50 !== "pdf_read") return {};
341667
+ if (name50 !== "screen_capture" && name50 !== "computer_use" && name50 !== "browser_use" && name50 !== "pdf_read") return {};
341605
341668
  const model = agent.activeModelConfig();
341606
341669
  if (!model?.vision) return {};
341607
341670
  try {
@@ -341727,7 +341790,7 @@ async function executeNewmarkTool(agent, name50, args, inputSchema, signal) {
341727
341790
  actorId: agent.runtimeActorId,
341728
341791
  workspaceId: terminalTakeoverWorkspaceId(wsDir),
341729
341792
  backend: process.env.NEWMARK_WSL_DISTRO ? "wsl" : process.platform === "win32" ? "windows" : process.platform,
341730
- allowEphemeralVisionImage: (name50 === "computer_use" || name50 === "browser_use" || name50 === "pdf_read" || name50 === "ocr_read") && !!agent.activeModelConfig()?.vision,
341793
+ allowEphemeralVisionImage: (name50 === "screen_capture" || name50 === "computer_use" || name50 === "browser_use" || name50 === "pdf_read" || name50 === "ocr_read") && !!agent.activeModelConfig()?.vision,
341731
341794
  signal
341732
341795
  });
341733
341796
  if (signal?.aborted) throw abortError4();
@@ -344870,6 +344933,7 @@ var Agent4 = class _Agent {
344870
344933
  memoryLabRebuildState = "idle";
344871
344934
  memoryLabRebuildError = "";
344872
344935
  displayImageDescriptionCache = /* @__PURE__ */ new Map();
344936
+ latestCapturedImageInputs = [];
344873
344937
  activeProcessAbortController = null;
344874
344938
  automationManager = null;
344875
344939
  activeAgentKernelRuntime = null;
@@ -347067,6 +347131,13 @@ ${String(event.toolArgs || "")}`;
347067
347131
  listConversationStates() {
347068
347132
  return this.listWorkspaceConversationStates(this.workspace.current);
347069
347133
  }
347134
+ registerCapturedImageInput(dataUrl, name50 = "active-screenshot.jpg") {
347135
+ if (!String(dataUrl || "").startsWith("data:image/")) return null;
347136
+ const prepared = this.prepareSubmittedConversationImages([{ dataUrl, name: name50, type: dataUrl.slice(5, dataUrl.indexOf(";")) }]);
347137
+ const attachment = prepared.attachments[0] || null;
347138
+ this.latestCapturedImageInputs = attachment ? [attachment] : [];
347139
+ return attachment;
347140
+ }
347070
347141
  subagentConcurrencyLimit() {
347071
347142
  return this.intelligence === "ultra" ? 16 : 4;
347072
347143
  }
@@ -351984,6 +352055,13 @@ ${items.map((item) => this.formatAutomation(item)).join("\n")}`;
351984
352055
  }
351985
352056
  latestSubmittedImages(attachmentId = "") {
351986
352057
  const normalizedId = String(attachmentId || "").trim();
352058
+ const captured = hydrateConversationImageAttachments(this.rootPath, this.latestCapturedImageInputs).flatMap((attachment) => attachment.dataUrl ? [{ id: attachment.id, dataUrl: attachment.dataUrl }] : []);
352059
+ if (normalizedId) {
352060
+ const capturedMatch = captured.find((item) => item.id === normalizedId);
352061
+ if (capturedMatch) return [capturedMatch];
352062
+ } else if (captured.length) {
352063
+ return captured;
352064
+ }
351987
352065
  for (let index = this.chatMessages.length - 1; index >= 0; index -= 1) {
351988
352066
  const message = this.chatMessages[index];
351989
352067
  if (message?.role !== "user") continue;
@@ -353168,6 +353246,155 @@ var ConversationKernel = class {
353168
353246
  followUp: queued?.followUp.slice() || []
353169
353247
  };
353170
353248
  }
353249
+ queueItems(target) {
353250
+ const runtime = this.findRuntime(target);
353251
+ if (!runtime) return [];
353252
+ return runtime.pendingNextTurn.flatMap((item) => {
353253
+ if (item.queueMode !== "followUp") return [];
353254
+ if (typeof item.message === "string") return [];
353255
+ const id = String(item.message.clientMessageId || "");
353256
+ if (!id) return [];
353257
+ return [{
353258
+ id,
353259
+ text: String(item.message.visibleUserInput || item.message.text || "").replace(/^\[Next queued while current turn is running\]\n/, ""),
353260
+ queueMode: item.queueMode,
353261
+ requestedMode: item.message.visibleMode,
353262
+ goalObjective: item.message.goalObjective,
353263
+ runId: item.message.runId,
353264
+ createdAt: String(item.message.createdAt || "")
353265
+ }];
353266
+ });
353267
+ }
353268
+ enqueueNext(target, input2) {
353269
+ const runtime = this.findRuntime(target);
353270
+ if (!runtime?.activePromise || !runtime.runId) throw new Error("Target conversation is not running");
353271
+ const id = String(input2.id || "").trim().slice(0, 200);
353272
+ const text = String(input2.text || "").trim();
353273
+ if (!id || !text) throw new Error("Queue item id and text are required");
353274
+ const existing = this.queueItems(runtime.target).find((item) => item.id === id);
353275
+ if (existing) return existing;
353276
+ const prompt = `[Next queued while current turn is running]
353277
+ ${text}`;
353278
+ const createdAt = String(input2.createdAt || (/* @__PURE__ */ new Date()).toISOString());
353279
+ runtime.pendingNextTurn.push({
353280
+ message: {
353281
+ text: prompt,
353282
+ visibleUserInput: text,
353283
+ visibleMode: String(input2.requestedMode || "build"),
353284
+ goalObjective: String(input2.goalObjective || "") || void 0,
353285
+ clientMessageId: id,
353286
+ runId: runtime.runId,
353287
+ createdAt
353288
+ },
353289
+ queueMode: "followUp"
353290
+ });
353291
+ runtime.runner.retainConversationContinuations([{
353292
+ content: prompt,
353293
+ queueMode: "followUp",
353294
+ clientMessageId: id,
353295
+ runId: runtime.runId,
353296
+ createdAt
353297
+ }]);
353298
+ this.trackQueuedMessage(runtime, prompt, "followUp");
353299
+ this.emitQueueUpdate(runtime);
353300
+ return this.queueItems(runtime.target).find((item) => item.id === id);
353301
+ }
353302
+ updateQueueItem(target, idInput, textInput) {
353303
+ const runtime = this.findRuntime(target);
353304
+ if (!runtime) throw new Error("Target conversation runtime is unavailable");
353305
+ const id = String(idInput || "").trim();
353306
+ const text = String(textInput || "").trim();
353307
+ if (!id || !text) throw new Error("Queue item id and text are required");
353308
+ const pending3 = runtime.pendingNextTurn.find((item) => typeof item.message !== "string" && item.message.clientMessageId === id);
353309
+ if (!pending3 || typeof pending3.message === "string") throw new Error("Queue item is no longer editable");
353310
+ const oldPrompt = pending3.message.text;
353311
+ pending3.message.text = `[Next queued while current turn is running]
353312
+ ${text}`;
353313
+ pending3.message.visibleUserInput = text;
353314
+ runtime.runner.consumeConversationContinuation({ content: oldPrompt, queueMode: pending3.queueMode, clientMessageId: id });
353315
+ runtime.runner.retainConversationContinuations([{
353316
+ content: pending3.message.text,
353317
+ queueMode: pending3.queueMode,
353318
+ clientMessageId: id,
353319
+ runId: pending3.message.runId
353320
+ }]);
353321
+ this.replaceTrackedQueuedMessage(runtime, oldPrompt, pending3.message.text, pending3.queueMode);
353322
+ this.emitQueueUpdate(runtime);
353323
+ return this.queueItems(runtime.target).find((item) => item.id === id);
353324
+ }
353325
+ deleteQueueItem(target, idInput) {
353326
+ const runtime = this.findRuntime(target);
353327
+ if (!runtime) return false;
353328
+ const id = String(idInput || "").trim();
353329
+ const index = runtime.pendingNextTurn.findIndex((item) => typeof item.message !== "string" && item.message.clientMessageId === id);
353330
+ if (index < 0) return false;
353331
+ const [removed] = runtime.pendingNextTurn.splice(index, 1);
353332
+ if (typeof removed.message !== "string") {
353333
+ runtime.runner.consumeConversationContinuation({ content: removed.message.text, queueMode: removed.queueMode, clientMessageId: id });
353334
+ this.consumeQueuedMessage(runtime, removed.message.text);
353335
+ }
353336
+ this.emitQueueUpdate(runtime);
353337
+ return true;
353338
+ }
353339
+ setQueuePaused(target, paused) {
353340
+ const runtime = this.findRuntime(target);
353341
+ if (!runtime) throw new Error("Target conversation runtime is unavailable");
353342
+ runtime.queuePaused = paused;
353343
+ this.emitQueueUpdate(runtime);
353344
+ if (!paused && !runtime.activePromise && runtime.pendingNextTurn.length) {
353345
+ this.schedulePendingRuntimeContinuation(runtime, runtime.runId);
353346
+ }
353347
+ return runtime.queuePaused;
353348
+ }
353349
+ queueAction(target, action, input2 = {}) {
353350
+ const runtime = this.findRuntime(target);
353351
+ if (!runtime) throw new Error("Target conversation runtime is unavailable");
353352
+ let receipt;
353353
+ if (action === "enqueue") {
353354
+ this.enqueueNext(runtime.target, {
353355
+ id: String(input2.id || ""),
353356
+ text: String(input2.text || ""),
353357
+ requestedMode: input2.requestedMode,
353358
+ goalObjective: input2.goalObjective,
353359
+ createdAt: input2.createdAt
353360
+ });
353361
+ } else if (action === "update") {
353362
+ this.updateQueueItem(runtime.target, String(input2.id || ""), String(input2.text || ""));
353363
+ } else if (action === "delete") {
353364
+ if (!this.deleteQueueItem(runtime.target, String(input2.id || ""))) throw new Error("Queue item was not found");
353365
+ } else if (action === "toggle_pause") {
353366
+ this.setQueuePaused(runtime.target, !runtime.queuePaused);
353367
+ } else if (action === "guide") {
353368
+ const item = this.queueItems(runtime.target).find((entry) => entry.id === String(input2.id || ""));
353369
+ if (!item) throw new Error("Queue item was not found");
353370
+ receipt = this.enqueueGuide({
353371
+ clientMessageId: item.id,
353372
+ guideId: (0, import_crypto16.randomUUID)(),
353373
+ target: runtime.target,
353374
+ runId: runtime.runId,
353375
+ deliveryMode: "steer",
353376
+ text: item.goalObjective ? `Goal for the current Build:
353377
+ ${item.goalObjective}` : item.text,
353378
+ goalObjective: item.goalObjective,
353379
+ createdAt: item.createdAt || (/* @__PURE__ */ new Date()).toISOString()
353380
+ });
353381
+ if (receipt.status === "rejected") return {
353382
+ ok: false,
353383
+ queueItems: this.queueItems(runtime.target),
353384
+ queuePaused: runtime.queuePaused,
353385
+ queued: this.queued(runtime.target),
353386
+ receipt
353387
+ };
353388
+ this.deleteQueueItem(runtime.target, item.id);
353389
+ }
353390
+ return {
353391
+ ok: true,
353392
+ queueItems: this.queueItems(runtime.target),
353393
+ queuePaused: runtime.queuePaused,
353394
+ queued: this.queued(runtime.target),
353395
+ receipt
353396
+ };
353397
+ }
353171
353398
  events(target) {
353172
353399
  return this.findRuntime(target)?.events.slice() || [];
353173
353400
  }
@@ -353196,6 +353423,8 @@ var ConversationKernel = class {
353196
353423
  workRuns: this.bindWorkRunsToRuntimeTarget(conversationSnapshot.workRuns, normalized),
353197
353424
  target: normalized,
353198
353425
  queued: this.queued(normalized),
353426
+ queueItems: this.queueItems(normalized),
353427
+ queuePaused: runtime?.queuePaused === true,
353199
353428
  workEvents: this.events(normalized),
353200
353429
  runtime: this.runtimeState(normalized),
353201
353430
  mode: runner.mode,
@@ -353631,7 +353860,7 @@ var ConversationKernel = class {
353631
353860
  if (runtime.stopRequestedRunId === runId) {
353632
353861
  stopped = true;
353633
353862
  this.settleCooperativeStop(runtime, runId);
353634
- } else if (runtime.pendingNextTurn.length > 0) {
353863
+ } else if (!runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
353635
353864
  this.schedulePendingRuntimeContinuation(runtime, runId);
353636
353865
  }
353637
353866
  }
@@ -353666,7 +353895,7 @@ var ConversationKernel = class {
353666
353895
  return this.result(runtime, lastTokens);
353667
353896
  }
353668
353897
  for (; ; ) {
353669
- while (runtime.pendingNextTurn.length > 0) {
353898
+ while (!runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
353670
353899
  if (runtime.stopRequestedRunId === runtime.runId) return this.result(runtime, lastTokens);
353671
353900
  const next = runtime.pendingNextTurn.shift();
353672
353901
  if (next.queueMode === "steer" && typeof next.message !== "string" && !!next.message.clientMessageId) {
@@ -353708,11 +353937,11 @@ ${batchText}`,
353708
353937
  this.mirrorHostIfTargetActive(runtime);
353709
353938
  return this.result(runtime, lastTokens);
353710
353939
  }
353711
- this.clearQueued(runtime);
353940
+ if (!runtime.pendingNextTurn.length) this.clearQueued(runtime);
353712
353941
  const completedRunId = runtime.runId;
353713
353942
  runtime.runner.finishConversationWorkRun(completedRunId, "completed");
353714
353943
  await new Promise((resolve16) => setImmediate(resolve16));
353715
- if (runtime.runId === completedRunId && runtime.stopRequestedRunId !== completedRunId && runtime.pendingNextTurn.length > 0) {
353944
+ if (runtime.runId === completedRunId && runtime.stopRequestedRunId !== completedRunId && !runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
353716
353945
  runtime.guideAcceptanceClosedRunId = "";
353717
353946
  if (!runtime.runner.resumeConversationWorkRun(completedRunId)) {
353718
353947
  throw new Error(`Unable to resume deferred Guide work run ${completedRunId}`);
@@ -353803,6 +354032,7 @@ Review this persisted peer result and summarize or continue the parent task as n
353803
354032
  events: [],
353804
354033
  pendingNextTurn: [],
353805
354034
  queued: { steering: [], followUp: [] },
354035
+ queuePaused: false,
353806
354036
  runId: "",
353807
354037
  generation: this.generations.get(target.runtimeKey) || 0,
353808
354038
  stopRequestedRunId: "",
@@ -353898,7 +354128,7 @@ Review this persisted peer result and summarize or continue the parent task as n
353898
354128
  }
353899
354129
  setImmediate(() => {
353900
354130
  runtime.pendingContinuationRunId = void 0;
353901
- if (runtime.runId !== runId || runtime.activePromise || runtime.stopRequestedRunId === runId) return;
354131
+ if (runtime.runId !== runId || runtime.activePromise || runtime.stopRequestedRunId === runId || runtime.queuePaused) return;
353902
354132
  const next = runtime.pendingNextTurn.shift();
353903
354133
  if (!next) return;
353904
354134
  const message = typeof next.message === "string" ? { text: next.message, runId } : { ...next.message, runId: next.message.runId || runId };
@@ -354049,7 +354279,36 @@ Review this persisted peer result and summarize or continue the parent task as n
354049
354279
  const text = typeof message === "string" ? message : message.text;
354050
354280
  const prompt = isSteer ? text : `[Next queued while current turn is running]
354051
354281
  ${text}`;
354052
- if (!isSteer) this.trackQueuedMessage(runtime, prompt, queueMode);
354282
+ if (!isSteer) {
354283
+ const structured = typeof message === "string" ? null : message;
354284
+ const clientMessageId = String(structured?.clientMessageId || (0, import_crypto16.randomUUID)());
354285
+ const queuedMessage = {
354286
+ ...structured || {},
354287
+ text: prompt,
354288
+ visibleUserInput: structured?.visibleUserInput || text,
354289
+ visibleMode: structured?.visibleMode || runtime.options.mode,
354290
+ clientMessageId,
354291
+ runId: structured?.runId || runtime.runId,
354292
+ createdAt: String(structured?.createdAt || (/* @__PURE__ */ new Date()).toISOString())
354293
+ };
354294
+ if (!runtime.pendingNextTurn.some((item) => typeof item.message !== "string" && item.message.clientMessageId === clientMessageId)) {
354295
+ runtime.pendingNextTurn.push({ message: queuedMessage, queueMode: "followUp" });
354296
+ }
354297
+ runtime.runner.retainConversationContinuations([{
354298
+ content: prompt,
354299
+ queueMode: "followUp",
354300
+ clientMessageId,
354301
+ runId: queuedMessage.runId,
354302
+ images: queuedMessage.images?.map((image) => ({ ...image })),
354303
+ attachments: queuedMessage.attachments?.map((attachment) => ({ ...attachment })),
354304
+ createdAt: queuedMessage.createdAt
354305
+ }]);
354306
+ this.trackQueuedMessage(runtime, prompt, "followUp");
354307
+ runtime.runner.recordWorkStatus(runtime.stopRequestedRunId === runtime.runId ? "Next message retained while stopping." : "Next message queued.");
354308
+ if (runtime.stopRequestedRunId === runtime.runId) runtime.forceStopArmedRunId = "";
354309
+ this.emitQueueUpdate(runtime);
354310
+ return;
354311
+ }
354053
354312
  if (runtime.stopRequestedRunId === runtime.runId) {
354054
354313
  runtime.forceStopArmedRunId = "";
354055
354314
  const structured = typeof message === "string" ? void 0 : message;
@@ -354095,6 +354354,12 @@ ${text}`;
354095
354354
  }
354096
354355
  if (changed) this.emitQueueUpdate(runtime);
354097
354356
  }
354357
+ replaceTrackedQueuedMessage(runtime, oldMessage, nextMessage, queueMode) {
354358
+ this.queueState(runtime);
354359
+ const list = queueMode === "steer" ? runtime.queued.steering : runtime.queued.followUp;
354360
+ const index = list.indexOf(oldMessage);
354361
+ if (index >= 0) list[index] = nextMessage;
354362
+ }
354098
354363
  emitQueueUpdate(runtime) {
354099
354364
  this.queueState(runtime);
354100
354365
  runtime.runner.emitWorkEvent({
@@ -354216,9 +354481,10 @@ ${text}`;
354216
354481
  const runId = runtime.runId;
354217
354482
  await Promise.resolve();
354218
354483
  if (runtime.runId !== runId || runtime.stopRequestedRunId === runId) return true;
354219
- if (runtime.pendingNextTurn.length > 0 || runtime.runner.subagents.readRootInbox().length > 0) return false;
354484
+ const hasSteering = runtime.pendingNextTurn.some((item) => item.queueMode === "steer");
354485
+ if (hasSteering || runtime.runner.subagents.readRootInbox().length > 0) return false;
354220
354486
  runtime.guideAcceptanceClosedRunId = runId;
354221
- if (runtime.pendingNextTurn.length > 0 || runtime.runner.subagents.readRootInbox().length > 0) {
354487
+ if (runtime.pendingNextTurn.some((item) => item.queueMode === "steer") || runtime.runner.subagents.readRootInbox().length > 0) {
354222
354488
  runtime.guideAcceptanceClosedRunId = "";
354223
354489
  return false;
354224
354490
  }
@@ -354429,6 +354695,9 @@ async function handle(request) {
354429
354695
  target
354430
354696
  });
354431
354697
  }
354698
+ if (request.method === "queue_action") {
354699
+ return kernel.queueAction(requestTarget(request.params), request.params.action, request.params.input);
354700
+ }
354432
354701
  if (request.method === "checkpoint") return kernel.checkpoint(requestTarget(request.params));
354433
354702
  if (request.method === "context_compress") {
354434
354703
  return kernel.compressContext(requestTarget(request.params), request.params.options);
@@ -192,6 +192,9 @@ async function handle(request) {
192
192
  target,
193
193
  });
194
194
  }
195
+ if (request.method === 'queue_action') {
196
+ return kernel.queueAction(requestTarget(request.params), request.params.action, request.params.input);
197
+ }
195
198
  if (request.method === 'checkpoint')
196
199
  return kernel.checkpoint(requestTarget(request.params));
197
200
  if (request.method === 'context_compress') {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "newmark-agent",
3
3
  "productName": "Newmark Agent",
4
- "version": "0.4.7",
4
+ "version": "0.4.8",
5
5
  "description": "Newmark Agent — Portable AI coding agent with rich GUI and CLI (TypeScript)",
6
6
  "homepage": "https://github.com/positer/Newmark-Agent",
7
7
  "repository": {
@@ -53,7 +53,7 @@
53
53
  "test:desktop": "npm run build && npm run test:desktop:built",
54
54
  "test:deletion-safety": "npm run build && npm run test:deletion-safety:built",
55
55
  "test:deletion-safety:built": "node scripts/deletion-safety-stress.cjs",
56
- "test:desktop:built": "node dist/tests/verify.js && node dist/tests/thinkingTierMapCacheStressVerify.js && node dist/tests/computerUseSessionVerify.js && node dist/tests/contextSystemV2Verify.js && node dist/tests/contextSystemV2StressVerify.js && node dist/tests/providerAdapterV2Verify.js && node dist/tests/providerTimeoutRecoveryVerify.js && node dist/tests/agentRuntimeV2Verify.js && node dist/tests/toolchainExposureV2Verify.js && node dist/tests/localOcrFallbackVerify.js && node dist/tests/dev018ModeSubagentStressVerify.js && node dist/tests/conversationBranchStressVerify.js && node dist/tests/conversationArchiveConcurrencyVerify.js && node dist/tests/conversationArchiveRuntimeVerify.js && node dist/tests/dev040ComprehensiveStressVerify.js && node dist/tests/memoryPolicyVerify.js && node dist/tests/newmarkSelectVerify.js && node dist/tests/mcpManagerVerify.js && node dist/tests/dshCompatibilityVerify.js && node dist/tests/performanceOptimizationVerify.js && node scripts/compression-pressure-stress.cjs && node dist/tests/compressionFidelityVerify.js && node dist/tests/responseTrajectoryVerify.js && node dist/tests/normalChatRegressionVerify.js && node dist/tests/dev008-subagent.js && node dist/tests/dev009Verify.js && node dist/tests/runtimeIsolationVerify.js && node dist/tests/runtimePoolCapacityVerify.js && node dist/tests/guideWorkRunVerify.js && node dist/tests/modelSwitchBehaviorVerify.js && node scripts/flow-pause-stop-draft-stress.cjs && node dist/tests/guideUiReconcileVerify.js && node dist/tests/queueAttachmentIsolationVerify.js && node dist/tests/workspaceMenuVerify.js && node dist/tests/userImagePersistenceVerify.js && node dist/tests/displayImageVerify.js && node dist/tests/visualPreferencesVerify.js && node dist/tests/browserUseVerify.js && node dist/tests/toolProcessVerify.js && node dist/tests/toolProvisioningVerify.js && node dist/tests/taskToolsVerify.js && node dist/tests/contextCacheHitStressVerify.js && node dist/tests/startupPrewarmVerify.js && node dist/tests/pdfPreviewServerVerify.js && node dist/tests/editorLifecycleVerify.js && node dist/tests/terminalTakeoverVerify.js && node dist/tests/workspaceFileRouterVerify.js && node dist/tests/computerUsePerformanceVerify.js && node dist/tests/autoRouterVerify.js && node dist/tests/autoAgentIntegrationVerify.js && node dist/tests/autoRouteRatingVerify.js && node dist/tests/providerIdentityVerify.js && node dist/tests/modelValidationVerify.js && node dist/tests/modelValidationAgentIntegrationVerify.js && node scripts/deletion-safety-stress.cjs",
56
+ "test:desktop:built": "node dist/tests/verify.js && node dist/tests/thinkingTierMapCacheStressVerify.js && node dist/tests/computerUseSessionVerify.js && node dist/tests/contextSystemV2Verify.js && node dist/tests/contextSystemV2StressVerify.js && node dist/tests/providerAdapterV2Verify.js && node dist/tests/providerTimeoutRecoveryVerify.js && node dist/tests/agentRuntimeV2Verify.js && node dist/tests/toolchainExposureV2Verify.js && node dist/tests/localOcrFallbackVerify.js && node dist/tests/dev018ModeSubagentStressVerify.js && node dist/tests/conversationBranchStressVerify.js && node dist/tests/conversationArchiveConcurrencyVerify.js && node dist/tests/conversationArchiveRuntimeVerify.js && node dist/tests/dev040ComprehensiveStressVerify.js && node dist/tests/memoryPolicyVerify.js && node dist/tests/newmarkSelectVerify.js && node dist/tests/mcpManagerVerify.js && node dist/tests/dshCompatibilityVerify.js && node dist/tests/performanceOptimizationVerify.js && node scripts/compression-pressure-stress.cjs && node dist/tests/compressionFidelityVerify.js && node dist/tests/responseTrajectoryVerify.js && node dist/tests/normalChatRegressionVerify.js && node dist/tests/dev008-subagent.js && node dist/tests/dev009Verify.js && node dist/tests/runtimeIsolationVerify.js && node dist/tests/runtimePoolCapacityVerify.js && node dist/tests/guideWorkRunVerify.js && node dist/tests/modelSwitchBehaviorVerify.js && node scripts/flow-pause-stop-draft-stress.cjs && node dist/tests/guideUiReconcileVerify.js && node dist/tests/queueAttachmentIsolationVerify.js && node dist/tests/workspaceMenuVerify.js && node dist/tests/userImagePersistenceVerify.js && node dist/tests/displayImageVerify.js && node dist/tests/visualPreferencesVerify.js && node dist/tests/browserUseVerify.js && node dist/tests/toolProcessVerify.js && node dist/tests/toolProvisioningVerify.js && node dist/tests/taskToolsVerify.js && node dist/tests/contextCacheHitStressVerify.js && node dist/tests/startupPrewarmVerify.js && node dist/tests/pdfPreviewServerVerify.js && node dist/tests/editorLifecycleVerify.js && node dist/tests/terminalTakeoverVerify.js && node dist/tests/workspaceFileRouterVerify.js && node dist/tests/screenCaptureIndependentVerify.js && node dist/tests/computerUsePerformanceVerify.js && node dist/tests/autoRouterVerify.js && node dist/tests/autoAgentIntegrationVerify.js && node dist/tests/autoRouteRatingVerify.js && node dist/tests/providerIdentityVerify.js && node dist/tests/modelValidationVerify.js && node dist/tests/modelValidationAgentIntegrationVerify.js && node scripts/deletion-safety-stress.cjs",
57
57
  "test:conversation-branch-stress": "npm run build && node dist/tests/conversationBranchStressVerify.js",
58
58
  "test:conversation-archive-concurrency": "npm run build && node dist/tests/conversationArchiveConcurrencyVerify.js",
59
59
  "test:memory-policy": "npm run build && node dist/tests/memoryPolicyVerify.js",