jinzd-ai-cli 0.4.213 → 0.4.214
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/README.md +5 -2
- package/README.zh-CN.md +5 -2
- package/dist/{batch-PKY63TME.js → batch-NPUUDETK.js} +2 -2
- package/dist/{chunk-FGUKBIYO.js → chunk-5FG7PSVM.js} +2 -2
- package/dist/{chunk-IWLVH32D.js → chunk-DBYMX2ZC.js} +1 -1
- package/dist/{chunk-J35V3IAH.js → chunk-JOJA35RK.js} +1 -1
- package/dist/{chunk-G3PW3AOB.js → chunk-JQC7IATA.js} +1 -1
- package/dist/{chunk-THNECAAY.js → chunk-R5CJD2AB.js} +380 -74
- package/dist/{chunk-UDMU4FUF.js → chunk-TR6MSPSS.js} +1 -1
- package/dist/{chunk-MRGWPCFQ.js → chunk-YFHF3PVB.js} +1 -1
- package/dist/{chunk-7NTFMLJJ.js → chunk-YMFGGCUP.js} +1 -1
- package/dist/{ci-HBZ6CIW5.js → ci-3TU7WCY4.js} +2 -2
- package/dist/{constants-CAUBTSFW.js → constants-BKR7T3QH.js} +1 -1
- package/dist/{doctor-cli-5Z5UWYW6.js → doctor-cli-TGVSWKDB.js} +4 -4
- package/dist/electron-server.js +558 -184
- package/dist/{hub-ZRADBR76.js → hub-GURYEW6F.js} +1 -1
- package/dist/index.js +17 -16
- package/dist/{run-tests-DSOJBJWA.js → run-tests-F44JA2YW.js} +2 -2
- package/dist/{run-tests-7J3PNWVS.js → run-tests-R6FL6CQ3.js} +1 -1
- package/dist/{server-U4I7RI42.js → server-FXWCSCDZ.js} +88 -8
- package/dist/{server-PWBWHVYB.js → server-GQXC46R5.js} +4 -4
- package/dist/{task-orchestrator-RUXWRMQV.js → task-orchestrator-6AZD5WSR.js} +4 -4
- package/dist/{usage-2P6TIBTN.js → usage-W7J2QA3G.js} +2 -2
- package/dist/web/client/app.js +4 -1
- package/package.json +1 -1
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
} from "./chunk-T2NL5ZIA.js";
|
|
6
6
|
import {
|
|
7
7
|
runTestsTool
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-TR6MSPSS.js";
|
|
9
9
|
import {
|
|
10
10
|
runTool
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-YMFGGCUP.js";
|
|
12
12
|
import {
|
|
13
13
|
getDangerLevel,
|
|
14
14
|
isFileWriteTool,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
SUBAGENT_ALLOWED_TOOLS,
|
|
27
27
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
28
28
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-DBYMX2ZC.js";
|
|
30
30
|
import {
|
|
31
31
|
fileCheckpoints
|
|
32
32
|
} from "./chunk-4BKXL7SM.js";
|
|
@@ -4896,6 +4896,218 @@ function formatResults2(query, data, _requested) {
|
|
|
4896
4896
|
return header + "\n" + results.join("\n\n");
|
|
4897
4897
|
}
|
|
4898
4898
|
|
|
4899
|
+
// src/agents/agent-config.ts
|
|
4900
|
+
import { existsSync as existsSync12, readdirSync as readdirSync6, readFileSync as readFileSync9 } from "fs";
|
|
4901
|
+
import { join as join7 } from "path";
|
|
4902
|
+
import { homedir as homedir4 } from "os";
|
|
4903
|
+
var READ_ONLY_TOOLS2 = /* @__PURE__ */ new Set([
|
|
4904
|
+
"read_file",
|
|
4905
|
+
"list_dir",
|
|
4906
|
+
"grep_files",
|
|
4907
|
+
"glob_files",
|
|
4908
|
+
"web_fetch",
|
|
4909
|
+
"google_search",
|
|
4910
|
+
"write_todos",
|
|
4911
|
+
"find_symbol",
|
|
4912
|
+
"get_outline",
|
|
4913
|
+
"find_references",
|
|
4914
|
+
"search_code"
|
|
4915
|
+
]);
|
|
4916
|
+
var BUILTIN_AGENTS = [
|
|
4917
|
+
{
|
|
4918
|
+
name: "explorer",
|
|
4919
|
+
description: "Read-only code exploration and evidence gathering.",
|
|
4920
|
+
permissionProfile: "read-only",
|
|
4921
|
+
allowedTools: [...READ_ONLY_TOOLS2],
|
|
4922
|
+
maxToolRounds: 10,
|
|
4923
|
+
contextPolicy: "task-only",
|
|
4924
|
+
system: "Act as a read-only explorer. Inspect code, collect evidence, and do not modify files.",
|
|
4925
|
+
source: "builtin"
|
|
4926
|
+
},
|
|
4927
|
+
{
|
|
4928
|
+
name: "worker",
|
|
4929
|
+
description: "Implementation and focused fixes within sub-agent safety limits.",
|
|
4930
|
+
permissionProfile: "workspace-write",
|
|
4931
|
+
maxToolRounds: 15,
|
|
4932
|
+
contextPolicy: "task-only",
|
|
4933
|
+
system: "Act as a focused implementation worker. Keep edits scoped and report changed files.",
|
|
4934
|
+
source: "builtin"
|
|
4935
|
+
},
|
|
4936
|
+
{
|
|
4937
|
+
name: "reviewer",
|
|
4938
|
+
description: "Code review focused on bugs, regressions, and missing tests.",
|
|
4939
|
+
permissionProfile: "read-only",
|
|
4940
|
+
allowedTools: [...READ_ONLY_TOOLS2],
|
|
4941
|
+
maxToolRounds: 12,
|
|
4942
|
+
contextPolicy: "task-only",
|
|
4943
|
+
system: "Act as a code reviewer. Lead with concrete findings, file evidence, and residual risks.",
|
|
4944
|
+
source: "builtin"
|
|
4945
|
+
},
|
|
4946
|
+
{
|
|
4947
|
+
name: "security",
|
|
4948
|
+
description: "Security audit with read-only evidence collection.",
|
|
4949
|
+
permissionProfile: "read-only",
|
|
4950
|
+
allowedTools: [...READ_ONLY_TOOLS2],
|
|
4951
|
+
maxToolRounds: 12,
|
|
4952
|
+
contextPolicy: "task-only",
|
|
4953
|
+
system: "Act as a security reviewer. Look for trust-boundary, injection, filesystem, network, and secret-handling issues.",
|
|
4954
|
+
source: "builtin"
|
|
4955
|
+
},
|
|
4956
|
+
{
|
|
4957
|
+
name: "tester",
|
|
4958
|
+
description: "Test planning and regression analysis without direct shell execution.",
|
|
4959
|
+
permissionProfile: "read-only",
|
|
4960
|
+
allowedTools: [...READ_ONLY_TOOLS2],
|
|
4961
|
+
maxToolRounds: 12,
|
|
4962
|
+
contextPolicy: "task-only",
|
|
4963
|
+
system: "Act as a tester. Inspect tests, identify coverage gaps, and propose precise regression checks.",
|
|
4964
|
+
source: "builtin"
|
|
4965
|
+
}
|
|
4966
|
+
];
|
|
4967
|
+
function normalizeName(name) {
|
|
4968
|
+
return name.trim().toLowerCase();
|
|
4969
|
+
}
|
|
4970
|
+
function isStringArray(value) {
|
|
4971
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
4972
|
+
}
|
|
4973
|
+
function parseAgentConfig(raw, source, path3) {
|
|
4974
|
+
if (!raw || typeof raw !== "object") return null;
|
|
4975
|
+
const obj = raw;
|
|
4976
|
+
if (typeof obj.name !== "string" || obj.name.trim() === "") return null;
|
|
4977
|
+
const cfg = {
|
|
4978
|
+
name: obj.name.trim(),
|
|
4979
|
+
source,
|
|
4980
|
+
path: path3
|
|
4981
|
+
};
|
|
4982
|
+
if (typeof obj.description === "string") cfg.description = obj.description;
|
|
4983
|
+
if (typeof obj.provider === "string") cfg.provider = obj.provider;
|
|
4984
|
+
if (typeof obj.model === "string") cfg.model = obj.model;
|
|
4985
|
+
if (typeof obj.system === "string") cfg.system = obj.system;
|
|
4986
|
+
if (typeof obj.instructions === "string") cfg.instructions = obj.instructions;
|
|
4987
|
+
if (typeof obj.systemInstructions === "string") cfg.systemInstructions = obj.systemInstructions;
|
|
4988
|
+
if (isStringArray(obj.allowedTools)) cfg.allowedTools = obj.allowedTools;
|
|
4989
|
+
if (isStringArray(obj.blockedTools)) cfg.blockedTools = obj.blockedTools;
|
|
4990
|
+
if (typeof obj.permissionProfile === "string") cfg.permissionProfile = obj.permissionProfile;
|
|
4991
|
+
if (typeof obj.maxToolRounds === "number" && Number.isFinite(obj.maxToolRounds)) cfg.maxToolRounds = obj.maxToolRounds;
|
|
4992
|
+
if (typeof obj.contextPolicy === "string") cfg.contextPolicy = obj.contextPolicy;
|
|
4993
|
+
return cfg;
|
|
4994
|
+
}
|
|
4995
|
+
function loadAgentDir(dir, source) {
|
|
4996
|
+
if (!existsSync12(dir)) return [];
|
|
4997
|
+
const out = [];
|
|
4998
|
+
for (const file of readdirSync6(dir)) {
|
|
4999
|
+
if (!file.endsWith(".json")) continue;
|
|
5000
|
+
const path3 = join7(dir, file);
|
|
5001
|
+
try {
|
|
5002
|
+
const parsed = JSON.parse(readFileSync9(path3, "utf-8"));
|
|
5003
|
+
const cfg = parseAgentConfig(parsed, source, path3);
|
|
5004
|
+
if (cfg) out.push(cfg);
|
|
5005
|
+
} catch {
|
|
5006
|
+
}
|
|
5007
|
+
}
|
|
5008
|
+
return out;
|
|
5009
|
+
}
|
|
5010
|
+
function getAgentDirs(configDir, cwd = process.cwd()) {
|
|
5011
|
+
return {
|
|
5012
|
+
user: join7(configDir ?? join7(homedir4(), CONFIG_DIR_NAME), "agents"),
|
|
5013
|
+
project: join7(cwd, CONFIG_DIR_NAME, "agents")
|
|
5014
|
+
};
|
|
5015
|
+
}
|
|
5016
|
+
function listAgentConfigs(configDir, cwd = process.cwd()) {
|
|
5017
|
+
const dirs = getAgentDirs(configDir, cwd);
|
|
5018
|
+
const byName = /* @__PURE__ */ new Map();
|
|
5019
|
+
for (const cfg of BUILTIN_AGENTS) byName.set(normalizeName(cfg.name), { ...cfg });
|
|
5020
|
+
for (const cfg of loadAgentDir(dirs.user, "user")) byName.set(normalizeName(cfg.name), cfg);
|
|
5021
|
+
for (const cfg of loadAgentDir(dirs.project, "project")) byName.set(normalizeName(cfg.name), cfg);
|
|
5022
|
+
return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
5023
|
+
}
|
|
5024
|
+
function resolveAgentConfig(name, configDir, cwd = process.cwd()) {
|
|
5025
|
+
const target = normalizeName(name);
|
|
5026
|
+
return listAgentConfigs(configDir, cwd).find((cfg) => normalizeName(cfg.name) === target);
|
|
5027
|
+
}
|
|
5028
|
+
function getAgentInstructions(agent) {
|
|
5029
|
+
return agent.system ?? agent.systemInstructions ?? agent.instructions;
|
|
5030
|
+
}
|
|
5031
|
+
function getEffectiveAgentTools(agent) {
|
|
5032
|
+
let allowed = new Set(SUBAGENT_ALLOWED_TOOLS);
|
|
5033
|
+
if (agent.permissionProfile === "read-only") {
|
|
5034
|
+
allowed = new Set([...allowed].filter((name) => READ_ONLY_TOOLS2.has(name)));
|
|
5035
|
+
}
|
|
5036
|
+
if (agent.allowedTools && agent.allowedTools.length > 0) {
|
|
5037
|
+
const requested = new Set(agent.allowedTools);
|
|
5038
|
+
allowed = new Set([...allowed].filter((name) => requested.has(name)));
|
|
5039
|
+
}
|
|
5040
|
+
if (agent.blockedTools && agent.blockedTools.length > 0) {
|
|
5041
|
+
for (const name of agent.blockedTools) allowed.delete(name);
|
|
5042
|
+
}
|
|
5043
|
+
return allowed;
|
|
5044
|
+
}
|
|
5045
|
+
function getEffectiveMaxRounds(requestedMaxRounds, agent) {
|
|
5046
|
+
const agentMax = agent.maxToolRounds && agent.maxToolRounds > 0 ? Math.round(agent.maxToolRounds) : SUBAGENT_MAX_ROUNDS_LIMIT;
|
|
5047
|
+
return Math.min(requestedMaxRounds, agentMax, SUBAGENT_MAX_ROUNDS_LIMIT);
|
|
5048
|
+
}
|
|
5049
|
+
|
|
5050
|
+
// src/agents/agent-runtime.ts
|
|
5051
|
+
var nextId = 1;
|
|
5052
|
+
var preferredAgentName = "worker";
|
|
5053
|
+
var runs = [];
|
|
5054
|
+
var MAX_RUNS = 50;
|
|
5055
|
+
function nowIso() {
|
|
5056
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
5057
|
+
}
|
|
5058
|
+
function startAgentRun(input) {
|
|
5059
|
+
const run = {
|
|
5060
|
+
id: `agent-${nextId++}`,
|
|
5061
|
+
agentName: input.agentName,
|
|
5062
|
+
task: input.task,
|
|
5063
|
+
status: "running",
|
|
5064
|
+
startedAt: nowIso(),
|
|
5065
|
+
toolNames: [],
|
|
5066
|
+
agentIndex: input.agentIndex,
|
|
5067
|
+
stopRequested: false
|
|
5068
|
+
};
|
|
5069
|
+
runs.unshift(run);
|
|
5070
|
+
if (runs.length > MAX_RUNS) runs.splice(MAX_RUNS);
|
|
5071
|
+
return run;
|
|
5072
|
+
}
|
|
5073
|
+
function recordAgentTool(runId, toolName) {
|
|
5074
|
+
const run = runs.find((r) => r.id === runId);
|
|
5075
|
+
if (!run) return;
|
|
5076
|
+
if (!run.toolNames.includes(toolName)) run.toolNames.push(toolName);
|
|
5077
|
+
}
|
|
5078
|
+
function finishAgentRun(runId, status, summary, error) {
|
|
5079
|
+
const run = runs.find((r) => r.id === runId);
|
|
5080
|
+
if (!run) return;
|
|
5081
|
+
run.status = status;
|
|
5082
|
+
run.finishedAt = nowIso();
|
|
5083
|
+
if (summary) run.summary = summary;
|
|
5084
|
+
if (error) run.error = error;
|
|
5085
|
+
}
|
|
5086
|
+
function listAgentRuns() {
|
|
5087
|
+
return runs.map((run) => ({ ...run, toolNames: [...run.toolNames] }));
|
|
5088
|
+
}
|
|
5089
|
+
function requestAgentStop(idOrAll) {
|
|
5090
|
+
const target = idOrAll.trim().toLowerCase();
|
|
5091
|
+
let count = 0;
|
|
5092
|
+
for (const run of runs) {
|
|
5093
|
+
if (run.status !== "running") continue;
|
|
5094
|
+
if (target === "all" || run.id.toLowerCase() === target) {
|
|
5095
|
+
run.stopRequested = true;
|
|
5096
|
+
count++;
|
|
5097
|
+
}
|
|
5098
|
+
}
|
|
5099
|
+
return count;
|
|
5100
|
+
}
|
|
5101
|
+
function isAgentStopRequested(runId) {
|
|
5102
|
+
return runs.find((r) => r.id === runId)?.stopRequested ?? false;
|
|
5103
|
+
}
|
|
5104
|
+
function setPreferredAgentName(name) {
|
|
5105
|
+
preferredAgentName = name.trim() || "worker";
|
|
5106
|
+
}
|
|
5107
|
+
function getPreferredAgentName() {
|
|
5108
|
+
return preferredAgentName;
|
|
5109
|
+
}
|
|
5110
|
+
|
|
4899
5111
|
// src/tools/builtin/spawn-agent.ts
|
|
4900
5112
|
var spawnAgentContext = {
|
|
4901
5113
|
provider: null,
|
|
@@ -4910,18 +5122,27 @@ function agentPrefix(agentIndex) {
|
|
|
4910
5122
|
return theme.dim(` \u2503${agentIndex} `);
|
|
4911
5123
|
}
|
|
4912
5124
|
var SubAgentExecutor = class {
|
|
4913
|
-
constructor(registry, agentIndex = null) {
|
|
5125
|
+
constructor(registry, agentIndex = null, runId) {
|
|
4914
5126
|
this.registry = registry;
|
|
5127
|
+
this.runId = runId;
|
|
4915
5128
|
this.prefix = agentPrefix(agentIndex);
|
|
4916
5129
|
}
|
|
4917
5130
|
round = 0;
|
|
4918
5131
|
totalRounds = 0;
|
|
4919
5132
|
prefix = PREFIX;
|
|
5133
|
+
toolNames = [];
|
|
4920
5134
|
setRoundInfo(current, total) {
|
|
4921
5135
|
this.round = current;
|
|
4922
5136
|
this.totalRounds = total;
|
|
4923
5137
|
}
|
|
4924
5138
|
async execute(call) {
|
|
5139
|
+
if (this.runId && isAgentStopRequested(this.runId)) {
|
|
5140
|
+
return {
|
|
5141
|
+
callId: call.id,
|
|
5142
|
+
content: "Sub-agent stop requested.",
|
|
5143
|
+
isError: true
|
|
5144
|
+
};
|
|
5145
|
+
}
|
|
4925
5146
|
const tool = this.registry.get(call.name);
|
|
4926
5147
|
if (!tool) {
|
|
4927
5148
|
return {
|
|
@@ -4942,6 +5163,8 @@ var SubAgentExecutor = class {
|
|
|
4942
5163
|
};
|
|
4943
5164
|
}
|
|
4944
5165
|
this.printToolCall(call, dangerLevel);
|
|
5166
|
+
if (!this.toolNames.includes(call.name)) this.toolNames.push(call.name);
|
|
5167
|
+
if (this.runId) recordAgentTool(this.runId, call.name);
|
|
4945
5168
|
try {
|
|
4946
5169
|
const rawContent = await runTool(tool, call.arguments, call.name);
|
|
4947
5170
|
const content = truncateOutput(rawContent, call.name);
|
|
@@ -4961,7 +5184,6 @@ var SubAgentExecutor = class {
|
|
|
4961
5184
|
}
|
|
4962
5185
|
return results;
|
|
4963
5186
|
}
|
|
4964
|
-
// ── 带前缀的终端输出 ──
|
|
4965
5187
|
printPrefixed(text) {
|
|
4966
5188
|
for (const line of text.split("\n")) {
|
|
4967
5189
|
console.log(this.prefix + line);
|
|
@@ -5002,7 +5224,7 @@ var SubAgentExecutor = class {
|
|
|
5002
5224
|
}
|
|
5003
5225
|
}
|
|
5004
5226
|
};
|
|
5005
|
-
function buildSubAgentSystemPrompt(task, parentSystemPrompt) {
|
|
5227
|
+
function buildSubAgentSystemPrompt(task, agent, parentSystemPrompt) {
|
|
5006
5228
|
const parts = [];
|
|
5007
5229
|
if (parentSystemPrompt) {
|
|
5008
5230
|
parts.push(parentSystemPrompt);
|
|
@@ -5010,6 +5232,8 @@ function buildSubAgentSystemPrompt(task, parentSystemPrompt) {
|
|
|
5010
5232
|
parts.push(
|
|
5011
5233
|
`# Sub-Agent Mode
|
|
5012
5234
|
|
|
5235
|
+
**Agent Role**: ${agent.name}${agent.description ? ` \u2014 ${agent.description}` : ""}
|
|
5236
|
+
|
|
5013
5237
|
You are a focused sub-agent delegated by the main agent to complete a specific task.
|
|
5014
5238
|
|
|
5015
5239
|
**Your Task**:
|
|
@@ -5023,13 +5247,19 @@ ${task}
|
|
|
5023
5247
|
5. Destructive operations (rm -rf etc.) will be automatically blocked
|
|
5024
5248
|
6. Be efficient, minimize unnecessary tool call rounds`
|
|
5025
5249
|
);
|
|
5250
|
+
const agentInstructions = getAgentInstructions(agent);
|
|
5251
|
+
if (agentInstructions) {
|
|
5252
|
+
parts.push(`# Agent Instructions
|
|
5253
|
+
|
|
5254
|
+
${agentInstructions}`);
|
|
5255
|
+
}
|
|
5026
5256
|
return parts.join("\n\n---\n\n");
|
|
5027
5257
|
}
|
|
5028
|
-
function printSubAgentHeader(task, maxRounds, agentIndex = null) {
|
|
5258
|
+
function printSubAgentHeader(task, maxRounds, agentName, agentIndex = null) {
|
|
5029
5259
|
const prefix = agentPrefix(agentIndex);
|
|
5030
5260
|
console.log();
|
|
5031
5261
|
console.log(theme.dim(" \u250F\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
|
|
5032
|
-
const label = agentIndex !== null ? `\u{1F916} Sub-Agent #${agentIndex} Spawned` :
|
|
5262
|
+
const label = agentIndex !== null ? `\u{1F916} Sub-Agent #${agentIndex} Spawned (${agentName})` : `\u{1F916} Sub-Agent Spawned (${agentName})`;
|
|
5033
5263
|
console.log(prefix + theme.toolCall(label));
|
|
5034
5264
|
console.log(
|
|
5035
5265
|
prefix + theme.dim("Task: ") + (task.slice(0, 120) + (task.length > 120 ? "..." : ""))
|
|
@@ -5052,58 +5282,110 @@ function printSubAgentFooter(usage, agentIndex = null) {
|
|
|
5052
5282
|
console.log(theme.dim(" \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
|
|
5053
5283
|
console.log();
|
|
5054
5284
|
}
|
|
5055
|
-
|
|
5285
|
+
function summarizeContent(content) {
|
|
5286
|
+
const flat = content.replace(/\s+/g, " ").trim();
|
|
5287
|
+
return flat.length > 500 ? flat.slice(0, 497) + "..." : flat;
|
|
5288
|
+
}
|
|
5289
|
+
function extractEvidence(content, toolNames) {
|
|
5290
|
+
const evidence = /* @__PURE__ */ new Set();
|
|
5291
|
+
if (toolNames.length > 0) evidence.add(`Tools: ${toolNames.join(", ")}`);
|
|
5292
|
+
const matches = content.match(/(?:[\w.-]+[\\/])+[\w.-]+\.(?:ts|tsx|js|jsx|json|md|css|html|py|go|rs|yml|yaml)/g) ?? [];
|
|
5293
|
+
for (const match of matches.slice(0, 8)) evidence.add(match);
|
|
5294
|
+
return [...evidence].slice(0, 10);
|
|
5295
|
+
}
|
|
5296
|
+
function formatAgentResult(input) {
|
|
5297
|
+
const lines = [input.title, "", `**Agent**: ${input.agentName}`];
|
|
5298
|
+
if (input.task) lines.push(`**Task**: ${input.task}`);
|
|
5299
|
+
lines.push("", "### Summary", input.summary || "(no summary)", "", "### Key Evidence");
|
|
5300
|
+
if (input.evidence.length > 0) {
|
|
5301
|
+
for (const item of input.evidence) lines.push(`- ${item}`);
|
|
5302
|
+
} else {
|
|
5303
|
+
lines.push("- No structured evidence extracted.");
|
|
5304
|
+
}
|
|
5305
|
+
lines.push("", "### Tools Used");
|
|
5306
|
+
lines.push(input.toolNames.length > 0 ? input.toolNames.join(", ") : "No tools used.");
|
|
5307
|
+
lines.push("", "### Full Result", input.content, "");
|
|
5308
|
+
lines.push(`*Tokens: ${input.usage.inputTokens} in / ${input.usage.outputTokens} out*`);
|
|
5309
|
+
return lines;
|
|
5310
|
+
}
|
|
5311
|
+
async function runSubAgent(task, maxRounds, agentIndex, ctx, agent) {
|
|
5056
5312
|
if (!ctx.provider) {
|
|
5057
5313
|
throw new ToolError("spawn_agent", "provider not initialized (context not injected)");
|
|
5058
5314
|
}
|
|
5315
|
+
const providerFromConfig = agent.provider && ctx.providers?.has(agent.provider) ? ctx.providers.get(agent.provider) : void 0;
|
|
5316
|
+
const provider = providerFromConfig ?? ctx.provider;
|
|
5317
|
+
const model = agent.model ?? (providerFromConfig?.info?.defaultModel ?? ctx.model);
|
|
5318
|
+
const run = startAgentRun({
|
|
5319
|
+
agentName: agent.name,
|
|
5320
|
+
task,
|
|
5321
|
+
agentIndex: agentIndex ?? void 0
|
|
5322
|
+
});
|
|
5323
|
+
const effectiveTools = getEffectiveAgentTools(agent);
|
|
5059
5324
|
const subRegistry = new ToolRegistry();
|
|
5060
5325
|
for (const tool of subRegistry.listAll()) {
|
|
5061
|
-
if (!SUBAGENT_ALLOWED_TOOLS.has(tool.definition.name)) {
|
|
5326
|
+
if (!SUBAGENT_ALLOWED_TOOLS.has(tool.definition.name) || !effectiveTools.has(tool.definition.name)) {
|
|
5062
5327
|
subRegistry.unregister(tool.definition.name);
|
|
5063
5328
|
}
|
|
5064
5329
|
}
|
|
5065
|
-
const subExecutor = new SubAgentExecutor(subRegistry, agentIndex);
|
|
5330
|
+
const subExecutor = new SubAgentExecutor(subRegistry, agentIndex, run.id);
|
|
5066
5331
|
const subMessages = [
|
|
5067
5332
|
{ role: "user", content: task, timestamp: /* @__PURE__ */ new Date() }
|
|
5068
5333
|
];
|
|
5069
|
-
const subSystemPrompt = buildSubAgentSystemPrompt(task, ctx.systemPrompt);
|
|
5334
|
+
const subSystemPrompt = buildSubAgentSystemPrompt(task, agent, ctx.systemPrompt);
|
|
5070
5335
|
const toolDefs = subRegistry.getDefinitions();
|
|
5071
|
-
printSubAgentHeader(task, maxRounds, agentIndex);
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5336
|
+
printSubAgentHeader(task, maxRounds, agent.name, agentIndex);
|
|
5337
|
+
try {
|
|
5338
|
+
const loop = await runLeanAgentLoop({
|
|
5339
|
+
provider,
|
|
5340
|
+
messages: subMessages,
|
|
5341
|
+
model,
|
|
5342
|
+
maxRounds,
|
|
5343
|
+
chatParams: {
|
|
5344
|
+
temperature: ctx.modelParams.temperature,
|
|
5345
|
+
maxTokens: ctx.modelParams.maxTokens,
|
|
5346
|
+
timeout: ctx.modelParams.timeout,
|
|
5347
|
+
thinking: ctx.modelParams.thinking
|
|
5348
|
+
},
|
|
5349
|
+
executeTools: (calls) => subExecutor.executeAll(calls),
|
|
5350
|
+
systemPromptForRound: () => subSystemPrompt,
|
|
5351
|
+
toolDefsForRound: () => toolDefs,
|
|
5352
|
+
onRoundStart: (round) => {
|
|
5353
|
+
subExecutor.setRoundInfo(round + 1, maxRounds);
|
|
5354
|
+
if (ctx.configManager) {
|
|
5355
|
+
googleSearchContext.configManager = ctx.configManager;
|
|
5356
|
+
}
|
|
5357
|
+
},
|
|
5358
|
+
onRoundsExhausted: () => `(Sub-agent reached maximum rounds (${maxRounds}) without producing a final response)`,
|
|
5359
|
+
onError: (errMsg) => {
|
|
5360
|
+
process.stderr.write(`
|
|
5095
5361
|
[spawn_agent] Error in sub-agent loop: ${errMsg}
|
|
5096
5362
|
`);
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5363
|
+
return `(Sub-agent error: ${errMsg})`;
|
|
5364
|
+
}
|
|
5365
|
+
});
|
|
5366
|
+
printSubAgentFooter(loop.usage, agentIndex);
|
|
5367
|
+
const summary = summarizeContent(loop.content);
|
|
5368
|
+
const evidence = extractEvidence(loop.content, subExecutor.toolNames);
|
|
5369
|
+
const stopped = isAgentStopRequested(run.id);
|
|
5370
|
+
finishAgentRun(run.id, stopped ? "stopped" : "ok", summary);
|
|
5371
|
+
return {
|
|
5372
|
+
content: loop.content,
|
|
5373
|
+
usage: loop.usage,
|
|
5374
|
+
toolNames: subExecutor.toolNames,
|
|
5375
|
+
summary,
|
|
5376
|
+
evidence,
|
|
5377
|
+
agentName: agent.name
|
|
5378
|
+
};
|
|
5379
|
+
} catch (err) {
|
|
5380
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
5381
|
+
finishAgentRun(run.id, "error", void 0, message);
|
|
5382
|
+
throw err;
|
|
5383
|
+
}
|
|
5102
5384
|
}
|
|
5103
5385
|
var spawnAgentTool = {
|
|
5104
5386
|
definition: {
|
|
5105
5387
|
name: "spawn_agent",
|
|
5106
|
-
description: "Delegate subtask(s) to independent
|
|
5388
|
+
description: "Delegate subtask(s) to independent named agents. Each sub-agent has its own conversation context and agentic tool-call loop, inherits the parent safety boundary, and can only narrow the sub-agent tool whitelist. Pass `agent` to select a built-in or configured role. Built-ins: explorer, worker, reviewer, security, tester. Pass `task` for a single sub-agent, or `tasks` (array) to run multiple sub-agents IN PARALLEL. Returns summary, key evidence, and tools used for each sub-agent result.",
|
|
5107
5389
|
parameters: {
|
|
5108
5390
|
task: {
|
|
5109
5391
|
type: "string",
|
|
@@ -5121,7 +5403,12 @@ var spawnAgentTool = {
|
|
|
5121
5403
|
},
|
|
5122
5404
|
max_rounds: {
|
|
5123
5405
|
type: "number",
|
|
5124
|
-
description: "Max tool-call rounds per sub-agent (1-
|
|
5406
|
+
description: "Max tool-call rounds per sub-agent (1-30, default 15). Agent config can only reduce this value.",
|
|
5407
|
+
required: false
|
|
5408
|
+
},
|
|
5409
|
+
agent: {
|
|
5410
|
+
type: "string",
|
|
5411
|
+
description: "Agent role name from built-ins or ~/.aicli/agents / .aicli/agents JSON configs. Built-ins: explorer, worker, reviewer, security, tester.",
|
|
5125
5412
|
required: false
|
|
5126
5413
|
}
|
|
5127
5414
|
},
|
|
@@ -5141,10 +5428,17 @@ var spawnAgentTool = {
|
|
|
5141
5428
|
Math.max(Math.round(rawMaxRounds), 1),
|
|
5142
5429
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
5143
5430
|
);
|
|
5431
|
+
const requestedAgentName = typeof args["agent"] === "string" && args["agent"].trim() ? args["agent"].trim() : getPreferredAgentName();
|
|
5144
5432
|
const ctx = spawnAgentContext;
|
|
5145
5433
|
if (!ctx.provider) {
|
|
5146
5434
|
throw new ToolError("spawn_agent", "provider not initialized (context not injected)");
|
|
5147
5435
|
}
|
|
5436
|
+
const agent = resolveAgentConfig(requestedAgentName, ctx.configManager?.getConfigDir());
|
|
5437
|
+
if (!agent) {
|
|
5438
|
+
const available = listAgentConfigs(ctx.configManager?.getConfigDir()).map((cfg) => cfg.name).join(", ");
|
|
5439
|
+
throw new ToolError("spawn_agent", `unknown agent "${requestedAgentName}". Available agents: ${available}`);
|
|
5440
|
+
}
|
|
5441
|
+
const effectiveMaxRounds = getEffectiveMaxRounds(maxRounds, agent);
|
|
5148
5442
|
const hookConfig = ctx.configManager?.get("hooks") ?? void 0;
|
|
5149
5443
|
const hookConfigDir = ctx.configManager?.getConfigDir() ?? process.cwd();
|
|
5150
5444
|
const taskCount = singleTask ? 1 : tasksArr.length;
|
|
@@ -5152,7 +5446,8 @@ var spawnAgentTool = {
|
|
|
5152
5446
|
task: singleTask || void 0,
|
|
5153
5447
|
tasks: tasksArr.length > 0 ? tasksArr : void 0,
|
|
5154
5448
|
taskCount,
|
|
5155
|
-
maxRounds
|
|
5449
|
+
maxRounds: effectiveMaxRounds,
|
|
5450
|
+
agent: agent.name
|
|
5156
5451
|
};
|
|
5157
5452
|
const startDecisions = runLifecycleHooks(hookConfig, "SubagentStart", hookPayload, hookConfigDir);
|
|
5158
5453
|
const startDeny = startDecisions.find((d) => d.action === "deny");
|
|
@@ -5164,32 +5459,37 @@ var spawnAgentTool = {
|
|
|
5164
5459
|
subAgentGuard.active = true;
|
|
5165
5460
|
try {
|
|
5166
5461
|
if (singleTask) {
|
|
5167
|
-
const
|
|
5462
|
+
const result = await runSubAgent(singleTask, effectiveMaxRounds, null, ctx, agent);
|
|
5168
5463
|
subagentStatus = "ok";
|
|
5169
|
-
return
|
|
5170
|
-
"## Sub-Agent Result",
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5464
|
+
return formatAgentResult({
|
|
5465
|
+
title: "## Sub-Agent Result",
|
|
5466
|
+
content: result.content,
|
|
5467
|
+
usage: result.usage,
|
|
5468
|
+
toolNames: result.toolNames,
|
|
5469
|
+
summary: result.summary,
|
|
5470
|
+
evidence: result.evidence,
|
|
5471
|
+
agentName: result.agentName
|
|
5472
|
+
}).join("\n");
|
|
5177
5473
|
}
|
|
5178
5474
|
console.log();
|
|
5179
|
-
console.log(theme.toolCall(`\u{1F916} Spawning ${tasksArr.length} sub-agents in parallel...`));
|
|
5475
|
+
console.log(theme.toolCall(`\u{1F916} Spawning ${tasksArr.length} sub-agents in parallel as ${agent.name}...`));
|
|
5180
5476
|
const results = await Promise.all(
|
|
5181
|
-
tasksArr.map((t, i) => runSubAgent(t,
|
|
5477
|
+
tasksArr.map((t, i) => runSubAgent(t, effectiveMaxRounds, i + 1, ctx, agent))
|
|
5182
5478
|
);
|
|
5183
5479
|
const totalIn = results.reduce((s, r) => s + r.usage.inputTokens, 0);
|
|
5184
5480
|
const totalOut = results.reduce((s, r) => s + r.usage.outputTokens, 0);
|
|
5185
5481
|
const lines = [`## Parallel Sub-Agent Results (${results.length} agents)`, ""];
|
|
5186
5482
|
results.forEach((r, i) => {
|
|
5187
|
-
lines.push(
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5483
|
+
lines.push(...formatAgentResult({
|
|
5484
|
+
title: `### Sub-Agent #${i + 1}`,
|
|
5485
|
+
task: `${tasksArr[i].slice(0, 200)}${tasksArr[i].length > 200 ? "..." : ""}`,
|
|
5486
|
+
content: r.content,
|
|
5487
|
+
usage: r.usage,
|
|
5488
|
+
toolNames: r.toolNames,
|
|
5489
|
+
summary: r.summary,
|
|
5490
|
+
evidence: r.evidence,
|
|
5491
|
+
agentName: r.agentName
|
|
5492
|
+
}));
|
|
5193
5493
|
lines.push("");
|
|
5194
5494
|
});
|
|
5195
5495
|
lines.push("---");
|
|
@@ -5420,14 +5720,14 @@ var taskStopTool = {
|
|
|
5420
5720
|
|
|
5421
5721
|
// src/tools/builtin/git-tools.ts
|
|
5422
5722
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
5423
|
-
import { existsSync as
|
|
5424
|
-
import { join as
|
|
5723
|
+
import { existsSync as existsSync13 } from "fs";
|
|
5724
|
+
import { join as join8 } from "path";
|
|
5425
5725
|
function assertGitRepo(cwd) {
|
|
5426
5726
|
let dir = cwd;
|
|
5427
5727
|
const root = dir.split(/[\\/]/)[0] + (dir.includes("\\") ? "\\" : "/");
|
|
5428
5728
|
while (dir && dir !== root) {
|
|
5429
|
-
if (
|
|
5430
|
-
const parent =
|
|
5729
|
+
if (existsSync13(join8(dir, ".git"))) return;
|
|
5730
|
+
const parent = join8(dir, "..");
|
|
5431
5731
|
if (parent === dir) break;
|
|
5432
5732
|
dir = parent;
|
|
5433
5733
|
}
|
|
@@ -5692,7 +5992,7 @@ ${commitOutput.trim()}`;
|
|
|
5692
5992
|
};
|
|
5693
5993
|
|
|
5694
5994
|
// src/tools/builtin/notebook-edit.ts
|
|
5695
|
-
import { readFileSync as
|
|
5995
|
+
import { readFileSync as readFileSync10, existsSync as existsSync14 } from "fs";
|
|
5696
5996
|
import { writeFile } from "fs/promises";
|
|
5697
5997
|
import { resolve as resolve6, extname as extname2 } from "path";
|
|
5698
5998
|
var notebookEditTool = {
|
|
@@ -5747,10 +6047,10 @@ var notebookEditTool = {
|
|
|
5747
6047
|
if (extname2(absPath).toLowerCase() !== ".ipynb") {
|
|
5748
6048
|
throw new ToolError("notebook_edit", "path must point to a .ipynb file");
|
|
5749
6049
|
}
|
|
5750
|
-
if (!
|
|
6050
|
+
if (!existsSync14(absPath)) {
|
|
5751
6051
|
throw new ToolError("notebook_edit", `Notebook not found: ${filePath}`);
|
|
5752
6052
|
}
|
|
5753
|
-
const raw =
|
|
6053
|
+
const raw = readFileSync10(absPath, "utf-8");
|
|
5754
6054
|
const nb = parseNotebook(raw);
|
|
5755
6055
|
const cellIdx0 = cellIndexRaw - 1;
|
|
5756
6056
|
undoStack.push(absPath, `notebook_edit (${action}): ${filePath}`);
|
|
@@ -6167,8 +6467,8 @@ function estimateToolDefinitionTokens(def) {
|
|
|
6167
6467
|
|
|
6168
6468
|
// src/tools/registry.ts
|
|
6169
6469
|
import { pathToFileURL } from "url";
|
|
6170
|
-
import { existsSync as
|
|
6171
|
-
import { join as
|
|
6470
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readdirSync as readdirSync7 } from "fs";
|
|
6471
|
+
import { join as join9 } from "path";
|
|
6172
6472
|
var ToolRegistry = class {
|
|
6173
6473
|
tools = /* @__PURE__ */ new Map();
|
|
6174
6474
|
pluginToolNames = /* @__PURE__ */ new Set();
|
|
@@ -6329,7 +6629,7 @@ var ToolRegistry = class {
|
|
|
6329
6629
|
* Returns the number of successfully loaded plugins.
|
|
6330
6630
|
*/
|
|
6331
6631
|
async loadPlugins(pluginsDir, allowPlugins = false) {
|
|
6332
|
-
if (!
|
|
6632
|
+
if (!existsSync15(pluginsDir)) {
|
|
6333
6633
|
try {
|
|
6334
6634
|
mkdirSync5(pluginsDir, { recursive: true });
|
|
6335
6635
|
} catch {
|
|
@@ -6338,7 +6638,7 @@ var ToolRegistry = class {
|
|
|
6338
6638
|
}
|
|
6339
6639
|
let files;
|
|
6340
6640
|
try {
|
|
6341
|
-
files =
|
|
6641
|
+
files = readdirSync7(pluginsDir).filter((f) => f.endsWith(".js"));
|
|
6342
6642
|
} catch {
|
|
6343
6643
|
return 0;
|
|
6344
6644
|
}
|
|
@@ -6355,12 +6655,12 @@ var ToolRegistry = class {
|
|
|
6355
6655
|
process.stderr.write(
|
|
6356
6656
|
`
|
|
6357
6657
|
[plugins] \u26A0 Loading ${files.length} plugin(s) with FULL system privileges:
|
|
6358
|
-
` + files.map((f) => ` + ${
|
|
6658
|
+
` + files.map((f) => ` + ${join9(pluginsDir, f)}`).join("\n") + "\n\n"
|
|
6359
6659
|
);
|
|
6360
6660
|
let loaded = 0;
|
|
6361
6661
|
for (const file of files) {
|
|
6362
6662
|
try {
|
|
6363
|
-
const fileUrl = pathToFileURL(
|
|
6663
|
+
const fileUrl = pathToFileURL(join9(pluginsDir, file)).href;
|
|
6364
6664
|
const mod = await import(fileUrl);
|
|
6365
6665
|
const tool = mod.tool ?? mod.default?.tool ?? mod.default;
|
|
6366
6666
|
if (!tool || typeof tool.execute !== "function" || !tool.definition?.name) {
|
|
@@ -6421,6 +6721,12 @@ export {
|
|
|
6421
6721
|
cleanupRejectedTeeFile,
|
|
6422
6722
|
askUserContext,
|
|
6423
6723
|
googleSearchContext,
|
|
6724
|
+
listAgentConfigs,
|
|
6725
|
+
resolveAgentConfig,
|
|
6726
|
+
listAgentRuns,
|
|
6727
|
+
requestAgentStop,
|
|
6728
|
+
setPreferredAgentName,
|
|
6729
|
+
getPreferredAgentName,
|
|
6424
6730
|
spawnAgentContext,
|
|
6425
6731
|
estimateTokens,
|
|
6426
6732
|
ToolRegistry
|