lsd-pi 1.2.2 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/resources/extensions/slash-commands/plan.js +11 -7
- package/dist/resources/extensions/subagent/agents.js +19 -9
- package/dist/resources/extensions/subagent/index.js +112 -20
- package/dist/resources/extensions/subagent/launch-helpers.js +3 -2
- package/package.json +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +11 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/src/providers/anthropic-shared.ts +12 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +62 -6
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js +15 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +1 -0
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +1 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/path-display.test.js +1 -0
- package/packages/pi-coding-agent/dist/tests/path-display.test.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +60 -7
- package/packages/pi-coding-agent/src/core/sdk.ts +1 -1
- package/packages/pi-coding-agent/src/core/skill-tool.test.ts +18 -0
- package/packages/pi-coding-agent/src/core/skills.ts +1 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +3 -0
- package/packages/pi-coding-agent/src/tests/path-display.test.ts +1 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/slash-commands/plan.ts +14 -8
- package/src/resources/extensions/subagent/agents.ts +22 -7
- package/src/resources/extensions/subagent/index.ts +138 -18
- package/src/resources/extensions/subagent/launch-helpers.ts +2 -1
|
@@ -226,13 +226,17 @@ function restoreStateFromSession(ctx) {
|
|
|
226
226
|
}
|
|
227
227
|
async function enablePlanModeWithModelSwitch(pi, ctx, currentModel, next = {}) {
|
|
228
228
|
enablePlanMode(pi, currentModel, next);
|
|
229
|
-
//
|
|
229
|
+
// Keep fallback behavior in before_agent_start for restored sessions or when
|
|
230
|
+
// immediate switching cannot be completed at entry-time.
|
|
230
231
|
reasoningModelSwitchDone = false;
|
|
231
232
|
if (!readAutoSwitchPlanModelSetting())
|
|
232
233
|
return;
|
|
233
|
-
|
|
234
|
+
const reasoningModel = parseQualifiedModelRef(readPlanModeReasoningModel());
|
|
235
|
+
if (!reasoningModel) {
|
|
234
236
|
ctx.ui?.notify?.("OpusPlan: set a Plan reasoning model in /settings to auto-switch on entry", "info");
|
|
237
|
+
return;
|
|
235
238
|
}
|
|
239
|
+
reasoningModelSwitchDone = await setModelIfNeeded(pi, ctx, reasoningModel);
|
|
236
240
|
}
|
|
237
241
|
function enablePlanMode(pi, currentModel, next = {}) {
|
|
238
242
|
const currentMode = getPermissionMode();
|
|
@@ -267,14 +271,15 @@ function leavePlanMode(pi, approvalStatus, nextPermissionMode, clearTask = false
|
|
|
267
271
|
}
|
|
268
272
|
async function setModelIfNeeded(pi, ctx, modelRef) {
|
|
269
273
|
if (!modelRef)
|
|
270
|
-
return;
|
|
274
|
+
return false;
|
|
271
275
|
const currentModel = parseQualifiedModelRef(ctx?.model ? `${ctx.model.provider}/${ctx.model.id}` : undefined);
|
|
272
276
|
if (sameModel(currentModel, modelRef))
|
|
273
|
-
return;
|
|
277
|
+
return true;
|
|
274
278
|
const model = resolveModelFromContext(ctx, modelRef);
|
|
275
279
|
if (!model)
|
|
276
|
-
return;
|
|
280
|
+
return false;
|
|
277
281
|
await pi.setModel(model, { persist: false });
|
|
282
|
+
return true;
|
|
278
283
|
}
|
|
279
284
|
function buildExecutionKickoffMessage(options) {
|
|
280
285
|
const { permissionMode, executeWithSubagent = false } = options;
|
|
@@ -531,8 +536,7 @@ export default function planCommand(pi) {
|
|
|
531
536
|
if (!reasoningModelSwitchDone && readAutoSwitchPlanModelSetting()) {
|
|
532
537
|
const reasoningModel = parseQualifiedModelRef(readPlanModeReasoningModel());
|
|
533
538
|
if (reasoningModel) {
|
|
534
|
-
reasoningModelSwitchDone =
|
|
535
|
-
await setModelIfNeeded(pi, ctx, reasoningModel);
|
|
539
|
+
reasoningModelSwitchDone = await setModelIfNeeded(pi, ctx, reasoningModel);
|
|
536
540
|
}
|
|
537
541
|
}
|
|
538
542
|
return { systemPrompt: buildPlanModeSystemPrompt() };
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import * as fs from "node:fs";
|
|
5
5
|
import * as path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
6
7
|
import { getAgentDir, parseFrontmatter } from "@gsd/pi-coding-agent";
|
|
7
8
|
const PROJECT_AGENT_DIR_CANDIDATES = [".lsd", ".gsd", ".pi"];
|
|
8
9
|
function normalizeAgentModel(model) {
|
|
@@ -50,7 +51,8 @@ function loadAgentsFromDir(dir, source) {
|
|
|
50
51
|
const tools = frontmatter.tools
|
|
51
52
|
?.split(",")
|
|
52
53
|
.map((t) => t.trim())
|
|
53
|
-
.filter(Boolean)
|
|
54
|
+
.filter(Boolean)
|
|
55
|
+
.filter((tool, index, all) => all.indexOf(tool) === index);
|
|
54
56
|
agents.push({
|
|
55
57
|
name: frontmatter.name,
|
|
56
58
|
description: frontmatter.description,
|
|
@@ -87,25 +89,33 @@ function findNearestProjectAgentsDir(cwd) {
|
|
|
87
89
|
currentDir = parentDir;
|
|
88
90
|
}
|
|
89
91
|
}
|
|
92
|
+
function getBundledAgentsDir() {
|
|
93
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
94
|
+
return path.resolve(here, "../../agents");
|
|
95
|
+
}
|
|
90
96
|
export function discoverAgents(cwd, scope) {
|
|
91
97
|
const userDir = path.join(getAgentDir(), "agents");
|
|
98
|
+
const bundledDir = getBundledAgentsDir();
|
|
92
99
|
const projectAgentsDir = findNearestProjectAgentsDir(cwd);
|
|
100
|
+
const bundledAgents = scope === "project" ? [] : loadAgentsFromDir(bundledDir, "bundled");
|
|
93
101
|
const userAgents = scope === "project" ? [] : loadAgentsFromDir(userDir, "user");
|
|
94
102
|
const projectAgents = scope === "user" || !projectAgentsDir ? [] : loadAgentsFromDir(projectAgentsDir, "project");
|
|
95
103
|
const agentMap = new Map();
|
|
96
|
-
|
|
97
|
-
for (const agent of
|
|
98
|
-
agentMap.set(agent.name, agent);
|
|
99
|
-
for (const agent of projectAgents)
|
|
104
|
+
const addAgents = (items) => {
|
|
105
|
+
for (const agent of items)
|
|
100
106
|
agentMap.set(agent.name, agent);
|
|
107
|
+
};
|
|
108
|
+
if (scope === "both") {
|
|
109
|
+
addAgents(bundledAgents);
|
|
110
|
+
addAgents(userAgents);
|
|
111
|
+
addAgents(projectAgents);
|
|
101
112
|
}
|
|
102
113
|
else if (scope === "user") {
|
|
103
|
-
|
|
104
|
-
|
|
114
|
+
addAgents(bundledAgents);
|
|
115
|
+
addAgents(userAgents);
|
|
105
116
|
}
|
|
106
117
|
else {
|
|
107
|
-
|
|
108
|
-
agentMap.set(agent.name, agent);
|
|
118
|
+
addAgents(projectAgents);
|
|
109
119
|
}
|
|
110
120
|
return { agents: Array.from(agentMap.values()), projectAgentsDir };
|
|
111
121
|
}
|
|
@@ -18,9 +18,9 @@ import * as os from "node:os";
|
|
|
18
18
|
import * as path from "node:path";
|
|
19
19
|
import { StringEnum } from "@gsd/pi-ai";
|
|
20
20
|
import { getAgentDir, getMarkdownTheme, } from "@gsd/pi-coding-agent";
|
|
21
|
-
import { Container, Markdown, Spacer, Text } from "@gsd/pi-tui";
|
|
21
|
+
import { Container, Key, Markdown, Spacer, Text } from "@gsd/pi-tui";
|
|
22
22
|
import { Type } from "@sinclair/typebox";
|
|
23
|
-
import { formatTokenCount } from "../shared/mod.js";
|
|
23
|
+
import { formatTokenCount, shortcutDesc } from "../shared/mod.js";
|
|
24
24
|
import { discoverAgents } from "./agents.js";
|
|
25
25
|
import { buildSubagentProcessArgs, getBundledExtensionPathsFromEnv } from "./launch-helpers.js";
|
|
26
26
|
import { createIsolation, mergeDeltaPatches, readIsolationMode, } from "./isolation.js";
|
|
@@ -394,7 +394,7 @@ async function waitForFile(filePath, signal, timeoutMs = 30 * 60 * 1000) {
|
|
|
394
394
|
}
|
|
395
395
|
return false;
|
|
396
396
|
}
|
|
397
|
-
async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, modelOverride, parentModel, signal, onUpdate, makeDetails) {
|
|
397
|
+
async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, modelOverride, parentModel, signal, onUpdate, makeDetails, foregroundHooks) {
|
|
398
398
|
const agent = agents.find((a) => a.name === agentName);
|
|
399
399
|
if (!agent) {
|
|
400
400
|
const available = agents.map((a) => `"${a.name}"`).join(", ") || "none";
|
|
@@ -434,6 +434,28 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
|
|
|
434
434
|
});
|
|
435
435
|
}
|
|
436
436
|
};
|
|
437
|
+
let wasAborted = false;
|
|
438
|
+
let deferTempPromptCleanup = false;
|
|
439
|
+
let tempPromptCleanupDone = false;
|
|
440
|
+
const cleanupTempPromptFiles = () => {
|
|
441
|
+
if (tempPromptCleanupDone)
|
|
442
|
+
return;
|
|
443
|
+
tempPromptCleanupDone = true;
|
|
444
|
+
if (tmpPromptPath)
|
|
445
|
+
try {
|
|
446
|
+
fs.unlinkSync(tmpPromptPath);
|
|
447
|
+
}
|
|
448
|
+
catch {
|
|
449
|
+
/* ignore */
|
|
450
|
+
}
|
|
451
|
+
if (tmpPromptDir)
|
|
452
|
+
try {
|
|
453
|
+
fs.rmdirSync(tmpPromptDir);
|
|
454
|
+
}
|
|
455
|
+
catch {
|
|
456
|
+
/* ignore */
|
|
457
|
+
}
|
|
458
|
+
};
|
|
437
459
|
try {
|
|
438
460
|
if (agent.systemPrompt.trim()) {
|
|
439
461
|
const tmp = writePromptToTempFile(agent.name, agent.systemPrompt);
|
|
@@ -441,7 +463,6 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
|
|
|
441
463
|
tmpPromptPath = tmp.filePath;
|
|
442
464
|
}
|
|
443
465
|
const args = buildSubagentProcessArgs(agent, task, tmpPromptPath, inferredModel);
|
|
444
|
-
let wasAborted = false;
|
|
445
466
|
const exitCode = await new Promise((resolve) => {
|
|
446
467
|
const bundledPaths = getBundledExtensionPathsFromEnv();
|
|
447
468
|
const extensionArgs = bundledPaths.flatMap((p) => ["--extension", p]);
|
|
@@ -459,6 +480,7 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
|
|
|
459
480
|
let buffer = "";
|
|
460
481
|
let completionSeen = false;
|
|
461
482
|
let resolved = false;
|
|
483
|
+
let foregroundReleased = false;
|
|
462
484
|
const procAbortController = new AbortController();
|
|
463
485
|
let resolveBackgroundResult;
|
|
464
486
|
let rejectBackgroundResult;
|
|
@@ -472,6 +494,27 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
|
|
|
472
494
|
resolved = true;
|
|
473
495
|
resolve(code);
|
|
474
496
|
};
|
|
497
|
+
const adoptToBackground = (jobId) => {
|
|
498
|
+
if (resolved || foregroundReleased)
|
|
499
|
+
return false;
|
|
500
|
+
foregroundReleased = true;
|
|
501
|
+
deferTempPromptCleanup = true;
|
|
502
|
+
currentResult.backgroundJobId = jobId;
|
|
503
|
+
finishForeground(0);
|
|
504
|
+
return true;
|
|
505
|
+
};
|
|
506
|
+
backgroundResultPromise.finally(() => {
|
|
507
|
+
if (deferTempPromptCleanup)
|
|
508
|
+
cleanupTempPromptFiles();
|
|
509
|
+
});
|
|
510
|
+
foregroundHooks?.onStart?.({
|
|
511
|
+
agentName,
|
|
512
|
+
task,
|
|
513
|
+
cwd: cwd ?? defaultCwd,
|
|
514
|
+
abortController: procAbortController,
|
|
515
|
+
resultPromise: backgroundResultPromise,
|
|
516
|
+
adoptToBackground,
|
|
517
|
+
});
|
|
475
518
|
proc.stdout.on("data", (data) => {
|
|
476
519
|
buffer += data.toString();
|
|
477
520
|
const lines = buffer.split("\n");
|
|
@@ -505,11 +548,13 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
|
|
|
505
548
|
exitCode: finalExitCode,
|
|
506
549
|
model: currentResult.model,
|
|
507
550
|
});
|
|
551
|
+
foregroundHooks?.onFinish?.();
|
|
508
552
|
finishForeground(finalExitCode);
|
|
509
553
|
});
|
|
510
554
|
proc.on("error", (error) => {
|
|
511
555
|
liveSubagentProcesses.delete(proc);
|
|
512
556
|
rejectBackgroundResult?.(error);
|
|
557
|
+
foregroundHooks?.onFinish?.();
|
|
513
558
|
finishForeground(1);
|
|
514
559
|
});
|
|
515
560
|
const killProc = () => {
|
|
@@ -546,20 +591,8 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
|
|
|
546
591
|
return currentResult;
|
|
547
592
|
}
|
|
548
593
|
finally {
|
|
549
|
-
if (
|
|
550
|
-
|
|
551
|
-
fs.unlinkSync(tmpPromptPath);
|
|
552
|
-
}
|
|
553
|
-
catch {
|
|
554
|
-
/* ignore */
|
|
555
|
-
}
|
|
556
|
-
if (tmpPromptDir)
|
|
557
|
-
try {
|
|
558
|
-
fs.rmdirSync(tmpPromptDir);
|
|
559
|
-
}
|
|
560
|
-
catch {
|
|
561
|
-
/* ignore */
|
|
562
|
-
}
|
|
594
|
+
if (!deferTempPromptCleanup)
|
|
595
|
+
cleanupTempPromptFiles();
|
|
563
596
|
}
|
|
564
597
|
}
|
|
565
598
|
const TaskItem = Type.Object({
|
|
@@ -610,6 +643,9 @@ const SubagentParams = Type.Object({
|
|
|
610
643
|
});
|
|
611
644
|
export default function (pi) {
|
|
612
645
|
let bgManager = null;
|
|
646
|
+
const foregroundSubagentStatusKey = "foreground-subagent";
|
|
647
|
+
const foregroundSubagentHint = "Ctrl+B: move foreground subagent to background";
|
|
648
|
+
let activeForegroundSubagent = null;
|
|
613
649
|
function getBgManager() {
|
|
614
650
|
if (!bgManager)
|
|
615
651
|
throw new Error("BackgroundJobManager not initialized.");
|
|
@@ -642,6 +678,7 @@ export default function (pi) {
|
|
|
642
678
|
});
|
|
643
679
|
});
|
|
644
680
|
pi.on("session_before_switch", async () => {
|
|
681
|
+
activeForegroundSubagent = null;
|
|
645
682
|
if (bgManager) {
|
|
646
683
|
for (const job of bgManager.getRunningJobs()) {
|
|
647
684
|
bgManager.cancel(job.id);
|
|
@@ -649,6 +686,7 @@ export default function (pi) {
|
|
|
649
686
|
}
|
|
650
687
|
});
|
|
651
688
|
pi.on("session_shutdown", async () => {
|
|
689
|
+
activeForegroundSubagent = null;
|
|
652
690
|
await stopLiveSubagents();
|
|
653
691
|
if (bgManager) {
|
|
654
692
|
bgManager.shutdown();
|
|
@@ -757,6 +795,38 @@ export default function (pi) {
|
|
|
757
795
|
ctx.ui.notify(`Available agents (${discovery.agents.length}):\n${lines.join("\n")}`, "info");
|
|
758
796
|
},
|
|
759
797
|
});
|
|
798
|
+
pi.registerShortcut(Key.ctrl("b"), {
|
|
799
|
+
description: shortcutDesc("Move foreground subagent to background", "/subagents list"),
|
|
800
|
+
handler: async (ctx) => {
|
|
801
|
+
const running = activeForegroundSubagent;
|
|
802
|
+
if (!running || running.claimed)
|
|
803
|
+
return;
|
|
804
|
+
const manager = bgManager;
|
|
805
|
+
if (!manager) {
|
|
806
|
+
ctx.ui.notify("Background subagent manager is not available.", "error");
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
running.claimed = true;
|
|
810
|
+
let jobId;
|
|
811
|
+
try {
|
|
812
|
+
jobId = manager.adoptRunning(running.agentName, running.task, running.cwd, running.abortController, running.resultPromise);
|
|
813
|
+
}
|
|
814
|
+
catch (error) {
|
|
815
|
+
running.claimed = false;
|
|
816
|
+
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
const released = running.adoptToBackground(jobId);
|
|
820
|
+
if (!released) {
|
|
821
|
+
running.claimed = false;
|
|
822
|
+
manager.cancel(jobId);
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
activeForegroundSubagent = null;
|
|
826
|
+
ctx.ui.setStatus(foregroundSubagentStatusKey, undefined);
|
|
827
|
+
ctx.ui.notify(`Moved ${running.agentName} to background as ${jobId}. Use /subagents wait ${jobId}, /subagents output ${jobId}, or /subagents cancel ${jobId}.`, "info");
|
|
828
|
+
},
|
|
829
|
+
});
|
|
760
830
|
pi.registerTool({
|
|
761
831
|
name: "await_subagent",
|
|
762
832
|
label: "Await Background Subagent",
|
|
@@ -785,13 +855,15 @@ export default function (pi) {
|
|
|
785
855
|
"Model selection can be overridden per call, otherwise it is inferred from the agent config, delegated-task preferences, or the current session model.",
|
|
786
856
|
"Modes: single ({ agent, task }), parallel ({ tasks: [{agent, task},...] }), chain ({ chain: [{agent, task},...] } with {previous} placeholder).",
|
|
787
857
|
"Agents are defined as .md files in the configured user agent directory (for LSD this is typically ~/.lsd/agent/agents/) or project-local .lsd/agents/, with legacy support for .gsd/agents/ and .pi/agents/.",
|
|
858
|
+
"If the user asks for a named subagent such as scout, worker, reviewer, or planner, invoke this tool directly rather than the Skill tool.",
|
|
788
859
|
"Use the /subagent command to list available agents and their descriptions.",
|
|
789
860
|
"Set background: true (single mode only) to run detached — returns immediately with a sa_xxxx job ID. Completion is announced back into the session. Use await_subagent or /subagents to manage background jobs.",
|
|
790
861
|
].join(" "),
|
|
791
862
|
promptGuidelines: [
|
|
792
863
|
"Use subagent to delegate self-contained tasks that benefit from an isolated context window.",
|
|
793
|
-
"
|
|
864
|
+
"The subagent tool is available directly as a tool call — invoke it programmatically like any other tool, not via a slash command. Do NOT type '/scout' or '/subagent' in the chat; call this tool with the correct parameters instead.",
|
|
794
865
|
"Valid call shapes: single mode uses { agent, task }, parallel mode uses { tasks: [{ agent, task }, ...] }, and chain mode uses { chain: [{ agent, task }, ...] }.",
|
|
866
|
+
"If the user names a subagent such as scout, worker, reviewer, or planner, use this subagent tool directly rather than the Skill tool or ad-hoc search.",
|
|
795
867
|
"Recon planning rule: use no scout for narrow known-file work, one scout for one broad unfamiliar subsystem, and parallel scouts only when the work spans multiple loosely-coupled subsystems.",
|
|
796
868
|
"Use scout only for broad or unfamiliar codebase reconnaissance before you read many files yourself; save direct reads for targeted lookups once the relevant files are known.",
|
|
797
869
|
"Do not use scout as the reviewer, auditor, or final judge. Scout should map architecture, files, ownership, and likely hotspots for another agent or the parent model to evaluate.",
|
|
@@ -1045,7 +1117,24 @@ export default function (pi) {
|
|
|
1045
1117
|
const taskId = crypto.randomUUID();
|
|
1046
1118
|
isolation = await createIsolation(effectiveCwd, taskId, isolationMode);
|
|
1047
1119
|
}
|
|
1048
|
-
const result = await runSingleAgent(ctx.cwd, agents, params.agent, params.task, isolation ? isolation.workDir : params.cwd, undefined, params.model, ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined, signal, onUpdate, makeDetails("single")
|
|
1120
|
+
const result = await runSingleAgent(ctx.cwd, agents, params.agent, params.task, isolation ? isolation.workDir : params.cwd, undefined, params.model, ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined, signal, onUpdate, makeDetails("single"), !isolation
|
|
1121
|
+
? {
|
|
1122
|
+
onStart: (control) => {
|
|
1123
|
+
activeForegroundSubagent = { ...control, claimed: false };
|
|
1124
|
+
ctx.ui.setStatus(foregroundSubagentStatusKey, foregroundSubagentHint);
|
|
1125
|
+
},
|
|
1126
|
+
onFinish: () => {
|
|
1127
|
+
activeForegroundSubagent = null;
|
|
1128
|
+
ctx.ui.setStatus(foregroundSubagentStatusKey, undefined);
|
|
1129
|
+
},
|
|
1130
|
+
}
|
|
1131
|
+
: undefined);
|
|
1132
|
+
if (result.backgroundJobId) {
|
|
1133
|
+
return {
|
|
1134
|
+
content: [{ type: "text", text: `Moved ${result.agent} to background as **${result.backgroundJobId}**. Use \`await_subagent\`, \`/subagents wait ${result.backgroundJobId}\`, or \`/subagents output ${result.backgroundJobId}\`.` }],
|
|
1135
|
+
details: makeDetails("single")([result]),
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1049
1138
|
// Capture and merge delta if isolated
|
|
1050
1139
|
if (isolation) {
|
|
1051
1140
|
const patches = await isolation.captureDelta();
|
|
@@ -1197,6 +1286,9 @@ export default function (pi) {
|
|
|
1197
1286
|
if (displayItems.length > COLLAPSED_ITEM_COUNT)
|
|
1198
1287
|
text += `\n${theme.fg("muted", "(Ctrl+O to expand)")}`;
|
|
1199
1288
|
}
|
|
1289
|
+
if (!isError && !r.backgroundJobId && !finalOutput) {
|
|
1290
|
+
text += `\n${theme.fg("muted", "Hint: Ctrl+B to move running foreground subagent to background")}`;
|
|
1291
|
+
}
|
|
1200
1292
|
const usageStr = formatUsageStats(r.usage, r.model);
|
|
1201
1293
|
if (usageStr)
|
|
1202
1294
|
text += `\n${theme.fg("dim", usageStr)}`;
|
|
@@ -15,8 +15,9 @@ export function buildSubagentProcessArgs(agent, task, tmpPromptPath, model) {
|
|
|
15
15
|
const args = ["--mode", "json", "-p", "--no-session"];
|
|
16
16
|
if (model)
|
|
17
17
|
args.push("--model", model);
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
const uniqueTools = agent.tools?.filter((tool, index, all) => all.indexOf(tool) === index);
|
|
19
|
+
if (uniqueTools && uniqueTools.length > 0)
|
|
20
|
+
args.push("--tools", uniqueTools.join(","));
|
|
20
21
|
if (tmpPromptPath)
|
|
21
22
|
args.push("--append-system-prompt", tmpPromptPath);
|
|
22
23
|
args.push(`Task: ${task}`);
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic-shared.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic-shared.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"anthropic-shared.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic-shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -323,7 +323,17 @@ export function convertMessages(messages, model, isOAuthToken, cacheControl) {
|
|
|
323
323
|
export function convertTools(tools, isOAuthToken) {
|
|
324
324
|
if (!tools)
|
|
325
325
|
return [];
|
|
326
|
-
|
|
326
|
+
const uniqueTools = [];
|
|
327
|
+
const seenToolNames = new Set();
|
|
328
|
+
for (const tool of tools) {
|
|
329
|
+
const mappedName = isOAuthToken ? toClaudeCodeName(tool.name) : tool.name;
|
|
330
|
+
if (seenToolNames.has(mappedName)) {
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
seenToolNames.add(mappedName);
|
|
334
|
+
uniqueTools.push(tool);
|
|
335
|
+
}
|
|
336
|
+
return uniqueTools.map((tool) => {
|
|
327
337
|
const jsonSchema = tool.parameters;
|
|
328
338
|
return {
|
|
329
339
|
name: isOAuthToken ? toClaudeCodeName(tool.name) : tool.name,
|