Skip to main content

v2.4.0

Released: June 28, 2026

Highlights

  • Agent Spawning (@toolpack-sdk/agents) — configure templates on BaseAgent.spawn and the SDK injects spawn_agent / spawn_agents_parallel tools into every run() call; the LLM picks a template, hands off a task, gets the result back, and continues — all within a single conversation turn
  • Hot Reload & Graceful Restart (@toolpack-sdk/agents) — HotReloadWatcher watches .ts/.tsx and .env* files, debounces rapid edits, compiles TypeScript automatically, then calls registry.scheduleRestart() which waits for all in-flight conversations to finish before calling process.exit(0)
  • Dynamic agent management (@toolpack-sdk/agents) — AgentRegistry.addAgent() and removeAgent() allow agents to be wired and started (or stopped and unregistered) at runtime after the registry is already running
  • EphemeralAgent exported (@toolpack-sdk/agents) — the lightweight one-shot agent used internally by the spawn tools is now a public export for direct use in tests and advanced orchestration

Breaking changes

None.


@toolpack-sdk/agents

Agent Spawning

Set spawn on any BaseAgent to let the LLM instantiate one-off helper agents on demand:

import { BaseAgent } from '@toolpack-sdk/agents';
import type { AgentSpawnConfig } from '@toolpack-sdk/agents';

class OrchestratorAgent extends BaseAgent {
name = 'orchestrator';
description = 'Coordinates research and coding tasks';
mode = 'agent';

spawn: AgentSpawnConfig = {
enabled: true,
templates: [
{
name: 'researcher',
description: 'Searches the web and summarises findings on a topic.',
systemPrompt: (task) => `You are a focused research agent. Task: ${task}`,
},
{
name: 'coder',
description: 'Writes or refactors code for a specific request.',
systemPrompt: (task) => `You are a senior engineer. Task: ${task}`,
model: 'claude-opus-4-8',
},
],
maxDepth: 3,
};

async invokeAgent(input) {
return this.run(input.message);
}
}

When run() executes, two tools are injected into the LLM's tool list:

  • spawn_agent — spawn one helper agent and await its result
  • spawn_agents_parallel — spawn multiple agents simultaneously via Promise.all

Spawned agents are ephemeral: no channels, no registry entry, discarded after use. They inherit the parent's spawn config so they can themselves spawn (up to maxDepth, default 3).

Key template options:

OptionTypeDescription
namestringUnique identifier. Use 'self' for self-replication.
descriptionstringPurpose shown to the LLM so it picks the right template.
systemPrompt(task: string) => stringCalled at spawn time with the task string.
modelstringModel override. Inherits parent when omitted.
allowPromptAdditionbooleanAllow LLM to append extra instructions via systemPromptAddition. Default: false.

Self-replication: add { name: 'self', ... } to templates. The replica inherits the parent's mode and system prompt with the template's systemPrompt(task) appended.

Depth cap: at maxDepth, the spawn tools are silently omitted from the spawned agent's run() call — no error is thrown.

systemPromptAddition in schema: the systemPromptAddition parameter only appears in the tool schema when at least one template has allowPromptAddition: true.

See spawn.md for the full guide.


Hot Reload & Graceful Restart

HotReloadWatcher watches source directories and triggers a graceful process restart:

import { AgentRegistry, HotReloadWatcher } from '@toolpack-sdk/agents';

const registry = new AgentRegistry([myAgent]);
await registry.start();

const watcher = new HotReloadWatcher({
watchPaths: ['./src'],
cwd: process.cwd(),
debounceMs: 30_000, // default: 30 s of silence before acting
onRestartNeeded: () => registry.scheduleRestart(),
onCompileError: (msg) => console.error('[tsc]', msg),
});
watcher.start();

Flow:

  1. A file change is detected. The debounce timer resets on every new change.
  2. After the debounce window of silence:
    • .ts / .tsx → runs npx tsc --build. On exit 0, calls onRestartNeeded. On non-zero, calls onCompileError (no restart).
    • .env* → calls onRestartNeeded directly (no compile step).
  3. registry.scheduleRestart() checks isAllIdle() immediately. If all agents are idle, restarts right away. Otherwise waits for agent:complete events.
  4. After maxWaitMinutes (default 30), forces the restart regardless.
  5. process.exit(0) — PM2 / systemd brings the process back with the new dist/ and .env.

scheduleRestart() is idempotent — subsequent calls are no-ops.

Pair with SQLiteConversationStore to preserve conversation history across restarts:

import { SQLiteConversationStore } from 'toolpack-sdk';

class MyAgent extends BaseAgent {
conversationHistory = new SQLiteConversationStore({ dbPath: './conversations.db' });
}

See hot-reload.md for the full guide.


Dynamic agent management

AgentRegistry now supports adding and removing agents at runtime after start():

// Add — wired + started immediately if the registry is already running
await registry.addAgent(new ResearchAgent({ apiKey: process.env.ANTHROPIC_API_KEY! }));

// Remove — stops the agent and unregisters its channels
await registry.removeAgent('old-agent');

// Check if all agents are currently idle
registry.isAllIdle(); // true when no agent has an active conversation lock

addAgent() called before start() defers wiring until the registry starts (unchanged behaviour).


EphemeralAgent — now public

EphemeralAgent is exported for direct use in tests or advanced orchestration:

import { EphemeralAgent } from '@toolpack-sdk/agents';

const agent = new EphemeralAgent(
'helper',
'One-off summariser',
{ ...AGENT_MODE, systemPrompt: 'Return bullet points only.' },
{ apiKey: process.env.ANTHROPIC_API_KEY! },
);
await agent.start();
const result = await agent.invokeAgent({ message: 'Summarise: ...' });

No channels, no interceptors, no registry entry.


New exports (@toolpack-sdk/agents)

ExportKindDescription
EphemeralAgentclassLightweight one-shot agent
AgentSpawnConfiginterfaceSpawn configuration on BaseAgent
AgentSpawnTemplateinterfaceSingle spawnable template definition
HotReloadWatcherclassFile watcher + graceful restart coordinator
HotReloadWatcherOptionstypeConstructor options for HotReloadWatcher
WatchFntypeInjectable fs.watch signature (for testing)
SpawnFntypeInjectable child_process.spawn signature (for testing)

toolpack-sdk and @toolpack-sdk/knowledge

Version bump to align with @toolpack-sdk/agents v2.4.0. No code changes.


Install

npm install toolpack-sdk@2.4.0
npm install @toolpack-sdk/knowledge@2.4.0
npm install @toolpack-sdk/agents@2.4.0