@livx.cc/agentx 0.99.40 → 0.99.41

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/index.d.ts CHANGED
@@ -1,15 +1,15 @@
1
- import { a as AgentOptions, H as Hooks, i as RunResult, A as Agent } from './Agent-D4-CLnxC.js';
2
- export { C as ChatFragment, b as CompactResult, D as DEFAULT_MUTATING, c as Decision, P as PermissionOptions, d as PermissionPolicy, e as PermissionRule, f as PreToolUseDecision, R as ReasoningEffort, g as RecordingHooks, h as RecordingLifecycle, T as ToolUse, j as ToolUseMeta, k as composeHooks, l as estimateTokens, p as planMode, r as reasoningToChatFragment } from './Agent-D4-CLnxC.js';
1
+ import { a as AgentOptions, H as Hooks, i as RunResult, A as Agent } from './Agent-DydgLoT-.js';
2
+ export { C as ChatFragment, b as CompactResult, D as DEFAULT_MUTATING, c as Decision, P as PermissionOptions, d as PermissionPolicy, e as PermissionRule, f as PreToolUseDecision, R as ReasoningEffort, g as RecordingHooks, h as RecordingLifecycle, T as ToolUse, j as ToolUseMeta, k as composeHooks, l as estimateTokens, p as planMode, r as reasoningToChatFragment } from './Agent-DydgLoT-.js';
3
3
  export { MODEL_ALIASES, ModelSwitch, ResolveModelSwitchOpts, modelShortLabel, resolveModelAlias, resolveModelSwitch } from './models.js';
4
4
  import { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';
5
5
  export { CommandExecutor, FileMetadata, IFilesystem, IndexedDbFilesystem, MemFilesystem, registerHeadlessCommands } from '@livx.cc/wcli/core';
6
6
  import { BodDB } from '@bod.ee/db';
7
- import { A as AgentTool, C as ChatLike, a as ChatOptions, b as ChatResponse, j as ToolCall, H as HostBridge, U as UserQuestion, g as MessageContent } from './tools-BWzPQVy0.js';
8
- export { c as ContentPart, d as HostEvent, I as IMAGE_ELIDE_STUB, e as IMAGE_REF_SCHEME, f as ImageRef, M as Message, R as Role, S as SandboxJobRegistry, h as StreamChunk, T as TodoItem, i as Tool, k as ToolContext, l as bashTool, m as clearImageRefs, n as contentBytes, o as contentText, p as defaultTools, q as editTool, r as elideImages, s as elideInlineImages, t as elideStaleImages, u as exitSessionTool, v as expandImagesForSend, w as imagePart, x as imageRefPart, y as imageRefResult, z as makeContext, B as makeJobTools, D as messageHasImage, E as messageHasImageRef, F as messageHasInlineImage, G as mintImageRef, J as parseImageRef, K as readTool, L as remintImageRefs, N as sendBytes, O as sendBytesPer, P as toWireTools, Q as todoWriteTool, V as toolImageRef, W as toolRegistry, X as toolsByName } from './tools-BWzPQVy0.js';
7
+ import { A as AgentTool, C as ChatLike, a as ChatOptions, b as ChatResponse, j as ToolCall, H as HostBridge, U as UserQuestion, g as MessageContent } from './tools-S-ArIR3o.js';
8
+ export { c as ContentPart, d as HostEvent, I as IMAGE_ELIDE_STUB, e as IMAGE_REF_SCHEME, f as ImageRef, M as Message, R as Role, S as SandboxJobRegistry, h as StreamChunk, T as TodoItem, i as Tool, k as ToolContext, l as bashTool, m as clearImageRefs, n as contentBytes, o as contentText, p as defaultTools, q as editTool, r as elideImages, s as elideInlineImages, t as elideStaleImages, u as exitSessionTool, v as expandImagesForSend, w as imagePart, x as imageRefPart, y as imageRefResult, z as makeContext, B as makeJobTools, D as messageHasImage, E as messageHasImageRef, F as messageHasInlineImage, G as mintImageRef, J as parseImageRef, K as readTool, L as remintImageRefs, N as sendBytes, O as sendBytesPer, P as toWireTools, Q as todoWriteTool, V as toolImageRef, W as toolRegistry, X as toolsByName } from './tools-S-ArIR3o.js';
9
9
  import { ShellJobRegistry } from './tools.shell.js';
10
10
  import { SpokenSplitter } from '@bod.ee/voice';
11
11
  export { AudioSink, AudioSource, AuthProvider, CartesiaTTS, CartesiaTTSOptions, STT_SAMPLE_RATE, SonioxSTT, SonioxSTTOptions, SttLike, TTS_SAMPLE_RATE, TtsLike, VoiceEngine, VoiceEngineOptions, VoiceState, resolveAuth } from '@bod.ee/voice';
12
- export { M as McpCall, a as McpImage, b as McpRoute, c as McpRouteResolver, d as McpToolResult, e as McpToolSearchOptions, f as McpToolSpec, g as MountedMcpLike, h as buildMcpCatalog, m as makeLazyMcpToolSearch, i as makeMcpToolSearch, j as makeMcpToolSearchFromMounted, k as mcpToolToAgentTool, l as mcpToolsToAgentTools } from './mcp-aONOXRNk.js';
12
+ export { M as McpCall, a as McpImage, b as McpRoute, c as McpRouteResolver, d as McpToolResult, e as McpToolSearchOptions, f as McpToolSpec, g as MountedMcpLike, h as buildMcpCatalog, m as makeLazyMcpToolSearch, i as makeMcpToolSearch, j as makeMcpToolSearchFromMounted, k as mcpToolToAgentTool, l as mcpToolsToAgentTools } from './mcp-D5eN0JyQ.js';
13
13
  import * as libx_js_src_modules_log from 'libx.js/src/modules/log';
14
14
  export { log } from 'libx.js/src/modules/log';
15
15
 
@@ -1286,6 +1286,18 @@ interface TaskToolOptions {
1286
1286
  * (the child's signal is aborted) and therefore honestly declarable as the tool's `maxDurationMs`.
1287
1287
  */
1288
1288
  maxDurationMs?: number;
1289
+ /** The parent's toolbelt — the child INHERITS it by default (otherwise it falls back to the jailed
1290
+ * `defaultTools()` and loses everything the host injected: a real shell, Write/Grep, MCP tools).
1291
+ * An agentType def's `tools` allowlist still narrows it (and can name one of these by name). */
1292
+ tools?: AgentTool[];
1293
+ /** The parent's system prompt — inherited by a plain (untyped) child so it keeps the host's persona
1294
+ * instead of reverting to agentx's generic built-in one. An agentType def's body overrides it. */
1295
+ systemPrompt?: string;
1296
+ /** Provider-specific options for the CHILD's model, recomputed per child (IoC — same seam duplex uses
1297
+ * for its workers). The child's model may differ from the parent's (explicit `model` / agentType def),
1298
+ * and provider options are NOT portable across providers (cursor `cwd`/`cursorSession` on anthropic
1299
+ * is a hard 400), so they are derived, never blindly inherited. */
1300
+ providerOptionsFor?: (model: string) => Record<string, unknown> | undefined;
1289
1301
  /** Origin-anchored real-disk dir for child transcript traces (see `AgentOptions.traceDir`). Passed
1290
1302
  * down UNCHANGED to nested children so every level writes to the same origin `.agent`. */
1291
1303
  traceDir?: string;
package/dist/index.js CHANGED
@@ -1363,11 +1363,12 @@ function toolRegistry() {
1363
1363
  const all = [bashTool, readTool, editTool, grepTool, globTool, writeTool, multiEditTool, applyEditsTool, repoMapTool, reviewTool(), todoWriteTool, webFetchTool, webSearchTool, webSearchAnthropicTool];
1364
1364
  return Object.fromEntries(all.map((t) => [t.name, t]));
1365
1365
  }
1366
- function toolsByName(names) {
1366
+ function toolsByName(names, available) {
1367
1367
  const reg = toolRegistry();
1368
+ const extra = Object.fromEntries((available ?? []).map((t) => [t.name, t]));
1368
1369
  return names.map((n) => {
1369
- const t = reg[n];
1370
- if (!t) throw new Error(`unknown tool '${n}'. Known: ${Object.keys(reg).join(", ")}`);
1370
+ const t = extra[n] ?? reg[n];
1371
+ if (!t) throw new Error(`unknown tool '${n}'. Known: ${[.../* @__PURE__ */ new Set([...Object.keys(extra), ...Object.keys(reg)])].join(", ")}`);
1371
1372
  return t;
1372
1373
  });
1373
1374
  }
@@ -1995,6 +1996,24 @@ function makeRealShellTool(options) {
1995
1996
  };
1996
1997
  return {
1997
1998
  name: "Shell",
1999
+ // Rebind for an isolated child agent (git worktree): same policy/env/timeouts, new cwd. The
2000
+ // `registry` is deliberately dropped — it is bound to the PARENT's cwd (and, in hosts like
2001
+ // shraga-ee, to the parent's session), so a background job started from the child would run
2002
+ // outside the child's isolation and report into the parent. Background stays a parent capability
2003
+ // (`makeShellJobTools`' companions drop out of an isolated child entirely — see their `withCwd`).
2004
+ // Only `run` is rebuilt: everything else is carried over from THIS instance, because a host may
2005
+ // have mutated the tool AFTER construction (shraga-ee renames `Shell` -> `Bash` and its system
2006
+ // prompt says `Bash` everywhere). Rebuilding from `options` alone silently dropped that rename,
2007
+ // so a worktree child advertised `Shell` while being told to call `Bash` — an unknown-tool error
2008
+ // on its first call, and a hard failure for an agentType def whose allowlist names `Bash`.
2009
+ // `description` is the ONE thing taken from the rebound tool instead: it is derived from the
2010
+ // options and states whether `background:true` works — the rebind drops the registry, so carrying
2011
+ // the parent's text over would advertise a background capability the child does not have. (The
2012
+ // spread also collapses the getter below to a plain value, which is why this override is explicit.)
2013
+ withCwd(cwd) {
2014
+ const rebound = makeRealShellTool({ ...options, cwd, registry: void 0 });
2015
+ return { ...this, description: rebound.description, run: rebound.run, withCwd: rebound.withCwd };
2016
+ },
1998
2017
  get description() {
1999
2018
  return `Run a shell command via /bin/sh in the working directory. Executes any installed binary \u2014 ls, cat, grep, git, bun, node, curl, scripts, etc. Returns combined stdout+stderr; non-zero exits are prefixed \`[exit N]\`. Runs non-interactively with no terminal (stdin is /dev/null): commands that prompt for input fail fast rather than hang \u2014 for privileged actions use a non-interactive flag (e.g. \`sudo -n\`), or ask the user to run the command themselves. Each command is killed after ${defaultTimeoutMs}ms (result \`[exit 124]\` with whatever output it produced) \u2014 pass \`timeoutMs\` (max ${maxTimeoutMs}) for a legitimately slower command, and always bound network commands yourself (e.g. \`curl -m 10\`). ` + backgroundDoc();
2000
2019
  },
@@ -2108,8 +2127,10 @@ ${body}` : head;
2108
2127
  }
2109
2128
  function makeShellJobTools(registry) {
2110
2129
  const idParam = { type: "object", properties: { id: { type: "string", description: "the job id from Shell({background:true})" } } };
2130
+ const dropOnRebind = { withCwd: () => void 0 };
2111
2131
  return [
2112
2132
  {
2133
+ ...dropOnRebind,
2113
2134
  name: "ShellOutput",
2114
2135
  description: "Read the accumulated output (tail) of a background Shell job by id.",
2115
2136
  parameters: { type: "object", required: ["id"], properties: { id: { type: "string" } } },
@@ -2122,6 +2143,7 @@ ${clean(out) || "(no output yet)"}`;
2122
2143
  }
2123
2144
  },
2124
2145
  {
2146
+ ...dropOnRebind,
2125
2147
  name: "ShellStatus",
2126
2148
  description: "Status of a background Shell job (running/exited/killed + exit code). Omit `id` to list all jobs.",
2127
2149
  parameters: idParam,
@@ -2135,6 +2157,7 @@ ${clean(out) || "(no output yet)"}`;
2135
2157
  }
2136
2158
  },
2137
2159
  {
2160
+ ...dropOnRebind,
2138
2161
  name: "ShellKill",
2139
2162
  description: "Stop a running background Shell job by id (SIGTERM).",
2140
2163
  parameters: { type: "object", required: ["id"], properties: { id: { type: "string" } } },
@@ -2946,6 +2969,53 @@ ${sections.join("\n\n---\n\n")}`;
2946
2969
  init_tools();
2947
2970
  import { mkdirSync as mkdirSync2, writeFileSync } from "fs";
2948
2971
  import { join as join3 } from "path";
2972
+
2973
+ // src/models.ts
2974
+ var MODEL_ALIASES = {
2975
+ fable: "claude-fable-5",
2976
+ "fable-5": "claude-fable-5",
2977
+ opus: "claude-opus-4-8",
2978
+ "opus-4-8": "claude-opus-4-8",
2979
+ "opus-4-7": "claude-opus-4-7",
2980
+ "opus-4-6": "claude-opus-4-6",
2981
+ sonnet: "claude-sonnet-4-6",
2982
+ haiku: "claude-haiku-4-5-20251001"
2983
+ };
2984
+ function resolveModelAlias(input) {
2985
+ const slash = input.indexOf("/");
2986
+ const prefix = slash === -1 ? "" : input.slice(0, slash + 1);
2987
+ const rest = slash === -1 ? input : input.slice(slash + 1);
2988
+ return prefix + (MODEL_ALIASES[rest.toLowerCase()] ?? rest);
2989
+ }
2990
+ function modelProvider(model) {
2991
+ const i = model.indexOf("/");
2992
+ if (i !== -1) return model.slice(0, i);
2993
+ if (/^claude-/i.test(model)) return "anthropic";
2994
+ return `?${model}`;
2995
+ }
2996
+ function modelShortLabel(model) {
2997
+ if (!model) return "default";
2998
+ const id = model.split("/").pop();
2999
+ return id.replace(/^claude-/, "").replace(/-\d.*$/, "");
3000
+ }
3001
+ function resolveModelSwitch(opts) {
3002
+ const { requested, current, prior, allowed } = opts;
3003
+ if (!requested) return { model: current, denied: false };
3004
+ if (allowed && !allowed.some((a) => modelShortLabel(a) === modelShortLabel(requested))) {
3005
+ return { model: current, denied: true };
3006
+ }
3007
+ const fmt = opts.format ?? ((from, to) => `_[switching from ${from} to ${to}]_
3008
+
3009
+ `);
3010
+ const changed = prior !== void 0 && modelShortLabel(prior) !== modelShortLabel(requested);
3011
+ return {
3012
+ model: requested,
3013
+ denied: false,
3014
+ notice: changed ? fmt(modelShortLabel(prior), modelShortLabel(requested)) : void 0
3015
+ };
3016
+ }
3017
+
3018
+ // src/subagent.ts
2949
3019
  init_OverlayFilesystem();
2950
3020
 
2951
3021
  // src/worktree.ts
@@ -3154,6 +3224,14 @@ function createWorktreeFs(cwd, label, index) {
3154
3224
  function releaseWorktree(handle) {
3155
3225
  return cleanupWorktree(handle.repoRoot, handle.slug, { force: true });
3156
3226
  }
3227
+ function rebindTools(tools, root) {
3228
+ if (!tools || !root) return tools;
3229
+ return tools.flatMap((t) => {
3230
+ if (!t.withCwd) return [t];
3231
+ const rebound = t.withCwd(root);
3232
+ return rebound ? [rebound] : [];
3233
+ });
3234
+ }
3157
3235
  function worktreePromptPrefix(branch) {
3158
3236
  return `You are running in an isolated git worktree on branch "${branch}". When you finish making changes, commit them with a clear message before replying with your summary. Your worktree will be removed after you finish \u2014 only committed work survives (on the branch).
3159
3237
 
@@ -3221,22 +3299,30 @@ async function runChildTraced(args) {
3221
3299
  await opts.hooks?.onSubagentStop?.(result, { label, agentType });
3222
3300
  return { res, result };
3223
3301
  }
3224
- function childOptionsFor(opts, fs, depth, maxDepth, agentType) {
3302
+ function childOptionsFor(opts, fs, depth, maxDepth, agentType, model, root) {
3225
3303
  let def;
3226
3304
  if (agentType) {
3227
3305
  def = (opts.agents ?? []).find((a) => a.name === agentType);
3228
3306
  if (!def) return `no subagent type '${agentType}'. Available: ${(opts.agents ?? []).map((a) => a.name).join(", ") || "(none defined)"}`;
3229
3307
  }
3230
- const childOpts = { ai: opts.ai, fs, model: def?.model ?? opts.model, subagents: true, depth: depth + 1, maxDepth, traceDir: opts.traceDir };
3308
+ const childModel = resolveModelAlias(model || def?.model || opts.model);
3309
+ const childOpts = { ai: opts.ai, fs, model: childModel, subagents: true, depth: depth + 1, maxDepth, traceDir: opts.traceDir };
3231
3310
  if (opts.maxSteps != null) childOpts.maxSteps = opts.maxSteps;
3232
- if (def?.systemPrompt) childOpts.systemPrompt = def.systemPrompt;
3311
+ const childPrompt = def?.systemPrompt ?? opts.systemPrompt;
3312
+ if (childPrompt) childOpts.systemPrompt = childPrompt;
3313
+ const inherited = rebindTools(opts.tools, root);
3233
3314
  if (def?.tools?.length) {
3234
3315
  try {
3235
- childOpts.tools = toolsByName(def.tools);
3316
+ childOpts.tools = toolsByName(def.tools, inherited);
3236
3317
  } catch (e) {
3237
3318
  return `subagent '${agentType}' declares an unknown tool \u2014 ${e.message}`;
3238
3319
  }
3320
+ } else if (inherited?.length) {
3321
+ childOpts.tools = inherited;
3239
3322
  }
3323
+ const po = opts.providerOptionsFor?.(childModel);
3324
+ if (po) childOpts.providerOptions = po;
3325
+ if (opts.hooks?.preToolUse) childOpts.hooks = { preToolUse: opts.hooks.preToolUse.bind(opts.hooks) };
3240
3326
  return childOpts;
3241
3327
  }
3242
3328
  function makeTaskTool(opts) {
@@ -3244,7 +3330,7 @@ function makeTaskTool(opts) {
3244
3330
  const maxDepth = opts.maxDepth ?? 2;
3245
3331
  return {
3246
3332
  name: "Task",
3247
- description: 'Delegate a self-contained sub-task to a child agent over the same filesystem. It runs autonomously with its own step budget and a wall-clock deadline, and returns a concise summary \u2014 use to isolate context-heavy work (broad search, a scoped refactor). Provide a short `description` and a full `prompt`. If it is interrupted or fails, the result is a STATUS HINT with a pointer to its full transcript (Read it to recover what it did, then decide whether to continue or restart) \u2014 do not assume an incomplete sub-task succeeded. Set `background: true` to run it detached (returns a job id to poll with JobOutput while you keep working); its file edits are overlay-isolated and commit when it finishes. Set `isolation: "worktree"` to run in a real git worktree (needed when the child uses real shell commands that must see/modify actual files) \u2014 slower (~200ms setup), auto-cleaned if no changes.',
3333
+ description: 'Delegate a self-contained sub-task to a child agent over the same filesystem. It runs autonomously with its own step budget and a wall-clock deadline, and returns a concise summary \u2014 use to isolate context-heavy work (broad search, a scoped refactor). Provide a short `description` and a full `prompt`. If it is interrupted or fails, the result is a STATUS HINT with a pointer to its full transcript (Read it to recover what it did, then decide whether to continue or restart) \u2014 do not assume an incomplete sub-task succeeded. Set `background: true` to run it detached (returns a job id to poll with JobOutput while you keep working); its VFS file edits are overlay-isolated and commit when it finishes \u2014 but a child that uses the real `Shell` writes straight to the working tree (an overlay cannot isolate a real process), so pair shell-heavy work with `isolation: "worktree"`. Set `isolation: "worktree"` to run in a real git worktree (needed when the child uses real shell commands that must see/modify actual files \u2014 its shell is re-bound to the worktree \u2014 keeping any name your host gave it \u2014 and background shell jobs, including inspecting or killing MINE, are unavailable there) \u2014 slower (~200ms setup), auto-cleaned if no changes. The child inherits YOUR tools and system prompt by default (and is subject to the same tool-use gate); pass `model` to run this one sub-task on a different model (e.g. a cheap one for bulk search, a stronger one for hard reasoning) \u2014 it overrides the agentType default.',
3248
3334
  parameters: {
3249
3335
  type: "object",
3250
3336
  required: ["description", "prompt"],
@@ -3252,6 +3338,7 @@ function makeTaskTool(opts) {
3252
3338
  description: { type: "string", description: "a short (3-5 word) label for the sub-task" },
3253
3339
  prompt: { type: "string", description: "the full instructions the child agent should carry out" },
3254
3340
  agentType: { type: "string", description: "optional named subagent type (its persona, model, and scoped tools) \u2014 see the catalog" },
3341
+ model: { type: "string", description: 'optional model for THIS sub-task (alias like "haiku"/"opus"/"sonnet", or a full id). Overrides the agentType default; otherwise the child runs on your model.' },
3255
3342
  background: { type: "boolean", description: "run detached (overlay-isolated, commits on finish); returns a job id to poll with JobOutput instead of blocking" },
3256
3343
  isolation: { type: "string", enum: ["overlay", "worktree"], description: 'isolation mode: "overlay" (default, VFS layer) or "worktree" (real git worktree for shell-heavy work)' }
3257
3344
  }
@@ -3262,7 +3349,7 @@ function makeTaskTool(opts) {
3262
3349
  maxDurationMs: opts.maxDurationMs ?? SUBAGENT_MAX_DURATION_MS,
3263
3350
  maxDurationEnforced: true,
3264
3351
  // the wall clock below ABORTS the child at this bound — it cannot be overrun, so the transport needs slack, not a doubling
3265
- async run({ description, prompt, agentType, background, isolation }, ctx) {
3352
+ async run({ description, prompt, agentType, model, background, isolation }, ctx) {
3266
3353
  if (depth >= maxDepth) {
3267
3354
  return `Error: Task depth limit reached (maxDepth ${maxDepth}). Cannot spawn another child agent \u2014 do this work directly instead.`;
3268
3355
  }
@@ -3285,7 +3372,7 @@ function makeTaskTool(opts) {
3285
3372
  fs2 = overlay;
3286
3373
  commit = () => overlay.commit();
3287
3374
  }
3288
- const childOpts2 = childOptionsFor(opts, fs2, depth, maxDepth, agentType);
3375
+ const childOpts2 = childOptionsFor(opts, fs2, depth, maxDepth, agentType, model, wtHandle2?.worktreePath);
3289
3376
  if (typeof childOpts2 === "string") throw new Error(childOpts2);
3290
3377
  const childPrompt = wtHandle2 ? worktreePromptPrefix(wtHandle2.branch) + String(prompt ?? "") : String(prompt ?? "");
3291
3378
  const { res, result } = await runChildTraced({ opts, childOpts: childOpts2, prompt: childPrompt, label, agentType, childDepth: depth + 1, signal });
@@ -3315,7 +3402,7 @@ function makeTaskTool(opts) {
3315
3402
  } else {
3316
3403
  fs = opts.fs;
3317
3404
  }
3318
- const childOpts = childOptionsFor(opts, fs, depth, maxDepth, agentType);
3405
+ const childOpts = childOptionsFor(opts, fs, depth, maxDepth, agentType, model, wtHandle?.worktreePath);
3319
3406
  if (typeof childOpts === "string") {
3320
3407
  wtHandle && releaseWorktree(wtHandle);
3321
3408
  return `Error: ${childOpts}`;
@@ -3344,7 +3431,7 @@ function makeTaskBatchTool(opts) {
3344
3431
  const maxParallel = opts.maxParallel ?? 4;
3345
3432
  return {
3346
3433
  name: "TaskBatch",
3347
- description: 'Delegate SEVERAL independent sub-tasks to child agents that run concurrently; returns all their summaries. Each child is write-isolated (its file edits are merged back in array order). Use for parallel fan-out (review/search/scoped refactors across files). Provide `tasks: [{ description, prompt, agentType? }]`. Set `isolation: "worktree"` to run each child in its own git worktree (needed for real shell commands) \u2014 slower, auto-cleaned if no changes.',
3434
+ description: 'Delegate SEVERAL independent sub-tasks to child agents that run concurrently; returns all their summaries. Each child is write-isolated at the VFS level (its file edits are merged back in array order); real `Shell` commands are NOT \u2014 use `isolation: "worktree"` for those. Use for parallel fan-out (review/search/scoped refactors across files). Provide `tasks: [{ description, prompt, agentType?, model? }]` \u2014 each child inherits your tools and system prompt, and `model` runs that one child on a different model. Set `isolation: "worktree"` to run each child in its own git worktree (needed for real shell commands) \u2014 slower, auto-cleaned if no changes.',
3348
3435
  parameters: {
3349
3436
  type: "object",
3350
3437
  required: ["tasks"],
@@ -3358,7 +3445,8 @@ function makeTaskBatchTool(opts) {
3358
3445
  properties: {
3359
3446
  description: { type: "string", description: "a short (3-5 word) label" },
3360
3447
  prompt: { type: "string", description: "the full instructions for this child" },
3361
- agentType: { type: "string", description: "optional named subagent type" }
3448
+ agentType: { type: "string", description: "optional named subagent type" },
3449
+ model: { type: "string", description: "optional model for this child (alias or full id); overrides the agentType default" }
3362
3450
  }
3363
3451
  }
3364
3452
  },
@@ -3391,7 +3479,7 @@ function makeTaskBatchTool(opts) {
3391
3479
  overlay = new OverlayFilesystem(opts.fs);
3392
3480
  fs = overlay;
3393
3481
  }
3394
- const childOpts = childOptionsFor(opts, fs, depth, maxDepth, t?.agentType);
3482
+ const childOpts = childOptionsFor(opts, fs, depth, maxDepth, t?.agentType, t?.model, wtHandle?.worktreePath);
3395
3483
  if (typeof childOpts === "string") return { label, error: childOpts, ok: false };
3396
3484
  try {
3397
3485
  const childPrompt = wtHandle ? worktreePromptPrefix(wtHandle.branch) + String(t?.prompt ?? "") : String(t?.prompt ?? "");
@@ -3818,6 +3906,10 @@ var AgentOptions = class {
3818
3906
  autoTest;
3819
3907
  /** Provider-specific options forwarded to ai.chat() (e.g. cursor mcpServers, cwd). */
3820
3908
  providerOptions;
3909
+ /** Derive `providerOptions` for a DELEGATED child whose model may differ from this agent's
3910
+ * (`Task({ model })` / an agentType def). Default: inherit `providerOptions` only when the child's
3911
+ * model is on the SAME provider — cursor's `cwd`/`cursorSession` on an anthropic child is a 400. */
3912
+ providerOptionsFor;
3821
3913
  /** Prompt caching (providers that support it, e.g. Anthropic): cache tools/system/conversation
3822
3914
  * prefix across the loop's steps — reads cost 0.1x, writes 1.25x. A multi-step agent loop
3823
3915
  * re-sends its whole prefix every step, so this is a large net cost cut. Default on. */
@@ -4041,7 +4133,19 @@ var Agent = class _Agent {
4041
4133
  agents = loaded.agents;
4042
4134
  if (loaded.catalog) systemPrompt += "\n\n" + loaded.catalog;
4043
4135
  }
4044
- const taskOpts = { ai: o.ai, model: o.model, fs, depth: o.depth, maxDepth: o.maxDepth, agents, hooks: o.hooks, traceDir: o.traceDir };
4136
+ const taskOpts = {
4137
+ ai: o.ai,
4138
+ model: o.model,
4139
+ fs,
4140
+ depth: o.depth,
4141
+ maxDepth: o.maxDepth,
4142
+ agents,
4143
+ hooks: o.hooks,
4144
+ traceDir: o.traceDir,
4145
+ tools: [...o.tools, ...this.injectedTools],
4146
+ systemPrompt: o.systemPrompt,
4147
+ providerOptionsFor: o.providerOptionsFor ?? ((m) => modelProvider(m) === modelProvider(o.model) ? o.providerOptions : void 0)
4148
+ };
4045
4149
  tools = [...tools, makeTaskTool(taskOpts), makeTaskBatchTool(taskOpts)];
4046
4150
  }
4047
4151
  if (o.checkpoints) tools = [...tools, ...checkpointTools()];
@@ -4906,45 +5010,6 @@ function lastAssistantText(messages) {
4906
5010
  return "";
4907
5011
  }
4908
5012
 
4909
- // src/models.ts
4910
- var MODEL_ALIASES = {
4911
- fable: "claude-fable-5",
4912
- "fable-5": "claude-fable-5",
4913
- opus: "claude-opus-4-8",
4914
- "opus-4-8": "claude-opus-4-8",
4915
- "opus-4-7": "claude-opus-4-7",
4916
- "opus-4-6": "claude-opus-4-6",
4917
- sonnet: "claude-sonnet-4-6",
4918
- haiku: "claude-haiku-4-5-20251001"
4919
- };
4920
- function resolveModelAlias(input) {
4921
- const slash = input.indexOf("/");
4922
- const prefix = slash === -1 ? "" : input.slice(0, slash + 1);
4923
- const rest = slash === -1 ? input : input.slice(slash + 1);
4924
- return prefix + (MODEL_ALIASES[rest.toLowerCase()] ?? rest);
4925
- }
4926
- function modelShortLabel(model) {
4927
- if (!model) return "default";
4928
- const id = model.split("/").pop();
4929
- return id.replace(/^claude-/, "").replace(/-\d.*$/, "");
4930
- }
4931
- function resolveModelSwitch(opts) {
4932
- const { requested, current, prior, allowed } = opts;
4933
- if (!requested) return { model: current, denied: false };
4934
- if (allowed && !allowed.some((a) => modelShortLabel(a) === modelShortLabel(requested))) {
4935
- return { model: current, denied: true };
4936
- }
4937
- const fmt = opts.format ?? ((from, to) => `_[switching from ${from} to ${to}]_
4938
-
4939
- `);
4940
- const changed = prior !== void 0 && modelShortLabel(prior) !== modelShortLabel(requested);
4941
- return {
4942
- model: requested,
4943
- denied: false,
4944
- notice: changed ? fmt(modelShortLabel(prior), modelShortLabel(requested)) : void 0
4945
- };
4946
- }
4947
-
4948
5013
  // src/index.ts
4949
5014
  init_NodeDiskFilesystem();
4950
5015