newmark-agent 0.4.6 → 0.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/app-icon-dark.svg +6 -0
- package/dist/assets/app-icon-dark.svg +6 -0
- package/dist/cli-commands.js +2 -1
- package/dist/cli-discovery.js +2 -0
- package/dist/conversation-utility-host.bundle.cjs +577 -166
- package/dist/conversation-utility-host.js +3 -0
- package/dist/core/agent.d.ts +40 -4
- package/dist/core/agent.js +251 -49
- package/dist/core/agentKernelRunner.d.ts +3 -0
- package/dist/core/agentKernelRunner.js +74 -91
- package/dist/core/config.js +1 -1
- package/dist/core/conversationKernel.d.ts +40 -0
- package/dist/core/conversationKernel.js +219 -8
- package/dist/core/electronUtilityAgentClient.d.ts +8 -0
- package/dist/core/electronUtilityAgentClient.js +5 -1
- package/dist/core/electronUtilityRuntimePool.d.ts +15 -0
- package/dist/core/electronUtilityRuntimePool.js +11 -0
- package/dist/core/installUpdate.js +11 -8
- package/dist/core/mobilePairing.d.ts +1 -0
- package/dist/core/mobilePairing.js +15 -1
- package/dist/core/subagent.d.ts +10 -3
- package/dist/core/subagent.js +23 -8
- package/dist/core/toolPolicy.js +14 -3
- package/dist/core/utilityAgentProtocol.d.ts +29 -1
- package/dist/core/utilityHostToolRouter.js +18 -0
- package/dist/core/wslAgentClient.d.ts +8 -0
- package/dist/core/wslAgentClient.js +5 -1
- package/dist/core/wslAgentProtocol.d.ts +18 -1
- package/dist/core/wslAgentRuntimePool.d.ts +15 -0
- package/dist/core/wslAgentRuntimePool.js +11 -0
- package/dist/launcher.js +14 -11
- package/dist/main.js +207 -9
- package/dist/providers/chat-completions.adapter.js +6 -2
- package/dist/providers/responses.adapter.js +1 -0
- package/dist/server.d.ts +33 -1
- package/dist/server.js +696 -48
- package/dist/toolchain/registry-seeder.js +3 -1
- package/dist/tools/index.js +57 -6
- package/dist/tools/nativeTools.js +2 -1
- package/dist/ui/index.html +88 -101
- package/dist/wsl-agent-host.bundle.cjs +577 -166
- package/dist/wsl-agent-host.js +3 -0
- package/package.json +4 -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" },
|
|
@@ -327563,7 +327564,7 @@ var NATIVE_TOOL_CATALOG = [
|
|
|
327563
327564
|
{ name: "pdf_read", label: "PDF read", description: "Read PDF text and render scanned pages through vision before local OCR fallback.", category: "core", defaultEnabled: true, protected: true, availability: "mode-scoped" },
|
|
327564
327565
|
{ name: "terminal_takeover", label: "Terminal takeover", description: "Maintain a persistent Agent-controlled shell session.", category: "desktop", defaultEnabled: true },
|
|
327565
327566
|
{ name: "ssh_workspace", label: "OpenSSH workspace", description: "Manage native OpenSSH connections and link remote workspaces by PC_Hash.", category: "ssh", defaultEnabled: true },
|
|
327566
|
-
{ name: "
|
|
327567
|
+
{ name: "SubAgent", label: "SubAgent", description: "Create one real same-conversation peer SubAgent.", category: "agent", defaultEnabled: true, protected: true, availability: "mode-scoped" },
|
|
327567
327568
|
{ name: "subagent_list", label: "Subagent list", description: "List same-conversation peer agents.", category: "agent", defaultEnabled: true, protected: true, availability: "mode-scoped" },
|
|
327568
327569
|
{ name: "subagent_read", label: "Subagent read", description: "Read bounded status, feedback, result, queue, and mailbox summaries for a same-conversation peer.", category: "agent", defaultEnabled: true, protected: true, availability: "mode-scoped" },
|
|
327569
327570
|
{ name: "subagent_send", label: "Subagent send", description: "Persist a message to a peer mailbox.", category: "agent", defaultEnabled: true, protected: true, availability: "mode-scoped" },
|
|
@@ -328315,7 +328316,7 @@ function defaultConfig() {
|
|
|
328315
328316
|
auto_archive_on_close: { _description: "Auto archive on close", _type: "boolean", value: true }
|
|
328316
328317
|
},
|
|
328317
328318
|
remote: {
|
|
328318
|
-
touch_enabled: { _description: "Allow mobile devices to reach this Newmark instance
|
|
328319
|
+
touch_enabled: { _description: "Allow mobile devices to reach this Newmark instance on the same LAN / Tailscale network", _type: "boolean", value: true }
|
|
328319
328320
|
},
|
|
328320
328321
|
models: {
|
|
328321
328322
|
providers: { _description: "LLM providers", _type: "array", value: [] },
|
|
@@ -328863,14 +328864,18 @@ var ChatCompletionsAdapter = class {
|
|
|
328863
328864
|
...request.systemPrompt ? [{ role: CHAT_SYSTEM_ROLE, content: request.systemPrompt }] : [],
|
|
328864
328865
|
...openAIChatMessages(request.messages)
|
|
328865
328866
|
];
|
|
328867
|
+
const tools = this.serializeTools(request.tools);
|
|
328866
328868
|
const body = {
|
|
328867
328869
|
model: request.model,
|
|
328868
328870
|
messages,
|
|
328869
328871
|
temperature: request.temperature,
|
|
328870
|
-
max_tokens: request.maxOutputTokens
|
|
328871
|
-
tools: this.serializeTools(request.tools),
|
|
328872
|
-
tool_choice: "auto"
|
|
328872
|
+
max_tokens: request.maxOutputTokens
|
|
328873
328873
|
};
|
|
328874
|
+
if (tools.length) {
|
|
328875
|
+
body.tools = tools;
|
|
328876
|
+
body.tool_choice = "auto";
|
|
328877
|
+
body.parallel_tool_calls = true;
|
|
328878
|
+
}
|
|
328874
328879
|
if (request.reasoningEffort) body.reasoning_effort = request.reasoningEffort;
|
|
328875
328880
|
if (request.sessionId) body.session_id = request.sessionId;
|
|
328876
328881
|
const base2 = request.baseUrl.replace(/\/+$/, "");
|
|
@@ -329124,6 +329129,7 @@ var ResponsesAdapter = class {
|
|
|
329124
329129
|
if (tools.length) {
|
|
329125
329130
|
body.tools = tools;
|
|
329126
329131
|
body.tool_choice = "auto";
|
|
329132
|
+
body.parallel_tool_calls = true;
|
|
329127
329133
|
}
|
|
329128
329134
|
const base2 = request.baseUrl.replace(/\/+$/, "");
|
|
329129
329135
|
return {
|
|
@@ -335741,6 +335747,7 @@ var import_crypto6 = require("crypto");
|
|
|
335741
335747
|
// src/core/toolPolicy.ts
|
|
335742
335748
|
var REQUIRED_TOOLS = /* @__PURE__ */ new Set(["pwd", "read", "glob", "grep"]);
|
|
335743
335749
|
var MODE_SCOPED_TOOLS = /* @__PURE__ */ new Set([
|
|
335750
|
+
"screen_capture",
|
|
335744
335751
|
"image_inspect",
|
|
335745
335752
|
"image_display",
|
|
335746
335753
|
"ocr_read",
|
|
@@ -335757,6 +335764,10 @@ var MODE_SCOPED_TOOLS = /* @__PURE__ */ new Set([
|
|
|
335757
335764
|
"task_read",
|
|
335758
335765
|
"task_create",
|
|
335759
335766
|
"question",
|
|
335767
|
+
"SubAgent",
|
|
335768
|
+
"subagent_create",
|
|
335769
|
+
// Legacy runtime alias. It is no longer published to models because its
|
|
335770
|
+
// generic name collides with the persistent task checklist.
|
|
335760
335771
|
"task",
|
|
335761
335772
|
"subagent_list",
|
|
335762
335773
|
"subagent_read",
|
|
@@ -335769,6 +335780,7 @@ var MODE_SCOPED_TOOLS = /* @__PURE__ */ new Set([
|
|
|
335769
335780
|
"branch_create"
|
|
335770
335781
|
]);
|
|
335771
335782
|
var PLAN_READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
335783
|
+
"screen_capture",
|
|
335772
335784
|
"task_read",
|
|
335773
335785
|
"pwd",
|
|
335774
335786
|
"read",
|
|
@@ -335790,6 +335802,8 @@ var PLAN_READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
|
335790
335802
|
"skill",
|
|
335791
335803
|
"linked_plan",
|
|
335792
335804
|
"build_history_query",
|
|
335805
|
+
"SubAgent",
|
|
335806
|
+
"subagent_create",
|
|
335793
335807
|
"task",
|
|
335794
335808
|
"subagent_list",
|
|
335795
335809
|
"subagent_read",
|
|
@@ -335813,7 +335827,9 @@ var CONCURRENCY_SAFE_TOOLS = /* @__PURE__ */ new Set([
|
|
|
335813
335827
|
"web_fetch",
|
|
335814
335828
|
"git_status",
|
|
335815
335829
|
"file_audit",
|
|
335816
|
-
"repo_security_audit"
|
|
335830
|
+
"repo_security_audit",
|
|
335831
|
+
"screen_capture",
|
|
335832
|
+
"SubAgent"
|
|
335817
335833
|
]);
|
|
335818
335834
|
function isConcurrencySafeTool(name50, riskLevel) {
|
|
335819
335835
|
const toolName = String(name50 || "").trim();
|
|
@@ -336896,6 +336912,13 @@ var ToolExecutor = class {
|
|
|
336896
336912
|
max_refs: { type: "number" },
|
|
336897
336913
|
attribute: { type: "string" }
|
|
336898
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
|
+
}, []),
|
|
336899
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.", {
|
|
336900
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"] },
|
|
336901
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." },
|
|
@@ -336981,7 +337004,7 @@ var ToolExecutor = class {
|
|
|
336981
337004
|
remote_root: { type: "string" },
|
|
336982
337005
|
remote_path: { type: "string" }
|
|
336983
337006
|
}, ["action"]),
|
|
336984
|
-
t3("
|
|
337007
|
+
t3("SubAgent", "Create one real same-conversation peer SubAgent and return immediately. This tool is only for delegation; never use it to create or update the conversation task checklist (use task_create for that). Creation is bound to the currently running Build Block: non-Ultra intelligence has a hard ceiling of 4 active peers for that Build, Ultra has 16, and excess calls terminate without creating or queueing a record. The peer has a stable human-readable name plus a separate exact id. Pass model to select an exact configured model deployment (deployment:providerId:modelId or an unambiguous provider/model name). When model is omitted, the peer inherits the parent Agent's currently resolved model deployment. Plan mode peers are forced to Plan.", { name: { type: "string", description: "Human-readable SubAgent name shown in the monitoring sidebar. Omit only when a named preset supplies it." }, nature: { type: "string", description: "Legacy alias for name." }, prompt: { type: "string", description: "Work delegated to this SubAgent; this is not a checklist item." }, preset: { type: "string" }, agent: { type: "string" }, model: { type: "string", description: "Optional exact model deployment. Omit to inherit the parent Agent resolved model." }, mode: { type: "string" }, input_mode: { type: "string" }, flow: { type: "string" } }, ["prompt"]),
|
|
336985
337008
|
t3("subagent_list", "List flat same-conversation peer agents, optionally filtered by status. Each entry exposes both the stable name and the exact id; use the id for any subsequent targeting.", { status: { type: "string", enum: ["idle", "queued", "working", "completed", "error", "closed"] } }, []),
|
|
336986
337009
|
t3("subagent_read", "Read one same-conversation peer status, queue/mailbox summary, latest bounded feedback, and result. Available for running, queued, completed, error, and closed peers. Pass the exact id returned by subagent_list, or a name for convenience lookup.", { id: { type: "string", description: "Exact peer id from subagent_list." }, name: { type: "string", description: "Convenience peer name; ambiguous names resolve to the first match." }, max_chars: { type: "number", description: "Bounded result size from 2000 to 32000 characters." } }, []),
|
|
336987
337010
|
t3("subagent_send", "Persist a mailbox message to a same-conversation peer agent. Target by exact id (preferred) or name.", { id: { type: "string", description: "Exact peer id from subagent_list." }, name: { type: "string", description: "Convenience peer name." }, message: { type: "string" }, prompt: { type: "string", description: "Legacy alias for message." }, kind: { type: "string", enum: ["directive", "question", "result", "handoff"] }, reply_to: { type: "string" }, correlation_id: { type: "string" } }, []),
|
|
@@ -337158,7 +337181,8 @@ var ToolExecutor = class {
|
|
|
337158
337181
|
return normalizeToolResult(output, { tool, workspacePath: wsPath, mode: context.mode || "" });
|
|
337159
337182
|
}
|
|
337160
337183
|
validateInvocation(tool, argsStr, _mode = "", inputSchema) {
|
|
337161
|
-
|
|
337184
|
+
const schemaTool = tool === "task" || tool === "subagent_create" ? "SubAgent" : tool;
|
|
337185
|
+
if (inputSchema === void 0 && !isNativeToolEnabled(schemaTool, this.config.nativeToolEnabled())) {
|
|
337162
337186
|
return { ok: false, error: `[tool disabled] ${tool} is disabled in Settings > Tools.` };
|
|
337163
337187
|
}
|
|
337164
337188
|
let parsed;
|
|
@@ -337180,11 +337204,11 @@ var ToolExecutor = class {
|
|
|
337180
337204
|
}, args);
|
|
337181
337205
|
return validation2.ok ? { ok: false, error: "[permission] Question is disabled by fully_autonomous option feedback." } : { ok: false, error: `[tool schema error] ${validation2.error}` };
|
|
337182
337206
|
}
|
|
337183
|
-
const definition = inputSchema === void 0 ? this.definitions().find((candidate) => candidate.function?.name ===
|
|
337207
|
+
const definition = inputSchema === void 0 ? this.definitions().find((candidate) => candidate.function?.name === schemaTool) : { function: { name: tool, parameters: inputSchema } };
|
|
337184
337208
|
if (!definition) {
|
|
337185
337209
|
return { ok: false, error: `[tool unsupported] ${tool || "(missing tool)"} is not available for the ${this.hostProfile.kind} host on ${this.hostProfile.platform}.` };
|
|
337186
337210
|
}
|
|
337187
|
-
const validation = this.argumentValidators.validate(
|
|
337211
|
+
const validation = this.argumentValidators.validate(schemaTool, definition.function.parameters, args);
|
|
337188
337212
|
return validation.ok ? { ok: true, args } : { ok: false, error: `[tool schema error] ${validation.error}` };
|
|
337189
337213
|
}
|
|
337190
337214
|
async execute(tool, argsStr, wsPath, context = {}) {
|
|
@@ -337385,6 +337409,44 @@ var ToolExecutor = class {
|
|
|
337385
337409
|
result: parsed
|
|
337386
337410
|
}, null, 2);
|
|
337387
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
|
+
}
|
|
337388
337450
|
case "computer_use": {
|
|
337389
337451
|
const action = normalizeComputerUseAction(g2("action"));
|
|
337390
337452
|
const owner = `${computerUseOwner(context, wsPath)}:${String(context.actorId || "root")}`;
|
|
@@ -337506,7 +337568,9 @@ var ToolExecutor = class {
|
|
|
337506
337568
|
case "ssh_workspace":
|
|
337507
337569
|
return await this.sshWorkspace(args, wsPath, context.signal);
|
|
337508
337570
|
case "task":
|
|
337509
|
-
|
|
337571
|
+
case "subagent_create":
|
|
337572
|
+
case "SubAgent":
|
|
337573
|
+
return `[SubAgent] SubAgent request accepted: ${g2("name")}`;
|
|
337510
337574
|
case "subagent_send":
|
|
337511
337575
|
return `[subagent_send] Routed to Agent runtime: ${g2("name")}`;
|
|
337512
337576
|
case "subagent_read":
|
|
@@ -337589,7 +337653,7 @@ var ToolExecutor = class {
|
|
|
337589
337653
|
}
|
|
337590
337654
|
hostSupportsTool(name50) {
|
|
337591
337655
|
if (name50.startsWith("browser_") && !this.hostProfile.electronBrowser) return false;
|
|
337592
|
-
if (name50 === "computer_use" && !this.hostProfile.windowsComputerUse) return false;
|
|
337656
|
+
if ((name50 === "computer_use" || name50 === "screen_capture") && !this.hostProfile.windowsComputerUse) return false;
|
|
337593
337657
|
return true;
|
|
337594
337658
|
}
|
|
337595
337659
|
async decorateBrowserUseReceipt(input, context, runtimeKey) {
|
|
@@ -338679,6 +338743,7 @@ var SubagentManager = class {
|
|
|
338679
338743
|
queueMicrotask(() => this.pump());
|
|
338680
338744
|
}
|
|
338681
338745
|
bind(options) {
|
|
338746
|
+
if (options.concurrency !== void 0) this.setConcurrencyLimit(options.concurrency);
|
|
338682
338747
|
if (options.executor) this.executor = options.executor;
|
|
338683
338748
|
if (options.onChange) this.onChange = options.onChange;
|
|
338684
338749
|
if (options.persist) this.persist = options.persist;
|
|
@@ -338695,12 +338760,13 @@ var SubagentManager = class {
|
|
|
338695
338760
|
removeRootInboxListener(listener) {
|
|
338696
338761
|
this.rootInboxListeners.delete(listener);
|
|
338697
338762
|
}
|
|
338698
|
-
create(name50, prompt, model, inputMode, agentMode = "build", createdByAgentId = this.rootAgentId, flowName = "", goalObjective = "", flowPc = 0) {
|
|
338763
|
+
create(name50, prompt, model, inputMode, agentMode = "build", createdByAgentId = this.rootAgentId, flowName = "", goalObjective = "", flowPc = 0, buildRunId = "", intelligenceTier = "") {
|
|
338699
338764
|
const id = (0, import_crypto8.randomUUID)();
|
|
338700
338765
|
const shortId = id.replace(/-/g, "").slice(0, 8);
|
|
338701
338766
|
const slug = natureSlug(name50);
|
|
338702
|
-
const
|
|
338703
|
-
const
|
|
338767
|
+
const createdName = String(name50 || "SubAgent").replace(/\s+/g, " ").trim().slice(0, 160) || "SubAgent";
|
|
338768
|
+
const displayName = createdName;
|
|
338769
|
+
const qualifiedName = `${slug}--${id}`;
|
|
338704
338770
|
const stamp = now();
|
|
338705
338771
|
const record = {
|
|
338706
338772
|
id,
|
|
@@ -338708,9 +338774,11 @@ var SubagentManager = class {
|
|
|
338708
338774
|
natureSlug: slug,
|
|
338709
338775
|
displayName,
|
|
338710
338776
|
qualifiedName,
|
|
338711
|
-
name:
|
|
338777
|
+
name: createdName,
|
|
338712
338778
|
conversationId: this.conversationId,
|
|
338713
338779
|
createdByAgentId,
|
|
338780
|
+
buildRunId: String(buildRunId || "").trim() || void 0,
|
|
338781
|
+
intelligenceTier: String(intelligenceTier || "").trim() || void 0,
|
|
338714
338782
|
prompt,
|
|
338715
338783
|
model: model || "default",
|
|
338716
338784
|
inputMode: inputMode || "guide",
|
|
@@ -339033,6 +339101,20 @@ var SubagentManager = class {
|
|
|
339033
339101
|
listAll() {
|
|
339034
339102
|
return [...this.subs.values()].map(cloneRecord);
|
|
339035
339103
|
}
|
|
339104
|
+
activeCountForBuild(buildRunId) {
|
|
339105
|
+
const target = String(buildRunId || "").trim();
|
|
339106
|
+
if (!target) return 0;
|
|
339107
|
+
return [...this.subs.values()].filter(
|
|
339108
|
+
(record) => record.buildRunId === target && (record.status === "queued" || record.status === "working")
|
|
339109
|
+
).length;
|
|
339110
|
+
}
|
|
339111
|
+
setConcurrencyLimit(value) {
|
|
339112
|
+
this.concurrency = Math.max(1, Math.min(16, Math.floor(Number(value) || 4)));
|
|
339113
|
+
this.pump();
|
|
339114
|
+
}
|
|
339115
|
+
concurrencyLimit() {
|
|
339116
|
+
return this.concurrency;
|
|
339117
|
+
}
|
|
339036
339118
|
pauseScheduling() {
|
|
339037
339119
|
if (this.schedulingPaused) return;
|
|
339038
339120
|
this.schedulingPaused = true;
|
|
@@ -340198,7 +340280,8 @@ function inferDomain(name50) {
|
|
|
340198
340280
|
}
|
|
340199
340281
|
if (name50 === "question") return "interaction";
|
|
340200
340282
|
if (name50 === "skill") return "skills";
|
|
340201
|
-
if (name50 === "task") return "subagent";
|
|
340283
|
+
if (name50 === "task" || name50 === "subagent_create" || name50 === "SubAgent") return "subagent";
|
|
340284
|
+
if (/^task_(read|create)$/.test(name50)) return "plan";
|
|
340202
340285
|
if (/^(linked_plan|build_history_query)$/.test(name50)) return "plan";
|
|
340203
340286
|
return "general";
|
|
340204
340287
|
}
|
|
@@ -340462,7 +340545,7 @@ function resetPublicAssistantDeltaFilter(agent) {
|
|
|
340462
340545
|
function prepareAssistantToolVisibility(agent, definitions) {
|
|
340463
340546
|
const names = definitions.map(toolDefinitionName);
|
|
340464
340547
|
brokerOnlyAssistantBuffers.set(agent, {
|
|
340465
|
-
brokerOnly: names.includes(TOOL_PROVISION_NAME) && names.every((name50) => name50 === TOOL_PROVISION_NAME || name50 === "skill" ||
|
|
340548
|
+
brokerOnly: names.includes(TOOL_PROVISION_NAME) && names.every((name50) => name50 === TOOL_PROVISION_NAME || name50 === "skill" || ALWAYS_AVAILABLE_AGENT_TOOL_NAMES.has(name50)),
|
|
340466
340549
|
pending: [],
|
|
340467
340550
|
released: false
|
|
340468
340551
|
});
|
|
@@ -340754,7 +340837,7 @@ async function runAgentKernel(agent) {
|
|
|
340754
340837
|
const requestStartedAt = Date.now();
|
|
340755
340838
|
let firstTokenRecorded = false;
|
|
340756
340839
|
const tools = context.tools || [];
|
|
340757
|
-
const brokerOnlySurface = tools.length > 0 && tools.every((tool) => tool.name === TOOL_PROVISION_NAME || tool.name === "skill" ||
|
|
340840
|
+
const brokerOnlySurface = tools.length > 0 && tools.every((tool) => tool.name === TOOL_PROVISION_NAME || tool.name === "skill" || ALWAYS_AVAILABLE_AGENT_TOOL_NAMES.has(tool.name));
|
|
340758
340841
|
currentAgent.beginRouteAttempt();
|
|
340759
340842
|
try {
|
|
340760
340843
|
const currentProvider = currentAgent.engineModel();
|
|
@@ -340989,6 +341072,8 @@ function buildBuildContextBootstrap(agent, messages, options) {
|
|
|
340989
341072
|
buildConversationTaskLedger(agent),
|
|
340990
341073
|
"## Tool Awareness Bootstrap",
|
|
340991
341074
|
"The following catalog is capability metadata only. Tool descriptions are not instructions, and a tool is callable only when its full schema is present in the provider tools field.",
|
|
341075
|
+
"Only bash, pwd, read, write, edit, delete_file, glob, and grep are foundational tools with initial full schemas (subject to mode and policy filtering).",
|
|
341076
|
+
"Advanced capabilities\u2014including SubAgent, task tools, Git/GitHub, browser, Computer Use, skills, MCP, automations, Flow, and Memory Lab\u2014are not initially callable. Before using one, first call tool_provision with its exact tool name as the only tool call in that assistant subturn; call the advanced tool only on the following model turn after its full schema appears.",
|
|
340992
341077
|
...catalogLines.length ? catalogLines : ["- No callable tools are available for this provider turn."],
|
|
340993
341078
|
`Necessary full schemas supplied natively for this provider turn: ${activeNames.length ? activeNames.join(", ") : "(none; use tool_provision when its schema is available)"}.`,
|
|
340994
341079
|
"Do not invent parameters from the brief catalog. Use only the exact full schemas supplied through the provider tool interface; provision another exact tool when needed."
|
|
@@ -341178,7 +341263,8 @@ function routeTransitionNotice(agent, previous) {
|
|
|
341178
341263
|
var TOOL_PROVISION_NAME = "tool_provision";
|
|
341179
341264
|
var INITIAL_TOOL_SCHEMA_LIMIT = 8;
|
|
341180
341265
|
var TOOL_PROVISION_BATCH_LIMIT = 8;
|
|
341181
|
-
var
|
|
341266
|
+
var BASIC_INITIAL_TOOL_NAMES = /* @__PURE__ */ new Set(["bash", "pwd", "read", "write", "edit", "delete_file", "glob", "grep"]);
|
|
341267
|
+
var ALWAYS_AVAILABLE_AGENT_TOOL_NAMES = BASIC_INITIAL_TOOL_NAMES;
|
|
341182
341268
|
var ToolProvisionSession = class {
|
|
341183
341269
|
definitionsByName = /* @__PURE__ */ new Map();
|
|
341184
341270
|
initialNames = /* @__PURE__ */ new Set();
|
|
@@ -341202,7 +341288,7 @@ var ToolProvisionSession = class {
|
|
|
341202
341288
|
const name50 = toolDefinitionName(definition);
|
|
341203
341289
|
if (this.definitionsByName.has(name50)) this.initialNames.add(name50);
|
|
341204
341290
|
}
|
|
341205
|
-
for (const name50 of
|
|
341291
|
+
for (const name50 of ALWAYS_AVAILABLE_AGENT_TOOL_NAMES) {
|
|
341206
341292
|
if (this.definitionsByName.has(name50)) this.initialNames.add(name50);
|
|
341207
341293
|
}
|
|
341208
341294
|
for (const name50 of this.provisionedNames) {
|
|
@@ -341360,29 +341446,6 @@ function toolSurfaceIdentityForAgent(agent) {
|
|
|
341360
341446
|
optionFeedback: agent.config.getStr("agent", "option_feedback")
|
|
341361
341447
|
});
|
|
341362
341448
|
}
|
|
341363
|
-
var CAPABILITY_TO_DOMAIN = {
|
|
341364
|
-
"vcs.inspect": ["git"],
|
|
341365
|
-
"code.search": ["core"],
|
|
341366
|
-
"test.run": ["core"],
|
|
341367
|
-
"web.search": ["web"],
|
|
341368
|
-
"automation.manage": ["automation"],
|
|
341369
|
-
"flow.manage": ["flow"],
|
|
341370
|
-
"memory.manage": ["memory"],
|
|
341371
|
-
"computer.manage": ["computer"],
|
|
341372
|
-
"browser.manage": ["browser"],
|
|
341373
|
-
"terminal.manage": ["general", "core"],
|
|
341374
|
-
"github.manage": ["general"],
|
|
341375
|
-
"ssh.manage": ["general"],
|
|
341376
|
-
"skill.manage": ["skills", "general"],
|
|
341377
|
-
"plan.manage": ["plan"],
|
|
341378
|
-
"history.query": ["plan"],
|
|
341379
|
-
"media.display": ["media"],
|
|
341380
|
-
"interaction.manage": ["interaction"]
|
|
341381
|
-
};
|
|
341382
|
-
var CAPABILITY_TOOL_HINTS = {
|
|
341383
|
-
"skill.manage": ["skill", "skill_download"],
|
|
341384
|
-
"memory.manage": ["memory_lab_read", "memory_lab_query", "memory_lab_update", "memory_lab_reindex"]
|
|
341385
|
-
};
|
|
341386
341449
|
function routeToolSurfaceV2(agent, definitions, toolchain, task) {
|
|
341387
341450
|
if (!agent.shouldExposeToolInterface()) {
|
|
341388
341451
|
return {
|
|
@@ -341394,67 +341457,34 @@ function routeToolSurfaceV2(agent, definitions, toolchain, task) {
|
|
|
341394
341457
|
].join("\n")
|
|
341395
341458
|
};
|
|
341396
341459
|
}
|
|
341397
|
-
|
|
341398
|
-
const
|
|
341399
|
-
|
|
341400
|
-
|
|
341401
|
-
|
|
341402
|
-
|
|
341403
|
-
|
|
341404
|
-
|
|
341405
|
-
|
|
341406
|
-
|
|
341407
|
-
|
|
341408
|
-
|
|
341409
|
-
|
|
341410
|
-
|
|
341411
|
-
|
|
341412
|
-
|
|
341413
|
-
|
|
341414
|
-
for (const toolName of CAPABILITY_TOOL_HINTS[capabilityId] || []) toolHints.add(toolName);
|
|
341415
|
-
}
|
|
341416
|
-
const names = definitions.map(toolDefinitionName);
|
|
341417
|
-
for (const name50 of names) {
|
|
341418
|
-
if (name50 && new RegExp(`(?:^|[^A-Za-z0-9_])${name50.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:$|[^A-Za-z0-9_])`, "i").test(task)) {
|
|
341419
|
-
toolHints.add(name50);
|
|
341420
|
-
}
|
|
341421
|
-
}
|
|
341422
|
-
const selected = definitions.filter((definition) => {
|
|
341423
|
-
const name50 = toolDefinitionName(definition);
|
|
341424
|
-
const descriptor = toolchain.registry.get(name50);
|
|
341425
|
-
if (!descriptor || descriptor.riskLevel === "destructive") return false;
|
|
341426
|
-
if (toolHints.has(name50)) return true;
|
|
341427
|
-
if (!domains.has(descriptor.capabilityId.slice(4))) return false;
|
|
341428
|
-
return true;
|
|
341429
|
-
}).sort((a3, b2) => {
|
|
341430
|
-
const aHint = toolHints.has(toolDefinitionName(a3)) ? 0 : 1;
|
|
341431
|
-
const bHint = toolHints.has(toolDefinitionName(b2)) ? 0 : 1;
|
|
341432
|
-
return aHint - bHint || names.indexOf(toolDefinitionName(a3)) - names.indexOf(toolDefinitionName(b2));
|
|
341433
|
-
}).slice(0, INITIAL_TOOL_SCHEMA_LIMIT);
|
|
341434
|
-
const selectedNames = new Set(selected.map(toolDefinitionName));
|
|
341435
|
-
const core = definitions.filter((definition) => {
|
|
341436
|
-
const name50 = toolDefinitionName(definition);
|
|
341437
|
-
return SUBAGENT_CORE_TOOL_NAMES.has(name50) && !selectedNames.has(name50);
|
|
341438
|
-
});
|
|
341439
|
-
const surface = core.length ? selected.concat(core) : selected;
|
|
341440
|
-
if (surface.length === definitions.length) return { definitions, systemPromptNotice: "" };
|
|
341441
|
-
if (!selected.length) {
|
|
341442
|
-
return {
|
|
341443
|
-
definitions: surface,
|
|
341444
|
-
systemPromptNotice: [
|
|
341445
|
-
"## Tool Interface Availability",
|
|
341446
|
-
"This turn was classified as conversational, so no task-specific tool schema was preloaded.",
|
|
341447
|
-
`The ${TOOL_PROVISION_NAME} interface still exposes the complete compact capability catalog and can provision an original tool schema when the task requires it.`
|
|
341448
|
-
].join("\n")
|
|
341449
|
-
};
|
|
341460
|
+
const surface = definitions.filter((definition) => BASIC_INITIAL_TOOL_NAMES.has(toolDefinitionName(definition)));
|
|
341461
|
+
const advancedCount = Math.max(0, definitions.length - surface.length);
|
|
341462
|
+
let planFingerprint = "";
|
|
341463
|
+
if (toolchain) {
|
|
341464
|
+
const planner = new ToolExposurePlanner(toolchain.registry, toolchain.catalog);
|
|
341465
|
+
const plan = planner.plan({
|
|
341466
|
+
agentRunId: agent.runtimeActorId,
|
|
341467
|
+
buildBlockId: agent.activeConversationId || "build",
|
|
341468
|
+
userInput: task,
|
|
341469
|
+
objective: "",
|
|
341470
|
+
previousToolCalls: [],
|
|
341471
|
+
toolUsageFrequency: /* @__PURE__ */ new Map(),
|
|
341472
|
+
permissionScope: ["workspace"],
|
|
341473
|
+
tokenBudget: 2e4,
|
|
341474
|
+
providerToolLimit: 0
|
|
341475
|
+
});
|
|
341476
|
+
planFingerprint = plan.plan.stableToolsetHash.slice(0, 8);
|
|
341450
341477
|
}
|
|
341451
341478
|
return {
|
|
341452
341479
|
definitions: surface,
|
|
341453
341480
|
systemPromptNotice: [
|
|
341454
341481
|
"## Tool Interface Availability",
|
|
341455
|
-
`
|
|
341456
|
-
|
|
341457
|
-
|
|
341482
|
+
`The initial full-schema surface is restricted to foundational workspace tools: ${surface.map(toolDefinitionName).join(", ") || "(none allowed in this mode)"}.`,
|
|
341483
|
+
`${advancedCount} advanced tools are advertised by capability in the compact ${TOOL_PROVISION_NAME} catalog without loading their schemas.`,
|
|
341484
|
+
"Advanced tools include SubAgent, task tools, Git/GitHub, browser, Computer Use, skills, MCP, automations, Flow, and Memory Lab.",
|
|
341485
|
+
`Call ${TOOL_PROVISION_NAME} as the only tool in a subturn to load any advanced tool by exact name; its original schema becomes available on the next model turn.`,
|
|
341486
|
+
"Do not call an advanced tool directly from the initial catalog: capability presence is not callability until provisioning has completed.",
|
|
341487
|
+
planFingerprint ? `Capability routing fingerprint: ${planFingerprint}.` : "Capability registry unavailable; the compact catalog remains authoritative."
|
|
341458
341488
|
].join("\n")
|
|
341459
341489
|
};
|
|
341460
341490
|
}
|
|
@@ -341523,10 +341553,12 @@ function toKernelTools(agent, definitions, provisioning) {
|
|
|
341523
341553
|
throw new Error(rawText);
|
|
341524
341554
|
}
|
|
341525
341555
|
const visionImage = visualFallbackImageInput(agent, name50, rawText);
|
|
341556
|
+
const capturedInput = name50 === "screen_capture" ? agent.registerCapturedImageInput(visionImage.image || "", "active-screenshot.jpg") : null;
|
|
341526
341557
|
const directImage = imageInspectDataUrl(name50, rawText);
|
|
341527
|
-
const text = spillOversizedToolResult(agent, name50, sanitizeVisualToolText(name50, rawText));
|
|
341558
|
+
const text = spillOversizedToolResult(agent, name50, capturedImageToolText(name50, sanitizeVisualToolText(name50, rawText), capturedInput?.id));
|
|
341528
341559
|
const content = [{ type: "text", text }];
|
|
341529
|
-
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) });
|
|
341530
341562
|
else if (visionImage.image) content.push({ type: "image", image: visionImage.image, mimeType: visionImage.mimeType });
|
|
341531
341563
|
if (directImage) content.push({ type: "image", image: directImage, mimeType: "image/png" });
|
|
341532
341564
|
const terminate = shouldTerminateAfterToolResult(name50) && (name50 !== "question" || agent.pendingOptions.length > 0);
|
|
@@ -341539,7 +341571,7 @@ function toKernelTools(agent, definitions, provisioning) {
|
|
|
341539
341571
|
} catch {
|
|
341540
341572
|
}
|
|
341541
341573
|
}
|
|
341542
|
-
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 };
|
|
341543
341575
|
}
|
|
341544
341576
|
};
|
|
341545
341577
|
}).filter((tool) => !!tool.name);
|
|
@@ -341563,7 +341595,7 @@ var INLINE_TOOL_RESULT_MAX_CHARS = 24e3;
|
|
|
341563
341595
|
function spillOversizedToolResult(agent, name50, text) {
|
|
341564
341596
|
const value = String(text || "");
|
|
341565
341597
|
if (value.length <= INLINE_TOOL_RESULT_MAX_CHARS) return value;
|
|
341566
|
-
if (["computer_use", "browser_use", "pdf_read", "image_inspect", "image_display", "task", "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)) {
|
|
341567
341599
|
return value;
|
|
341568
341600
|
}
|
|
341569
341601
|
const artifactId = agent.storeToolResultArtifact(name50, value);
|
|
@@ -341578,10 +341610,10 @@ function spillOversizedToolResult(agent, name50, text) {
|
|
|
341578
341610
|
].join("\n");
|
|
341579
341611
|
}
|
|
341580
341612
|
function sanitizeVisualToolText(name50, text) {
|
|
341581
|
-
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;
|
|
341582
341614
|
try {
|
|
341583
341615
|
const parsed = JSON.parse(text);
|
|
341584
|
-
if (name50 === "computer_use" || name50 === "browser_use" || name50 === "pdf_read") {
|
|
341616
|
+
if (name50 === "screen_capture" || name50 === "computer_use" || name50 === "browser_use" || name50 === "pdf_read") {
|
|
341585
341617
|
delete parsed.vision_image_path;
|
|
341586
341618
|
delete parsed.vision_image_data_url;
|
|
341587
341619
|
if (name50 === "pdf_read" && parsed.result && typeof parsed.result === "object") {
|
|
@@ -341597,7 +341629,7 @@ function sanitizeVisualToolText(name50, text) {
|
|
|
341597
341629
|
}
|
|
341598
341630
|
}
|
|
341599
341631
|
function discardComputerUseVisionImage(name50, text) {
|
|
341600
|
-
if (name50 !== "computer_use") return;
|
|
341632
|
+
if (name50 !== "screen_capture" && name50 !== "computer_use") return;
|
|
341601
341633
|
try {
|
|
341602
341634
|
const parsed = JSON.parse(text);
|
|
341603
341635
|
const screenshotPath = String(parsed.vision_image_path || "");
|
|
@@ -341615,8 +341647,20 @@ function imageInspectDataUrl(name50, text) {
|
|
|
341615
341647
|
return "";
|
|
341616
341648
|
}
|
|
341617
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
|
+
}
|
|
341618
341662
|
function visualFallbackImageInput(agent, name50, text) {
|
|
341619
|
-
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 {};
|
|
341620
341664
|
const model = agent.activeModelConfig();
|
|
341621
341665
|
if (!model?.vision) return {};
|
|
341622
341666
|
try {
|
|
@@ -341664,7 +341708,7 @@ async function executeNewmarkTool(agent, name50, args, inputSchema, signal) {
|
|
|
341664
341708
|
if (signal?.aborted) throw abortError4();
|
|
341665
341709
|
return result2;
|
|
341666
341710
|
};
|
|
341667
|
-
if (name50 === "task") return (await agent.handleSubagentEnvelope(args)).output;
|
|
341711
|
+
if (name50 === "task" || name50 === "subagent_create" || name50 === "SubAgent") return (await agent.handleSubagentEnvelope(args, true)).output;
|
|
341668
341712
|
if (name50 === "subagent_send") return (await agent.handleSubagentContinueEnvelope(args)).output;
|
|
341669
341713
|
if (name50 === "subagent_list") return agent.handleSubagentListEnvelope(args).output;
|
|
341670
341714
|
if (name50 === "subagent_read") return agent.handleSubagentReadEnvelope(args).output;
|
|
@@ -341742,7 +341786,7 @@ async function executeNewmarkTool(agent, name50, args, inputSchema, signal) {
|
|
|
341742
341786
|
actorId: agent.runtimeActorId,
|
|
341743
341787
|
workspaceId: terminalTakeoverWorkspaceId(wsDir),
|
|
341744
341788
|
backend: process.env.NEWMARK_WSL_DISTRO ? "wsl" : process.platform === "win32" ? "windows" : process.platform,
|
|
341745
|
-
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,
|
|
341746
341790
|
signal
|
|
341747
341791
|
});
|
|
341748
341792
|
if (signal?.aborted) throw abortError4();
|
|
@@ -344816,7 +344860,7 @@ var Agent4 = class _Agent {
|
|
|
344816
344860
|
this.tools = new ToolExecutor(rootPath, this.config, this.ssh, this.workspace);
|
|
344817
344861
|
this.skills = new SkillsManager(rootPath);
|
|
344818
344862
|
this.memoryLab = new MemoryLabManager(rootPath, this.config.getStr("general", "language"));
|
|
344819
|
-
this.subagents = new SubagentManager({ rootAgentId: this.runtimeActorId });
|
|
344863
|
+
this.subagents = new SubagentManager({ rootAgentId: this.runtimeActorId, concurrency: this.subagentConcurrencyLimit() });
|
|
344820
344864
|
if (this.mode === "goal" && !this.goal) {
|
|
344821
344865
|
this.goal = new GoalStateImpl("Set your objective");
|
|
344822
344866
|
}
|
|
@@ -344885,6 +344929,7 @@ var Agent4 = class _Agent {
|
|
|
344885
344929
|
memoryLabRebuildState = "idle";
|
|
344886
344930
|
memoryLabRebuildError = "";
|
|
344887
344931
|
displayImageDescriptionCache = /* @__PURE__ */ new Map();
|
|
344932
|
+
latestCapturedImageInputs = [];
|
|
344888
344933
|
activeProcessAbortController = null;
|
|
344889
344934
|
automationManager = null;
|
|
344890
344935
|
activeAgentKernelRuntime = null;
|
|
@@ -345415,6 +345460,7 @@ var Agent4 = class _Agent {
|
|
|
345415
345460
|
}
|
|
345416
345461
|
setIntelligence(tier, persist = false) {
|
|
345417
345462
|
this.intelligence = normalizeIntelligenceTier(tier);
|
|
345463
|
+
this.subagents?.setConcurrencyLimit(this.subagentConcurrencyLimit());
|
|
345418
345464
|
if (persist) {
|
|
345419
345465
|
this.config.set("models", "default_intelligence", this.intelligence);
|
|
345420
345466
|
this.config.save();
|
|
@@ -345619,12 +345665,17 @@ var Agent4 = class _Agent {
|
|
|
345619
345665
|
return path28.join(ws.path, "conversations", "state.json");
|
|
345620
345666
|
}
|
|
345621
345667
|
workspaceConversationStateKey(conversationId = this.activeConversationId) {
|
|
345622
|
-
|
|
345668
|
+
return this.workspaceConversationStateKeyFor(conversationId, this.workspace.current);
|
|
345669
|
+
}
|
|
345670
|
+
workspaceConversationStateKeyFor(conversationId, ws) {
|
|
345671
|
+
const prefix = this.workspaceConversationPrefixFor(ws);
|
|
345623
345672
|
if (!prefix) return null;
|
|
345624
345673
|
return `${prefix}-${this.safeConversationId(conversationId)}`;
|
|
345625
345674
|
}
|
|
345626
345675
|
workspaceConversationPrefix() {
|
|
345627
|
-
|
|
345676
|
+
return this.workspaceConversationPrefixFor(this.workspace.current);
|
|
345677
|
+
}
|
|
345678
|
+
workspaceConversationPrefixFor(ws) {
|
|
345628
345679
|
if (!ws) return null;
|
|
345629
345680
|
const supplied = String(ws.conversationStatePrefix || "").trim();
|
|
345630
345681
|
if (/^(?:internal|external)-[a-f0-9]{16}$/i.test(supplied)) return supplied.toLowerCase();
|
|
@@ -347074,8 +347125,56 @@ ${String(event.toolArgs || "")}`;
|
|
|
347074
347125
|
}
|
|
347075
347126
|
}
|
|
347076
347127
|
listConversationStates() {
|
|
347077
|
-
|
|
347078
|
-
|
|
347128
|
+
return this.listWorkspaceConversationStates(this.workspace.current);
|
|
347129
|
+
}
|
|
347130
|
+
registerCapturedImageInput(dataUrl, name50 = "active-screenshot.jpg") {
|
|
347131
|
+
if (!String(dataUrl || "").startsWith("data:image/")) return null;
|
|
347132
|
+
const prepared = this.prepareSubmittedConversationImages([{ dataUrl, name: name50, type: dataUrl.slice(5, dataUrl.indexOf(";")) }]);
|
|
347133
|
+
const attachment = prepared.attachments[0] || null;
|
|
347134
|
+
this.latestCapturedImageInputs = attachment ? [attachment] : [];
|
|
347135
|
+
return attachment;
|
|
347136
|
+
}
|
|
347137
|
+
subagentConcurrencyLimit() {
|
|
347138
|
+
return this.intelligence === "ultra" ? 16 : 4;
|
|
347139
|
+
}
|
|
347140
|
+
/** 当前工作区使用内存中的前台选择;后台工作区从各自持久化状态读取 active id。 */
|
|
347141
|
+
activeConversationIdForWorkspace(ws) {
|
|
347142
|
+
const targetWs = ws || this.workspace.current;
|
|
347143
|
+
if (!targetWs) return "default";
|
|
347144
|
+
const currentWs = this.workspace.current;
|
|
347145
|
+
const isCurrent = !!currentWs && path28.resolve(currentWs.path) === path28.resolve(targetWs.path);
|
|
347146
|
+
if (isCurrent) return this.safeConversationId(this.activeConversationId || "default");
|
|
347147
|
+
const stored = this.readStoredConversationState(targetWs);
|
|
347148
|
+
return this.safeConversationId(stored.activeConversationId || "default");
|
|
347149
|
+
}
|
|
347150
|
+
/**
|
|
347151
|
+
* 持久化的完整 work run 记录(含 interrupted/force_interrupted)。
|
|
347152
|
+
* 不依赖运行时内存(run 结束后内存清空,state 端点曾因此丢失被中断的构建记录),
|
|
347153
|
+
* 供 mobile 端点稳定透出完整对话信息;移动端按同一格式解析。
|
|
347154
|
+
*/
|
|
347155
|
+
getPersistedConversationWorkRuns(conversationId, ws = null) {
|
|
347156
|
+
const targetWs = ws || this.workspace.current;
|
|
347157
|
+
const clean = this.safeConversationId(conversationId || "default");
|
|
347158
|
+
const stateKey2 = this.workspaceConversationStateKeyFor(clean, targetWs);
|
|
347159
|
+
const stored = this.readStoredConversationState(targetWs);
|
|
347160
|
+
const persisted = stateKey2 && stored.conversations ? stored.conversations[stateKey2] : void 0;
|
|
347161
|
+
const tree = persisted ? this.normalizeConversationTree(persisted) : null;
|
|
347162
|
+
const runtimeNodeId = String(tree?.activeNodeId || "");
|
|
347163
|
+
const viewedNodeId = tree ? this.resolveConversationTreePath(tree, this.storedConversationTreePath(tree, persisted?.viewedBranchNodePath, runtimeNodeId)) : "";
|
|
347164
|
+
const viewedNode = tree?.nodes[viewedNodeId];
|
|
347165
|
+
return this.normalizeWorkRuns(viewedNode?.workRuns || persisted?.workRuns);
|
|
347166
|
+
}
|
|
347167
|
+
/** Exact membership check against the raw persisted state key, before UI content deduplication. */
|
|
347168
|
+
hasConversationInWorkspace(conversationId, ws) {
|
|
347169
|
+
const targetWs = ws || this.workspace.current;
|
|
347170
|
+
const stateKey2 = this.workspaceConversationStateKeyFor(this.safeConversationId(conversationId || "default"), targetWs);
|
|
347171
|
+
if (!stateKey2) return false;
|
|
347172
|
+
return Object.prototype.hasOwnProperty.call(this.readStoredConversationState(targetWs).conversations || {}, stateKey2);
|
|
347173
|
+
}
|
|
347174
|
+
/** 按工作区列对话(任意 ws,key 前缀 = kind-sha256(path).slice(0,16));供 mobile API 透出工作区从属对话 */
|
|
347175
|
+
listWorkspaceConversationStates(ws) {
|
|
347176
|
+
const stored = this.readStoredConversationState(ws);
|
|
347177
|
+
const prefix = this.workspaceConversationPrefixFor(ws) || "";
|
|
347079
347178
|
const scopedEntries = Object.entries(stored.conversations || {}).filter(([key3]) => !prefix || key3.startsWith(prefix));
|
|
347080
347179
|
if (scopedEntries.some(([, value]) => !Number.isFinite(value.order))) {
|
|
347081
347180
|
const legacyOrder = [...scopedEntries].sort(([, a3], [, b2]) => {
|
|
@@ -347086,7 +347185,7 @@ ${String(event.toolArgs || "")}`;
|
|
|
347086
347185
|
legacyOrder.forEach(([, value], index) => {
|
|
347087
347186
|
value.order = index;
|
|
347088
347187
|
});
|
|
347089
|
-
this.writeStoredConversationState(stored);
|
|
347188
|
+
this.writeStoredConversationState(stored, ws);
|
|
347090
347189
|
}
|
|
347091
347190
|
const rows = [];
|
|
347092
347191
|
for (const [key3, value] of Object.entries(stored.conversations || {})) {
|
|
@@ -347140,6 +347239,7 @@ ${String(event.toolArgs || "")}`;
|
|
|
347140
347239
|
this.subagents = sharedSubagentManager(this.subagentManagerKey(clean), {
|
|
347141
347240
|
conversationId: clean,
|
|
347142
347241
|
rootAgentId: state?.rootAgentId || this.runtimeActorId,
|
|
347242
|
+
concurrency: this.subagentConcurrencyLimit(),
|
|
347143
347243
|
state,
|
|
347144
347244
|
executor: (job) => this.runSubagentJob(job.record.id, job.prompt, job.flowName, job.reason),
|
|
347145
347245
|
persist: (subagentState) => this.persistSubagentState(clean, subagentState),
|
|
@@ -347209,15 +347309,14 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
347209
347309
|
}
|
|
347210
347310
|
getConversationSnapshot(conversationId = this.activeConversationId, options = {}) {
|
|
347211
347311
|
const clean = this.safeConversationId(conversationId || "default");
|
|
347212
|
-
const
|
|
347213
|
-
const
|
|
347214
|
-
const
|
|
347215
|
-
|
|
347216
|
-
|
|
347217
|
-
|
|
347218
|
-
})();
|
|
347312
|
+
const ws = options.workspace || this.workspace.current;
|
|
347313
|
+
const currentWs = this.workspace.current;
|
|
347314
|
+
const isActiveWorkspace = !ws && !currentWs || !!ws && !!currentWs && path28.resolve(ws.path) === path28.resolve(currentWs.path);
|
|
347315
|
+
const isActiveConversation = isActiveWorkspace && clean === this.safeConversationId(this.activeConversationId || "default");
|
|
347316
|
+
const stateKey2 = this.workspaceConversationStateKeyFor(clean, ws);
|
|
347317
|
+
const memoryKey = ws ? `${ws.isInternal ? "internal" : "external"}:${path28.resolve(ws.path)}::conversation:${clean}` : null;
|
|
347219
347318
|
const memory = memoryKey ? this.workspaceConversations.get(memoryKey) : void 0;
|
|
347220
|
-
const stored = this.readStoredConversationState();
|
|
347319
|
+
const stored = this.readStoredConversationState(ws);
|
|
347221
347320
|
const persisted = stateKey2 && stored.conversations ? stored.conversations[stateKey2] : void 0;
|
|
347222
347321
|
const tree = persisted ? this.normalizeConversationTree(persisted) : null;
|
|
347223
347322
|
const runtimeNodeId = String(tree?.activeNodeId || "");
|
|
@@ -347237,7 +347336,7 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
347237
347336
|
const continuations = this.normalizeContinuations(isActiveConversation && viewingRuntimeNode ? this.continuations : viewedNode?.continuations || persisted?.continuations || memory?.continuations);
|
|
347238
347337
|
return {
|
|
347239
347338
|
conversationId: clean,
|
|
347240
|
-
conversations: this.
|
|
347339
|
+
conversations: this.listWorkspaceConversationStates(ws),
|
|
347241
347340
|
conversationPlan: this.normalizeConversationPlan(isActiveConversation ? this.conversationPlan : persisted?.plan || memory?.plan),
|
|
347242
347341
|
linkedPlan: this.normalizeLinkedPlan(isActiveConversation ? this.linkedPlan : persisted?.linkedPlan || memory?.linkedPlan),
|
|
347243
347342
|
subagents: this.recordsForState(isActiveConversation ? this.subagents.serialize() : persisted?.subagentState || memory?.subagentState),
|
|
@@ -347247,9 +347346,9 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
347247
347346
|
historyMessages: history.length,
|
|
347248
347347
|
workRuns,
|
|
347249
347348
|
continuations,
|
|
347250
|
-
modelSelection: isActiveConversation ? this.currentConversationModelSelection() : persisted?.modelSelection || memory?.modelSelection ||
|
|
347349
|
+
modelSelection: isActiveConversation ? this.currentConversationModelSelection() : persisted?.modelSelection || memory?.modelSelection || { kind: "auto" },
|
|
347251
347350
|
flowSelection: isActiveConversation ? this.currentConversationFlowSelection() : persisted?.flowSelection || memory?.flowSelection || null,
|
|
347252
|
-
inputMode: this.inputMode,
|
|
347351
|
+
inputMode: isActiveConversation ? this.inputMode : persisted?.inputMode || memory?.inputMode || "guide",
|
|
347253
347352
|
mode: isActiveConversation ? this.mode : persisted?.mode || memory?.mode || "build",
|
|
347254
347353
|
goal: isActiveConversation ? this.serializeGoal() : persisted?.goal || memory?.goal || null,
|
|
347255
347354
|
branches: this.branchGroupMetadata(tree),
|
|
@@ -347536,12 +347635,16 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
347536
347635
|
if (clean === this.safeConversationId(this.activeConversationId)) this.setConversationFromStorage(clean);
|
|
347537
347636
|
return this.getConversationSnapshot(clean);
|
|
347538
347637
|
}
|
|
347539
|
-
setConversationPinned(id, pinned) {
|
|
347638
|
+
setConversationPinned(id, pinned, ws = this.workspace.current) {
|
|
347639
|
+
const targetWs = ws || this.workspace.current;
|
|
347640
|
+
if (!targetWs) return false;
|
|
347540
347641
|
const clean = this.safeConversationId(id || "default");
|
|
347541
|
-
this.
|
|
347542
|
-
const
|
|
347642
|
+
const currentWs = this.workspace.current;
|
|
347643
|
+
const isCurrent = !!currentWs && path28.resolve(currentWs.path) === path28.resolve(targetWs.path);
|
|
347644
|
+
if (isCurrent) this.saveWorkspaceConversationState();
|
|
347645
|
+
const stateKey2 = this.workspaceConversationStateKeyFor(clean, targetWs);
|
|
347543
347646
|
if (!stateKey2) return false;
|
|
347544
|
-
const stored = this.readStoredConversationState();
|
|
347647
|
+
const stored = this.readStoredConversationState(targetWs);
|
|
347545
347648
|
stored.conversations = stored.conversations || {};
|
|
347546
347649
|
const existing = stored.conversations[stateKey2];
|
|
347547
347650
|
if (!existing) return false;
|
|
@@ -347550,23 +347653,65 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
347550
347653
|
const siblingOrders = Object.entries(stored.conversations).filter(([key3, value]) => key3 !== stateKey2 && !!value.pinned === existing.pinned && Number.isFinite(value.order)).map(([, value]) => Number(value.order));
|
|
347551
347654
|
existing.order = siblingOrders.length ? Math.min(...siblingOrders) - 1 : 0;
|
|
347552
347655
|
existing.updatedAt = existing.updatedAt || (/* @__PURE__ */ new Date()).toISOString();
|
|
347553
|
-
this.writeStoredConversationState(stored);
|
|
347656
|
+
this.writeStoredConversationState(stored, targetWs);
|
|
347554
347657
|
return true;
|
|
347555
347658
|
}
|
|
347556
|
-
renameConversation(id, title) {
|
|
347659
|
+
renameConversation(id, title, ws = this.workspace.current) {
|
|
347660
|
+
const targetWs = ws || this.workspace.current;
|
|
347661
|
+
if (!targetWs) return false;
|
|
347557
347662
|
const clean = this.safeConversationId(id || "default");
|
|
347558
347663
|
const nextTitle = String(title || "").replace(/\s+/g, " ").trim().slice(0, 80);
|
|
347559
347664
|
if (!nextTitle) return false;
|
|
347560
|
-
this.
|
|
347561
|
-
const
|
|
347665
|
+
const currentWs = this.workspace.current;
|
|
347666
|
+
const isCurrent = !!currentWs && path28.resolve(currentWs.path) === path28.resolve(targetWs.path);
|
|
347667
|
+
if (isCurrent) this.saveWorkspaceConversationState();
|
|
347668
|
+
const stateKey2 = this.workspaceConversationStateKeyFor(clean, targetWs);
|
|
347562
347669
|
if (!stateKey2) return false;
|
|
347563
|
-
const stored = this.readStoredConversationState();
|
|
347670
|
+
const stored = this.readStoredConversationState(targetWs);
|
|
347564
347671
|
const existing = stored.conversations?.[stateKey2];
|
|
347565
347672
|
if (!existing) return false;
|
|
347566
347673
|
existing.title = nextTitle;
|
|
347567
|
-
this.writeStoredConversationState(stored);
|
|
347674
|
+
this.writeStoredConversationState(stored, targetWs);
|
|
347568
347675
|
return true;
|
|
347569
347676
|
}
|
|
347677
|
+
/** 为指定工作区创建空白对话,不临时切换全局前台工作区。 */
|
|
347678
|
+
createConversationInWorkspace(ws, title = "") {
|
|
347679
|
+
const existing = this.listWorkspaceConversationStates(ws);
|
|
347680
|
+
const id = this.safeConversationId(`conv-${Date.now()}-${crypto14.randomUUID().slice(0, 8)}`);
|
|
347681
|
+
const resolvedTitle = String(title || "").replace(/\s+/g, " ").trim().slice(0, 80) || `New chat ${existing.length + 1}`;
|
|
347682
|
+
const stateKey2 = this.workspaceConversationStateKeyFor(id, ws);
|
|
347683
|
+
if (!stateKey2) throw new Error("Conversation workspace is unavailable.");
|
|
347684
|
+
const unpinnedOrders = existing.filter((item) => !item.pinned).map((item) => Number(item.order || 0));
|
|
347685
|
+
const order = unpinnedOrders.length ? Math.min(...unpinnedOrders) - 1 : 0;
|
|
347686
|
+
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
347687
|
+
this.mutateStoredConversationState(ws, (latest) => {
|
|
347688
|
+
latest.version = 3;
|
|
347689
|
+
latest.activeConversationId = id;
|
|
347690
|
+
latest.conversations = latest.conversations || {};
|
|
347691
|
+
latest.conversations[stateKey2] = {
|
|
347692
|
+
title: resolvedTitle,
|
|
347693
|
+
chatMessages: [],
|
|
347694
|
+
history: [],
|
|
347695
|
+
plan: { items: [] },
|
|
347696
|
+
linkedPlan: { markdown: "", revision: 0 },
|
|
347697
|
+
workRuns: [],
|
|
347698
|
+
continuations: [],
|
|
347699
|
+
inputMode: this.defaultInputMode(),
|
|
347700
|
+
mode: "build",
|
|
347701
|
+
updatedAt: now2,
|
|
347702
|
+
pinned: false,
|
|
347703
|
+
pinnedAt: "",
|
|
347704
|
+
order,
|
|
347705
|
+
branchCommunication: false
|
|
347706
|
+
};
|
|
347707
|
+
return latest;
|
|
347708
|
+
});
|
|
347709
|
+
const currentWs = this.workspace.current;
|
|
347710
|
+
if (currentWs && path28.resolve(currentWs.path) === path28.resolve(ws.path)) {
|
|
347711
|
+
this.setConversationFromStorage(id);
|
|
347712
|
+
}
|
|
347713
|
+
return { id, title: resolvedTitle };
|
|
347714
|
+
}
|
|
347570
347715
|
/**
|
|
347571
347716
|
* 首 Build 命名判定:仅当 (1) 当前对话尚无历史 Build(排除当前 run)且
|
|
347572
347717
|
* (2) 其持久化 title 仍是自动生成(含为空)时返回 true。dev-0.4.3 起不再
|
|
@@ -347677,6 +347822,34 @@ Conversation title (a few words):`;
|
|
|
347677
347822
|
this.writeStoredConversationState(stored);
|
|
347678
347823
|
return true;
|
|
347679
347824
|
}
|
|
347825
|
+
/** Reorder one pinned group inside an explicit workspace without changing membership. */
|
|
347826
|
+
reorderWorkspaceConversationGroup(ids, ws) {
|
|
347827
|
+
const targetWs = ws || this.workspace.current;
|
|
347828
|
+
if (!targetWs || !Array.isArray(ids) || ids.length < 2) return false;
|
|
347829
|
+
const normalized = ids.map((id) => this.safeConversationId(String(id || "")));
|
|
347830
|
+
if (normalized.some((id) => !id) || new Set(normalized).size !== normalized.length) return false;
|
|
347831
|
+
const currentWs = this.workspace.current;
|
|
347832
|
+
const isCurrent = !!currentWs && path28.resolve(currentWs.path) === path28.resolve(targetWs.path);
|
|
347833
|
+
if (isCurrent) this.saveWorkspaceConversationState();
|
|
347834
|
+
let accepted = false;
|
|
347835
|
+
this.mutateStoredConversationState(targetWs, (latest) => {
|
|
347836
|
+
const prefix = this.workspaceConversationPrefixFor(targetWs) || "";
|
|
347837
|
+
const entries = Object.entries(latest.conversations || {}).filter(([key3]) => !prefix || key3.startsWith(prefix));
|
|
347838
|
+
const entryById = new Map(entries.map(([key3, value]) => [key3.slice(prefix.length + 1) || key3, value]));
|
|
347839
|
+
const requested = normalized.map((id) => entryById.get(id));
|
|
347840
|
+
if (requested.some((entry) => !entry)) return latest;
|
|
347841
|
+
if (new Set(requested.map((entry) => !!entry.pinned)).size !== 1) return latest;
|
|
347842
|
+
const orderSlots = requested.map((entry) => Number(entry.order));
|
|
347843
|
+
if (orderSlots.some((order) => !Number.isFinite(order))) return latest;
|
|
347844
|
+
orderSlots.sort((a3, b2) => a3 - b2);
|
|
347845
|
+
normalized.forEach((id, index) => {
|
|
347846
|
+
entryById.get(id).order = orderSlots[index];
|
|
347847
|
+
});
|
|
347848
|
+
accepted = true;
|
|
347849
|
+
return latest;
|
|
347850
|
+
});
|
|
347851
|
+
return accepted;
|
|
347852
|
+
}
|
|
347680
347853
|
flushConversationState() {
|
|
347681
347854
|
this.saveWorkspaceConversationState();
|
|
347682
347855
|
}
|
|
@@ -349625,21 +349798,21 @@ ${summary}`, segment, "local-summarize", true);
|
|
|
349625
349798
|
this.saveWorkspaceConversationState(true);
|
|
349626
349799
|
return { text, hiddenUserInput: true, goalContinuation: true };
|
|
349627
349800
|
}
|
|
349628
|
-
buildSessionArchive(messages,
|
|
349801
|
+
buildSessionArchive(messages, context, archiveDir) {
|
|
349629
349802
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace("T", "_").replace("Z", "");
|
|
349630
349803
|
const filename = `session_${stamp}_${crypto14.randomUUID().slice(0, 8)}.md`;
|
|
349631
349804
|
let markdown = `# Newmark Session \u2014 ${stamp}
|
|
349632
349805
|
|
|
349633
349806
|
`;
|
|
349634
|
-
markdown += `**Mode**: ${mode}
|
|
349635
|
-
**Model**: ${model}
|
|
349807
|
+
markdown += `**Mode**: ${context.mode}
|
|
349808
|
+
**Model**: ${context.model}
|
|
349636
349809
|
`;
|
|
349637
349810
|
markdown += `**Messages**: ${messages.length}
|
|
349638
349811
|
|
|
349639
349812
|
---
|
|
349640
349813
|
|
|
349641
349814
|
`;
|
|
349642
|
-
if (
|
|
349815
|
+
if (context.goal?.objective) markdown += `**Goal**: ${context.goal.objective}
|
|
349643
349816
|
|
|
349644
349817
|
`;
|
|
349645
349818
|
for (const msg of messages) {
|
|
@@ -349662,12 +349835,12 @@ ${msg.content}
|
|
|
349662
349835
|
writeSessionArchive(messages, mode, model) {
|
|
349663
349836
|
const archiveDir = this.archiveDir();
|
|
349664
349837
|
fs25.mkdirSync(archiveDir, { recursive: true });
|
|
349665
|
-
const archive = this.buildSessionArchive(messages, mode, model, archiveDir);
|
|
349838
|
+
const archive = this.buildSessionArchive(messages, { mode, model, goal: this.serializeGoal() }, archiveDir);
|
|
349666
349839
|
fs25.writeFileSync(path28.join(archiveDir, archive.filename), archive.markdown, "utf-8");
|
|
349667
349840
|
return archive.filename;
|
|
349668
349841
|
}
|
|
349669
|
-
async writeSessionArchiveAsync(messages,
|
|
349670
|
-
const archive = this.buildSessionArchive(messages,
|
|
349842
|
+
async writeSessionArchiveAsync(messages, context, archiveDir = this.archiveDir()) {
|
|
349843
|
+
const archive = this.buildSessionArchive(messages, context, archiveDir);
|
|
349671
349844
|
await fs25.promises.mkdir(archiveDir, { recursive: true });
|
|
349672
349845
|
const outPath = path28.join(archiveDir, archive.filename);
|
|
349673
349846
|
const tempPath = `${outPath}.${process.pid}.${crypto14.randomUUID()}.tmp`;
|
|
@@ -349754,30 +349927,36 @@ ${msg.content}
|
|
|
349754
349927
|
* large markdown payload and manifest use promise-based filesystem I/O so
|
|
349755
349928
|
* independent workspaces can archive in parallel without freezing Electron.
|
|
349756
349929
|
*/
|
|
349757
|
-
async archiveConversationAsync(conversationId) {
|
|
349758
|
-
return await this.archiveConversationAsyncUnlocked(conversationId);
|
|
349930
|
+
async archiveConversationAsync(conversationId, ws = this.workspace.current) {
|
|
349931
|
+
return await this.archiveConversationAsyncUnlocked(conversationId, ws);
|
|
349759
349932
|
}
|
|
349760
|
-
async archiveConversationAsyncUnlocked(conversationId) {
|
|
349761
|
-
const ws = this.workspace.current;
|
|
349933
|
+
async archiveConversationAsyncUnlocked(conversationId, targetWorkspace = this.workspace.current) {
|
|
349934
|
+
const ws = targetWorkspace || this.workspace.current;
|
|
349762
349935
|
if (!ws) return null;
|
|
349763
349936
|
const clean = this.safeConversationId(conversationId || "default");
|
|
349764
|
-
const stateKey2 = this.
|
|
349937
|
+
const stateKey2 = this.workspaceConversationStateKeyFor(clean, ws);
|
|
349765
349938
|
if (!stateKey2) return null;
|
|
349766
349939
|
const memoryKey = `${ws.isInternal ? "internal" : "external"}:${path28.resolve(ws.path)}::conversation:${clean}`;
|
|
349767
349940
|
const archiveDir = path28.join(ws.path, "archive");
|
|
349768
|
-
const workspacePrefix = this.
|
|
349769
|
-
const archiveMode = this.modeName();
|
|
349770
|
-
const archiveModel = this.model;
|
|
349941
|
+
const workspacePrefix = this.workspaceConversationPrefixFor(ws) || "";
|
|
349771
349942
|
const cachedStored = this.readStoredConversationState(ws);
|
|
349772
349943
|
const stored = JSON.parse(JSON.stringify(cachedStored || {}));
|
|
349773
349944
|
const persisted = stored.conversations?.[stateKey2];
|
|
349774
349945
|
if (persisted) this.normalizeConversationTree(persisted);
|
|
349775
349946
|
const memory = this.workspaceConversations.get(memoryKey);
|
|
349947
|
+
const archiveMode = persisted?.mode || memory?.mode || "build";
|
|
349948
|
+
const archiveSelection = persisted?.modelSelection || memory?.modelSelection;
|
|
349949
|
+
const archiveModel = archiveSelection?.kind === "deployment" ? archiveSelection.modelId : archiveSelection?.kind === "auto" ? "auto" : "auto";
|
|
349950
|
+
const archiveGoal = persisted?.goal || memory?.goal || null;
|
|
349776
349951
|
const persistedMessagesAvailable = persisted?.chatMessages !== void 0;
|
|
349777
349952
|
const sourceMessages = persisted?.chatMessages ?? memory?.chatMessages ?? [];
|
|
349778
349953
|
const sourceHistory = persistedMessagesAvailable ? persisted?.history ?? [] : memory?.history ?? persisted?.history ?? [];
|
|
349779
349954
|
const messages = this.normalizeConversationChatMessages(sourceMessages, sourceHistory);
|
|
349780
|
-
const filename = await this.writeSessionArchiveAsync(messages,
|
|
349955
|
+
const filename = await this.writeSessionArchiveAsync(messages, {
|
|
349956
|
+
mode: archiveMode,
|
|
349957
|
+
model: archiveModel,
|
|
349958
|
+
goal: archiveGoal
|
|
349959
|
+
}, archiveDir);
|
|
349781
349960
|
const archiveEntry = persisted ? JSON.parse(JSON.stringify(persisted)) : {
|
|
349782
349961
|
title: this.titleFromMessages(messages, clean),
|
|
349783
349962
|
chatMessages: messages,
|
|
@@ -349830,7 +350009,9 @@ ${msg.content}
|
|
|
349830
350009
|
this.workspaceConversations.delete(memoryKey);
|
|
349831
350010
|
const duplicateMemoryKey = `${ws.isInternal ? "internal" : "external"}:${path28.resolve(ws.path)}::conversation:${clean}`;
|
|
349832
350011
|
this.workspaceConversations.delete(duplicateMemoryKey);
|
|
349833
|
-
|
|
350012
|
+
const currentWs = this.workspace.current;
|
|
350013
|
+
const isCurrentWorkspace = !!currentWs && path28.resolve(currentWs.path) === path28.resolve(ws.path);
|
|
350014
|
+
if (isCurrentWorkspace && clean === this.safeConversationId(this.activeConversationId || "default")) {
|
|
349834
350015
|
this.activeConversationId = nextActiveId || "default";
|
|
349835
350016
|
this.loadWorkspaceConversationState();
|
|
349836
350017
|
}
|
|
@@ -351075,7 +351256,7 @@ ${persisted.map((guide, index) => `Guide ${index + 1}: ${guide.text}`).join("\n"
|
|
|
351075
351256
|
return `${accepted.output}
|
|
351076
351257
|
${settled?.result || settled?.error || ""}`.trim();
|
|
351077
351258
|
}
|
|
351078
|
-
async handleSubagentEnvelope(args) {
|
|
351259
|
+
async handleSubagentEnvelope(args, requireRunningBuild = false) {
|
|
351079
351260
|
try {
|
|
351080
351261
|
const params = JSON.parse(args);
|
|
351081
351262
|
const preset = this.resolveSubagentPreset(params);
|
|
@@ -351090,6 +351271,36 @@ ${settled?.result || settled?.error || ""}`.trim();
|
|
|
351090
351271
|
const requestedModel = this.normalizeSubagentModelSelection(params.model || preset?.model || inheritedModel);
|
|
351091
351272
|
const activeDeployment = this.activeDeployment();
|
|
351092
351273
|
const peerModel = requestedModel !== "auto" && !parseDeploymentSelectionValue2(requestedModel) && activeDeployment && requestedModel === activeDeployment.modelId ? `deployment:${encodeURIComponent(activeDeployment.providerId)}:${encodeURIComponent(activeDeployment.modelId)}` : requestedModel;
|
|
351274
|
+
const buildRunId = this.currentWorkRunId();
|
|
351275
|
+
const runningBuild = buildRunId ? this.workRuns.find((run) => run.runId === buildRunId && run.status === "running") : void 0;
|
|
351276
|
+
const limit = this.subagentConcurrencyLimit();
|
|
351277
|
+
if (requireRunningBuild && !runningBuild) {
|
|
351278
|
+
return {
|
|
351279
|
+
ok: false,
|
|
351280
|
+
output: "[SubAgent terminated] No running Build Block owns this call; no SubAgent was created.",
|
|
351281
|
+
error: "SubAgent tool calls require a running Build Block.",
|
|
351282
|
+
metadata: { kind: "subagent", buildRunId: buildRunId || "", limit, terminated: true }
|
|
351283
|
+
};
|
|
351284
|
+
}
|
|
351285
|
+
if (buildRunId && !runningBuild) {
|
|
351286
|
+
return {
|
|
351287
|
+
ok: false,
|
|
351288
|
+
output: `[SubAgent terminated] Build Block ${buildRunId} is not running; no SubAgent was created.`,
|
|
351289
|
+
error: "SubAgent creation requires a running Build Block.",
|
|
351290
|
+
metadata: { kind: "subagent", buildRunId, limit, terminated: true }
|
|
351291
|
+
};
|
|
351292
|
+
}
|
|
351293
|
+
if (runningBuild) {
|
|
351294
|
+
const activeForBuild = this.subagents.activeCountForBuild(buildRunId);
|
|
351295
|
+
if (activeForBuild >= limit) {
|
|
351296
|
+
return {
|
|
351297
|
+
ok: false,
|
|
351298
|
+
output: `[SubAgent terminated] Build Block ${buildRunId} reached the ${this.intelligence === "ultra" ? "Ultra" : "non-Ultra"} hard limit (${limit}); no SubAgent was created or queued.`,
|
|
351299
|
+
error: `SubAgent hard limit reached for Build Block ${buildRunId}: ${activeForBuild}/${limit}.`,
|
|
351300
|
+
metadata: { kind: "subagent", buildRunId, intelligence: this.intelligence, activeForBuild, limit, terminated: true }
|
|
351301
|
+
};
|
|
351302
|
+
}
|
|
351303
|
+
}
|
|
351093
351304
|
const id = this.subagents.create(
|
|
351094
351305
|
name50,
|
|
351095
351306
|
prompt,
|
|
@@ -351099,7 +351310,9 @@ ${settled?.result || settled?.error || ""}`.trim();
|
|
|
351099
351310
|
this.runtimeActorId,
|
|
351100
351311
|
peerFlow,
|
|
351101
351312
|
peerGoal,
|
|
351102
|
-
Number(params.flow_pc ?? params.flowPc ?? (peerMode === "flow" ? this.flowPc : 0))
|
|
351313
|
+
Number(params.flow_pc ?? params.flowPc ?? (peerMode === "flow" ? this.flowPc : 0)),
|
|
351314
|
+
runningBuild?.runId || "",
|
|
351315
|
+
this.intelligence
|
|
351103
351316
|
);
|
|
351104
351317
|
const sa = this.subagents.get(id);
|
|
351105
351318
|
if (sa && preset) {
|
|
@@ -351838,6 +352051,13 @@ ${items.map((item) => this.formatAutomation(item)).join("\n")}`;
|
|
|
351838
352051
|
}
|
|
351839
352052
|
latestSubmittedImages(attachmentId = "") {
|
|
351840
352053
|
const normalizedId = String(attachmentId || "").trim();
|
|
352054
|
+
const captured = hydrateConversationImageAttachments(this.rootPath, this.latestCapturedImageInputs).flatMap((attachment) => attachment.dataUrl ? [{ id: attachment.id, dataUrl: attachment.dataUrl }] : []);
|
|
352055
|
+
if (normalizedId) {
|
|
352056
|
+
const capturedMatch = captured.find((item) => item.id === normalizedId);
|
|
352057
|
+
if (capturedMatch) return [capturedMatch];
|
|
352058
|
+
} else if (captured.length) {
|
|
352059
|
+
return captured;
|
|
352060
|
+
}
|
|
351841
352061
|
for (let index = this.chatMessages.length - 1; index >= 0; index -= 1) {
|
|
351842
352062
|
const message = this.chatMessages[index];
|
|
351843
352063
|
if (message?.role !== "user") continue;
|
|
@@ -352407,7 +352627,7 @@ ${custom}`);
|
|
|
352407
352627
|
if (this.intelligence === "ultra") {
|
|
352408
352628
|
parts.push([
|
|
352409
352629
|
"[Ultra Intelligence \u2013 Orchestrator Role]",
|
|
352410
|
-
"You are the lead orchestrator. Actively decompose complex tasks into parallel sub-tasks. Use the `
|
|
352630
|
+
"You are the lead orchestrator. Actively decompose complex tasks into parallel sub-tasks. Use the `SubAgent` tool to create specialized SubAgents for each distinct sub-task. Use `task_create` only for the conversation checklist; it never creates a SubAgent. Coordinate the SubAgent team: assign clear responsibilities, merge results, resolve conflicts, and produce a unified final output. SubAgents are your team; delegate aggressively and manage them as a manager, not just a tool caller.",
|
|
352411
352631
|
"Do not attempt to do all the work yourself. Use SubAgents for parallel investigation, verification, implementation, and review."
|
|
352412
352632
|
].join("\n"));
|
|
352413
352633
|
}
|
|
@@ -352513,7 +352733,7 @@ ${custom}`);
|
|
|
352513
352733
|
"- Build history disclosure is two-layered. The request prompt contains only each historical Build Block user input, final summary, and completion status. When the current task continues, fixes, verifies, or depends on earlier Build Blocks, proactively call build_history_query to read the concrete tool activity and results of the relevant block, and reuse that information instead of re-investigating (re-running commands or re-reading files) from scratch. Querying history is read-only and never authorizes resuming that work; do not query merely to answer completion status already shown in the prompt.",
|
|
352514
352734
|
"- Linked plan disclosure: a durable conversation-linked Markdown plan exists and can be inspected or updated with linked_plan when explicitly needed or required by Plan mode. Its full Markdown and revision are not injected into every model request.",
|
|
352515
352735
|
"- A memory_lab_update, memory_lab_delete, or memory_lab_reindex call is unfinished until its awaited tool result contains rebuildReceipt.completed=true. The completion receipt is represented by the tool activity inside the current Build block and should not be repeated as a separate completion message.",
|
|
352516
|
-
`- Skills and subagents: skill searches enabled metadata and loads one SKILL.md body on demand; skill_download installs offline skill folders;
|
|
352736
|
+
`- Skills and subagents: skill searches enabled metadata and loads one SKILL.md body on demand; skill_download installs offline skill folders; SubAgent creates constrained peer agents tracked in agent state. task_create is only for the conversation checklist and never creates a SubAgent.`,
|
|
352517
352737
|
`- Visible output contract: assistant replies are sanitized before display to remove hidden-reasoning markers. ${visibleOutputContract}`,
|
|
352518
352738
|
"- During Build work, before the first tool call and between materially different tool phases, emit a concise public progress explanation of what you are checking or changing and why. This is visible commentary, not hidden chain-of-thought. Do not wait until the final answer to explain the work."
|
|
352519
352739
|
].join("\n");
|
|
@@ -353022,6 +353242,155 @@ var ConversationKernel = class {
|
|
|
353022
353242
|
followUp: queued?.followUp.slice() || []
|
|
353023
353243
|
};
|
|
353024
353244
|
}
|
|
353245
|
+
queueItems(target) {
|
|
353246
|
+
const runtime = this.findRuntime(target);
|
|
353247
|
+
if (!runtime) return [];
|
|
353248
|
+
return runtime.pendingNextTurn.flatMap((item) => {
|
|
353249
|
+
if (item.queueMode !== "followUp") return [];
|
|
353250
|
+
if (typeof item.message === "string") return [];
|
|
353251
|
+
const id = String(item.message.clientMessageId || "");
|
|
353252
|
+
if (!id) return [];
|
|
353253
|
+
return [{
|
|
353254
|
+
id,
|
|
353255
|
+
text: String(item.message.visibleUserInput || item.message.text || "").replace(/^\[Next queued while current turn is running\]\n/, ""),
|
|
353256
|
+
queueMode: item.queueMode,
|
|
353257
|
+
requestedMode: item.message.visibleMode,
|
|
353258
|
+
goalObjective: item.message.goalObjective,
|
|
353259
|
+
runId: item.message.runId,
|
|
353260
|
+
createdAt: String(item.message.createdAt || "")
|
|
353261
|
+
}];
|
|
353262
|
+
});
|
|
353263
|
+
}
|
|
353264
|
+
enqueueNext(target, input) {
|
|
353265
|
+
const runtime = this.findRuntime(target);
|
|
353266
|
+
if (!runtime?.activePromise || !runtime.runId) throw new Error("Target conversation is not running");
|
|
353267
|
+
const id = String(input.id || "").trim().slice(0, 200);
|
|
353268
|
+
const text = String(input.text || "").trim();
|
|
353269
|
+
if (!id || !text) throw new Error("Queue item id and text are required");
|
|
353270
|
+
const existing = this.queueItems(runtime.target).find((item) => item.id === id);
|
|
353271
|
+
if (existing) return existing;
|
|
353272
|
+
const prompt = `[Next queued while current turn is running]
|
|
353273
|
+
${text}`;
|
|
353274
|
+
const createdAt = String(input.createdAt || (/* @__PURE__ */ new Date()).toISOString());
|
|
353275
|
+
runtime.pendingNextTurn.push({
|
|
353276
|
+
message: {
|
|
353277
|
+
text: prompt,
|
|
353278
|
+
visibleUserInput: text,
|
|
353279
|
+
visibleMode: String(input.requestedMode || "build"),
|
|
353280
|
+
goalObjective: String(input.goalObjective || "") || void 0,
|
|
353281
|
+
clientMessageId: id,
|
|
353282
|
+
runId: runtime.runId,
|
|
353283
|
+
createdAt
|
|
353284
|
+
},
|
|
353285
|
+
queueMode: "followUp"
|
|
353286
|
+
});
|
|
353287
|
+
runtime.runner.retainConversationContinuations([{
|
|
353288
|
+
content: prompt,
|
|
353289
|
+
queueMode: "followUp",
|
|
353290
|
+
clientMessageId: id,
|
|
353291
|
+
runId: runtime.runId,
|
|
353292
|
+
createdAt
|
|
353293
|
+
}]);
|
|
353294
|
+
this.trackQueuedMessage(runtime, prompt, "followUp");
|
|
353295
|
+
this.emitQueueUpdate(runtime);
|
|
353296
|
+
return this.queueItems(runtime.target).find((item) => item.id === id);
|
|
353297
|
+
}
|
|
353298
|
+
updateQueueItem(target, idInput, textInput) {
|
|
353299
|
+
const runtime = this.findRuntime(target);
|
|
353300
|
+
if (!runtime) throw new Error("Target conversation runtime is unavailable");
|
|
353301
|
+
const id = String(idInput || "").trim();
|
|
353302
|
+
const text = String(textInput || "").trim();
|
|
353303
|
+
if (!id || !text) throw new Error("Queue item id and text are required");
|
|
353304
|
+
const pending3 = runtime.pendingNextTurn.find((item) => typeof item.message !== "string" && item.message.clientMessageId === id);
|
|
353305
|
+
if (!pending3 || typeof pending3.message === "string") throw new Error("Queue item is no longer editable");
|
|
353306
|
+
const oldPrompt = pending3.message.text;
|
|
353307
|
+
pending3.message.text = `[Next queued while current turn is running]
|
|
353308
|
+
${text}`;
|
|
353309
|
+
pending3.message.visibleUserInput = text;
|
|
353310
|
+
runtime.runner.consumeConversationContinuation({ content: oldPrompt, queueMode: pending3.queueMode, clientMessageId: id });
|
|
353311
|
+
runtime.runner.retainConversationContinuations([{
|
|
353312
|
+
content: pending3.message.text,
|
|
353313
|
+
queueMode: pending3.queueMode,
|
|
353314
|
+
clientMessageId: id,
|
|
353315
|
+
runId: pending3.message.runId
|
|
353316
|
+
}]);
|
|
353317
|
+
this.replaceTrackedQueuedMessage(runtime, oldPrompt, pending3.message.text, pending3.queueMode);
|
|
353318
|
+
this.emitQueueUpdate(runtime);
|
|
353319
|
+
return this.queueItems(runtime.target).find((item) => item.id === id);
|
|
353320
|
+
}
|
|
353321
|
+
deleteQueueItem(target, idInput) {
|
|
353322
|
+
const runtime = this.findRuntime(target);
|
|
353323
|
+
if (!runtime) return false;
|
|
353324
|
+
const id = String(idInput || "").trim();
|
|
353325
|
+
const index = runtime.pendingNextTurn.findIndex((item) => typeof item.message !== "string" && item.message.clientMessageId === id);
|
|
353326
|
+
if (index < 0) return false;
|
|
353327
|
+
const [removed] = runtime.pendingNextTurn.splice(index, 1);
|
|
353328
|
+
if (typeof removed.message !== "string") {
|
|
353329
|
+
runtime.runner.consumeConversationContinuation({ content: removed.message.text, queueMode: removed.queueMode, clientMessageId: id });
|
|
353330
|
+
this.consumeQueuedMessage(runtime, removed.message.text);
|
|
353331
|
+
}
|
|
353332
|
+
this.emitQueueUpdate(runtime);
|
|
353333
|
+
return true;
|
|
353334
|
+
}
|
|
353335
|
+
setQueuePaused(target, paused) {
|
|
353336
|
+
const runtime = this.findRuntime(target);
|
|
353337
|
+
if (!runtime) throw new Error("Target conversation runtime is unavailable");
|
|
353338
|
+
runtime.queuePaused = paused;
|
|
353339
|
+
this.emitQueueUpdate(runtime);
|
|
353340
|
+
if (!paused && !runtime.activePromise && runtime.pendingNextTurn.length) {
|
|
353341
|
+
this.schedulePendingRuntimeContinuation(runtime, runtime.runId);
|
|
353342
|
+
}
|
|
353343
|
+
return runtime.queuePaused;
|
|
353344
|
+
}
|
|
353345
|
+
queueAction(target, action, input = {}) {
|
|
353346
|
+
const runtime = this.findRuntime(target);
|
|
353347
|
+
if (!runtime) throw new Error("Target conversation runtime is unavailable");
|
|
353348
|
+
let receipt;
|
|
353349
|
+
if (action === "enqueue") {
|
|
353350
|
+
this.enqueueNext(runtime.target, {
|
|
353351
|
+
id: String(input.id || ""),
|
|
353352
|
+
text: String(input.text || ""),
|
|
353353
|
+
requestedMode: input.requestedMode,
|
|
353354
|
+
goalObjective: input.goalObjective,
|
|
353355
|
+
createdAt: input.createdAt
|
|
353356
|
+
});
|
|
353357
|
+
} else if (action === "update") {
|
|
353358
|
+
this.updateQueueItem(runtime.target, String(input.id || ""), String(input.text || ""));
|
|
353359
|
+
} else if (action === "delete") {
|
|
353360
|
+
if (!this.deleteQueueItem(runtime.target, String(input.id || ""))) throw new Error("Queue item was not found");
|
|
353361
|
+
} else if (action === "toggle_pause") {
|
|
353362
|
+
this.setQueuePaused(runtime.target, !runtime.queuePaused);
|
|
353363
|
+
} else if (action === "guide") {
|
|
353364
|
+
const item = this.queueItems(runtime.target).find((entry) => entry.id === String(input.id || ""));
|
|
353365
|
+
if (!item) throw new Error("Queue item was not found");
|
|
353366
|
+
receipt = this.enqueueGuide({
|
|
353367
|
+
clientMessageId: item.id,
|
|
353368
|
+
guideId: (0, import_crypto16.randomUUID)(),
|
|
353369
|
+
target: runtime.target,
|
|
353370
|
+
runId: runtime.runId,
|
|
353371
|
+
deliveryMode: "steer",
|
|
353372
|
+
text: item.goalObjective ? `Goal for the current Build:
|
|
353373
|
+
${item.goalObjective}` : item.text,
|
|
353374
|
+
goalObjective: item.goalObjective,
|
|
353375
|
+
createdAt: item.createdAt || (/* @__PURE__ */ new Date()).toISOString()
|
|
353376
|
+
});
|
|
353377
|
+
if (receipt.status === "rejected") return {
|
|
353378
|
+
ok: false,
|
|
353379
|
+
queueItems: this.queueItems(runtime.target),
|
|
353380
|
+
queuePaused: runtime.queuePaused,
|
|
353381
|
+
queued: this.queued(runtime.target),
|
|
353382
|
+
receipt
|
|
353383
|
+
};
|
|
353384
|
+
this.deleteQueueItem(runtime.target, item.id);
|
|
353385
|
+
}
|
|
353386
|
+
return {
|
|
353387
|
+
ok: true,
|
|
353388
|
+
queueItems: this.queueItems(runtime.target),
|
|
353389
|
+
queuePaused: runtime.queuePaused,
|
|
353390
|
+
queued: this.queued(runtime.target),
|
|
353391
|
+
receipt
|
|
353392
|
+
};
|
|
353393
|
+
}
|
|
353025
353394
|
events(target) {
|
|
353026
353395
|
return this.findRuntime(target)?.events.slice() || [];
|
|
353027
353396
|
}
|
|
@@ -353050,6 +353419,8 @@ var ConversationKernel = class {
|
|
|
353050
353419
|
workRuns: this.bindWorkRunsToRuntimeTarget(conversationSnapshot.workRuns, normalized),
|
|
353051
353420
|
target: normalized,
|
|
353052
353421
|
queued: this.queued(normalized),
|
|
353422
|
+
queueItems: this.queueItems(normalized),
|
|
353423
|
+
queuePaused: runtime?.queuePaused === true,
|
|
353053
353424
|
workEvents: this.events(normalized),
|
|
353054
353425
|
runtime: this.runtimeState(normalized),
|
|
353055
353426
|
mode: runner.mode,
|
|
@@ -353485,7 +353856,7 @@ var ConversationKernel = class {
|
|
|
353485
353856
|
if (runtime.stopRequestedRunId === runId) {
|
|
353486
353857
|
stopped = true;
|
|
353487
353858
|
this.settleCooperativeStop(runtime, runId);
|
|
353488
|
-
} else if (runtime.pendingNextTurn.length > 0) {
|
|
353859
|
+
} else if (!runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
|
|
353489
353860
|
this.schedulePendingRuntimeContinuation(runtime, runId);
|
|
353490
353861
|
}
|
|
353491
353862
|
}
|
|
@@ -353520,7 +353891,7 @@ var ConversationKernel = class {
|
|
|
353520
353891
|
return this.result(runtime, lastTokens);
|
|
353521
353892
|
}
|
|
353522
353893
|
for (; ; ) {
|
|
353523
|
-
while (runtime.pendingNextTurn.length > 0) {
|
|
353894
|
+
while (!runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
|
|
353524
353895
|
if (runtime.stopRequestedRunId === runtime.runId) return this.result(runtime, lastTokens);
|
|
353525
353896
|
const next = runtime.pendingNextTurn.shift();
|
|
353526
353897
|
if (next.queueMode === "steer" && typeof next.message !== "string" && !!next.message.clientMessageId) {
|
|
@@ -353562,11 +353933,11 @@ ${batchText}`,
|
|
|
353562
353933
|
this.mirrorHostIfTargetActive(runtime);
|
|
353563
353934
|
return this.result(runtime, lastTokens);
|
|
353564
353935
|
}
|
|
353565
|
-
this.clearQueued(runtime);
|
|
353936
|
+
if (!runtime.pendingNextTurn.length) this.clearQueued(runtime);
|
|
353566
353937
|
const completedRunId = runtime.runId;
|
|
353567
353938
|
runtime.runner.finishConversationWorkRun(completedRunId, "completed");
|
|
353568
353939
|
await new Promise((resolve16) => setImmediate(resolve16));
|
|
353569
|
-
if (runtime.runId === completedRunId && runtime.stopRequestedRunId !== completedRunId && runtime.pendingNextTurn.length > 0) {
|
|
353940
|
+
if (runtime.runId === completedRunId && runtime.stopRequestedRunId !== completedRunId && !runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
|
|
353570
353941
|
runtime.guideAcceptanceClosedRunId = "";
|
|
353571
353942
|
if (!runtime.runner.resumeConversationWorkRun(completedRunId)) {
|
|
353572
353943
|
throw new Error(`Unable to resume deferred Guide work run ${completedRunId}`);
|
|
@@ -353657,6 +354028,7 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
353657
354028
|
events: [],
|
|
353658
354029
|
pendingNextTurn: [],
|
|
353659
354030
|
queued: { steering: [], followUp: [] },
|
|
354031
|
+
queuePaused: false,
|
|
353660
354032
|
runId: "",
|
|
353661
354033
|
generation: this.generations.get(target.runtimeKey) || 0,
|
|
353662
354034
|
stopRequestedRunId: "",
|
|
@@ -353752,7 +354124,7 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
353752
354124
|
}
|
|
353753
354125
|
setImmediate(() => {
|
|
353754
354126
|
runtime.pendingContinuationRunId = void 0;
|
|
353755
|
-
if (runtime.runId !== runId || runtime.activePromise || runtime.stopRequestedRunId === runId) return;
|
|
354127
|
+
if (runtime.runId !== runId || runtime.activePromise || runtime.stopRequestedRunId === runId || runtime.queuePaused) return;
|
|
353756
354128
|
const next = runtime.pendingNextTurn.shift();
|
|
353757
354129
|
if (!next) return;
|
|
353758
354130
|
const message = typeof next.message === "string" ? { text: next.message, runId } : { ...next.message, runId: next.message.runId || runId };
|
|
@@ -353903,7 +354275,36 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
353903
354275
|
const text = typeof message === "string" ? message : message.text;
|
|
353904
354276
|
const prompt = isSteer ? text : `[Next queued while current turn is running]
|
|
353905
354277
|
${text}`;
|
|
353906
|
-
if (!isSteer)
|
|
354278
|
+
if (!isSteer) {
|
|
354279
|
+
const structured = typeof message === "string" ? null : message;
|
|
354280
|
+
const clientMessageId = String(structured?.clientMessageId || (0, import_crypto16.randomUUID)());
|
|
354281
|
+
const queuedMessage = {
|
|
354282
|
+
...structured || {},
|
|
354283
|
+
text: prompt,
|
|
354284
|
+
visibleUserInput: structured?.visibleUserInput || text,
|
|
354285
|
+
visibleMode: structured?.visibleMode || runtime.options.mode,
|
|
354286
|
+
clientMessageId,
|
|
354287
|
+
runId: structured?.runId || runtime.runId,
|
|
354288
|
+
createdAt: String(structured?.createdAt || (/* @__PURE__ */ new Date()).toISOString())
|
|
354289
|
+
};
|
|
354290
|
+
if (!runtime.pendingNextTurn.some((item) => typeof item.message !== "string" && item.message.clientMessageId === clientMessageId)) {
|
|
354291
|
+
runtime.pendingNextTurn.push({ message: queuedMessage, queueMode: "followUp" });
|
|
354292
|
+
}
|
|
354293
|
+
runtime.runner.retainConversationContinuations([{
|
|
354294
|
+
content: prompt,
|
|
354295
|
+
queueMode: "followUp",
|
|
354296
|
+
clientMessageId,
|
|
354297
|
+
runId: queuedMessage.runId,
|
|
354298
|
+
images: queuedMessage.images?.map((image) => ({ ...image })),
|
|
354299
|
+
attachments: queuedMessage.attachments?.map((attachment) => ({ ...attachment })),
|
|
354300
|
+
createdAt: queuedMessage.createdAt
|
|
354301
|
+
}]);
|
|
354302
|
+
this.trackQueuedMessage(runtime, prompt, "followUp");
|
|
354303
|
+
runtime.runner.recordWorkStatus(runtime.stopRequestedRunId === runtime.runId ? "Next message retained while stopping." : "Next message queued.");
|
|
354304
|
+
if (runtime.stopRequestedRunId === runtime.runId) runtime.forceStopArmedRunId = "";
|
|
354305
|
+
this.emitQueueUpdate(runtime);
|
|
354306
|
+
return;
|
|
354307
|
+
}
|
|
353907
354308
|
if (runtime.stopRequestedRunId === runtime.runId) {
|
|
353908
354309
|
runtime.forceStopArmedRunId = "";
|
|
353909
354310
|
const structured = typeof message === "string" ? void 0 : message;
|
|
@@ -353949,6 +354350,12 @@ ${text}`;
|
|
|
353949
354350
|
}
|
|
353950
354351
|
if (changed) this.emitQueueUpdate(runtime);
|
|
353951
354352
|
}
|
|
354353
|
+
replaceTrackedQueuedMessage(runtime, oldMessage, nextMessage, queueMode) {
|
|
354354
|
+
this.queueState(runtime);
|
|
354355
|
+
const list = queueMode === "steer" ? runtime.queued.steering : runtime.queued.followUp;
|
|
354356
|
+
const index = list.indexOf(oldMessage);
|
|
354357
|
+
if (index >= 0) list[index] = nextMessage;
|
|
354358
|
+
}
|
|
353952
354359
|
emitQueueUpdate(runtime) {
|
|
353953
354360
|
this.queueState(runtime);
|
|
353954
354361
|
runtime.runner.emitWorkEvent({
|
|
@@ -354070,9 +354477,10 @@ ${text}`;
|
|
|
354070
354477
|
const runId = runtime.runId;
|
|
354071
354478
|
await Promise.resolve();
|
|
354072
354479
|
if (runtime.runId !== runId || runtime.stopRequestedRunId === runId) return true;
|
|
354073
|
-
|
|
354480
|
+
const hasSteering = runtime.pendingNextTurn.some((item) => item.queueMode === "steer");
|
|
354481
|
+
if (hasSteering || runtime.runner.subagents.readRootInbox().length > 0) return false;
|
|
354074
354482
|
runtime.guideAcceptanceClosedRunId = runId;
|
|
354075
|
-
if (runtime.pendingNextTurn.
|
|
354483
|
+
if (runtime.pendingNextTurn.some((item) => item.queueMode === "steer") || runtime.runner.subagents.readRootInbox().length > 0) {
|
|
354076
354484
|
runtime.guideAcceptanceClosedRunId = "";
|
|
354077
354485
|
return false;
|
|
354078
354486
|
}
|
|
@@ -354225,6 +354633,9 @@ async function handle(request) {
|
|
|
354225
354633
|
target
|
|
354226
354634
|
});
|
|
354227
354635
|
}
|
|
354636
|
+
if (request.method === "queue_action") {
|
|
354637
|
+
return kernel.queueAction(checkedTarget(request.params.target), request.params.action, request.params.input);
|
|
354638
|
+
}
|
|
354228
354639
|
if (request.method === "checkpoint") return kernel.checkpoint(checkedTarget(request.params.target));
|
|
354229
354640
|
if (request.method === "context_compress") {
|
|
354230
354641
|
return kernel.compressContext(checkedTarget(request.params.target), request.params.options);
|