@humain/terminal 0.1.0 → 0.2.1
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/CHANGELOG.md +33 -0
- package/dist/bundle/chunks/{anthropic-messages-XULXUBIG.js → anthropic-messages-QFCEKGI3.js} +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-JEG2XOYC.js → azure-openai-responses-G4ZMHV37.js} +1 -1
- package/dist/bundle/chunks/chunk-7T6XCLJF.js +22 -0
- package/dist/bundle/chunks/chunk-D6HHRSB5.js +103 -0
- package/dist/bundle/chunks/chunk-EY4DWHQU.js +2 -0
- package/dist/bundle/chunks/{chunk-RM336IEI.js → chunk-I47ZWR55.js} +486 -509
- package/dist/bundle/chunks/{chunk-JUPSJTFQ.js → chunk-K4JAZYQH.js} +1 -1
- package/dist/bundle/chunks/{chunk-HPPQHK3J.js → chunk-KKIB2TVR.js} +1 -1
- package/dist/bundle/chunks/chunk-LI2YVPWP.js +2 -0
- package/dist/bundle/chunks/{chunk-BZQ53VGE.js → chunk-XSR434CO.js} +1 -1
- package/dist/bundle/chunks/compat-QCV26HNS.js +2 -0
- package/dist/bundle/chunks/dist-PRPIUY3U.js +2 -0
- package/dist/bundle/chunks/esm-E7UVEYTO.js +4 -0
- package/dist/bundle/chunks/{extract-TRW5FBY6.js → extract-CTIFQZDJ.js} +15 -14
- package/dist/bundle/chunks/{google-generative-ai-OX6VSCA6.js → google-generative-ai-RSUU4MWO.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-GW76GSS2.js → google-vertex-CKQPOITO.js} +1 -1
- package/dist/bundle/chunks/host-WP3MVKS2.js +2 -0
- package/dist/bundle/chunks/{node-KOIP55YZ.js → node-NF43OPII.js} +1 -1
- package/dist/bundle/chunks/{node-XY3CBY3C.js → node-UMFM7CDZ.js} +1 -1
- package/dist/bundle/chunks/{openai-codex-responses-NPLWP6ZC.js → openai-codex-responses-S34V5ZSD.js} +1 -1
- package/dist/bundle/chunks/{openai-completions-OT2GTJKC.js → openai-completions-T2IGVUEI.js} +1 -1
- package/dist/bundle/chunks/{openai-responses-5A6CR7GI.js → openai-responses-GYZODCT3.js} +1 -1
- package/dist/bundle/chunks/readability-LAGF34IB.js +3 -0
- package/dist/bundle/chunks/turndown.cjs-HRMZVRUL.js +2 -0
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli.js +1 -5
- package/dist/core/agent-session.js +2 -2
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js +21 -8
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/subagent-env.d.ts +18 -0
- package/dist/core/tools/subagent-env.d.ts.map +1 -0
- package/dist/core/tools/subagent-env.js +43 -0
- package/dist/core/tools/subagent-env.js.map +1 -0
- package/dist/core/tools/subagent-scheduler.d.ts +31 -0
- package/dist/core/tools/subagent-scheduler.d.ts.map +1 -0
- package/dist/core/tools/subagent-scheduler.js +203 -0
- package/dist/core/tools/subagent-scheduler.js.map +1 -0
- package/dist/core/tools/subagent.d.ts +83 -3
- package/dist/core/tools/subagent.d.ts.map +1 -1
- package/dist/core/tools/subagent.js +214 -76
- package/dist/core/tools/subagent.js.map +1 -1
- package/dist/humain/index.d.ts.map +1 -1
- package/dist/humain/index.js +2 -0
- package/dist/humain/index.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/CHANGELOG.md +78 -0
- package/dist/humain/mcp-adapter/vendor/README.md +125 -19
- package/dist/humain/mcp-adapter/vendor/agent-plugin-loader.ts +69 -30
- package/dist/humain/mcp-adapter/vendor/agent-plugin-provenance.ts +36 -0
- package/dist/humain/mcp-adapter/vendor/claude-plugin-loader.ts +365 -0
- package/dist/humain/mcp-adapter/vendor/commands.ts +13 -15
- package/dist/humain/mcp-adapter/vendor/config.ts +198 -30
- package/dist/humain/mcp-adapter/vendor/consent-manager.ts +40 -9
- package/dist/humain/mcp-adapter/vendor/direct-tool-surface.ts +250 -0
- package/dist/humain/mcp-adapter/vendor/direct-tools.ts +9 -228
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-loader.js +74 -32
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-loader.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-provenance.d.ts +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-provenance.js +31 -0
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-provenance.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/claude-plugin-loader.d.ts +9 -0
- package/dist/humain/mcp-adapter/vendor/dist/claude-plugin-loader.js +362 -0
- package/dist/humain/mcp-adapter/vendor/dist/claude-plugin-loader.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/config.d.ts +3 -1
- package/dist/humain/mcp-adapter/vendor/dist/config.js +189 -27
- package/dist/humain/mcp-adapter/vendor/dist/config.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/dist/metadata-cache.js +7 -16
- package/dist/humain/mcp-adapter/vendor/dist/metadata-cache.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/dist/package-mcp-loader.js +5 -17
- package/dist/humain/mcp-adapter/vendor/dist/package-mcp-loader.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/dist/types.d.ts +30 -4
- package/dist/humain/mcp-adapter/vendor/dist/types.js +26 -0
- package/dist/humain/mcp-adapter/vendor/dist/types.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/dist/utils.d.ts +6 -0
- package/dist/humain/mcp-adapter/vendor/dist/utils.js +65 -6
- package/dist/humain/mcp-adapter/vendor/dist/utils.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/host-html-template.ts +20 -19
- package/dist/humain/mcp-adapter/vendor/http-ca.ts +84 -0
- package/dist/humain/mcp-adapter/vendor/index.bundle.mjs +37102 -15103
- package/dist/humain/mcp-adapter/vendor/index.ts +828 -164
- package/dist/humain/mcp-adapter/vendor/init.ts +48 -10
- package/dist/humain/mcp-adapter/vendor/lazy-loader.ts +7 -0
- package/dist/humain/mcp-adapter/vendor/mcp-auth-fetch.ts +113 -0
- package/dist/humain/mcp-adapter/vendor/mcp-auth-flow.ts +256 -77
- package/dist/humain/mcp-adapter/vendor/mcp-auth.ts +316 -54
- package/dist/humain/mcp-adapter/vendor/mcp-code.ts +45 -18
- package/dist/humain/mcp-adapter/vendor/mcp-install.ts +60 -0
- package/dist/humain/mcp-adapter/vendor/mcp-oauth-provider.ts +70 -6
- package/dist/humain/mcp-adapter/vendor/mcp-output-guard.ts +53 -42
- package/dist/humain/mcp-adapter/vendor/mcp-panel-theme.ts +105 -0
- package/dist/humain/mcp-adapter/vendor/mcp-panel.ts +366 -331
- package/dist/humain/mcp-adapter/vendor/mcp-references.ts +9 -14
- package/dist/humain/mcp-adapter/vendor/mcp-script-worker.mjs +3 -1
- package/dist/humain/mcp-adapter/vendor/mcp-setup-panel.ts +383 -341
- package/dist/humain/mcp-adapter/vendor/mcp-status.ts +5 -0
- package/dist/humain/mcp-adapter/vendor/metadata-cache.ts +7 -16
- package/dist/humain/mcp-adapter/vendor/namespace-tools.ts +61 -3
- package/dist/humain/mcp-adapter/vendor/oauth.ts +6 -2
- package/dist/humain/mcp-adapter/vendor/package-mcp-loader.ts +5 -17
- package/dist/humain/mcp-adapter/vendor/package.json +13 -3
- package/dist/humain/mcp-adapter/vendor/prompts.ts +35 -3
- package/dist/humain/mcp-adapter/vendor/proxy-modes.ts +108 -7
- package/dist/humain/mcp-adapter/vendor/runtime-owner.ts +16 -1
- package/dist/humain/mcp-adapter/vendor/sampling-handler.ts +9 -32
- package/dist/humain/mcp-adapter/vendor/sandbox-proxy-template.ts +20 -93
- package/dist/humain/mcp-adapter/vendor/server-manager.ts +227 -40
- package/dist/humain/mcp-adapter/vendor/session-approvals.ts +187 -0
- package/dist/humain/mcp-adapter/vendor/skills/mcp-scripting/SKILL.md +9 -1
- package/dist/humain/mcp-adapter/vendor/state.ts +10 -1
- package/dist/humain/mcp-adapter/vendor/tool-approval.ts +10 -22
- package/dist/humain/mcp-adapter/vendor/tool-metadata.ts +14 -0
- package/dist/humain/mcp-adapter/vendor/types.ts +57 -4
- package/dist/humain/mcp-adapter/vendor/ui-server.ts +36 -28
- package/dist/humain/mcp-adapter/vendor/utils.ts +64 -6
- package/dist/humain/node-http.d.ts +3 -0
- package/dist/humain/node-http.d.ts.map +1 -0
- package/dist/humain/node-http.js +119 -0
- package/dist/humain/node-http.js.map +1 -0
- package/dist/humain/node-provider.d.ts +4 -0
- package/dist/humain/node-provider.d.ts.map +1 -0
- package/dist/humain/node-provider.js +359 -0
- package/dist/humain/node-provider.js.map +1 -0
- package/dist/humain/web-access/vendor/abortable.d.ts +3 -0
- package/dist/humain/web-access/vendor/abortable.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/abortable.js +22 -0
- package/dist/humain/web-access/vendor/abortable.js.map +1 -0
- package/dist/humain/web-access/vendor/crawl4ai.d.ts +9 -0
- package/dist/humain/web-access/vendor/crawl4ai.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/crawl4ai.js +187 -0
- package/dist/humain/web-access/vendor/crawl4ai.js.map +1 -0
- package/dist/humain/web-access/vendor/credential-source.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/credential-source.js +1 -0
- package/dist/humain/web-access/vendor/credential-source.js.map +1 -1
- package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/curator-page.js +20 -2
- package/dist/humain/web-access/vendor/curator-page.js.map +1 -1
- package/dist/humain/web-access/vendor/curator-run.d.ts +11 -0
- package/dist/humain/web-access/vendor/curator-run.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/curator-run.js +38 -0
- package/dist/humain/web-access/vendor/curator-run.js.map +1 -0
- package/dist/humain/web-access/vendor/curator-server.d.ts +1 -0
- package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/curator-server.js +2 -0
- package/dist/humain/web-access/vendor/curator-server.js.map +1 -1
- package/dist/humain/web-access/vendor/duckduckgo.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/duckduckgo.js +1 -1
- package/dist/humain/web-access/vendor/duckduckgo.js.map +1 -1
- package/dist/humain/web-access/vendor/extract.d.ts +1 -1
- package/dist/humain/web-access/vendor/extract.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/extract.js +58 -11
- package/dist/humain/web-access/vendor/extract.js.map +1 -1
- package/dist/humain/web-access/vendor/fetch-params.js +1 -1
- package/dist/humain/web-access/vendor/fetch-params.js.map +1 -1
- package/dist/humain/web-access/vendor/gemini-search.d.ts +2 -2
- package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/gemini-search.js +12 -5
- package/dist/humain/web-access/vendor/gemini-search.js.map +1 -1
- package/dist/humain/web-access/vendor/index.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/index.js +23 -19
- package/dist/humain/web-access/vendor/index.js.map +1 -1
- package/dist/humain/web-access/vendor/openai-search.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/openai-search.js +40 -14
- package/dist/humain/web-access/vendor/openai-search.js.map +1 -1
- package/dist/humain/web-access/vendor/page-query.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/page-query.js +6 -2
- package/dist/humain/web-access/vendor/page-query.js.map +1 -1
- package/dist/humain/web-access/vendor/query-rewrite.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/query-rewrite.js +6 -2
- package/dist/humain/web-access/vendor/query-rewrite.js.map +1 -1
- package/dist/humain/web-access/vendor/serpapi.d.ts +4 -0
- package/dist/humain/web-access/vendor/serpapi.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/serpapi.js +215 -0
- package/dist/humain/web-access/vendor/serpapi.js.map +1 -0
- package/dist/humain/web-access/vendor/ssrf-protection.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/ssrf-protection.js +5 -1
- package/dist/humain/web-access/vendor/ssrf-protection.js.map +1 -1
- package/dist/humain/web-access/vendor/storage.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/storage.js +9 -0
- package/dist/humain/web-access/vendor/storage.js.map +1 -1
- package/dist/humain/web-access/vendor/summary-review.d.ts +1 -1
- package/dist/humain/web-access/vendor/summary-review.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/summary-review.js +35 -24
- package/dist/humain/web-access/vendor/summary-review.js.map +1 -1
- package/dist/humain/web-access/vendor/utils.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/utils.js +5 -3
- package/dist/humain/web-access/vendor/utils.js.map +1 -1
- package/dist/index.js +1 -51
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +16 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +7 -2
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +46 -21
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +10 -13
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/json-event.d.ts +8 -0
- package/dist/modes/json-event.d.ts.map +1 -1
- package/dist/modes/json-event.js +17 -0
- package/dist/modes/json-event.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +3 -2
- package/dist/modes/print-mode.js.map +1 -1
- package/docs/environment-variables.md +8 -0
- package/docs/humain-terminal.md +6 -0
- package/docs/json.md +16 -0
- package/docs/providers.md +19 -1
- package/npm-shrinkwrap.json +6 -6
- package/package.json +2 -2
- package/src/humain/mcp-adapter/UPSTREAM.md +56 -7
- package/src/humain/mcp-adapter/upstream.json +6 -4
- package/src/humain/mcp-adapter/vendor/CHANGELOG.md +78 -0
- package/src/humain/web-access/UPSTREAM.md +18 -8
- package/src/humain/web-access/upstream.json +6 -5
- package/dist/bundle/chunks/chunk-2LC3S3VV.js +0 -105
|
@@ -23,19 +23,13 @@ import { getMarkdownTheme } from "../../modes/interactive/theme/theme.js";
|
|
|
23
23
|
import { parseFrontmatter } from "../../utils/frontmatter.js";
|
|
24
24
|
import { withFileMutationQueue } from "./file-mutation-queue.js";
|
|
25
25
|
import { shortenPath } from "./render-utils.js";
|
|
26
|
+
import { currentSubagentDepth, currentTaskId, maxParallelTasks, maxSubagentConcurrency, maxSubagentDepth, PARENT_TASK_ID_ENV, SUBAGENT_DEPTH_ENV, TASK_BASE_REVISION_ENV, TASK_ID_ENV, } from "./subagent-env.js";
|
|
27
|
+
import { runDag, validateTaskGraph } from "./subagent-scheduler.js";
|
|
28
|
+
export { SUBAGENT_DEPTH_ENV } from "./subagent-env.js";
|
|
26
29
|
import { createSubagentWorktree, isGitWorkTree, } from "./subagent-worktree.js";
|
|
27
30
|
import { wrapToolDefinition } from "./tool-definition-wrapper.js";
|
|
28
|
-
const MAX_PARALLEL_TASKS = 8;
|
|
29
|
-
const MAX_CONCURRENCY = 4;
|
|
30
31
|
const COLLAPSED_ITEM_COUNT = 10;
|
|
31
32
|
const PER_TASK_OUTPUT_CAP = 50 * 1024;
|
|
32
|
-
/** Children must not delegate further: depth 0 = top-level agent, depth >= 1 = subagent. */
|
|
33
|
-
export const SUBAGENT_DEPTH_ENV = "HUMAIN_TERMINAL_SUBAGENT_DEPTH";
|
|
34
|
-
const MAX_SUBAGENT_DEPTH = 1;
|
|
35
|
-
function currentSubagentDepth() {
|
|
36
|
-
const raw = Number(process.env[SUBAGENT_DEPTH_ENV] ?? "0");
|
|
37
|
-
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 0;
|
|
38
|
-
}
|
|
39
33
|
function loadAgentsFromDir(dir, source) {
|
|
40
34
|
const agents = [];
|
|
41
35
|
if (!fs.existsSync(dir)) {
|
|
@@ -211,6 +205,16 @@ function formatToolCall(toolName, args, themeFg) {
|
|
|
211
205
|
}
|
|
212
206
|
}
|
|
213
207
|
}
|
|
208
|
+
export function renderTaskWithContext(task, context) {
|
|
209
|
+
const parts = [`Task: ${task}`];
|
|
210
|
+
if (context?.files?.length)
|
|
211
|
+
parts.push(`Context files:\n${context.files.map((f) => `- ${f}`).join("\n")}`);
|
|
212
|
+
if (context?.acceptance?.length)
|
|
213
|
+
parts.push(`Acceptance criteria:\n${context.acceptance.map((a) => `- ${a}`).join("\n")}`);
|
|
214
|
+
if (context?.baseRevision)
|
|
215
|
+
parts.push(`Base revision: ${context.baseRevision}`);
|
|
216
|
+
return parts.join("\n\n");
|
|
217
|
+
}
|
|
214
218
|
function getFinalOutput(messages) {
|
|
215
219
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
216
220
|
const msg = messages[i];
|
|
@@ -259,28 +263,6 @@ function getDisplayItems(messages) {
|
|
|
259
263
|
}
|
|
260
264
|
return items;
|
|
261
265
|
}
|
|
262
|
-
async function mapWithConcurrencyLimit(items, concurrency, fn, signal, onAbort) {
|
|
263
|
-
if (items.length === 0)
|
|
264
|
-
return [];
|
|
265
|
-
const limit = Math.max(1, Math.min(concurrency, items.length));
|
|
266
|
-
const results = new Array(items.length);
|
|
267
|
-
let nextIndex = 0;
|
|
268
|
-
const workers = new Array(limit).fill(null).map(async () => {
|
|
269
|
-
while (true) {
|
|
270
|
-
const current = nextIndex++;
|
|
271
|
-
if (current >= items.length)
|
|
272
|
-
return;
|
|
273
|
-
if (signal?.aborted) {
|
|
274
|
-
if (onAbort)
|
|
275
|
-
results[current] = await onAbort(items[current], current);
|
|
276
|
-
continue;
|
|
277
|
-
}
|
|
278
|
-
results[current] = await fn(items[current], current);
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
await Promise.all(workers);
|
|
282
|
-
return results;
|
|
283
|
-
}
|
|
284
266
|
async function writePromptToTempFile(agentName, prompt) {
|
|
285
267
|
const tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "humain-subagent-"));
|
|
286
268
|
const safeName = agentName.replace(/[^\w.-]+/g, "_");
|
|
@@ -303,7 +285,9 @@ function getCliInvocation(args) {
|
|
|
303
285
|
}
|
|
304
286
|
return { command: "humain-terminal", args };
|
|
305
287
|
}
|
|
306
|
-
async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, isolation, step, model, parentModel, signal, onUpdate, makeDetails, toolCallId, childIndex) {
|
|
288
|
+
async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, isolation, step, model, parentModel, signal, onUpdate, makeDetails, toolCallId, childIndex, options) {
|
|
289
|
+
const childDepth = currentSubagentDepth() + 1;
|
|
290
|
+
const parentTaskId = currentTaskId() ?? toolCallId;
|
|
307
291
|
const agent = agents.find((a) => a.name === agentName);
|
|
308
292
|
if (!agent) {
|
|
309
293
|
const available = agents.map((a) => `"${a.name}"`).join(", ") || "none";
|
|
@@ -311,12 +295,18 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, isolatio
|
|
|
311
295
|
agent: agentName,
|
|
312
296
|
agentSource: "unknown",
|
|
313
297
|
task,
|
|
298
|
+
taskId: options.taskId,
|
|
299
|
+
parentTaskId,
|
|
300
|
+
depth: childDepth,
|
|
314
301
|
exitCode: 1,
|
|
315
302
|
messages: [],
|
|
316
303
|
stderr: `Unknown agent: "${agentName}". Available agents: ${available}.`,
|
|
317
304
|
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },
|
|
318
305
|
step,
|
|
319
306
|
isolation: "shared",
|
|
307
|
+
thinking: options.thinking,
|
|
308
|
+
attempt: options.attempt,
|
|
309
|
+
baseRevision: options.context?.baseRevision,
|
|
320
310
|
};
|
|
321
311
|
}
|
|
322
312
|
let worktree = null;
|
|
@@ -342,12 +332,19 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, isolatio
|
|
|
342
332
|
}
|
|
343
333
|
if (agent.tools && agent.tools.length > 0)
|
|
344
334
|
args.push("--tools", agent.tools.join(","));
|
|
335
|
+
if (options.thinking)
|
|
336
|
+
args.push("--thinking", options.thinking);
|
|
345
337
|
let tmpPromptDir = null;
|
|
346
338
|
let tmpPromptPath = null;
|
|
347
339
|
const currentResult = {
|
|
348
340
|
agent: agentName,
|
|
349
341
|
agentSource: agent.source,
|
|
350
342
|
task,
|
|
343
|
+
taskId: options.taskId,
|
|
344
|
+
parentTaskId,
|
|
345
|
+
depth: childDepth,
|
|
346
|
+
thinking: options.thinking,
|
|
347
|
+
attempt: options.attempt,
|
|
351
348
|
exitCode: 0,
|
|
352
349
|
messages: [],
|
|
353
350
|
stderr: "",
|
|
@@ -355,6 +352,7 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, isolatio
|
|
|
355
352
|
model: model ?? `${parentModel.provider}/${parentModel.id}`,
|
|
356
353
|
step,
|
|
357
354
|
isolation: "shared",
|
|
355
|
+
baseRevision: options.context?.baseRevision,
|
|
358
356
|
};
|
|
359
357
|
const emitUpdate = () => {
|
|
360
358
|
if (onUpdate) {
|
|
@@ -386,14 +384,24 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, isolatio
|
|
|
386
384
|
tmpPromptPath = tmp.filePath;
|
|
387
385
|
args.push("--append-system-prompt", tmpPromptPath);
|
|
388
386
|
}
|
|
389
|
-
args.push(
|
|
387
|
+
args.push(renderTaskWithContext(task, options.context));
|
|
390
388
|
const exitCode = await new Promise((resolve) => {
|
|
391
389
|
const invocation = getCliInvocation(args);
|
|
390
|
+
const env = {
|
|
391
|
+
...process.env,
|
|
392
|
+
[SUBAGENT_DEPTH_ENV]: String(childDepth),
|
|
393
|
+
[TASK_ID_ENV]: options.taskId,
|
|
394
|
+
[PARENT_TASK_ID_ENV]: parentTaskId,
|
|
395
|
+
};
|
|
396
|
+
if (options.context?.baseRevision)
|
|
397
|
+
env[TASK_BASE_REVISION_ENV] = options.context.baseRevision;
|
|
398
|
+
else
|
|
399
|
+
delete env[TASK_BASE_REVISION_ENV];
|
|
392
400
|
const proc = spawn(invocation.command, invocation.args, {
|
|
393
401
|
cwd: childCwd,
|
|
394
402
|
shell: false,
|
|
395
403
|
stdio: ["ignore", "pipe", "pipe"],
|
|
396
|
-
env
|
|
404
|
+
env,
|
|
397
405
|
});
|
|
398
406
|
let buffer = "";
|
|
399
407
|
let settled = false;
|
|
@@ -549,9 +557,14 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, isolatio
|
|
|
549
557
|
}
|
|
550
558
|
return currentResult;
|
|
551
559
|
}
|
|
560
|
+
const ThinkingLevelSchema = StringEnum(["off", "minimal", "low", "medium", "high", "xhigh", "max"], {
|
|
561
|
+
description: "Reasoning effort for this child. Maps to the CLI --thinking level. Defaults to the child's own default.",
|
|
562
|
+
});
|
|
552
563
|
const TaskItem = Type.Object({
|
|
553
564
|
agent: Type.String({ description: "Name of the agent to invoke" }),
|
|
554
565
|
task: Type.String({ description: "Task to delegate to the agent" }),
|
|
566
|
+
id: Type.Optional(Type.String({ description: "Stable task id. Defaults to <toolCallId>-<index>. Referenced by dependsOn." })),
|
|
567
|
+
thinking: Type.Optional(ThinkingLevelSchema),
|
|
555
568
|
model: Type.Optional(Type.String({
|
|
556
569
|
description: "Optional canonical provider/model for this child. Defaults to the parent provider/model.",
|
|
557
570
|
})),
|
|
@@ -559,6 +572,26 @@ const TaskItem = Type.Object({
|
|
|
559
572
|
isolation: Type.Optional(StringEnum(["shared", "worktree"], {
|
|
560
573
|
description: "Filesystem isolation for this child. 'worktree' runs it in a disposable git worktree and merges its changes back; the caller's policy sets this, not the model.",
|
|
561
574
|
})),
|
|
575
|
+
dependsOn: Type.Optional(Type.Array(Type.String(), {
|
|
576
|
+
description: "Ids of sibling tasks that must complete successfully before this one starts.",
|
|
577
|
+
})),
|
|
578
|
+
ownerPaths: Type.Optional(Type.Array(Type.String(), {
|
|
579
|
+
description: "Repo-relative paths this task owns. Siblings whose ownerPaths overlap run one after another instead of in parallel.",
|
|
580
|
+
})),
|
|
581
|
+
onFailure: Type.Optional(Type.Object({
|
|
582
|
+
retryWith: Type.Optional(Type.Object({
|
|
583
|
+
model: Type.Optional(Type.String({ description: "Canonical provider/model for the retry." })),
|
|
584
|
+
thinking: Type.Optional(ThinkingLevelSchema),
|
|
585
|
+
})),
|
|
586
|
+
maxAttempts: Type.Optional(Type.Integer({ minimum: 1, maximum: 3, description: "Total attempts including the first. Default 1." })),
|
|
587
|
+
}, {
|
|
588
|
+
description: "Retry only this task on failure with a different model or thinking level. The caller's policy sets this.",
|
|
589
|
+
})),
|
|
590
|
+
context: Type.Optional(Type.Object({
|
|
591
|
+
files: Type.Optional(Type.Array(Type.String(), { description: "Files the child should read first." })),
|
|
592
|
+
acceptance: Type.Optional(Type.Array(Type.String(), { description: "Acceptance criteria the child must satisfy." })),
|
|
593
|
+
baseRevision: Type.Optional(Type.String({ description: "Git revision the packet was assembled against." })),
|
|
594
|
+
}, { description: "Bounded context packet for this child." })),
|
|
562
595
|
});
|
|
563
596
|
const ChainItem = Type.Object({
|
|
564
597
|
agent: Type.String({ description: "Name of the agent to invoke" }),
|
|
@@ -566,6 +599,7 @@ const ChainItem = Type.Object({
|
|
|
566
599
|
model: Type.Optional(Type.String({
|
|
567
600
|
description: "Optional canonical provider/model for this child. Defaults to the parent provider/model.",
|
|
568
601
|
})),
|
|
602
|
+
thinking: Type.Optional(ThinkingLevelSchema),
|
|
569
603
|
cwd: Type.Optional(Type.String({ description: "Working directory for the agent process" })),
|
|
570
604
|
});
|
|
571
605
|
const AgentScopeSchema = StringEnum(["user", "project", "both"], {
|
|
@@ -578,6 +612,7 @@ const SubagentParams = Type.Object({
|
|
|
578
612
|
model: Type.Optional(Type.String({
|
|
579
613
|
description: "Optional canonical provider/model for this child. Defaults to the parent provider/model.",
|
|
580
614
|
})),
|
|
615
|
+
thinking: Type.Optional(ThinkingLevelSchema),
|
|
581
616
|
tasks: Type.Optional(Type.Array(TaskItem, { description: "Array of {agent, task} for parallel execution" })),
|
|
582
617
|
chain: Type.Optional(Type.Array(ChainItem, { description: "Array of {agent, task} for sequential execution" })),
|
|
583
618
|
agentScope: Type.Optional(AgentScopeSchema),
|
|
@@ -594,13 +629,14 @@ export function createSubagentToolDefinition(cwd) {
|
|
|
594
629
|
description: [
|
|
595
630
|
"Delegate tasks to specialized subagents with isolated context.",
|
|
596
631
|
"Modes: single (agent + task), parallel (tasks array), chain (sequential with {previous} placeholder).",
|
|
597
|
-
"
|
|
632
|
+
"Parallel tasks may declare id, dependsOn (start after those ids succeed), ownerPaths (overlapping siblings run one at a time), thinking (reasoning level), context (files, acceptance criteria, base revision) and onFailure (retry this task with another model or thinking level).",
|
|
633
|
+
"The optional isolation, thinking and onFailure fields are policy-set for each child.",
|
|
598
634
|
`Default agent scope is "user" (from ${path.join(getAgentDir(), "agents")}).`,
|
|
599
635
|
`To enable project-local agents in ${CONFIG_DIR_NAME}/agents, set agentScope: "both" (or "project").`,
|
|
600
636
|
].join(" "),
|
|
601
637
|
promptSnippet: "subagent: delegate work to isolated subagents — single task, parallel batch (tasks array), or sequential chain with {previous} placeholder",
|
|
602
638
|
promptGuidelines: [
|
|
603
|
-
"Use subagent to fan out independent work in parallel (tasks array) or run multi-step pipelines (chain). Subagents run with isolated context
|
|
639
|
+
"Use subagent to fan out independent work in parallel (tasks array) or run multi-step pipelines (chain). Subagents run with isolated context. Nested delegation is allowed only up to the configured depth; a child at the limit must complete its task directly.",
|
|
604
640
|
],
|
|
605
641
|
parameters: SubagentParams,
|
|
606
642
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
@@ -615,17 +651,29 @@ export function createSubagentToolDefinition(cwd) {
|
|
|
615
651
|
// the tool args and reconcile it against results by index.
|
|
616
652
|
const requestedChildren = () => {
|
|
617
653
|
if (params.tasks && params.tasks.length > 0)
|
|
618
|
-
return params.tasks.map((t) => ({
|
|
654
|
+
return params.tasks.map((t, i) => ({
|
|
655
|
+
agent: t.agent,
|
|
656
|
+
task: t.task,
|
|
657
|
+
taskId: t.id ?? `${toolCallId}-${i}`,
|
|
658
|
+
}));
|
|
619
659
|
if (params.chain && params.chain.length > 0)
|
|
620
|
-
return params.chain.map((s, i) => ({
|
|
660
|
+
return params.chain.map((s, i) => ({
|
|
661
|
+
agent: s.agent,
|
|
662
|
+
task: s.task,
|
|
663
|
+
step: i + 1,
|
|
664
|
+
taskId: `${toolCallId}-${i}`,
|
|
665
|
+
}));
|
|
621
666
|
if (params.agent)
|
|
622
|
-
return [{ agent: params.agent, task: params.task }];
|
|
667
|
+
return [{ agent: params.agent, task: params.task, taskId: `${toolCallId}-0` }];
|
|
623
668
|
return [];
|
|
624
669
|
};
|
|
625
670
|
const stubResult = (child, errorMessage) => ({
|
|
626
671
|
agent: child.agent,
|
|
627
672
|
agentSource: "unknown",
|
|
628
673
|
task: child.task ?? "",
|
|
674
|
+
taskId: child.taskId ?? `${toolCallId}-${child.step !== undefined ? child.step - 1 : 0}`,
|
|
675
|
+
parentTaskId: currentTaskId() ?? toolCallId,
|
|
676
|
+
depth: currentSubagentDepth() + 1,
|
|
629
677
|
exitCode: 1,
|
|
630
678
|
messages: [],
|
|
631
679
|
stderr: "",
|
|
@@ -641,12 +689,12 @@ export function createSubagentToolDefinition(cwd) {
|
|
|
641
689
|
projectAgentsDir: discovery.projectAgentsDir,
|
|
642
690
|
results,
|
|
643
691
|
});
|
|
644
|
-
if (currentSubagentDepth() >=
|
|
692
|
+
if (currentSubagentDepth() >= maxSubagentDepth()) {
|
|
645
693
|
return {
|
|
646
694
|
content: [
|
|
647
695
|
{
|
|
648
696
|
type: "text",
|
|
649
|
-
text:
|
|
697
|
+
text: `Nested delegation limit reached (depth ${currentSubagentDepth()} of ${maxSubagentDepth()}). Complete the task directly.`,
|
|
650
698
|
},
|
|
651
699
|
],
|
|
652
700
|
details: makeDetails("single")([]),
|
|
@@ -725,7 +773,7 @@ export function createSubagentToolDefinition(cwd) {
|
|
|
725
773
|
}
|
|
726
774
|
}
|
|
727
775
|
: undefined;
|
|
728
|
-
const result = await runSingleAgent(defaultCwd, agents, step.agent, taskWithContext, step.cwd, undefined, i + 1, step.model, parentModel, signal, chainUpdate, makeDetails("chain"), toolCallId, i);
|
|
776
|
+
const result = await runSingleAgent(defaultCwd, agents, step.agent, taskWithContext, step.cwd, undefined, i + 1, step.model, parentModel, signal, chainUpdate, makeDetails("chain"), toolCallId, i, { taskId: `${toolCallId}-${i}`, thinking: step.thinking });
|
|
729
777
|
results.push(result);
|
|
730
778
|
const isError = isFailedResult(result);
|
|
731
779
|
if (isError) {
|
|
@@ -747,32 +795,61 @@ export function createSubagentToolDefinition(cwd) {
|
|
|
747
795
|
};
|
|
748
796
|
}
|
|
749
797
|
if (params.tasks && params.tasks.length > 0) {
|
|
750
|
-
|
|
798
|
+
const taskCap = maxParallelTasks();
|
|
799
|
+
if (params.tasks.length > taskCap)
|
|
751
800
|
return {
|
|
752
801
|
content: [
|
|
753
|
-
{
|
|
754
|
-
type: "text",
|
|
755
|
-
text: `Too many parallel tasks (${params.tasks.length}). Max is ${MAX_PARALLEL_TASKS}.`,
|
|
756
|
-
},
|
|
802
|
+
{ type: "text", text: `Too many parallel tasks (${params.tasks.length}). Max is ${taskCap}.` },
|
|
757
803
|
],
|
|
758
|
-
details: makeDetails("parallel")(stubAllChildren(`not run: too many parallel tasks (max ${
|
|
804
|
+
details: makeDetails("parallel")(stubAllChildren(`not run: too many parallel tasks (max ${taskCap})`)),
|
|
759
805
|
isError: true,
|
|
760
806
|
};
|
|
761
|
-
|
|
762
|
-
const
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
807
|
+
const childDepth = currentSubagentDepth() + 1;
|
|
808
|
+
const graph = params.tasks.map((t, i) => ({
|
|
809
|
+
...t,
|
|
810
|
+
id: t.id ?? `${toolCallId}-${i}`,
|
|
811
|
+
dependsOn: t.dependsOn ?? [],
|
|
812
|
+
ownerPaths: t.ownerPaths ?? [],
|
|
813
|
+
}));
|
|
814
|
+
const graphError = validateTaskGraph(graph);
|
|
815
|
+
if (graphError) {
|
|
816
|
+
return {
|
|
817
|
+
content: [{ type: "text", text: `Invalid task graph: ${graphError}.` }],
|
|
818
|
+
details: makeDetails("parallel")(stubAllChildren(`not run: invalid task graph (${graphError})`)),
|
|
819
|
+
isError: true,
|
|
774
820
|
};
|
|
775
821
|
}
|
|
822
|
+
const taskEvents = [];
|
|
823
|
+
const emitTaskEvent = (event) => {
|
|
824
|
+
taskEvents.push(event);
|
|
825
|
+
};
|
|
826
|
+
const now = () => Date.now();
|
|
827
|
+
for (const g of graph)
|
|
828
|
+
emitTaskEvent({
|
|
829
|
+
type: "schedule",
|
|
830
|
+
taskId: g.id,
|
|
831
|
+
dependsOn: g.dependsOn,
|
|
832
|
+
ownerPaths: g.ownerPaths,
|
|
833
|
+
baseRevision: g.context?.baseRevision,
|
|
834
|
+
at: now(),
|
|
835
|
+
});
|
|
836
|
+
const allResults = graph.map((g) => ({
|
|
837
|
+
agent: g.agent,
|
|
838
|
+
agentSource: "unknown",
|
|
839
|
+
task: g.task,
|
|
840
|
+
taskId: g.id,
|
|
841
|
+
parentTaskId: currentTaskId() ?? toolCallId,
|
|
842
|
+
depth: childDepth,
|
|
843
|
+
exitCode: -1, // -1 = still running
|
|
844
|
+
messages: [],
|
|
845
|
+
stderr: "",
|
|
846
|
+
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },
|
|
847
|
+
isolation: "shared",
|
|
848
|
+
}));
|
|
849
|
+
const detailsWithEvents = (results) => ({
|
|
850
|
+
...makeDetails("parallel")(results),
|
|
851
|
+
taskEvents: [...taskEvents],
|
|
852
|
+
});
|
|
776
853
|
const emitParallelUpdate = () => {
|
|
777
854
|
if (onUpdate) {
|
|
778
855
|
const running = allResults.filter((r) => r.exitCode === -1).length;
|
|
@@ -781,23 +858,84 @@ export function createSubagentToolDefinition(cwd) {
|
|
|
781
858
|
content: [
|
|
782
859
|
{ type: "text", text: `Parallel: ${done}/${allResults.length} done, ${running} running...` },
|
|
783
860
|
],
|
|
784
|
-
details:
|
|
861
|
+
details: detailsWithEvents([...allResults]),
|
|
785
862
|
});
|
|
786
863
|
}
|
|
787
864
|
};
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
865
|
+
let results;
|
|
866
|
+
try {
|
|
867
|
+
results = await runDag(graph, maxSubagentConcurrency(), async (g, index) => {
|
|
868
|
+
const maxAttempts = Math.min(3, Math.max(1, g.onFailure?.maxAttempts ?? 1));
|
|
869
|
+
let attempt = 1;
|
|
870
|
+
let model = g.model;
|
|
871
|
+
let thinking = g.thinking;
|
|
872
|
+
let result;
|
|
873
|
+
for (;;) {
|
|
874
|
+
emitTaskEvent({ type: "start", taskId: g.id, attempt, at: now() });
|
|
875
|
+
result = await runSingleAgent(defaultCwd, agents, g.agent, g.task, g.cwd, g.isolation, undefined, model, parentModel, signal, (partial) => {
|
|
876
|
+
if (partial.details?.results[0]) {
|
|
877
|
+
allResults[index] = partial.details.results[0];
|
|
878
|
+
emitParallelUpdate();
|
|
879
|
+
}
|
|
880
|
+
}, detailsWithEvents, toolCallId, index, { taskId: g.id, thinking, attempt, context: g.context });
|
|
881
|
+
if (!isFailedResult(result)) {
|
|
882
|
+
emitTaskEvent({ type: "complete", taskId: g.id, attempt, at: now() });
|
|
883
|
+
break;
|
|
884
|
+
}
|
|
885
|
+
emitTaskEvent({
|
|
886
|
+
type: "fail",
|
|
887
|
+
taskId: g.id,
|
|
888
|
+
attempt,
|
|
889
|
+
reason: getResultOutput(result).slice(0, 200),
|
|
890
|
+
at: now(),
|
|
891
|
+
});
|
|
892
|
+
if (attempt >= maxAttempts || signal?.aborted)
|
|
893
|
+
break;
|
|
894
|
+
const next = attempt + 1;
|
|
895
|
+
model = g.onFailure?.retryWith?.model ?? model;
|
|
896
|
+
thinking = g.onFailure?.retryWith?.thinking ?? thinking;
|
|
897
|
+
emitTaskEvent({
|
|
898
|
+
type: "escalate",
|
|
899
|
+
taskId: g.id,
|
|
900
|
+
fromAttempt: attempt,
|
|
901
|
+
toAttempt: next,
|
|
902
|
+
model: model ?? `${parentModel.provider}/${parentModel.id}`,
|
|
903
|
+
thinking,
|
|
904
|
+
at: now(),
|
|
905
|
+
});
|
|
906
|
+
attempt = next;
|
|
795
907
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
908
|
+
allResults[index] = result;
|
|
909
|
+
emitParallelUpdate();
|
|
910
|
+
return result;
|
|
911
|
+
}, isFailedResult, (g, index, failedDependency) => {
|
|
912
|
+
const stub = stubResult({ agent: g.agent, task: g.task, taskId: g.id }, `not run: dependency "${failedDependency}" failed`);
|
|
913
|
+
allResults[index] = stub;
|
|
914
|
+
emitParallelUpdate();
|
|
915
|
+
return stub;
|
|
916
|
+
}, (event) => {
|
|
917
|
+
if (event.type === "wait")
|
|
918
|
+
emitTaskEvent({ type: "wait", taskId: event.id, reason: "concurrency", at: now() });
|
|
919
|
+
else if (event.type === "serialize")
|
|
920
|
+
emitTaskEvent({ type: "serialize", taskId: event.id, after: event.after, at: now() });
|
|
921
|
+
else if (event.type === "skip")
|
|
922
|
+
emitTaskEvent({
|
|
923
|
+
type: "skip",
|
|
924
|
+
taskId: event.id,
|
|
925
|
+
failedDependency: event.failedDependency,
|
|
926
|
+
at: now(),
|
|
927
|
+
});
|
|
928
|
+
// "start" is emitted inside run() together with the attempt number.
|
|
929
|
+
}, signal, (g) => stubResult({ agent: g.agent, task: g.task, taskId: g.id }, "not run: subagent was aborted"));
|
|
930
|
+
}
|
|
931
|
+
catch (err) {
|
|
932
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
933
|
+
return {
|
|
934
|
+
content: [{ type: "text", text: `Parallel scheduling failed: ${message}` }],
|
|
935
|
+
details: detailsWithEvents(stubAllChildren(`not run: scheduling failed (${message})`)),
|
|
936
|
+
isError: true,
|
|
937
|
+
};
|
|
938
|
+
}
|
|
801
939
|
const successCount = results.filter((r) => !isFailedResult(r)).length;
|
|
802
940
|
const summaries = results.map((r) => {
|
|
803
941
|
const output = truncateParallelOutput(getResultOutput(r));
|
|
@@ -813,12 +951,12 @@ export function createSubagentToolDefinition(cwd) {
|
|
|
813
951
|
text: `Parallel: ${successCount}/${results.length} succeeded\n\n${summaries.join("\n\n---\n\n")}`,
|
|
814
952
|
},
|
|
815
953
|
],
|
|
816
|
-
details:
|
|
954
|
+
details: detailsWithEvents(results),
|
|
817
955
|
isError: successCount !== results.length,
|
|
818
956
|
};
|
|
819
957
|
}
|
|
820
958
|
if (params.agent && params.task) {
|
|
821
|
-
const result = await runSingleAgent(defaultCwd, agents, params.agent, params.task, params.cwd, params.isolation, undefined, params.model, parentModel, signal, onUpdate, makeDetails("single"), toolCallId, 0);
|
|
959
|
+
const result = await runSingleAgent(defaultCwd, agents, params.agent, params.task, params.cwd, params.isolation, undefined, params.model, parentModel, signal, onUpdate, makeDetails("single"), toolCallId, 0, { taskId: `${toolCallId}-0`, thinking: params.thinking });
|
|
822
960
|
const isError = isFailedResult(result);
|
|
823
961
|
if (isError) {
|
|
824
962
|
const errorMsg = getResultOutput(result);
|