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
|
@@ -327556,6 +327556,7 @@ var NATIVE_TOOL_CATALOG = [
|
|
|
327556
327556
|
{ name: "browser_reload", label: "Browser reload", description: "Reload the built-in browser.", category: "browser", defaultEnabled: true },
|
|
327557
327557
|
{ name: "browser_cdp", label: "Browser CDP", description: "Run an advanced Chrome DevTools Protocol command.", category: "browser", defaultEnabled: true },
|
|
327558
327558
|
{ name: "browser_use", label: "Browser Use", description: "Observe and control the built-in browser through scoped opaque element refs and structured receipts.", category: "browser", defaultEnabled: true },
|
|
327559
|
+
{ name: "screen_capture", label: "Active screenshot", description: "Capture the Windows desktop or one visible application without starting the full Computer Use control surface.", category: "desktop", defaultEnabled: true, protected: true, availability: "mode-scoped" },
|
|
327559
327560
|
{ name: "computer_use", label: "Computer Use", description: "Observe and control Windows desktop UI with screenshots and semantic objects.", category: "desktop", defaultEnabled: true },
|
|
327560
327561
|
{ name: "image_inspect", label: "Image inspect", description: "Crop and magnify images submitted in the current conversation for closer visual inspection.", category: "core", defaultEnabled: true, protected: true, availability: "mode-scoped" },
|
|
327561
327562
|
{ name: "image_display", label: "Image display", description: "Present a workspace PNG/JPEG inside the current Build Block.", category: "core", defaultEnabled: true, protected: true, availability: "mode-scoped" },
|
|
@@ -335746,6 +335747,7 @@ var import_crypto6 = require("crypto");
|
|
|
335746
335747
|
// src/core/toolPolicy.ts
|
|
335747
335748
|
var REQUIRED_TOOLS = /* @__PURE__ */ new Set(["pwd", "read", "glob", "grep"]);
|
|
335748
335749
|
var MODE_SCOPED_TOOLS = /* @__PURE__ */ new Set([
|
|
335750
|
+
"screen_capture",
|
|
335749
335751
|
"image_inspect",
|
|
335750
335752
|
"image_display",
|
|
335751
335753
|
"ocr_read",
|
|
@@ -335778,6 +335780,7 @@ var MODE_SCOPED_TOOLS = /* @__PURE__ */ new Set([
|
|
|
335778
335780
|
"branch_create"
|
|
335779
335781
|
]);
|
|
335780
335782
|
var PLAN_READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
335783
|
+
"screen_capture",
|
|
335781
335784
|
"task_read",
|
|
335782
335785
|
"pwd",
|
|
335783
335786
|
"read",
|
|
@@ -335825,6 +335828,7 @@ var CONCURRENCY_SAFE_TOOLS = /* @__PURE__ */ new Set([
|
|
|
335825
335828
|
"git_status",
|
|
335826
335829
|
"file_audit",
|
|
335827
335830
|
"repo_security_audit",
|
|
335831
|
+
"screen_capture",
|
|
335828
335832
|
"SubAgent"
|
|
335829
335833
|
]);
|
|
335830
335834
|
function isConcurrencySafeTool(name50, riskLevel) {
|
|
@@ -336908,6 +336912,13 @@ var ToolExecutor = class {
|
|
|
336908
336912
|
max_refs: { type: "number" },
|
|
336909
336913
|
attribute: { type: "string" }
|
|
336910
336914
|
}, ["action"]),
|
|
336915
|
+
t3("screen_capture", "Read-only active Windows screenshot available without provisioning or starting full Computer Use. Capture the whole desktop or one visible application. The image is a one-use model input and is deleted immediately; semantic Windows UI objects are returned alongside it.", {
|
|
336916
|
+
target: { type: "string", enum: ["desktop", "application"], description: "Capture the whole desktop or one visible application. Defaults to desktop." },
|
|
336917
|
+
app_target: { type: "string", description: "For target=application: application title, process name, process id, or window handle." },
|
|
336918
|
+
capture_max_width: { type: "number", minimum: 320, maximum: 2048, description: "Maximum ephemeral screenshot width; defaults to 1280. Aspect ratio is preserved and the source is never enlarged." },
|
|
336919
|
+
capture_max_height: { type: "number", minimum: 240, maximum: 2048, description: "Maximum ephemeral screenshot height; defaults to 960. Aspect ratio is preserved and the source is never enlarged." },
|
|
336920
|
+
max_chars: { type: "number", minimum: 1e3, maximum: 1e5, description: "Maximum returned semantic UI text characters." }
|
|
336921
|
+
}, []),
|
|
336911
336922
|
t3("computer_use", "Native Windows desktop control with persistent observation/action helpers. Use observe/app_observe before acting. sequence may perform up to three stable low-risk move/click/scroll/wait/app_activate steps and stops when focus, window, menu, dialog, scene, or risk changes. Vision screenshots remain one-time inputs and are deleted immediately.", {
|
|
336912
336923
|
action: { type: "string", enum: ["observe", "app_list", "app_observe", "sequence", "takeover_start", "takeover_stop", "move", "click", "scroll", "type", "key", "wait", "app_activate", "app_click", "app_scroll", "app_type", "app_key"] },
|
|
336913
336924
|
capture_max_width: { type: "number", minimum: 320, maximum: 2048, description: "For observe/app_observe only. Maximum ephemeral screenshot width; defaults to 1280. Aspect ratio is preserved and the source is never enlarged." },
|
|
@@ -337398,6 +337409,44 @@ var ToolExecutor = class {
|
|
|
337398
337409
|
result: parsed
|
|
337399
337410
|
}, null, 2);
|
|
337400
337411
|
}
|
|
337412
|
+
case "screen_capture": {
|
|
337413
|
+
const target = g2("target").toLowerCase() === "application" ? "application" : "desktop";
|
|
337414
|
+
if (process.env.NEWMARK_WSL_DISTRO) {
|
|
337415
|
+
const result = await requestWindowsHostTool("screen_capture", args, {
|
|
337416
|
+
conversationId: context.conversationId || "default",
|
|
337417
|
+
workspaceId: context.workspaceId || terminalTakeoverWorkspaceId(context.workspacePath || wsPath),
|
|
337418
|
+
actorId: context.actorId || ROOT_TERMINAL_ACTOR_ID,
|
|
337419
|
+
runtimeKey: browserUseScope(context, wsPath).runtimeKey,
|
|
337420
|
+
allowEphemeralVisionImage: context.allowEphemeralVisionImage === true,
|
|
337421
|
+
mode: context.mode || "build"
|
|
337422
|
+
}, 12e4, context.signal);
|
|
337423
|
+
return typeof result === "string" ? result : JSON.stringify(result);
|
|
337424
|
+
}
|
|
337425
|
+
if (process.env.NEWMARK_ISOLATED_RUNTIME === "1") {
|
|
337426
|
+
const result = await requestUtilityHostTool("screen_capture", args, {
|
|
337427
|
+
conversationId: context.conversationId || "default",
|
|
337428
|
+
workspaceId: context.workspaceId || terminalTakeoverWorkspaceId(context.workspacePath || wsPath),
|
|
337429
|
+
actorId: context.actorId || ROOT_TERMINAL_ACTOR_ID,
|
|
337430
|
+
workspacePath: context.workspacePath || wsPath,
|
|
337431
|
+
backend: "utility",
|
|
337432
|
+
mode: context.mode || "build",
|
|
337433
|
+
allowEphemeralVisionImage: context.allowEphemeralVisionImage === true
|
|
337434
|
+
}, 12e4, context.signal);
|
|
337435
|
+
return typeof result === "string" ? result : JSON.stringify(result);
|
|
337436
|
+
}
|
|
337437
|
+
return await runComputerUse({
|
|
337438
|
+
action: target === "application" ? "app_observe" : "observe",
|
|
337439
|
+
appTarget: g2("app_target"),
|
|
337440
|
+
windowHandle: target === "application" ? g2("app_target") : "",
|
|
337441
|
+
maxChars: Number(args.max_chars || 3e4),
|
|
337442
|
+
workspacePath: wsPath,
|
|
337443
|
+
allowEphemeralVisionImage: context.allowEphemeralVisionImage === true,
|
|
337444
|
+
captureMaxWidth: Number(args.capture_max_width),
|
|
337445
|
+
captureMaxHeight: Number(args.capture_max_height),
|
|
337446
|
+
invocation: context.invocation,
|
|
337447
|
+
ownerId: `screen-capture:${computerUseOwner(context, wsPath)}:${String(context.actorId || "root")}`
|
|
337448
|
+
});
|
|
337449
|
+
}
|
|
337401
337450
|
case "computer_use": {
|
|
337402
337451
|
const action = normalizeComputerUseAction(g2("action"));
|
|
337403
337452
|
const owner = `${computerUseOwner(context, wsPath)}:${String(context.actorId || "root")}`;
|
|
@@ -337604,7 +337653,7 @@ var ToolExecutor = class {
|
|
|
337604
337653
|
}
|
|
337605
337654
|
hostSupportsTool(name50) {
|
|
337606
337655
|
if (name50.startsWith("browser_") && !this.hostProfile.electronBrowser) return false;
|
|
337607
|
-
if (name50 === "computer_use" && !this.hostProfile.windowsComputerUse) return false;
|
|
337656
|
+
if ((name50 === "computer_use" || name50 === "screen_capture") && !this.hostProfile.windowsComputerUse) return false;
|
|
337608
337657
|
return true;
|
|
337609
337658
|
}
|
|
337610
337659
|
async decorateBrowserUseReceipt(input, context, runtimeKey) {
|
|
@@ -340934,7 +340983,7 @@ async function runAgentKernel(agent) {
|
|
|
340934
340983
|
return;
|
|
340935
340984
|
}
|
|
340936
340985
|
const publicError = normalizePublicProviderError(error, [currentAgent.activeModelConfig()?.api_key]);
|
|
340937
|
-
if (/\b402\b|insufficient balance|insufficient funds|payment required
|
|
340986
|
+
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)) {
|
|
340938
340987
|
currentAgent.noteProviderBalanceFailure();
|
|
340939
340988
|
}
|
|
340940
340989
|
const final = assistantMessage2(model, [{ type: "text", text: `[Error] ${publicError}` }], "error");
|
|
@@ -341504,10 +341553,12 @@ function toKernelTools(agent, definitions, provisioning) {
|
|
|
341504
341553
|
throw new Error(rawText);
|
|
341505
341554
|
}
|
|
341506
341555
|
const visionImage = visualFallbackImageInput(agent, name50, rawText);
|
|
341556
|
+
const capturedInput = name50 === "screen_capture" ? agent.registerCapturedImageInput(visionImage.image || "", "active-screenshot.jpg") : null;
|
|
341507
341557
|
const directImage = imageInspectDataUrl(name50, rawText);
|
|
341508
|
-
const text = spillOversizedToolResult(agent, name50, sanitizeVisualToolText(name50, rawText));
|
|
341558
|
+
const text = spillOversizedToolResult(agent, name50, capturedImageToolText(name50, sanitizeVisualToolText(name50, rawText), capturedInput?.id));
|
|
341509
341559
|
const content = [{ type: "text", text }];
|
|
341510
|
-
if (
|
|
341560
|
+
if (name50 === "screen_capture" && capturedInput?.dataUrl) content.push({ type: "image", image: capturedInput.dataUrl, mimeType: capturedInput.mimeType });
|
|
341561
|
+
else if (visionImage.imagePath) content.push({ type: "image", imagePath: visionImage.imagePath, mimeType: imageMimeForPath(visionImage.imagePath) });
|
|
341511
341562
|
else if (visionImage.image) content.push({ type: "image", image: visionImage.image, mimeType: visionImage.mimeType });
|
|
341512
341563
|
if (directImage) content.push({ type: "image", image: directImage, mimeType: "image/png" });
|
|
341513
341564
|
const terminate = shouldTerminateAfterToolResult(name50) && (name50 !== "question" || agent.pendingOptions.length > 0);
|
|
@@ -341520,7 +341571,7 @@ function toKernelTools(agent, definitions, provisioning) {
|
|
|
341520
341571
|
} catch {
|
|
341521
341572
|
}
|
|
341522
341573
|
}
|
|
341523
|
-
return { content, details: { tool: name50, ok: true, terminate, ...launchReceipt ? { launchReceipt } : {}, visionImagePath: visionImage.imagePath || void 0, ephemeralVisionImage: !!visionImage.image, displayImage }, terminate };
|
|
341574
|
+
return { content, details: { tool: name50, ok: true, terminate, ...launchReceipt ? { launchReceipt } : {}, visionImagePath: visionImage.imagePath || void 0, ephemeralVisionImage: !!visionImage.image, capturedAttachmentId: capturedInput?.id, displayImage }, terminate };
|
|
341524
341575
|
}
|
|
341525
341576
|
};
|
|
341526
341577
|
}).filter((tool) => !!tool.name);
|
|
@@ -341544,7 +341595,7 @@ var INLINE_TOOL_RESULT_MAX_CHARS = 24e3;
|
|
|
341544
341595
|
function spillOversizedToolResult(agent, name50, text) {
|
|
341545
341596
|
const value = String(text || "");
|
|
341546
341597
|
if (value.length <= INLINE_TOOL_RESULT_MAX_CHARS) return value;
|
|
341547
|
-
if (["computer_use", "browser_use", "pdf_read", "image_inspect", "image_display", "task", "subagent_create", "SubAgent", "subagent_send", "subagent_result", "subagent_read", "linked_plan", "question"].includes(name50)) {
|
|
341598
|
+
if (["screen_capture", "computer_use", "browser_use", "pdf_read", "image_inspect", "image_display", "task", "subagent_create", "SubAgent", "subagent_send", "subagent_result", "subagent_read", "linked_plan", "question"].includes(name50)) {
|
|
341548
341599
|
return value;
|
|
341549
341600
|
}
|
|
341550
341601
|
const artifactId = agent.storeToolResultArtifact(name50, value);
|
|
@@ -341559,10 +341610,10 @@ function spillOversizedToolResult(agent, name50, text) {
|
|
|
341559
341610
|
].join("\n");
|
|
341560
341611
|
}
|
|
341561
341612
|
function sanitizeVisualToolText(name50, text) {
|
|
341562
|
-
if (name50 !== "computer_use" && name50 !== "browser_use" && name50 !== "pdf_read" && name50 !== "image_inspect") return text;
|
|
341613
|
+
if (name50 !== "screen_capture" && name50 !== "computer_use" && name50 !== "browser_use" && name50 !== "pdf_read" && name50 !== "image_inspect") return text;
|
|
341563
341614
|
try {
|
|
341564
341615
|
const parsed = JSON.parse(text);
|
|
341565
|
-
if (name50 === "computer_use" || name50 === "browser_use" || name50 === "pdf_read") {
|
|
341616
|
+
if (name50 === "screen_capture" || name50 === "computer_use" || name50 === "browser_use" || name50 === "pdf_read") {
|
|
341566
341617
|
delete parsed.vision_image_path;
|
|
341567
341618
|
delete parsed.vision_image_data_url;
|
|
341568
341619
|
if (name50 === "pdf_read" && parsed.result && typeof parsed.result === "object") {
|
|
@@ -341578,7 +341629,7 @@ function sanitizeVisualToolText(name50, text) {
|
|
|
341578
341629
|
}
|
|
341579
341630
|
}
|
|
341580
341631
|
function discardComputerUseVisionImage(name50, text) {
|
|
341581
|
-
if (name50 !== "computer_use") return;
|
|
341632
|
+
if (name50 !== "screen_capture" && name50 !== "computer_use") return;
|
|
341582
341633
|
try {
|
|
341583
341634
|
const parsed = JSON.parse(text);
|
|
341584
341635
|
const screenshotPath = String(parsed.vision_image_path || "");
|
|
@@ -341596,8 +341647,20 @@ function imageInspectDataUrl(name50, text) {
|
|
|
341596
341647
|
return "";
|
|
341597
341648
|
}
|
|
341598
341649
|
}
|
|
341650
|
+
function capturedImageToolText(name50, text, attachmentId) {
|
|
341651
|
+
if (name50 !== "screen_capture" || !attachmentId) return text;
|
|
341652
|
+
try {
|
|
341653
|
+
const parsed = JSON.parse(text);
|
|
341654
|
+
parsed.attachment_id = attachmentId;
|
|
341655
|
+
parsed.image_input_channel = "user-image";
|
|
341656
|
+
parsed.inspect_next = { tool: "image_inspect", actions: ["source_info", "crop"], max_scale: 4 };
|
|
341657
|
+
return JSON.stringify(parsed, null, 2);
|
|
341658
|
+
} catch {
|
|
341659
|
+
return text;
|
|
341660
|
+
}
|
|
341661
|
+
}
|
|
341599
341662
|
function visualFallbackImageInput(agent, name50, text) {
|
|
341600
|
-
if (name50 !== "computer_use" && name50 !== "browser_use" && name50 !== "pdf_read") return {};
|
|
341663
|
+
if (name50 !== "screen_capture" && name50 !== "computer_use" && name50 !== "browser_use" && name50 !== "pdf_read") return {};
|
|
341601
341664
|
const model = agent.activeModelConfig();
|
|
341602
341665
|
if (!model?.vision) return {};
|
|
341603
341666
|
try {
|
|
@@ -341723,7 +341786,7 @@ async function executeNewmarkTool(agent, name50, args, inputSchema, signal) {
|
|
|
341723
341786
|
actorId: agent.runtimeActorId,
|
|
341724
341787
|
workspaceId: terminalTakeoverWorkspaceId(wsDir),
|
|
341725
341788
|
backend: process.env.NEWMARK_WSL_DISTRO ? "wsl" : process.platform === "win32" ? "windows" : process.platform,
|
|
341726
|
-
allowEphemeralVisionImage: (name50 === "computer_use" || name50 === "browser_use" || name50 === "pdf_read" || name50 === "ocr_read") && !!agent.activeModelConfig()?.vision,
|
|
341789
|
+
allowEphemeralVisionImage: (name50 === "screen_capture" || name50 === "computer_use" || name50 === "browser_use" || name50 === "pdf_read" || name50 === "ocr_read") && !!agent.activeModelConfig()?.vision,
|
|
341727
341790
|
signal
|
|
341728
341791
|
});
|
|
341729
341792
|
if (signal?.aborted) throw abortError4();
|
|
@@ -342988,8 +343051,8 @@ function classifyRouteFailure(error) {
|
|
|
342988
343051
|
if (statusCode === 400 || /bad request|invalid parameter|invalid request/i.test(text)) {
|
|
342989
343052
|
return { type: "invalid_request", retryable: false, switchAllowed: false, statusCode };
|
|
342990
343053
|
}
|
|
342991
|
-
if (statusCode === 402 || /insufficient balance|insufficient funds|payment required
|
|
342992
|
-
return { type: "balance_exhausted", retryable: false, switchAllowed:
|
|
343054
|
+
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)) {
|
|
343055
|
+
return { type: "balance_exhausted", retryable: false, switchAllowed: true, statusCode: statusCode || 402 };
|
|
342993
343056
|
}
|
|
342994
343057
|
if (statusCode === 429 || /rate limit|too many requests/i.test(text)) {
|
|
342995
343058
|
return { type: "rate_limited", retryable: true, switchAllowed: true, statusCode: 429, retryAfterMs };
|
|
@@ -343127,13 +343190,13 @@ var AutoRouter = class {
|
|
|
343127
343190
|
}
|
|
343128
343191
|
planAttempts(decision, candidates, failure) {
|
|
343129
343192
|
const current = decision.resolvedDeployment;
|
|
343130
|
-
if (!current || !failure.error.
|
|
343193
|
+
if (!current || !failure.error.switchAllowed || failure.streamCommitted || failure.sideEffectCommitted) return [];
|
|
343131
343194
|
const remainingAttempts = Math.max(0, 3 - decision.attempts.length);
|
|
343132
343195
|
if (!remainingAttempts) return [];
|
|
343133
343196
|
const attempts = [];
|
|
343134
343197
|
const retryDelayMs = failure.error.retryAfterMs ?? 250;
|
|
343135
343198
|
const alreadyRetriedCurrent = decision.attempts.some((attempt) => attempt.kind === "retry_same_deployment" && sameDeployment(attempt.deployment, current));
|
|
343136
|
-
if (!alreadyRetriedCurrent && retryDelayMs <= (decision.retryBudgetMs ?? 5e3)) {
|
|
343199
|
+
if (failure.error.retryable && !alreadyRetriedCurrent && retryDelayMs <= (decision.retryBudgetMs ?? 5e3)) {
|
|
343137
343200
|
attempts.push({
|
|
343138
343201
|
deployment: { ...current },
|
|
343139
343202
|
kind: "retry_same_deployment",
|
|
@@ -343154,11 +343217,16 @@ var AutoRouter = class {
|
|
|
343154
343217
|
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");
|
|
343155
343218
|
const equivalent = currentGroup ? eligible.find((candidate) => candidate.deployment.logicalModelGroupId === currentGroup && !candidate.fallbackOnly) : void 0;
|
|
343156
343219
|
const fallback = eligible.find((candidate) => candidate.fallbackOnly);
|
|
343157
|
-
|
|
343220
|
+
const rankedAlternates = decision.rankedCandidates.map((ranked) => eligible.find((candidate) => sameDeployment(candidate.deployment, ranked.deployment))).filter((candidate) => !!candidate && candidate !== equivalent && candidate !== fallback && !candidate.fallbackOnly);
|
|
343221
|
+
for (const candidate of eligible) {
|
|
343222
|
+
if (candidate === equivalent || candidate === fallback || candidate.fallbackOnly || rankedAlternates.some((existing) => sameDeployment(existing.deployment, candidate.deployment))) continue;
|
|
343223
|
+
rankedAlternates.push(candidate);
|
|
343224
|
+
}
|
|
343225
|
+
for (const next of [equivalent, fallback, ...rankedAlternates]) {
|
|
343158
343226
|
if (!next || attempts.length >= 2) continue;
|
|
343159
343227
|
attempts.push({
|
|
343160
343228
|
deployment: { ...next.deployment },
|
|
343161
|
-
kind: next === equivalent ? "equivalent_deployment" : "fallback_model",
|
|
343229
|
+
kind: next === equivalent ? "equivalent_deployment" : next === fallback ? "fallback_model" : "alternate_model",
|
|
343162
343230
|
status: "planned",
|
|
343163
343231
|
errorType: failure.error.type,
|
|
343164
343232
|
streamCommitted: false,
|
|
@@ -343401,7 +343469,7 @@ function percentile(values, fraction) {
|
|
|
343401
343469
|
}
|
|
343402
343470
|
function failureFromType(type) {
|
|
343403
343471
|
const retryable = type === "timeout" || type === "rate_limited" || type === "transport" || type === "server_error" || type === "empty_response";
|
|
343404
|
-
return { type, retryable, switchAllowed: retryable };
|
|
343472
|
+
return { type, retryable, switchAllowed: retryable || type === "balance_exhausted" };
|
|
343405
343473
|
}
|
|
343406
343474
|
|
|
343407
343475
|
// src/context/services/agent-context-manager.ts
|
|
@@ -344866,6 +344934,7 @@ var Agent4 = class _Agent {
|
|
|
344866
344934
|
memoryLabRebuildState = "idle";
|
|
344867
344935
|
memoryLabRebuildError = "";
|
|
344868
344936
|
displayImageDescriptionCache = /* @__PURE__ */ new Map();
|
|
344937
|
+
latestCapturedImageInputs = [];
|
|
344869
344938
|
activeProcessAbortController = null;
|
|
344870
344939
|
automationManager = null;
|
|
344871
344940
|
activeAgentKernelRuntime = null;
|
|
@@ -345506,7 +345575,9 @@ var Agent4 = class _Agent {
|
|
|
345506
345575
|
}
|
|
345507
345576
|
updateProviders(value) {
|
|
345508
345577
|
const before = this.config.providers();
|
|
345509
|
-
|
|
345578
|
+
const merged = mergeProviderSecrets(value, before);
|
|
345579
|
+
resetEditedModelValidationEvidence(merged, before);
|
|
345580
|
+
this.config.set("models", "providers", merged);
|
|
345510
345581
|
const after = this.config.providers();
|
|
345511
345582
|
const beforeById = new Map(before.map((provider) => [provider.id, provider]));
|
|
345512
345583
|
const afterById = new Map(after.map((provider) => [provider.id, provider]));
|
|
@@ -347063,6 +347134,13 @@ ${String(event.toolArgs || "")}`;
|
|
|
347063
347134
|
listConversationStates() {
|
|
347064
347135
|
return this.listWorkspaceConversationStates(this.workspace.current);
|
|
347065
347136
|
}
|
|
347137
|
+
registerCapturedImageInput(dataUrl, name50 = "active-screenshot.jpg") {
|
|
347138
|
+
if (!String(dataUrl || "").startsWith("data:image/")) return null;
|
|
347139
|
+
const prepared = this.prepareSubmittedConversationImages([{ dataUrl, name: name50, type: dataUrl.slice(5, dataUrl.indexOf(";")) }]);
|
|
347140
|
+
const attachment = prepared.attachments[0] || null;
|
|
347141
|
+
this.latestCapturedImageInputs = attachment ? [attachment] : [];
|
|
347142
|
+
return attachment;
|
|
347143
|
+
}
|
|
347066
347144
|
subagentConcurrencyLimit() {
|
|
347067
347145
|
return this.intelligence === "ultra" ? 16 : 4;
|
|
347068
347146
|
}
|
|
@@ -347585,6 +347663,19 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
347585
347663
|
this.writeStoredConversationState(stored, targetWs);
|
|
347586
347664
|
return true;
|
|
347587
347665
|
}
|
|
347666
|
+
reorderConversationContinuations(orderedIds) {
|
|
347667
|
+
const currentIds = this.continuations.filter((item) => item.queueMode === "followUp" && !!item.clientMessageId).map((item) => String(item.clientMessageId));
|
|
347668
|
+
const completeOrder = orderedIds.length === currentIds.length && new Set(orderedIds).size === orderedIds.length && orderedIds.every((id) => currentIds.includes(id));
|
|
347669
|
+
if (!completeOrder) throw new Error("A complete queue order with unique current item ids is required");
|
|
347670
|
+
const byId = new Map(this.continuations.flatMap((item) => item.queueMode === "followUp" && item.clientMessageId ? [[String(item.clientMessageId), item]] : []));
|
|
347671
|
+
let nextIndex = 0;
|
|
347672
|
+
this.continuations = this.continuations.map((item) => {
|
|
347673
|
+
if (item.queueMode !== "followUp" || !item.clientMessageId) return item;
|
|
347674
|
+
return byId.get(orderedIds[nextIndex++]);
|
|
347675
|
+
});
|
|
347676
|
+
this.saveWorkspaceConversationState(true);
|
|
347677
|
+
return this.conversationContinuations();
|
|
347678
|
+
}
|
|
347588
347679
|
renameConversation(id, title, ws = this.workspace.current) {
|
|
347589
347680
|
const targetWs = ws || this.workspace.current;
|
|
347590
347681
|
if (!targetWs) return false;
|
|
@@ -350390,6 +350481,9 @@ ${msg.content}
|
|
|
350390
350481
|
const fallbackEnabled = this.config.getBool("models", "fallback_on_unavailable");
|
|
350391
350482
|
const observedFailure = classifyRouteFailure(errorText);
|
|
350392
350483
|
const observedDeployment = this.activeDeployment();
|
|
350484
|
+
if (observedFailure.type === "balance_exhausted" && observedDeployment) {
|
|
350485
|
+
this.providerBalanceBlockedUntilByDeployment.set(deploymentIdentity(observedDeployment), Date.now() + 5 * 6e4);
|
|
350486
|
+
}
|
|
350393
350487
|
const previousAttempt = observedDeployment && this.lastRouteDecision ? [...this.lastRouteDecision.attempts].reverse().find((attempt) => deploymentIdentity(attempt.deployment) === deploymentIdentity(observedDeployment)) : void 0;
|
|
350394
350488
|
if (this.model === "auto" && this.routeAttemptStartedAt === 0 && (this.lastRouteDecision?.finalStatus === "failed" || this.lastRouteDecision?.finalStatus === "blocked") && previousAttempt?.status === "failed" && previousAttempt.errorType === observedFailure.type) {
|
|
350395
350489
|
return null;
|
|
@@ -350440,14 +350534,12 @@ ${msg.content}
|
|
|
350440
350534
|
return current2.modelId;
|
|
350441
350535
|
}
|
|
350442
350536
|
if (!fallbackEnabled) return null;
|
|
350443
|
-
if (!observedFailure.
|
|
350537
|
+
if (!observedFailure.switchAllowed || this.routeStreamCommitted || this.routeSideEffectCommitted) return null;
|
|
350444
350538
|
const current = this.model;
|
|
350445
|
-
const
|
|
350539
|
+
const currentDeployment = observedDeployment;
|
|
350540
|
+
const all = this.scopedSwitchModels(current).filter((m2) => !currentDeployment || deploymentIdentity(this.deploymentRef(m2)) !== deploymentIdentity(currentDeployment));
|
|
350446
350541
|
if (!all.length) return null;
|
|
350447
|
-
const usable = all.filter((m2) =>
|
|
350448
|
-
const status = String(m2.evaluation?.status || "unknown").toLowerCase();
|
|
350449
|
-
return status !== "unavailable" && !status.startsWith("error");
|
|
350450
|
-
});
|
|
350542
|
+
const usable = all.filter((m2) => !this.isBalanceBlockedDeployment(this.deploymentRef(m2)) && !modelConfigIsUnavailable(m2));
|
|
350451
350543
|
if (!usable.length) return null;
|
|
350452
350544
|
const pref = this.config.autoSwitchPreference();
|
|
350453
350545
|
const ranked = [...usable].sort((a3, b2) => this.modelScore(b2, pref, false, false) - this.modelScore(a3, pref, false, false));
|
|
@@ -351123,7 +351215,7 @@ ${persisted.map((guide, index) => `Guide ${index + 1}: ${guide.text}`).join("\n"
|
|
|
351123
351215
|
throw e3;
|
|
351124
351216
|
}
|
|
351125
351217
|
const msg = e3 instanceof Error ? e3.message : String(e3);
|
|
351126
|
-
if (/\b402\b|insufficient balance|insufficient funds|payment required
|
|
351218
|
+
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)) {
|
|
351127
351219
|
this.noteProviderBalanceFailure();
|
|
351128
351220
|
}
|
|
351129
351221
|
this.status = "error";
|
|
@@ -351980,6 +352072,13 @@ ${items.map((item) => this.formatAutomation(item)).join("\n")}`;
|
|
|
351980
352072
|
}
|
|
351981
352073
|
latestSubmittedImages(attachmentId = "") {
|
|
351982
352074
|
const normalizedId = String(attachmentId || "").trim();
|
|
352075
|
+
const captured = hydrateConversationImageAttachments(this.rootPath, this.latestCapturedImageInputs).flatMap((attachment) => attachment.dataUrl ? [{ id: attachment.id, dataUrl: attachment.dataUrl }] : []);
|
|
352076
|
+
if (normalizedId) {
|
|
352077
|
+
const capturedMatch = captured.find((item) => item.id === normalizedId);
|
|
352078
|
+
if (capturedMatch) return [capturedMatch];
|
|
352079
|
+
} else if (captured.length) {
|
|
352080
|
+
return captured;
|
|
352081
|
+
}
|
|
351983
352082
|
for (let index = this.chatMessages.length - 1; index >= 0; index -= 1) {
|
|
351984
352083
|
const message = this.chatMessages[index];
|
|
351985
352084
|
if (message?.role !== "user") continue;
|
|
@@ -353024,11 +353123,63 @@ function routeProviderFingerprint(provider) {
|
|
|
353024
353123
|
enabled: provider.enabled,
|
|
353025
353124
|
models: (provider.models || []).map((model) => ({
|
|
353026
353125
|
name: model.name,
|
|
353126
|
+
display: model.display,
|
|
353127
|
+
description: model.description,
|
|
353128
|
+
maxTokens: model.max_tokens,
|
|
353129
|
+
vision: model.vision,
|
|
353130
|
+
thinking: !!model.thinking,
|
|
353131
|
+
imageOutput: !!model.image_output,
|
|
353027
353132
|
enabled: model.enabled !== false,
|
|
353028
|
-
|
|
353133
|
+
preview: !!model.preview,
|
|
353134
|
+
logicalModelGroupId: model.logical_model_group_id || "",
|
|
353135
|
+
privacy: model.privacy || [],
|
|
353136
|
+
capabilities: model.capabilities || [],
|
|
353137
|
+
supportedParameters: model.supported_parameters || [],
|
|
353138
|
+
routePreference: model.route_preference,
|
|
353139
|
+
fallbackOnly: !!model.fallback_only,
|
|
353140
|
+
thinkingTierMap: model.thinking_tier_map || {}
|
|
353029
353141
|
}))
|
|
353030
353142
|
});
|
|
353031
353143
|
}
|
|
353144
|
+
function modelConfigurationFingerprint(model) {
|
|
353145
|
+
const { validation, evaluation, _previous_name, previous_name, ...configuration } = model;
|
|
353146
|
+
void validation;
|
|
353147
|
+
void evaluation;
|
|
353148
|
+
void _previous_name;
|
|
353149
|
+
void previous_name;
|
|
353150
|
+
return JSON.stringify(configuration);
|
|
353151
|
+
}
|
|
353152
|
+
function resetEditedModelValidationEvidence(incomingProviders, existingProviders) {
|
|
353153
|
+
const existingById = new Map(existingProviders.map((provider) => [provider.id, provider]));
|
|
353154
|
+
const existingByName = new Map(existingProviders.map((provider) => [provider.name, provider]));
|
|
353155
|
+
for (const rawProvider of incomingProviders) {
|
|
353156
|
+
if (!rawProvider || typeof rawProvider !== "object" || Array.isArray(rawProvider)) continue;
|
|
353157
|
+
const provider = rawProvider;
|
|
353158
|
+
const previousProvider = existingById.get(String(provider.id || "")) || existingByName.get(String(provider._previous_name || provider.previous_name || provider.name || ""));
|
|
353159
|
+
const models = Array.isArray(provider.models) ? provider.models : [];
|
|
353160
|
+
const providerConnectionChanged = !!previousProvider && (String(provider.base_url || provider.endpoint || "") !== previousProvider.base_url || String(provider.protocol || "") !== previousProvider.protocol);
|
|
353161
|
+
for (const rawModel of models) {
|
|
353162
|
+
if (!rawModel || typeof rawModel !== "object" || Array.isArray(rawModel)) continue;
|
|
353163
|
+
const model = rawModel;
|
|
353164
|
+
const previousName = String(model._previous_name || model.previous_name || model.name || "");
|
|
353165
|
+
const previousModel = previousProvider?.models.find((candidate) => candidate.name === previousName);
|
|
353166
|
+
const edited = providerConnectionChanged || !!previousModel && modelConfigurationFingerprint(model) !== modelConfigurationFingerprint(previousModel);
|
|
353167
|
+
delete model._previous_name;
|
|
353168
|
+
delete model.previous_name;
|
|
353169
|
+
if (!edited) continue;
|
|
353170
|
+
model.validation = { level: "discovered", status: "degraded", checked_at: "", capabilities: {} };
|
|
353171
|
+
delete model.evaluation;
|
|
353172
|
+
model.speed_rating = "unknown";
|
|
353173
|
+
model.capability_rating = "unknown";
|
|
353174
|
+
}
|
|
353175
|
+
}
|
|
353176
|
+
}
|
|
353177
|
+
function modelConfigIsUnavailable(model) {
|
|
353178
|
+
const validationStatus = effectiveModelValidationStatus(model);
|
|
353179
|
+
if (model.validation?.level !== "discovered" && (validationStatus === "unavailable" || validationStatus === "auth_error" || validationStatus === "invalid_config")) return true;
|
|
353180
|
+
const evaluationStatus = validationStatus === "degraded" ? "degraded" : String(model.evaluation?.status || "").toLowerCase();
|
|
353181
|
+
return evaluationStatus === "unavailable" || evaluationStatus.startsWith("error");
|
|
353182
|
+
}
|
|
353032
353183
|
function parseDeploymentSelectionValue2(value) {
|
|
353033
353184
|
const marker = String(value || "").trim();
|
|
353034
353185
|
if (!marker.startsWith("deployment:")) return null;
|
|
@@ -353045,9 +353196,9 @@ function parseDeploymentSelectionValue2(value) {
|
|
|
353045
353196
|
function effectiveModelValidationStatus(model) {
|
|
353046
353197
|
const raw = String(model.validation?.status || "").toLowerCase();
|
|
353047
353198
|
if (raw === "auth_error") return raw;
|
|
353199
|
+
if (String(model.validation?.level || "").toLowerCase() === "discovered") return "degraded";
|
|
353048
353200
|
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;
|
|
353049
353201
|
if (textEvidence && raw === "unavailable") return "degraded";
|
|
353050
|
-
if (!raw && String(model.validation?.level || "").toLowerCase() === "discovered") return "degraded";
|
|
353051
353202
|
return ["verified", "degraded", "unavailable", "auth_error", "rate_limited", "invalid_config"].includes(raw) ? raw : "unavailable";
|
|
353052
353203
|
}
|
|
353053
353204
|
function routeToolIsReadOnly(name50, rawArgs) {
|
|
@@ -353164,6 +353315,184 @@ var ConversationKernel = class {
|
|
|
353164
353315
|
followUp: queued?.followUp.slice() || []
|
|
353165
353316
|
};
|
|
353166
353317
|
}
|
|
353318
|
+
queueItems(target) {
|
|
353319
|
+
const runtime = this.findRuntime(target);
|
|
353320
|
+
if (!runtime) return [];
|
|
353321
|
+
return runtime.pendingNextTurn.flatMap((item) => {
|
|
353322
|
+
if (item.queueMode !== "followUp") return [];
|
|
353323
|
+
if (typeof item.message === "string") return [];
|
|
353324
|
+
const id = String(item.message.clientMessageId || "");
|
|
353325
|
+
if (!id) return [];
|
|
353326
|
+
return [{
|
|
353327
|
+
id,
|
|
353328
|
+
text: String(item.message.visibleUserInput || item.message.text || "").replace(/^\[Next queued while current turn is running\]\n/, ""),
|
|
353329
|
+
queueMode: item.queueMode,
|
|
353330
|
+
requestedMode: item.message.visibleMode,
|
|
353331
|
+
goalObjective: item.message.goalObjective,
|
|
353332
|
+
runId: item.message.runId,
|
|
353333
|
+
createdAt: String(item.message.createdAt || "")
|
|
353334
|
+
}];
|
|
353335
|
+
});
|
|
353336
|
+
}
|
|
353337
|
+
enqueueNext(target, input) {
|
|
353338
|
+
const runtime = this.findRuntime(target);
|
|
353339
|
+
if (!runtime?.activePromise || !runtime.runId) throw new Error("Target conversation is not running");
|
|
353340
|
+
const id = String(input.id || "").trim().slice(0, 200);
|
|
353341
|
+
const text = String(input.text || "").trim();
|
|
353342
|
+
if (!id || !text) throw new Error("Queue item id and text are required");
|
|
353343
|
+
const existing = this.queueItems(runtime.target).find((item) => item.id === id);
|
|
353344
|
+
if (existing) return existing;
|
|
353345
|
+
const prompt = `[Next queued while current turn is running]
|
|
353346
|
+
${text}`;
|
|
353347
|
+
const createdAt = String(input.createdAt || (/* @__PURE__ */ new Date()).toISOString());
|
|
353348
|
+
runtime.pendingNextTurn.push({
|
|
353349
|
+
message: {
|
|
353350
|
+
text: prompt,
|
|
353351
|
+
visibleUserInput: text,
|
|
353352
|
+
visibleMode: String(input.requestedMode || "build"),
|
|
353353
|
+
goalObjective: String(input.goalObjective || "") || void 0,
|
|
353354
|
+
clientMessageId: id,
|
|
353355
|
+
runId: runtime.runId,
|
|
353356
|
+
createdAt
|
|
353357
|
+
},
|
|
353358
|
+
queueMode: "followUp"
|
|
353359
|
+
});
|
|
353360
|
+
runtime.runner.retainConversationContinuations([{
|
|
353361
|
+
content: prompt,
|
|
353362
|
+
queueMode: "followUp",
|
|
353363
|
+
clientMessageId: id,
|
|
353364
|
+
runId: runtime.runId,
|
|
353365
|
+
createdAt
|
|
353366
|
+
}]);
|
|
353367
|
+
this.trackQueuedMessage(runtime, prompt, "followUp");
|
|
353368
|
+
this.emitQueueUpdate(runtime);
|
|
353369
|
+
return this.queueItems(runtime.target).find((item) => item.id === id);
|
|
353370
|
+
}
|
|
353371
|
+
updateQueueItem(target, idInput, textInput) {
|
|
353372
|
+
const runtime = this.findRuntime(target);
|
|
353373
|
+
if (!runtime) throw new Error("Target conversation runtime is unavailable");
|
|
353374
|
+
const id = String(idInput || "").trim();
|
|
353375
|
+
const text = String(textInput || "").trim();
|
|
353376
|
+
if (!id || !text) throw new Error("Queue item id and text are required");
|
|
353377
|
+
const pending3 = runtime.pendingNextTurn.find((item) => typeof item.message !== "string" && item.message.clientMessageId === id);
|
|
353378
|
+
if (!pending3 || typeof pending3.message === "string") throw new Error("Queue item is no longer editable");
|
|
353379
|
+
const oldPrompt = pending3.message.text;
|
|
353380
|
+
pending3.message.text = `[Next queued while current turn is running]
|
|
353381
|
+
${text}`;
|
|
353382
|
+
pending3.message.visibleUserInput = text;
|
|
353383
|
+
runtime.runner.consumeConversationContinuation({ content: oldPrompt, queueMode: pending3.queueMode, clientMessageId: id });
|
|
353384
|
+
runtime.runner.retainConversationContinuations([{
|
|
353385
|
+
content: pending3.message.text,
|
|
353386
|
+
queueMode: pending3.queueMode,
|
|
353387
|
+
clientMessageId: id,
|
|
353388
|
+
runId: pending3.message.runId
|
|
353389
|
+
}]);
|
|
353390
|
+
this.replaceTrackedQueuedMessage(runtime, oldPrompt, pending3.message.text, pending3.queueMode);
|
|
353391
|
+
this.emitQueueUpdate(runtime);
|
|
353392
|
+
return this.queueItems(runtime.target).find((item) => item.id === id);
|
|
353393
|
+
}
|
|
353394
|
+
deleteQueueItem(target, idInput) {
|
|
353395
|
+
const runtime = this.findRuntime(target);
|
|
353396
|
+
if (!runtime) return false;
|
|
353397
|
+
const id = String(idInput || "").trim();
|
|
353398
|
+
const index = runtime.pendingNextTurn.findIndex((item) => typeof item.message !== "string" && item.message.clientMessageId === id);
|
|
353399
|
+
if (index < 0) return false;
|
|
353400
|
+
const [removed] = runtime.pendingNextTurn.splice(index, 1);
|
|
353401
|
+
if (typeof removed.message !== "string") {
|
|
353402
|
+
runtime.runner.consumeConversationContinuation({ content: removed.message.text, queueMode: removed.queueMode, clientMessageId: id });
|
|
353403
|
+
this.consumeQueuedMessage(runtime, removed.message.text);
|
|
353404
|
+
}
|
|
353405
|
+
this.emitQueueUpdate(runtime);
|
|
353406
|
+
return true;
|
|
353407
|
+
}
|
|
353408
|
+
reorderQueueItems(target, orderedIdsInput) {
|
|
353409
|
+
const runtime = this.findRuntime(target);
|
|
353410
|
+
if (!runtime) throw new Error("Target conversation runtime is unavailable");
|
|
353411
|
+
const currentItems = this.queueItems(runtime.target);
|
|
353412
|
+
const orderedIds = Array.isArray(orderedIdsInput) ? orderedIdsInput.map((id) => String(id || "").trim()) : [];
|
|
353413
|
+
const currentIds = currentItems.map((item) => item.id);
|
|
353414
|
+
const completeOrder = orderedIds.length === currentIds.length && new Set(orderedIds).size === orderedIds.length && orderedIds.every((id) => currentIds.includes(id));
|
|
353415
|
+
if (!completeOrder) throw new Error("A complete queue order with unique current item ids is required");
|
|
353416
|
+
const persistedIds = runtime.runner.conversationContinuations().filter((item) => item.queueMode === "followUp" && !!item.clientMessageId).map((item) => String(item.clientMessageId));
|
|
353417
|
+
if (persistedIds.length !== currentIds.length || new Set(persistedIds).size !== persistedIds.length || persistedIds.some((id) => !currentIds.includes(id))) {
|
|
353418
|
+
throw new Error("Persisted queue does not match the complete queue order");
|
|
353419
|
+
}
|
|
353420
|
+
const pendingById = new Map(runtime.pendingNextTurn.flatMap((item) => {
|
|
353421
|
+
if (item.queueMode !== "followUp" || typeof item.message === "string" || !item.message.clientMessageId) return [];
|
|
353422
|
+
return [[String(item.message.clientMessageId), item]];
|
|
353423
|
+
}));
|
|
353424
|
+
const reorderedPending = orderedIds.map((id) => pendingById.get(id));
|
|
353425
|
+
let nextIndex = 0;
|
|
353426
|
+
runtime.pendingNextTurn = runtime.pendingNextTurn.map((item) => {
|
|
353427
|
+
if (item.queueMode !== "followUp" || typeof item.message === "string" || !item.message.clientMessageId) return item;
|
|
353428
|
+
return reorderedPending[nextIndex++];
|
|
353429
|
+
});
|
|
353430
|
+
runtime.runner.reorderConversationContinuations(orderedIds);
|
|
353431
|
+
runtime.queued.followUp = orderedIds.map((id) => pendingById.get(id)).map((item) => typeof item.message === "string" ? item.message : item.message.text);
|
|
353432
|
+
this.emitQueueUpdate(runtime);
|
|
353433
|
+
return this.queueItems(runtime.target);
|
|
353434
|
+
}
|
|
353435
|
+
setQueuePaused(target, paused) {
|
|
353436
|
+
const runtime = this.findRuntime(target);
|
|
353437
|
+
if (!runtime) throw new Error("Target conversation runtime is unavailable");
|
|
353438
|
+
runtime.queuePaused = paused;
|
|
353439
|
+
this.emitQueueUpdate(runtime);
|
|
353440
|
+
if (!paused && !runtime.activePromise && runtime.pendingNextTurn.length) {
|
|
353441
|
+
this.schedulePendingRuntimeContinuation(runtime, runtime.runId);
|
|
353442
|
+
}
|
|
353443
|
+
return runtime.queuePaused;
|
|
353444
|
+
}
|
|
353445
|
+
queueAction(target, action, input = {}) {
|
|
353446
|
+
const runtime = this.findRuntime(target);
|
|
353447
|
+
if (!runtime) throw new Error("Target conversation runtime is unavailable");
|
|
353448
|
+
let receipt;
|
|
353449
|
+
if (action === "enqueue") {
|
|
353450
|
+
this.enqueueNext(runtime.target, {
|
|
353451
|
+
id: String(input.id || ""),
|
|
353452
|
+
text: String(input.text || ""),
|
|
353453
|
+
requestedMode: input.requestedMode,
|
|
353454
|
+
goalObjective: input.goalObjective,
|
|
353455
|
+
createdAt: input.createdAt
|
|
353456
|
+
});
|
|
353457
|
+
} else if (action === "update") {
|
|
353458
|
+
this.updateQueueItem(runtime.target, String(input.id || ""), String(input.text || ""));
|
|
353459
|
+
} else if (action === "delete") {
|
|
353460
|
+
if (!this.deleteQueueItem(runtime.target, String(input.id || ""))) throw new Error("Queue item was not found");
|
|
353461
|
+
} else if (action === "reorder") {
|
|
353462
|
+
this.reorderQueueItems(runtime.target, input.orderedIds || []);
|
|
353463
|
+
} else if (action === "toggle_pause") {
|
|
353464
|
+
this.setQueuePaused(runtime.target, !runtime.queuePaused);
|
|
353465
|
+
} else if (action === "guide") {
|
|
353466
|
+
const item = this.queueItems(runtime.target).find((entry) => entry.id === String(input.id || ""));
|
|
353467
|
+
if (!item) throw new Error("Queue item was not found");
|
|
353468
|
+
receipt = this.enqueueGuide({
|
|
353469
|
+
clientMessageId: item.id,
|
|
353470
|
+
guideId: (0, import_crypto16.randomUUID)(),
|
|
353471
|
+
target: runtime.target,
|
|
353472
|
+
runId: runtime.runId,
|
|
353473
|
+
deliveryMode: "steer",
|
|
353474
|
+
text: item.goalObjective ? `Goal for the current Build:
|
|
353475
|
+
${item.goalObjective}` : item.text,
|
|
353476
|
+
goalObjective: item.goalObjective,
|
|
353477
|
+
createdAt: item.createdAt || (/* @__PURE__ */ new Date()).toISOString()
|
|
353478
|
+
});
|
|
353479
|
+
if (receipt.status === "rejected") return {
|
|
353480
|
+
ok: false,
|
|
353481
|
+
queueItems: this.queueItems(runtime.target),
|
|
353482
|
+
queuePaused: runtime.queuePaused,
|
|
353483
|
+
queued: this.queued(runtime.target),
|
|
353484
|
+
receipt
|
|
353485
|
+
};
|
|
353486
|
+
this.deleteQueueItem(runtime.target, item.id);
|
|
353487
|
+
}
|
|
353488
|
+
return {
|
|
353489
|
+
ok: true,
|
|
353490
|
+
queueItems: this.queueItems(runtime.target),
|
|
353491
|
+
queuePaused: runtime.queuePaused,
|
|
353492
|
+
queued: this.queued(runtime.target),
|
|
353493
|
+
receipt
|
|
353494
|
+
};
|
|
353495
|
+
}
|
|
353167
353496
|
events(target) {
|
|
353168
353497
|
return this.findRuntime(target)?.events.slice() || [];
|
|
353169
353498
|
}
|
|
@@ -353192,6 +353521,8 @@ var ConversationKernel = class {
|
|
|
353192
353521
|
workRuns: this.bindWorkRunsToRuntimeTarget(conversationSnapshot.workRuns, normalized),
|
|
353193
353522
|
target: normalized,
|
|
353194
353523
|
queued: this.queued(normalized),
|
|
353524
|
+
queueItems: this.queueItems(normalized),
|
|
353525
|
+
queuePaused: runtime?.queuePaused === true,
|
|
353195
353526
|
workEvents: this.events(normalized),
|
|
353196
353527
|
runtime: this.runtimeState(normalized),
|
|
353197
353528
|
mode: runner.mode,
|
|
@@ -353627,7 +353958,7 @@ var ConversationKernel = class {
|
|
|
353627
353958
|
if (runtime.stopRequestedRunId === runId) {
|
|
353628
353959
|
stopped = true;
|
|
353629
353960
|
this.settleCooperativeStop(runtime, runId);
|
|
353630
|
-
} else if (runtime.pendingNextTurn.length > 0) {
|
|
353961
|
+
} else if (!runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
|
|
353631
353962
|
this.schedulePendingRuntimeContinuation(runtime, runId);
|
|
353632
353963
|
}
|
|
353633
353964
|
}
|
|
@@ -353662,7 +353993,7 @@ var ConversationKernel = class {
|
|
|
353662
353993
|
return this.result(runtime, lastTokens);
|
|
353663
353994
|
}
|
|
353664
353995
|
for (; ; ) {
|
|
353665
|
-
while (runtime.pendingNextTurn.length > 0) {
|
|
353996
|
+
while (!runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
|
|
353666
353997
|
if (runtime.stopRequestedRunId === runtime.runId) return this.result(runtime, lastTokens);
|
|
353667
353998
|
const next = runtime.pendingNextTurn.shift();
|
|
353668
353999
|
if (next.queueMode === "steer" && typeof next.message !== "string" && !!next.message.clientMessageId) {
|
|
@@ -353704,11 +354035,11 @@ ${batchText}`,
|
|
|
353704
354035
|
this.mirrorHostIfTargetActive(runtime);
|
|
353705
354036
|
return this.result(runtime, lastTokens);
|
|
353706
354037
|
}
|
|
353707
|
-
this.clearQueued(runtime);
|
|
354038
|
+
if (!runtime.pendingNextTurn.length) this.clearQueued(runtime);
|
|
353708
354039
|
const completedRunId = runtime.runId;
|
|
353709
354040
|
runtime.runner.finishConversationWorkRun(completedRunId, "completed");
|
|
353710
354041
|
await new Promise((resolve16) => setImmediate(resolve16));
|
|
353711
|
-
if (runtime.runId === completedRunId && runtime.stopRequestedRunId !== completedRunId && runtime.pendingNextTurn.length > 0) {
|
|
354042
|
+
if (runtime.runId === completedRunId && runtime.stopRequestedRunId !== completedRunId && !runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
|
|
353712
354043
|
runtime.guideAcceptanceClosedRunId = "";
|
|
353713
354044
|
if (!runtime.runner.resumeConversationWorkRun(completedRunId)) {
|
|
353714
354045
|
throw new Error(`Unable to resume deferred Guide work run ${completedRunId}`);
|
|
@@ -353799,6 +354130,7 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
353799
354130
|
events: [],
|
|
353800
354131
|
pendingNextTurn: [],
|
|
353801
354132
|
queued: { steering: [], followUp: [] },
|
|
354133
|
+
queuePaused: false,
|
|
353802
354134
|
runId: "",
|
|
353803
354135
|
generation: this.generations.get(target.runtimeKey) || 0,
|
|
353804
354136
|
stopRequestedRunId: "",
|
|
@@ -353894,7 +354226,7 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
353894
354226
|
}
|
|
353895
354227
|
setImmediate(() => {
|
|
353896
354228
|
runtime.pendingContinuationRunId = void 0;
|
|
353897
|
-
if (runtime.runId !== runId || runtime.activePromise || runtime.stopRequestedRunId === runId) return;
|
|
354229
|
+
if (runtime.runId !== runId || runtime.activePromise || runtime.stopRequestedRunId === runId || runtime.queuePaused) return;
|
|
353898
354230
|
const next = runtime.pendingNextTurn.shift();
|
|
353899
354231
|
if (!next) return;
|
|
353900
354232
|
const message = typeof next.message === "string" ? { text: next.message, runId } : { ...next.message, runId: next.message.runId || runId };
|
|
@@ -354045,7 +354377,36 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
354045
354377
|
const text = typeof message === "string" ? message : message.text;
|
|
354046
354378
|
const prompt = isSteer ? text : `[Next queued while current turn is running]
|
|
354047
354379
|
${text}`;
|
|
354048
|
-
if (!isSteer)
|
|
354380
|
+
if (!isSteer) {
|
|
354381
|
+
const structured = typeof message === "string" ? null : message;
|
|
354382
|
+
const clientMessageId = String(structured?.clientMessageId || (0, import_crypto16.randomUUID)());
|
|
354383
|
+
const queuedMessage = {
|
|
354384
|
+
...structured || {},
|
|
354385
|
+
text: prompt,
|
|
354386
|
+
visibleUserInput: structured?.visibleUserInput || text,
|
|
354387
|
+
visibleMode: structured?.visibleMode || runtime.options.mode,
|
|
354388
|
+
clientMessageId,
|
|
354389
|
+
runId: structured?.runId || runtime.runId,
|
|
354390
|
+
createdAt: String(structured?.createdAt || (/* @__PURE__ */ new Date()).toISOString())
|
|
354391
|
+
};
|
|
354392
|
+
if (!runtime.pendingNextTurn.some((item) => typeof item.message !== "string" && item.message.clientMessageId === clientMessageId)) {
|
|
354393
|
+
runtime.pendingNextTurn.push({ message: queuedMessage, queueMode: "followUp" });
|
|
354394
|
+
}
|
|
354395
|
+
runtime.runner.retainConversationContinuations([{
|
|
354396
|
+
content: prompt,
|
|
354397
|
+
queueMode: "followUp",
|
|
354398
|
+
clientMessageId,
|
|
354399
|
+
runId: queuedMessage.runId,
|
|
354400
|
+
images: queuedMessage.images?.map((image) => ({ ...image })),
|
|
354401
|
+
attachments: queuedMessage.attachments?.map((attachment) => ({ ...attachment })),
|
|
354402
|
+
createdAt: queuedMessage.createdAt
|
|
354403
|
+
}]);
|
|
354404
|
+
this.trackQueuedMessage(runtime, prompt, "followUp");
|
|
354405
|
+
runtime.runner.recordWorkStatus(runtime.stopRequestedRunId === runtime.runId ? "Next message retained while stopping." : "Next message queued.");
|
|
354406
|
+
if (runtime.stopRequestedRunId === runtime.runId) runtime.forceStopArmedRunId = "";
|
|
354407
|
+
this.emitQueueUpdate(runtime);
|
|
354408
|
+
return;
|
|
354409
|
+
}
|
|
354049
354410
|
if (runtime.stopRequestedRunId === runtime.runId) {
|
|
354050
354411
|
runtime.forceStopArmedRunId = "";
|
|
354051
354412
|
const structured = typeof message === "string" ? void 0 : message;
|
|
@@ -354091,6 +354452,12 @@ ${text}`;
|
|
|
354091
354452
|
}
|
|
354092
354453
|
if (changed) this.emitQueueUpdate(runtime);
|
|
354093
354454
|
}
|
|
354455
|
+
replaceTrackedQueuedMessage(runtime, oldMessage, nextMessage, queueMode) {
|
|
354456
|
+
this.queueState(runtime);
|
|
354457
|
+
const list = queueMode === "steer" ? runtime.queued.steering : runtime.queued.followUp;
|
|
354458
|
+
const index = list.indexOf(oldMessage);
|
|
354459
|
+
if (index >= 0) list[index] = nextMessage;
|
|
354460
|
+
}
|
|
354094
354461
|
emitQueueUpdate(runtime) {
|
|
354095
354462
|
this.queueState(runtime);
|
|
354096
354463
|
runtime.runner.emitWorkEvent({
|
|
@@ -354212,9 +354579,10 @@ ${text}`;
|
|
|
354212
354579
|
const runId = runtime.runId;
|
|
354213
354580
|
await Promise.resolve();
|
|
354214
354581
|
if (runtime.runId !== runId || runtime.stopRequestedRunId === runId) return true;
|
|
354215
|
-
|
|
354582
|
+
const hasSteering = runtime.pendingNextTurn.some((item) => item.queueMode === "steer");
|
|
354583
|
+
if (hasSteering || runtime.runner.subagents.readRootInbox().length > 0) return false;
|
|
354216
354584
|
runtime.guideAcceptanceClosedRunId = runId;
|
|
354217
|
-
if (runtime.pendingNextTurn.
|
|
354585
|
+
if (runtime.pendingNextTurn.some((item) => item.queueMode === "steer") || runtime.runner.subagents.readRootInbox().length > 0) {
|
|
354218
354586
|
runtime.guideAcceptanceClosedRunId = "";
|
|
354219
354587
|
return false;
|
|
354220
354588
|
}
|
|
@@ -354367,6 +354735,9 @@ async function handle(request) {
|
|
|
354367
354735
|
target
|
|
354368
354736
|
});
|
|
354369
354737
|
}
|
|
354738
|
+
if (request.method === "queue_action") {
|
|
354739
|
+
return kernel.queueAction(checkedTarget(request.params.target), request.params.action, request.params.input);
|
|
354740
|
+
}
|
|
354370
354741
|
if (request.method === "checkpoint") return kernel.checkpoint(checkedTarget(request.params.target));
|
|
354371
354742
|
if (request.method === "context_compress") {
|
|
354372
354743
|
return kernel.compressContext(checkedTarget(request.params.target), request.params.options);
|