v2.4.0
Released: June 28, 2026
Highlights
- Agent Spawning (
@toolpack-sdk/agents) — configure templates onBaseAgent.spawnand the SDK injectsspawn_agent/spawn_agents_paralleltools into everyrun()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) —HotReloadWatcherwatches.ts/.tsxand.env*files, debounces rapid edits, compiles TypeScript automatically, then callsregistry.scheduleRestart()which waits for all in-flight conversations to finish before callingprocess.exit(0) - Dynamic agent management (
@toolpack-sdk/agents) —AgentRegistry.addAgent()andremoveAgent()allow agents to be wired and started (or stopped and unregistered) at runtime after the registry is already running EphemeralAgentexported (@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 resultspawn_agents_parallel— spawn multiple agents simultaneously viaPromise.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:
| Option | Type | Description |
|---|---|---|
name | string | Unique identifier. Use 'self' for self-replication. |
description | string | Purpose shown to the LLM so it picks the right template. |
systemPrompt | (task: string) => string | Called at spawn time with the task string. |
model | string | Model override. Inherits parent when omitted. |
allowPromptAddition | boolean | Allow 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:
- A file change is detected. The debounce timer resets on every new change.
- After the debounce window of silence:
.ts/.tsx→ runsnpx tsc --build. On exit 0, callsonRestartNeeded. On non-zero, callsonCompileError(no restart)..env*→ callsonRestartNeededdirectly (no compile step).
registry.scheduleRestart()checksisAllIdle()immediately. If all agents are idle, restarts right away. Otherwise waits foragent:completeevents.- After
maxWaitMinutes(default 30), forces the restart regardless. process.exit(0)— PM2 / systemd brings the process back with the newdist/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)
| Export | Kind | Description |
|---|---|---|
EphemeralAgent | class | Lightweight one-shot agent |
AgentSpawnConfig | interface | Spawn configuration on BaseAgent |
AgentSpawnTemplate | interface | Single spawnable template definition |
HotReloadWatcher | class | File watcher + graceful restart coordinator |
HotReloadWatcherOptions | type | Constructor options for HotReloadWatcher |
WatchFn | type | Injectable fs.watch signature (for testing) |
SpawnFn | type | Injectable 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