@rubytech/taskmaster 1.23.0 → 1.24.0

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.
@@ -300,9 +300,17 @@ export function buildAgentSystemPrompt(params) {
300
300
  "- cron: manage scheduled events and wake events (use for reminders; when scheduling a reminder, write the systemEvent text as something that will read like a reminder when it fires, and mention that it is a reminder depending on the time gap between setting and firing; include recent context in reminder text if appropriate)",
301
301
  "- sessions_list: list sessions",
302
302
  "- sessions_history: fetch session history",
303
+ "- sessions_spawn: spawn a background sub-agent for a task (returns immediately; result is announced when done)",
303
304
  ].join("\n"),
304
305
  "TOOLS.md does not control tool availability; it is user guidance for how to use external tools.",
305
- "If a task is more complex or takes longer, spawn a sub-agent. It will do the work for you and ping you when it's done. You can always check up on it.",
306
+ "## Delegation",
307
+ "Your default mode is to delegate work to sub-agents. Any task beyond a straightforward conversational reply should be handled by a sub-agent via `sessions_spawn`.",
308
+ "Delegation keeps you responsive — you hand off the work and continue chatting. The sub-agent runs in the background; when it finishes, its result is announced back into this conversation automatically.",
309
+ "",
310
+ "**Delegate when the task involves:** tool calls (file reads/writes, memory operations, web searches, document reading, image generation, research, calculations, composing longer content, or any multi-step work).",
311
+ "**Handle inline only when:** the response is purely conversational — a greeting, a quick factual answer from your own knowledge, a yes/no, or a brief opinion that requires no tool calls.",
312
+ "",
313
+ "When spawning, provide a clear `task` description and a short `label` so you can track it. You don't need to tell the user you're delegating — just do it. The result will flow back naturally.",
306
314
  "",
307
315
  "## Tool Call Style",
308
316
  "Every text block you produce is delivered as a separate message. Unnecessary text blocks = unnecessary messages sent to the user.",
@@ -29,7 +29,12 @@ const PUBLIC_AGENT_INDICATORS = [
29
29
  /** Formatting section headers commonly found at the end of AGENTS files. */
30
30
  const FORMATTING_HEADERS = ["## WhatsApp Formatting", "## Message Formatting", "## Formatting"];
31
31
  /** Section headers that typically precede "## Capabilities" in admin agents. */
32
- const CAPABILITIES_HEADERS = ["## Capabilities", "## Stripe CLI Operations", "## User Management"];
32
+ const CAPABILITIES_HEADERS = [
33
+ "## Capabilities",
34
+ "## Tools",
35
+ "## Stripe CLI Operations",
36
+ "## User Management",
37
+ ];
33
38
  function isPublicAgent(content) {
34
39
  return PUBLIC_AGENT_INDICATORS.some((p) => content.includes(p));
35
40
  }
@@ -703,6 +708,67 @@ async function patchBeagleAdminDriverContactTone(_agentsPath, content) {
703
708
  return null;
704
709
  return content.replace(ADMIN_DRIVER_CONTACT_OLD, ADMIN_DRIVER_CONTACT_NEW);
705
710
  }
711
+ // ---------------------------------------------------------------------------
712
+ // Migration: Sub-Agent Delegation (v1.24)
713
+ // ---------------------------------------------------------------------------
714
+ const DELEGATION_SECTION = `## Delegation — Sub-Agents
715
+
716
+ **Default to delegation.** Any task that requires tool calls — reading files, searching memory, generating content, web lookups, document processing, image work — should be spawned as a sub-agent using \`sessions_spawn\`. You stay free to keep chatting with the business owner.
717
+
718
+ **How it works:**
719
+ 1. Call \`sessions_spawn\` with a clear \`task\` and a short \`label\`
720
+ 2. The sub-agent runs in the background with the same tools and memory access you have
721
+ 3. When it finishes, its result is announced back into your conversation automatically
722
+ 4. You summarise the result naturally — don't mention sub-agents or background tasks
723
+
724
+ **Delegate:**
725
+ - Memory searches and lookups
726
+ - File reading/writing
727
+ - Document reading (PDFs, DOCX, etc.)
728
+ - Web searches and fetches
729
+ - Content creation (drafts, summaries, reports)
730
+ - Image generation
731
+ - Multi-step research tasks
732
+ - Anything that takes more than a moment
733
+
734
+ **Handle inline (no delegation):**
735
+ - Quick conversational replies (greetings, opinions, yes/no)
736
+ - Brief factual answers you already know
737
+ - Clarifying questions before starting work
738
+ - Confirming or acknowledging something the owner said
739
+
740
+ When multiple independent tasks come up, spawn multiple sub-agents in parallel. Don't wait for one to finish before starting the next.`;
741
+ function hasDelegationSection(content) {
742
+ return content.includes("## Delegation") || content.includes("sessions_spawn");
743
+ }
744
+ async function patchDelegationSection(_agentsPath, content) {
745
+ if (isPublicAgent(content))
746
+ return null;
747
+ if (hasDelegationSection(content))
748
+ return null;
749
+ return insertSection(content, DELEGATION_SECTION, findCapabilitiesInsertPoint);
750
+ }
751
+ // ---------------------------------------------------------------------------
752
+ // SOUL.md Migration: Sub-Agent Delegation (v1.24)
753
+ // ---------------------------------------------------------------------------
754
+ const SOUL_DELEGATION_SECTION = `## How You Work
755
+
756
+ **Delegate everything that isn't a quick reply.** Your role is to stay responsive — thinking, conversing, and directing. Actual work (research, file operations, document reading, content creation, memory lookups, calculations) gets handed to sub-agents via \`sessions_spawn\`. They run in the background and report back when done. You keep chatting.`;
757
+ function soulHasDelegation(content) {
758
+ return content.includes("## How You Work") || content.includes("sessions_spawn");
759
+ }
760
+ async function patchSoulDelegation(content) {
761
+ if (soulHasDelegation(content))
762
+ return null;
763
+ // Insert before "## What You Don't Do" if present
764
+ const insertBefore = "## What You Don't Do";
765
+ const idx = content.indexOf(insertBefore);
766
+ if (idx !== -1) {
767
+ return content.slice(0, idx) + SOUL_DELEGATION_SECTION + "\n\n" + content.slice(idx);
768
+ }
769
+ // Fallback: append
770
+ return content.trimEnd() + "\n\n" + SOUL_DELEGATION_SECTION + "\n";
771
+ }
706
772
  const MIGRATIONS = [
707
773
  { name: "skill-recommendations", apply: patchSkillRecommendations },
708
774
  { name: "owner-learning", apply: patchOwnerLearning },
@@ -720,6 +786,7 @@ const MIGRATIONS = [
720
786
  { name: "beagle-public-tourist-phone", apply: patchBeaglePublicTouristPhone },
721
787
  { name: "beagle-admin-driver-reply-explicit", apply: patchBeagleAdminDriverReplyExplicit },
722
788
  { name: "beagle-admin-driver-contact-tone", apply: patchBeagleAdminDriverContactTone },
789
+ { name: "delegation-section", apply: patchDelegationSection },
723
790
  ];
724
791
  /**
725
792
  * Run all workspace migrations for every configured agent.
@@ -760,5 +827,20 @@ export async function runWorkspaceMigrations(cfg) {
760
827
  log.warn(`failed to write AGENTS.md for agent "${agentId}": ${String(err)}`);
761
828
  }
762
829
  }
830
+ // SOUL.md migrations (admin agents only)
831
+ const soulPath = path.join(wsDir, "SOUL.md");
832
+ try {
833
+ const soulContent = await fs.readFile(soulPath, "utf-8");
834
+ if (!isPublicAgent(content)) {
835
+ const soulResult = await patchSoulDelegation(soulContent);
836
+ if (soulResult !== null) {
837
+ await fs.writeFile(soulPath, soulResult, "utf-8");
838
+ log.info(`patched SOUL.md for agent "${agentId}": delegation`);
839
+ }
840
+ }
841
+ }
842
+ catch {
843
+ // No SOUL.md or read error — skip.
844
+ }
763
845
  }
764
846
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.23.0",
3
- "commit": "5f986ce0b2d43f417ba758b5088fe32301c97fd8",
4
- "builtAt": "2026-03-07T07:28:38.033Z"
2
+ "version": "1.24.0",
3
+ "commit": "83d5e346e0e5015508f4c0771f27c53e03f49fa8",
4
+ "builtAt": "2026-03-07T09:26:50.521Z"
5
5
  }
@@ -294,6 +294,41 @@ export function reconcileSkillReadTool(params) {
294
294
  }
295
295
  return { config, changes };
296
296
  }
297
+ /**
298
+ * Add `sessions_spawn` to admin agents whose explicit allow list has
299
+ * `sessions_list` but lacks `sessions_spawn`.
300
+ *
301
+ * `sessions_spawn` was added to `group:sessions` but most admin agents use
302
+ * individual tool names rather than the group reference. This reconciliation
303
+ * patches them on gateway startup so sub-agent delegation works.
304
+ *
305
+ * Runs unconditionally on gateway startup. Idempotent — skips agents that
306
+ * already have `sessions_spawn` or `group:sessions`.
307
+ */
308
+ export function reconcileSessionsSpawnTool(params) {
309
+ const config = structuredClone(params.config);
310
+ const changes = [];
311
+ const agents = config.agents?.list;
312
+ if (!Array.isArray(agents))
313
+ return { config, changes };
314
+ for (const agent of agents) {
315
+ if (!agent || !isAdminAgent(agent))
316
+ continue;
317
+ const allow = agent.tools?.allow;
318
+ if (!Array.isArray(allow))
319
+ continue;
320
+ // Already covered
321
+ if (allow.includes("sessions_spawn") || allow.includes("group:sessions"))
322
+ continue;
323
+ // Only patch agents that have sessions_list (confirms they use individual session tool names)
324
+ if (!allow.includes("sessions_list"))
325
+ continue;
326
+ const idx = allow.indexOf("sessions_list");
327
+ allow.splice(idx + 1, 0, "sessions_spawn");
328
+ changes.push(`Added sessions_spawn to agent "${agent.id ?? "<unnamed>"}" tools.allow.`);
329
+ }
330
+ return { config, changes };
331
+ }
297
332
  /**
298
333
  * Individual skill tool names that should be replaced by `group:skills`.
299
334
  * Matches the members of TOOL_GROUPS["group:skills"] in tool-policy.ts.