newmark-agent 0.4.7 → 0.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/conversation-utility-host.bundle.cjs +407 -36
- package/dist/conversation-utility-host.js +3 -0
- package/dist/core/agent.d.ts +3 -0
- package/dist/core/agent.js +122 -10
- package/dist/core/agentKernelRunner.js +28 -11
- package/dist/core/autoRouter.d.ts +1 -1
- package/dist/core/autoRouter.js +16 -7
- package/dist/core/conversationKernel.d.ts +43 -0
- package/dist/core/conversationKernel.js +262 -8
- package/dist/core/electronUtilityAgentClient.d.ts +2 -0
- package/dist/core/electronUtilityAgentClient.js +5 -1
- package/dist/core/electronUtilityRuntimePool.d.ts +3 -0
- package/dist/core/electronUtilityRuntimePool.js +11 -0
- package/dist/core/toolPolicy.js +3 -0
- package/dist/core/utilityAgentProtocol.d.ts +23 -1
- package/dist/core/utilityHostToolRouter.js +18 -0
- package/dist/core/wslAgentClient.d.ts +2 -0
- package/dist/core/wslAgentClient.js +5 -1
- package/dist/core/wslAgentProtocol.d.ts +12 -1
- package/dist/core/wslAgentRuntimePool.d.ts +3 -0
- package/dist/core/wslAgentRuntimePool.js +11 -0
- package/dist/main.js +226 -13
- package/dist/preload.js +2 -0
- package/dist/server.d.ts +47 -1
- package/dist/server.js +304 -38
- package/dist/tools/index.js +46 -1
- package/dist/tools/nativeTools.js +1 -0
- package/dist/ui/index.html +150 -14
- package/dist/wsl-agent-host.bundle.cjs +407 -36
- package/dist/wsl-agent-host.js +3 -0
- package/package.json +5 -2
|
@@ -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) {
|
|
@@ -340938,7 +340987,7 @@ async function runAgentKernel(agent) {
|
|
|
340938
340987
|
return;
|
|
340939
340988
|
}
|
|
340940
340989
|
const publicError = normalizePublicProviderError(error, [currentAgent.activeModelConfig()?.api_key]);
|
|
340941
|
-
if (/\b402\b|insufficient balance|insufficient funds|payment required
|
|
340990
|
+
if (/\b402\b|insufficient balance|insufficient funds|payment required|insufficient[_ -]?quota|quota (?:exceeded|exhausted)|credit(?:s| balance)? (?:exhausted|depleted)|billing hard limit|budget exhausted|余额不足|额度不足|配额(?:不足|耗尽|超限)/i.test(publicError)) {
|
|
340942
340991
|
currentAgent.noteProviderBalanceFailure();
|
|
340943
340992
|
}
|
|
340944
340993
|
const final = assistantMessage2(model, [{ type: "text", text: `[Error] ${publicError}` }], "error");
|
|
@@ -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 (
|
|
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();
|
|
@@ -342992,8 +343055,8 @@ function classifyRouteFailure(error) {
|
|
|
342992
343055
|
if (statusCode === 400 || /bad request|invalid parameter|invalid request/i.test(text)) {
|
|
342993
343056
|
return { type: "invalid_request", retryable: false, switchAllowed: false, statusCode };
|
|
342994
343057
|
}
|
|
342995
|
-
if (statusCode === 402 || /insufficient balance|insufficient funds|payment required
|
|
342996
|
-
return { type: "balance_exhausted", retryable: false, switchAllowed:
|
|
343058
|
+
if (statusCode === 402 || /insufficient balance|insufficient funds|payment required|insufficient[_ -]?quota|quota (?:exceeded|exhausted)|credit(?:s| balance)? (?:exhausted|depleted)|billing hard limit|budget exhausted|余额不足|额度不足|配额(?:不足|耗尽|超限)/i.test(text)) {
|
|
343059
|
+
return { type: "balance_exhausted", retryable: false, switchAllowed: true, statusCode: statusCode || 402 };
|
|
342997
343060
|
}
|
|
342998
343061
|
if (statusCode === 429 || /rate limit|too many requests/i.test(text)) {
|
|
342999
343062
|
return { type: "rate_limited", retryable: true, switchAllowed: true, statusCode: 429, retryAfterMs };
|
|
@@ -343131,13 +343194,13 @@ var AutoRouter = class {
|
|
|
343131
343194
|
}
|
|
343132
343195
|
planAttempts(decision, candidates, failure) {
|
|
343133
343196
|
const current = decision.resolvedDeployment;
|
|
343134
|
-
if (!current || !failure.error.
|
|
343197
|
+
if (!current || !failure.error.switchAllowed || failure.streamCommitted || failure.sideEffectCommitted) return [];
|
|
343135
343198
|
const remainingAttempts = Math.max(0, 3 - decision.attempts.length);
|
|
343136
343199
|
if (!remainingAttempts) return [];
|
|
343137
343200
|
const attempts = [];
|
|
343138
343201
|
const retryDelayMs = failure.error.retryAfterMs ?? 250;
|
|
343139
343202
|
const alreadyRetriedCurrent = decision.attempts.some((attempt) => attempt.kind === "retry_same_deployment" && sameDeployment(attempt.deployment, current));
|
|
343140
|
-
if (!alreadyRetriedCurrent && retryDelayMs <= (decision.retryBudgetMs ?? 5e3)) {
|
|
343203
|
+
if (failure.error.retryable && !alreadyRetriedCurrent && retryDelayMs <= (decision.retryBudgetMs ?? 5e3)) {
|
|
343141
343204
|
attempts.push({
|
|
343142
343205
|
deployment: { ...current },
|
|
343143
343206
|
kind: "retry_same_deployment",
|
|
@@ -343158,11 +343221,16 @@ var AutoRouter = class {
|
|
|
343158
343221
|
const eligible = candidates.filter((candidate) => candidate.enabled && inScope(candidate.deployment, scope) && inSubset(candidate.deployment, subset) && !sameDeployment(candidate.deployment, current) && !attemptedDeployments.some((attempted) => sameDeployment(candidate.deployment, attempted)) && validationEligible(candidate, now2).length === 0 && this.passedInitialHardFilters(decision, candidate) && this.circuitState(candidate.deployment, now2, false) !== "open");
|
|
343159
343222
|
const equivalent = currentGroup ? eligible.find((candidate) => candidate.deployment.logicalModelGroupId === currentGroup && !candidate.fallbackOnly) : void 0;
|
|
343160
343223
|
const fallback = eligible.find((candidate) => candidate.fallbackOnly);
|
|
343161
|
-
|
|
343224
|
+
const rankedAlternates = decision.rankedCandidates.map((ranked) => eligible.find((candidate) => sameDeployment(candidate.deployment, ranked.deployment))).filter((candidate) => !!candidate && candidate !== equivalent && candidate !== fallback && !candidate.fallbackOnly);
|
|
343225
|
+
for (const candidate of eligible) {
|
|
343226
|
+
if (candidate === equivalent || candidate === fallback || candidate.fallbackOnly || rankedAlternates.some((existing) => sameDeployment(existing.deployment, candidate.deployment))) continue;
|
|
343227
|
+
rankedAlternates.push(candidate);
|
|
343228
|
+
}
|
|
343229
|
+
for (const next of [equivalent, fallback, ...rankedAlternates]) {
|
|
343162
343230
|
if (!next || attempts.length >= 2) continue;
|
|
343163
343231
|
attempts.push({
|
|
343164
343232
|
deployment: { ...next.deployment },
|
|
343165
|
-
kind: next === equivalent ? "equivalent_deployment" : "fallback_model",
|
|
343233
|
+
kind: next === equivalent ? "equivalent_deployment" : next === fallback ? "fallback_model" : "alternate_model",
|
|
343166
343234
|
status: "planned",
|
|
343167
343235
|
errorType: failure.error.type,
|
|
343168
343236
|
streamCommitted: false,
|
|
@@ -343405,7 +343473,7 @@ function percentile(values, fraction) {
|
|
|
343405
343473
|
}
|
|
343406
343474
|
function failureFromType(type) {
|
|
343407
343475
|
const retryable = type === "timeout" || type === "rate_limited" || type === "transport" || type === "server_error" || type === "empty_response";
|
|
343408
|
-
return { type, retryable, switchAllowed: retryable };
|
|
343476
|
+
return { type, retryable, switchAllowed: retryable || type === "balance_exhausted" };
|
|
343409
343477
|
}
|
|
343410
343478
|
|
|
343411
343479
|
// src/context/services/agent-context-manager.ts
|
|
@@ -344870,6 +344938,7 @@ var Agent4 = class _Agent {
|
|
|
344870
344938
|
memoryLabRebuildState = "idle";
|
|
344871
344939
|
memoryLabRebuildError = "";
|
|
344872
344940
|
displayImageDescriptionCache = /* @__PURE__ */ new Map();
|
|
344941
|
+
latestCapturedImageInputs = [];
|
|
344873
344942
|
activeProcessAbortController = null;
|
|
344874
344943
|
automationManager = null;
|
|
344875
344944
|
activeAgentKernelRuntime = null;
|
|
@@ -345510,7 +345579,9 @@ var Agent4 = class _Agent {
|
|
|
345510
345579
|
}
|
|
345511
345580
|
updateProviders(value) {
|
|
345512
345581
|
const before = this.config.providers();
|
|
345513
|
-
|
|
345582
|
+
const merged = mergeProviderSecrets(value, before);
|
|
345583
|
+
resetEditedModelValidationEvidence(merged, before);
|
|
345584
|
+
this.config.set("models", "providers", merged);
|
|
345514
345585
|
const after = this.config.providers();
|
|
345515
345586
|
const beforeById = new Map(before.map((provider) => [provider.id, provider]));
|
|
345516
345587
|
const afterById = new Map(after.map((provider) => [provider.id, provider]));
|
|
@@ -347067,6 +347138,13 @@ ${String(event.toolArgs || "")}`;
|
|
|
347067
347138
|
listConversationStates() {
|
|
347068
347139
|
return this.listWorkspaceConversationStates(this.workspace.current);
|
|
347069
347140
|
}
|
|
347141
|
+
registerCapturedImageInput(dataUrl, name50 = "active-screenshot.jpg") {
|
|
347142
|
+
if (!String(dataUrl || "").startsWith("data:image/")) return null;
|
|
347143
|
+
const prepared = this.prepareSubmittedConversationImages([{ dataUrl, name: name50, type: dataUrl.slice(5, dataUrl.indexOf(";")) }]);
|
|
347144
|
+
const attachment = prepared.attachments[0] || null;
|
|
347145
|
+
this.latestCapturedImageInputs = attachment ? [attachment] : [];
|
|
347146
|
+
return attachment;
|
|
347147
|
+
}
|
|
347070
347148
|
subagentConcurrencyLimit() {
|
|
347071
347149
|
return this.intelligence === "ultra" ? 16 : 4;
|
|
347072
347150
|
}
|
|
@@ -347589,6 +347667,19 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
347589
347667
|
this.writeStoredConversationState(stored, targetWs);
|
|
347590
347668
|
return true;
|
|
347591
347669
|
}
|
|
347670
|
+
reorderConversationContinuations(orderedIds) {
|
|
347671
|
+
const currentIds = this.continuations.filter((item) => item.queueMode === "followUp" && !!item.clientMessageId).map((item) => String(item.clientMessageId));
|
|
347672
|
+
const completeOrder = orderedIds.length === currentIds.length && new Set(orderedIds).size === orderedIds.length && orderedIds.every((id) => currentIds.includes(id));
|
|
347673
|
+
if (!completeOrder) throw new Error("A complete queue order with unique current item ids is required");
|
|
347674
|
+
const byId = new Map(this.continuations.flatMap((item) => item.queueMode === "followUp" && item.clientMessageId ? [[String(item.clientMessageId), item]] : []));
|
|
347675
|
+
let nextIndex = 0;
|
|
347676
|
+
this.continuations = this.continuations.map((item) => {
|
|
347677
|
+
if (item.queueMode !== "followUp" || !item.clientMessageId) return item;
|
|
347678
|
+
return byId.get(orderedIds[nextIndex++]);
|
|
347679
|
+
});
|
|
347680
|
+
this.saveWorkspaceConversationState(true);
|
|
347681
|
+
return this.conversationContinuations();
|
|
347682
|
+
}
|
|
347592
347683
|
renameConversation(id, title, ws = this.workspace.current) {
|
|
347593
347684
|
const targetWs = ws || this.workspace.current;
|
|
347594
347685
|
if (!targetWs) return false;
|
|
@@ -350394,6 +350485,9 @@ ${msg.content}
|
|
|
350394
350485
|
const fallbackEnabled = this.config.getBool("models", "fallback_on_unavailable");
|
|
350395
350486
|
const observedFailure = classifyRouteFailure(errorText);
|
|
350396
350487
|
const observedDeployment = this.activeDeployment();
|
|
350488
|
+
if (observedFailure.type === "balance_exhausted" && observedDeployment) {
|
|
350489
|
+
this.providerBalanceBlockedUntilByDeployment.set(deploymentIdentity(observedDeployment), Date.now() + 5 * 6e4);
|
|
350490
|
+
}
|
|
350397
350491
|
const previousAttempt = observedDeployment && this.lastRouteDecision ? [...this.lastRouteDecision.attempts].reverse().find((attempt) => deploymentIdentity(attempt.deployment) === deploymentIdentity(observedDeployment)) : void 0;
|
|
350398
350492
|
if (this.model === "auto" && this.routeAttemptStartedAt === 0 && (this.lastRouteDecision?.finalStatus === "failed" || this.lastRouteDecision?.finalStatus === "blocked") && previousAttempt?.status === "failed" && previousAttempt.errorType === observedFailure.type) {
|
|
350399
350493
|
return null;
|
|
@@ -350444,14 +350538,12 @@ ${msg.content}
|
|
|
350444
350538
|
return current2.modelId;
|
|
350445
350539
|
}
|
|
350446
350540
|
if (!fallbackEnabled) return null;
|
|
350447
|
-
if (!observedFailure.
|
|
350541
|
+
if (!observedFailure.switchAllowed || this.routeStreamCommitted || this.routeSideEffectCommitted) return null;
|
|
350448
350542
|
const current = this.model;
|
|
350449
|
-
const
|
|
350543
|
+
const currentDeployment = observedDeployment;
|
|
350544
|
+
const all = this.scopedSwitchModels(current).filter((m2) => !currentDeployment || deploymentIdentity(this.deploymentRef(m2)) !== deploymentIdentity(currentDeployment));
|
|
350450
350545
|
if (!all.length) return null;
|
|
350451
|
-
const usable = all.filter((m2) =>
|
|
350452
|
-
const status = String(m2.evaluation?.status || "unknown").toLowerCase();
|
|
350453
|
-
return status !== "unavailable" && !status.startsWith("error");
|
|
350454
|
-
});
|
|
350546
|
+
const usable = all.filter((m2) => !this.isBalanceBlockedDeployment(this.deploymentRef(m2)) && !modelConfigIsUnavailable(m2));
|
|
350455
350547
|
if (!usable.length) return null;
|
|
350456
350548
|
const pref = this.config.autoSwitchPreference();
|
|
350457
350549
|
const ranked = [...usable].sort((a3, b2) => this.modelScore(b2, pref, false, false) - this.modelScore(a3, pref, false, false));
|
|
@@ -351127,7 +351219,7 @@ ${persisted.map((guide, index) => `Guide ${index + 1}: ${guide.text}`).join("\n"
|
|
|
351127
351219
|
throw e3;
|
|
351128
351220
|
}
|
|
351129
351221
|
const msg = e3 instanceof Error ? e3.message : String(e3);
|
|
351130
|
-
if (/\b402\b|insufficient balance|insufficient funds|payment required
|
|
351222
|
+
if (/\b402\b|insufficient balance|insufficient funds|payment required|insufficient[_ -]?quota|quota (?:exceeded|exhausted)|credit(?:s| balance)? (?:exhausted|depleted)|billing hard limit|budget exhausted|余额不足|额度不足|配额(?:不足|耗尽|超限)/i.test(msg)) {
|
|
351131
351223
|
this.noteProviderBalanceFailure();
|
|
351132
351224
|
}
|
|
351133
351225
|
this.status = "error";
|
|
@@ -351984,6 +352076,13 @@ ${items.map((item) => this.formatAutomation(item)).join("\n")}`;
|
|
|
351984
352076
|
}
|
|
351985
352077
|
latestSubmittedImages(attachmentId = "") {
|
|
351986
352078
|
const normalizedId = String(attachmentId || "").trim();
|
|
352079
|
+
const captured = hydrateConversationImageAttachments(this.rootPath, this.latestCapturedImageInputs).flatMap((attachment) => attachment.dataUrl ? [{ id: attachment.id, dataUrl: attachment.dataUrl }] : []);
|
|
352080
|
+
if (normalizedId) {
|
|
352081
|
+
const capturedMatch = captured.find((item) => item.id === normalizedId);
|
|
352082
|
+
if (capturedMatch) return [capturedMatch];
|
|
352083
|
+
} else if (captured.length) {
|
|
352084
|
+
return captured;
|
|
352085
|
+
}
|
|
351987
352086
|
for (let index = this.chatMessages.length - 1; index >= 0; index -= 1) {
|
|
351988
352087
|
const message = this.chatMessages[index];
|
|
351989
352088
|
if (message?.role !== "user") continue;
|
|
@@ -353028,11 +353127,63 @@ function routeProviderFingerprint(provider) {
|
|
|
353028
353127
|
enabled: provider.enabled,
|
|
353029
353128
|
models: (provider.models || []).map((model) => ({
|
|
353030
353129
|
name: model.name,
|
|
353130
|
+
display: model.display,
|
|
353131
|
+
description: model.description,
|
|
353132
|
+
maxTokens: model.max_tokens,
|
|
353133
|
+
vision: model.vision,
|
|
353134
|
+
thinking: !!model.thinking,
|
|
353135
|
+
imageOutput: !!model.image_output,
|
|
353031
353136
|
enabled: model.enabled !== false,
|
|
353032
|
-
|
|
353137
|
+
preview: !!model.preview,
|
|
353138
|
+
logicalModelGroupId: model.logical_model_group_id || "",
|
|
353139
|
+
privacy: model.privacy || [],
|
|
353140
|
+
capabilities: model.capabilities || [],
|
|
353141
|
+
supportedParameters: model.supported_parameters || [],
|
|
353142
|
+
routePreference: model.route_preference,
|
|
353143
|
+
fallbackOnly: !!model.fallback_only,
|
|
353144
|
+
thinkingTierMap: model.thinking_tier_map || {}
|
|
353033
353145
|
}))
|
|
353034
353146
|
});
|
|
353035
353147
|
}
|
|
353148
|
+
function modelConfigurationFingerprint(model) {
|
|
353149
|
+
const { validation, evaluation, _previous_name, previous_name, ...configuration } = model;
|
|
353150
|
+
void validation;
|
|
353151
|
+
void evaluation;
|
|
353152
|
+
void _previous_name;
|
|
353153
|
+
void previous_name;
|
|
353154
|
+
return JSON.stringify(configuration);
|
|
353155
|
+
}
|
|
353156
|
+
function resetEditedModelValidationEvidence(incomingProviders, existingProviders) {
|
|
353157
|
+
const existingById = new Map(existingProviders.map((provider) => [provider.id, provider]));
|
|
353158
|
+
const existingByName = new Map(existingProviders.map((provider) => [provider.name, provider]));
|
|
353159
|
+
for (const rawProvider of incomingProviders) {
|
|
353160
|
+
if (!rawProvider || typeof rawProvider !== "object" || Array.isArray(rawProvider)) continue;
|
|
353161
|
+
const provider = rawProvider;
|
|
353162
|
+
const previousProvider = existingById.get(String(provider.id || "")) || existingByName.get(String(provider._previous_name || provider.previous_name || provider.name || ""));
|
|
353163
|
+
const models = Array.isArray(provider.models) ? provider.models : [];
|
|
353164
|
+
const providerConnectionChanged = !!previousProvider && (String(provider.base_url || provider.endpoint || "") !== previousProvider.base_url || String(provider.protocol || "") !== previousProvider.protocol);
|
|
353165
|
+
for (const rawModel of models) {
|
|
353166
|
+
if (!rawModel || typeof rawModel !== "object" || Array.isArray(rawModel)) continue;
|
|
353167
|
+
const model = rawModel;
|
|
353168
|
+
const previousName = String(model._previous_name || model.previous_name || model.name || "");
|
|
353169
|
+
const previousModel = previousProvider?.models.find((candidate) => candidate.name === previousName);
|
|
353170
|
+
const edited = providerConnectionChanged || !!previousModel && modelConfigurationFingerprint(model) !== modelConfigurationFingerprint(previousModel);
|
|
353171
|
+
delete model._previous_name;
|
|
353172
|
+
delete model.previous_name;
|
|
353173
|
+
if (!edited) continue;
|
|
353174
|
+
model.validation = { level: "discovered", status: "degraded", checked_at: "", capabilities: {} };
|
|
353175
|
+
delete model.evaluation;
|
|
353176
|
+
model.speed_rating = "unknown";
|
|
353177
|
+
model.capability_rating = "unknown";
|
|
353178
|
+
}
|
|
353179
|
+
}
|
|
353180
|
+
}
|
|
353181
|
+
function modelConfigIsUnavailable(model) {
|
|
353182
|
+
const validationStatus = effectiveModelValidationStatus(model);
|
|
353183
|
+
if (model.validation?.level !== "discovered" && (validationStatus === "unavailable" || validationStatus === "auth_error" || validationStatus === "invalid_config")) return true;
|
|
353184
|
+
const evaluationStatus = validationStatus === "degraded" ? "degraded" : String(model.evaluation?.status || "").toLowerCase();
|
|
353185
|
+
return evaluationStatus === "unavailable" || evaluationStatus.startsWith("error");
|
|
353186
|
+
}
|
|
353036
353187
|
function parseDeploymentSelectionValue2(value) {
|
|
353037
353188
|
const marker = String(value || "").trim();
|
|
353038
353189
|
if (!marker.startsWith("deployment:")) return null;
|
|
@@ -353049,9 +353200,9 @@ function parseDeploymentSelectionValue2(value) {
|
|
|
353049
353200
|
function effectiveModelValidationStatus(model) {
|
|
353050
353201
|
const raw = String(model.validation?.status || "").toLowerCase();
|
|
353051
353202
|
if (raw === "auth_error") return raw;
|
|
353203
|
+
if (String(model.validation?.level || "").toLowerCase() === "discovered") return "degraded";
|
|
353052
353204
|
const textEvidence = model.validation?.capabilities?.text === true || model.validation?.capabilities?.text_input === true || model.validation?.capabilities?.text_output === true || model.evaluation?.text_input === true || model.evaluation?.text_output === true;
|
|
353053
353205
|
if (textEvidence && raw === "unavailable") return "degraded";
|
|
353054
|
-
if (!raw && String(model.validation?.level || "").toLowerCase() === "discovered") return "degraded";
|
|
353055
353206
|
return ["verified", "degraded", "unavailable", "auth_error", "rate_limited", "invalid_config"].includes(raw) ? raw : "unavailable";
|
|
353056
353207
|
}
|
|
353057
353208
|
function routeToolIsReadOnly(name50, rawArgs) {
|
|
@@ -353168,6 +353319,184 @@ var ConversationKernel = class {
|
|
|
353168
353319
|
followUp: queued?.followUp.slice() || []
|
|
353169
353320
|
};
|
|
353170
353321
|
}
|
|
353322
|
+
queueItems(target) {
|
|
353323
|
+
const runtime = this.findRuntime(target);
|
|
353324
|
+
if (!runtime) return [];
|
|
353325
|
+
return runtime.pendingNextTurn.flatMap((item) => {
|
|
353326
|
+
if (item.queueMode !== "followUp") return [];
|
|
353327
|
+
if (typeof item.message === "string") return [];
|
|
353328
|
+
const id = String(item.message.clientMessageId || "");
|
|
353329
|
+
if (!id) return [];
|
|
353330
|
+
return [{
|
|
353331
|
+
id,
|
|
353332
|
+
text: String(item.message.visibleUserInput || item.message.text || "").replace(/^\[Next queued while current turn is running\]\n/, ""),
|
|
353333
|
+
queueMode: item.queueMode,
|
|
353334
|
+
requestedMode: item.message.visibleMode,
|
|
353335
|
+
goalObjective: item.message.goalObjective,
|
|
353336
|
+
runId: item.message.runId,
|
|
353337
|
+
createdAt: String(item.message.createdAt || "")
|
|
353338
|
+
}];
|
|
353339
|
+
});
|
|
353340
|
+
}
|
|
353341
|
+
enqueueNext(target, input2) {
|
|
353342
|
+
const runtime = this.findRuntime(target);
|
|
353343
|
+
if (!runtime?.activePromise || !runtime.runId) throw new Error("Target conversation is not running");
|
|
353344
|
+
const id = String(input2.id || "").trim().slice(0, 200);
|
|
353345
|
+
const text = String(input2.text || "").trim();
|
|
353346
|
+
if (!id || !text) throw new Error("Queue item id and text are required");
|
|
353347
|
+
const existing = this.queueItems(runtime.target).find((item) => item.id === id);
|
|
353348
|
+
if (existing) return existing;
|
|
353349
|
+
const prompt = `[Next queued while current turn is running]
|
|
353350
|
+
${text}`;
|
|
353351
|
+
const createdAt = String(input2.createdAt || (/* @__PURE__ */ new Date()).toISOString());
|
|
353352
|
+
runtime.pendingNextTurn.push({
|
|
353353
|
+
message: {
|
|
353354
|
+
text: prompt,
|
|
353355
|
+
visibleUserInput: text,
|
|
353356
|
+
visibleMode: String(input2.requestedMode || "build"),
|
|
353357
|
+
goalObjective: String(input2.goalObjective || "") || void 0,
|
|
353358
|
+
clientMessageId: id,
|
|
353359
|
+
runId: runtime.runId,
|
|
353360
|
+
createdAt
|
|
353361
|
+
},
|
|
353362
|
+
queueMode: "followUp"
|
|
353363
|
+
});
|
|
353364
|
+
runtime.runner.retainConversationContinuations([{
|
|
353365
|
+
content: prompt,
|
|
353366
|
+
queueMode: "followUp",
|
|
353367
|
+
clientMessageId: id,
|
|
353368
|
+
runId: runtime.runId,
|
|
353369
|
+
createdAt
|
|
353370
|
+
}]);
|
|
353371
|
+
this.trackQueuedMessage(runtime, prompt, "followUp");
|
|
353372
|
+
this.emitQueueUpdate(runtime);
|
|
353373
|
+
return this.queueItems(runtime.target).find((item) => item.id === id);
|
|
353374
|
+
}
|
|
353375
|
+
updateQueueItem(target, idInput, textInput) {
|
|
353376
|
+
const runtime = this.findRuntime(target);
|
|
353377
|
+
if (!runtime) throw new Error("Target conversation runtime is unavailable");
|
|
353378
|
+
const id = String(idInput || "").trim();
|
|
353379
|
+
const text = String(textInput || "").trim();
|
|
353380
|
+
if (!id || !text) throw new Error("Queue item id and text are required");
|
|
353381
|
+
const pending3 = runtime.pendingNextTurn.find((item) => typeof item.message !== "string" && item.message.clientMessageId === id);
|
|
353382
|
+
if (!pending3 || typeof pending3.message === "string") throw new Error("Queue item is no longer editable");
|
|
353383
|
+
const oldPrompt = pending3.message.text;
|
|
353384
|
+
pending3.message.text = `[Next queued while current turn is running]
|
|
353385
|
+
${text}`;
|
|
353386
|
+
pending3.message.visibleUserInput = text;
|
|
353387
|
+
runtime.runner.consumeConversationContinuation({ content: oldPrompt, queueMode: pending3.queueMode, clientMessageId: id });
|
|
353388
|
+
runtime.runner.retainConversationContinuations([{
|
|
353389
|
+
content: pending3.message.text,
|
|
353390
|
+
queueMode: pending3.queueMode,
|
|
353391
|
+
clientMessageId: id,
|
|
353392
|
+
runId: pending3.message.runId
|
|
353393
|
+
}]);
|
|
353394
|
+
this.replaceTrackedQueuedMessage(runtime, oldPrompt, pending3.message.text, pending3.queueMode);
|
|
353395
|
+
this.emitQueueUpdate(runtime);
|
|
353396
|
+
return this.queueItems(runtime.target).find((item) => item.id === id);
|
|
353397
|
+
}
|
|
353398
|
+
deleteQueueItem(target, idInput) {
|
|
353399
|
+
const runtime = this.findRuntime(target);
|
|
353400
|
+
if (!runtime) return false;
|
|
353401
|
+
const id = String(idInput || "").trim();
|
|
353402
|
+
const index = runtime.pendingNextTurn.findIndex((item) => typeof item.message !== "string" && item.message.clientMessageId === id);
|
|
353403
|
+
if (index < 0) return false;
|
|
353404
|
+
const [removed] = runtime.pendingNextTurn.splice(index, 1);
|
|
353405
|
+
if (typeof removed.message !== "string") {
|
|
353406
|
+
runtime.runner.consumeConversationContinuation({ content: removed.message.text, queueMode: removed.queueMode, clientMessageId: id });
|
|
353407
|
+
this.consumeQueuedMessage(runtime, removed.message.text);
|
|
353408
|
+
}
|
|
353409
|
+
this.emitQueueUpdate(runtime);
|
|
353410
|
+
return true;
|
|
353411
|
+
}
|
|
353412
|
+
reorderQueueItems(target, orderedIdsInput) {
|
|
353413
|
+
const runtime = this.findRuntime(target);
|
|
353414
|
+
if (!runtime) throw new Error("Target conversation runtime is unavailable");
|
|
353415
|
+
const currentItems = this.queueItems(runtime.target);
|
|
353416
|
+
const orderedIds = Array.isArray(orderedIdsInput) ? orderedIdsInput.map((id) => String(id || "").trim()) : [];
|
|
353417
|
+
const currentIds = currentItems.map((item) => item.id);
|
|
353418
|
+
const completeOrder = orderedIds.length === currentIds.length && new Set(orderedIds).size === orderedIds.length && orderedIds.every((id) => currentIds.includes(id));
|
|
353419
|
+
if (!completeOrder) throw new Error("A complete queue order with unique current item ids is required");
|
|
353420
|
+
const persistedIds = runtime.runner.conversationContinuations().filter((item) => item.queueMode === "followUp" && !!item.clientMessageId).map((item) => String(item.clientMessageId));
|
|
353421
|
+
if (persistedIds.length !== currentIds.length || new Set(persistedIds).size !== persistedIds.length || persistedIds.some((id) => !currentIds.includes(id))) {
|
|
353422
|
+
throw new Error("Persisted queue does not match the complete queue order");
|
|
353423
|
+
}
|
|
353424
|
+
const pendingById = new Map(runtime.pendingNextTurn.flatMap((item) => {
|
|
353425
|
+
if (item.queueMode !== "followUp" || typeof item.message === "string" || !item.message.clientMessageId) return [];
|
|
353426
|
+
return [[String(item.message.clientMessageId), item]];
|
|
353427
|
+
}));
|
|
353428
|
+
const reorderedPending = orderedIds.map((id) => pendingById.get(id));
|
|
353429
|
+
let nextIndex = 0;
|
|
353430
|
+
runtime.pendingNextTurn = runtime.pendingNextTurn.map((item) => {
|
|
353431
|
+
if (item.queueMode !== "followUp" || typeof item.message === "string" || !item.message.clientMessageId) return item;
|
|
353432
|
+
return reorderedPending[nextIndex++];
|
|
353433
|
+
});
|
|
353434
|
+
runtime.runner.reorderConversationContinuations(orderedIds);
|
|
353435
|
+
runtime.queued.followUp = orderedIds.map((id) => pendingById.get(id)).map((item) => typeof item.message === "string" ? item.message : item.message.text);
|
|
353436
|
+
this.emitQueueUpdate(runtime);
|
|
353437
|
+
return this.queueItems(runtime.target);
|
|
353438
|
+
}
|
|
353439
|
+
setQueuePaused(target, paused) {
|
|
353440
|
+
const runtime = this.findRuntime(target);
|
|
353441
|
+
if (!runtime) throw new Error("Target conversation runtime is unavailable");
|
|
353442
|
+
runtime.queuePaused = paused;
|
|
353443
|
+
this.emitQueueUpdate(runtime);
|
|
353444
|
+
if (!paused && !runtime.activePromise && runtime.pendingNextTurn.length) {
|
|
353445
|
+
this.schedulePendingRuntimeContinuation(runtime, runtime.runId);
|
|
353446
|
+
}
|
|
353447
|
+
return runtime.queuePaused;
|
|
353448
|
+
}
|
|
353449
|
+
queueAction(target, action, input2 = {}) {
|
|
353450
|
+
const runtime = this.findRuntime(target);
|
|
353451
|
+
if (!runtime) throw new Error("Target conversation runtime is unavailable");
|
|
353452
|
+
let receipt;
|
|
353453
|
+
if (action === "enqueue") {
|
|
353454
|
+
this.enqueueNext(runtime.target, {
|
|
353455
|
+
id: String(input2.id || ""),
|
|
353456
|
+
text: String(input2.text || ""),
|
|
353457
|
+
requestedMode: input2.requestedMode,
|
|
353458
|
+
goalObjective: input2.goalObjective,
|
|
353459
|
+
createdAt: input2.createdAt
|
|
353460
|
+
});
|
|
353461
|
+
} else if (action === "update") {
|
|
353462
|
+
this.updateQueueItem(runtime.target, String(input2.id || ""), String(input2.text || ""));
|
|
353463
|
+
} else if (action === "delete") {
|
|
353464
|
+
if (!this.deleteQueueItem(runtime.target, String(input2.id || ""))) throw new Error("Queue item was not found");
|
|
353465
|
+
} else if (action === "reorder") {
|
|
353466
|
+
this.reorderQueueItems(runtime.target, input2.orderedIds || []);
|
|
353467
|
+
} else if (action === "toggle_pause") {
|
|
353468
|
+
this.setQueuePaused(runtime.target, !runtime.queuePaused);
|
|
353469
|
+
} else if (action === "guide") {
|
|
353470
|
+
const item = this.queueItems(runtime.target).find((entry) => entry.id === String(input2.id || ""));
|
|
353471
|
+
if (!item) throw new Error("Queue item was not found");
|
|
353472
|
+
receipt = this.enqueueGuide({
|
|
353473
|
+
clientMessageId: item.id,
|
|
353474
|
+
guideId: (0, import_crypto16.randomUUID)(),
|
|
353475
|
+
target: runtime.target,
|
|
353476
|
+
runId: runtime.runId,
|
|
353477
|
+
deliveryMode: "steer",
|
|
353478
|
+
text: item.goalObjective ? `Goal for the current Build:
|
|
353479
|
+
${item.goalObjective}` : item.text,
|
|
353480
|
+
goalObjective: item.goalObjective,
|
|
353481
|
+
createdAt: item.createdAt || (/* @__PURE__ */ new Date()).toISOString()
|
|
353482
|
+
});
|
|
353483
|
+
if (receipt.status === "rejected") return {
|
|
353484
|
+
ok: false,
|
|
353485
|
+
queueItems: this.queueItems(runtime.target),
|
|
353486
|
+
queuePaused: runtime.queuePaused,
|
|
353487
|
+
queued: this.queued(runtime.target),
|
|
353488
|
+
receipt
|
|
353489
|
+
};
|
|
353490
|
+
this.deleteQueueItem(runtime.target, item.id);
|
|
353491
|
+
}
|
|
353492
|
+
return {
|
|
353493
|
+
ok: true,
|
|
353494
|
+
queueItems: this.queueItems(runtime.target),
|
|
353495
|
+
queuePaused: runtime.queuePaused,
|
|
353496
|
+
queued: this.queued(runtime.target),
|
|
353497
|
+
receipt
|
|
353498
|
+
};
|
|
353499
|
+
}
|
|
353171
353500
|
events(target) {
|
|
353172
353501
|
return this.findRuntime(target)?.events.slice() || [];
|
|
353173
353502
|
}
|
|
@@ -353196,6 +353525,8 @@ var ConversationKernel = class {
|
|
|
353196
353525
|
workRuns: this.bindWorkRunsToRuntimeTarget(conversationSnapshot.workRuns, normalized),
|
|
353197
353526
|
target: normalized,
|
|
353198
353527
|
queued: this.queued(normalized),
|
|
353528
|
+
queueItems: this.queueItems(normalized),
|
|
353529
|
+
queuePaused: runtime?.queuePaused === true,
|
|
353199
353530
|
workEvents: this.events(normalized),
|
|
353200
353531
|
runtime: this.runtimeState(normalized),
|
|
353201
353532
|
mode: runner.mode,
|
|
@@ -353631,7 +353962,7 @@ var ConversationKernel = class {
|
|
|
353631
353962
|
if (runtime.stopRequestedRunId === runId) {
|
|
353632
353963
|
stopped = true;
|
|
353633
353964
|
this.settleCooperativeStop(runtime, runId);
|
|
353634
|
-
} else if (runtime.pendingNextTurn.length > 0) {
|
|
353965
|
+
} else if (!runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
|
|
353635
353966
|
this.schedulePendingRuntimeContinuation(runtime, runId);
|
|
353636
353967
|
}
|
|
353637
353968
|
}
|
|
@@ -353666,7 +353997,7 @@ var ConversationKernel = class {
|
|
|
353666
353997
|
return this.result(runtime, lastTokens);
|
|
353667
353998
|
}
|
|
353668
353999
|
for (; ; ) {
|
|
353669
|
-
while (runtime.pendingNextTurn.length > 0) {
|
|
354000
|
+
while (!runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
|
|
353670
354001
|
if (runtime.stopRequestedRunId === runtime.runId) return this.result(runtime, lastTokens);
|
|
353671
354002
|
const next = runtime.pendingNextTurn.shift();
|
|
353672
354003
|
if (next.queueMode === "steer" && typeof next.message !== "string" && !!next.message.clientMessageId) {
|
|
@@ -353708,11 +354039,11 @@ ${batchText}`,
|
|
|
353708
354039
|
this.mirrorHostIfTargetActive(runtime);
|
|
353709
354040
|
return this.result(runtime, lastTokens);
|
|
353710
354041
|
}
|
|
353711
|
-
this.clearQueued(runtime);
|
|
354042
|
+
if (!runtime.pendingNextTurn.length) this.clearQueued(runtime);
|
|
353712
354043
|
const completedRunId = runtime.runId;
|
|
353713
354044
|
runtime.runner.finishConversationWorkRun(completedRunId, "completed");
|
|
353714
354045
|
await new Promise((resolve16) => setImmediate(resolve16));
|
|
353715
|
-
if (runtime.runId === completedRunId && runtime.stopRequestedRunId !== completedRunId && runtime.pendingNextTurn.length > 0) {
|
|
354046
|
+
if (runtime.runId === completedRunId && runtime.stopRequestedRunId !== completedRunId && !runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
|
|
353716
354047
|
runtime.guideAcceptanceClosedRunId = "";
|
|
353717
354048
|
if (!runtime.runner.resumeConversationWorkRun(completedRunId)) {
|
|
353718
354049
|
throw new Error(`Unable to resume deferred Guide work run ${completedRunId}`);
|
|
@@ -353803,6 +354134,7 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
353803
354134
|
events: [],
|
|
353804
354135
|
pendingNextTurn: [],
|
|
353805
354136
|
queued: { steering: [], followUp: [] },
|
|
354137
|
+
queuePaused: false,
|
|
353806
354138
|
runId: "",
|
|
353807
354139
|
generation: this.generations.get(target.runtimeKey) || 0,
|
|
353808
354140
|
stopRequestedRunId: "",
|
|
@@ -353898,7 +354230,7 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
353898
354230
|
}
|
|
353899
354231
|
setImmediate(() => {
|
|
353900
354232
|
runtime.pendingContinuationRunId = void 0;
|
|
353901
|
-
if (runtime.runId !== runId || runtime.activePromise || runtime.stopRequestedRunId === runId) return;
|
|
354233
|
+
if (runtime.runId !== runId || runtime.activePromise || runtime.stopRequestedRunId === runId || runtime.queuePaused) return;
|
|
353902
354234
|
const next = runtime.pendingNextTurn.shift();
|
|
353903
354235
|
if (!next) return;
|
|
353904
354236
|
const message = typeof next.message === "string" ? { text: next.message, runId } : { ...next.message, runId: next.message.runId || runId };
|
|
@@ -354049,7 +354381,36 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
354049
354381
|
const text = typeof message === "string" ? message : message.text;
|
|
354050
354382
|
const prompt = isSteer ? text : `[Next queued while current turn is running]
|
|
354051
354383
|
${text}`;
|
|
354052
|
-
if (!isSteer)
|
|
354384
|
+
if (!isSteer) {
|
|
354385
|
+
const structured = typeof message === "string" ? null : message;
|
|
354386
|
+
const clientMessageId = String(structured?.clientMessageId || (0, import_crypto16.randomUUID)());
|
|
354387
|
+
const queuedMessage = {
|
|
354388
|
+
...structured || {},
|
|
354389
|
+
text: prompt,
|
|
354390
|
+
visibleUserInput: structured?.visibleUserInput || text,
|
|
354391
|
+
visibleMode: structured?.visibleMode || runtime.options.mode,
|
|
354392
|
+
clientMessageId,
|
|
354393
|
+
runId: structured?.runId || runtime.runId,
|
|
354394
|
+
createdAt: String(structured?.createdAt || (/* @__PURE__ */ new Date()).toISOString())
|
|
354395
|
+
};
|
|
354396
|
+
if (!runtime.pendingNextTurn.some((item) => typeof item.message !== "string" && item.message.clientMessageId === clientMessageId)) {
|
|
354397
|
+
runtime.pendingNextTurn.push({ message: queuedMessage, queueMode: "followUp" });
|
|
354398
|
+
}
|
|
354399
|
+
runtime.runner.retainConversationContinuations([{
|
|
354400
|
+
content: prompt,
|
|
354401
|
+
queueMode: "followUp",
|
|
354402
|
+
clientMessageId,
|
|
354403
|
+
runId: queuedMessage.runId,
|
|
354404
|
+
images: queuedMessage.images?.map((image) => ({ ...image })),
|
|
354405
|
+
attachments: queuedMessage.attachments?.map((attachment) => ({ ...attachment })),
|
|
354406
|
+
createdAt: queuedMessage.createdAt
|
|
354407
|
+
}]);
|
|
354408
|
+
this.trackQueuedMessage(runtime, prompt, "followUp");
|
|
354409
|
+
runtime.runner.recordWorkStatus(runtime.stopRequestedRunId === runtime.runId ? "Next message retained while stopping." : "Next message queued.");
|
|
354410
|
+
if (runtime.stopRequestedRunId === runtime.runId) runtime.forceStopArmedRunId = "";
|
|
354411
|
+
this.emitQueueUpdate(runtime);
|
|
354412
|
+
return;
|
|
354413
|
+
}
|
|
354053
354414
|
if (runtime.stopRequestedRunId === runtime.runId) {
|
|
354054
354415
|
runtime.forceStopArmedRunId = "";
|
|
354055
354416
|
const structured = typeof message === "string" ? void 0 : message;
|
|
@@ -354095,6 +354456,12 @@ ${text}`;
|
|
|
354095
354456
|
}
|
|
354096
354457
|
if (changed) this.emitQueueUpdate(runtime);
|
|
354097
354458
|
}
|
|
354459
|
+
replaceTrackedQueuedMessage(runtime, oldMessage, nextMessage, queueMode) {
|
|
354460
|
+
this.queueState(runtime);
|
|
354461
|
+
const list = queueMode === "steer" ? runtime.queued.steering : runtime.queued.followUp;
|
|
354462
|
+
const index = list.indexOf(oldMessage);
|
|
354463
|
+
if (index >= 0) list[index] = nextMessage;
|
|
354464
|
+
}
|
|
354098
354465
|
emitQueueUpdate(runtime) {
|
|
354099
354466
|
this.queueState(runtime);
|
|
354100
354467
|
runtime.runner.emitWorkEvent({
|
|
@@ -354216,9 +354583,10 @@ ${text}`;
|
|
|
354216
354583
|
const runId = runtime.runId;
|
|
354217
354584
|
await Promise.resolve();
|
|
354218
354585
|
if (runtime.runId !== runId || runtime.stopRequestedRunId === runId) return true;
|
|
354219
|
-
|
|
354586
|
+
const hasSteering = runtime.pendingNextTurn.some((item) => item.queueMode === "steer");
|
|
354587
|
+
if (hasSteering || runtime.runner.subagents.readRootInbox().length > 0) return false;
|
|
354220
354588
|
runtime.guideAcceptanceClosedRunId = runId;
|
|
354221
|
-
if (runtime.pendingNextTurn.
|
|
354589
|
+
if (runtime.pendingNextTurn.some((item) => item.queueMode === "steer") || runtime.runner.subagents.readRootInbox().length > 0) {
|
|
354222
354590
|
runtime.guideAcceptanceClosedRunId = "";
|
|
354223
354591
|
return false;
|
|
354224
354592
|
}
|
|
@@ -354429,6 +354797,9 @@ async function handle(request) {
|
|
|
354429
354797
|
target
|
|
354430
354798
|
});
|
|
354431
354799
|
}
|
|
354800
|
+
if (request.method === "queue_action") {
|
|
354801
|
+
return kernel.queueAction(requestTarget(request.params), request.params.action, request.params.input);
|
|
354802
|
+
}
|
|
354432
354803
|
if (request.method === "checkpoint") return kernel.checkpoint(requestTarget(request.params));
|
|
354433
354804
|
if (request.method === "context_compress") {
|
|
354434
354805
|
return kernel.compressContext(requestTarget(request.params), request.params.options);
|