v2.7.0
Released: July 27, 2026
Highlights
- Rules system (
toolpack-sdk) — inject always-on behavioral constraints from Markdown files into the system prompt, scoped per mode with an optional__global__/folder that applies across all modes sharing the same rules directory - Anthropic on Vertex AI provider (
toolpack-sdk) — run Claude Sonnet 4.5 and Haiku 4.5 through Google Cloud Vertex AI with no API key required; uses Application Default Credentials - BaseAgent: concurrent conversation safety (
@toolpack-sdk/agents) — channel context (conversation ID, triggering channel) is now stored inAsyncLocalStorageso two conversations arriving at the same agent simultaneously can no longer clobber each other's values - BaseAgent: per-request mode (
@toolpack-sdk/agents) — mode is now snapshotted pergenerate()call instead of callingsetMode()on every run, eliminating a race condition when multiple agents share one Toolpack instance - Scheduler: run history (
@toolpack-sdk/agents) — completed and failed job executions are recorded in ajob_runstable; retrieve them withgetHistory(jobId) - Parallel agent spawning (
@toolpack-sdk/agents) — newspawn_agents_paralleltool lets the LLM instantiate multiple helper agents simultaneously and wait for all results
Breaking changes
None.
toolpack-sdk
Rules system
Rules are always-on behavioral constraints loaded from Markdown files and appended to the system prompt on every request. Unlike Skills (which are conditionally matched), Rules are always injected.
Set rulesDir on any mode to enable:
const analystMode = createMode({
name: 'equity-analyst',
systemPrompt: 'You are an Indian equity market analyst.',
rulesDir: '.warren/rules', // auto-discovers __global__/ and equity-analyst/
});
Directory layout:
.warren/rules/
__global__/
compliance.md ← injected for all modes pointing to this directory
equity-analyst/
india-only.md ← injected for this mode only
Rules are injected last in the system prompt chain (base → override → mode → rules), placing them closest to the conversation for maximum recency weight.
__global__/applies to every mode that shares the samerulesDir- Files are scanned recursively; only
.mdfiles are loaded - Two-level cache (
fileCacheper path,modeCachepermodeName:dir) means each file is read from disk at most once per process - Duplicate files (same resolved absolute path) are deduplicated — first-seen wins
RuleLoaderis exported fromtoolpack-sdkfor custom use
Default path: .toolpack/rules (used when rulesDir is not set on the mode).
See the Rules guide for the full reference.
Anthropic on Vertex AI provider
Run Claude models through Google Cloud Vertex AI without an Anthropic API key. Authentication uses Application Default Credentials (gcloud auth application-default login).
import { Toolpack } from 'toolpack-sdk';
import { AnthropicVertexAdapter } from 'toolpack-sdk/providers';
const sdk = await Toolpack.init({
provider: new AnthropicVertexAdapter({
projectId: 'my-gcp-project',
region: 'us-east5', // optional, defaults to us-east5
}),
tools: true,
});
Supported models: claude-sonnet-4-5@20250929, claude-haiku-4-5@20251001, claude-3-5-sonnet-v2@20241022, claude-3-5-haiku@20241022.
Environment variable fallbacks: ANTHROPIC_VERTEX_PROJECT_ID / GOOGLE_CLOUD_PROJECT for project, ANTHROPIC_VERTEX_REGION for region.
VertexAI: new models and thinking budget
Two new Gemini models are registered: gemini-3.5-flash and gemini-3.1-pro-preview (1M token context window, 65 536 max output tokens).
VertexAIAdapter now accepts a thinkingBudget option for Gemini 2.5+ models. Set to 0 to disable thinking entirely:
new VertexAIAdapter({ thinkingBudget: 8192 });
Internal rawContentCache stores Vertex AI Content objects keyed by tool call ID, preserving thought_signature fields required by Gemini thinking models across multi-turn tool-calling loops.
Skills: mode-gated auto-injection
Skill auto-injection is now opt-in per mode. The skill interceptor only runs when the active mode has skillInterceptor: true set. Modes without this flag are unaffected — no BM25 overhead on every request.
const myMode = createMode({
name: 'research',
skillInterceptor: true, // opt in to automatic skill injection
});
@toolpack-sdk/agents
BaseAgent: concurrent conversation safety
Channel context fields (conversationId, triggeringChannel, isTriggerChannel) are now stored in AsyncLocalStorage instead of instance-level fields. Each inbound message gets its own isolated async context, so two conversations processed concurrently by the same agent instance can no longer clobber each other's values.
The legacy instance fields (_conversationId, _triggeringChannel, _isTriggerChannel) remain for backward compatibility but are now only used as a final fallback when no async-local context is present.
BaseAgent: per-request mode (no more setMode() on every run)
run() previously called this.toolpack.setMode() on every invocation, mutating shared AIClient.activeMode. This caused a race condition when two agents shared one Toolpack instance — a setMode() from one run could override the mode of a concurrent run.
Mode is now passed as a per-request parameter to generate() and stream(), where it is snapshotted for the entire request. setMode() is only called once in start() for backward compatibility.
BaseAgent: parallel agent spawning
When spawn is configured, the LLM now has access to a spawn_agents_parallel tool in addition to the existing spawn_agent tool. It accepts an array of { template, task } entries and runs all of them concurrently with Promise.all:
// LLM call
{
"tool": "spawn_agents_parallel",
"input": {
"tasks": [
{ "template": "researcher", "task": "Find recent news on HDFC Bank" },
{ "template": "researcher", "task": "Find recent news on Infosys" }
]
}
}
BaseAgent: streaming mode
run() now checks mode.streaming and, when true, switches to toolpack.stream() instead of generate(). No config change needed — set streaming: true on the mode:
const streamingMode = createMode({
name: 'live-agent',
streaming: true,
});
AgentMind: concurrent belief deduplication
AgentMind now maintains a shared _inFlightBeliefs set across all DraftBuffer instances for the same agent. When two concurrent runs produce the same belief content, only the first one is written — the second is detected as an in-flight duplicate and skipped, preventing duplicate entries in the belief store.
Scheduler: job run history
SchedulerStore now maintains a job_runs table (SQLite). Every completed or failed execution is recorded automatically.
New type:
interface JobRun {
id: number;
jobId: string;
outcome: 'completed' | 'failed';
ranAt: number; // Unix timestamp ms
durationMs?: number;
error?: string;
}
New methods on SchedulerStore:
| Method | Description |
|---|---|
markCompleted(id, ranAt?) | Record a successful execution |
markFailed(id, error, ranAt?) | Record a failed execution with the error message |
getHistory(id, limit?) | Return execution records, newest first (default limit: 20) |
const runs = store.getHistory('job-abc', 10);
runs.forEach(r => console.log(r.outcome, r.durationMs));