Skip to content

Context Engineering

Context engineering is the practice of finding the smallest set of high-signal tokens that maximize the likelihood of desired outcomes. Reactive Agents provides a systematic context engineering system that adapts to your model’s capabilities.

Every model has different context capacity, latency characteristics, and instruction-following quality. Context Profiles let you tune all context-related thresholds to match your model tier.

TierModelsCompactionTool Result SizeRules
localOllama, llama, phi, qwenEvery 4 steps400 charsSimplified
midhaiku, mini, flashEvery 6 steps800 charsStandard
largesonnet, gpt-4oEvery 8 steps1,200 charsStandard
frontieropus, o1, o3Every 12 steps2,000 charsDetailed
// Use the tier auto-detection (inferred from model name)
const agent = await ReactiveAgents.create()
.withProvider("ollama")
.withModel("qwen3:4b")
.withReasoning()
.withTools()
.withContextProfile({ tier: "local" })
.build();
// Override specific thresholds
const agent = await ReactiveAgents.create()
.withProvider("anthropic")
.withModel("claude-haiku-4-5-20251001")
.withContextProfile({
tier: "mid",
toolResultMaxChars: 1000, // Override default 800
compactAfterSteps: 8, // Start compacting later
})
.build();
PropertyDescription
tier"local" | "mid" | "large" | "frontier"
compactAfterStepsSteps before older history is compacted
fullDetailStepsSteps kept at full detail during compaction
toolResultMaxCharsMax chars for tool result in context
rulesComplexity"simplified" | "standard" | "detailed"
promptVerbosity"minimal" | "standard" | "full"
toolSchemaDetail"names-only" | "names-and-types" | "full"

As agents work through multi-step tasks, context grows. Reactive Agents uses a four-level progressive compaction strategy:

LevelApplied ToFormat
Level 1 — Full DetailLast fullDetailSteps stepsComplete ReAct format
Level 2 — SummarySteps within compactAfterSteps windowOne-line preview
Level 3 — GroupedOlder steps"Steps 3-8: file-read ×2, file-write ×1"
Level 4 — DroppedAncient steps without preserveOnCompactionRemoved entirely

Preservation rules: Error observations and the first file-write per path are always preserved, regardless of their age.

The budget system allocates tokens across context sections and adapts as iterations progress:

import { allocateBudget, estimateTokens } from "@reactive-agents/reasoning";
const budget = allocateBudget(
128_000, // total model context tokens
profile, // ContextProfile
3, // current iteration
10, // max iterations
);
// budget.allocated.stepHistory → tokens reserved for history
// budget.allocated.toolSchemas → tokens for tool definitions
// budget.remaining → tokens still available

The scratchpad-write / scratchpad-read built-in tools let agents persist notes outside the context window. Notes survive compaction and are available across tool calls.

ACTION: scratchpad-write({"key": "plan", "content": "Step 1: search, Step 2: write report"})
Observation: {"saved": true, "key": "plan"}
ACTION: scratchpad-read({"key": "plan"})
Observation: {"key": "plan", "content": "Step 1: search, Step 2: write report"}

This implements Anthropic’s recommended structured note-taking pattern for long-horizon tasks.

Every tool result is now tracked as a typed ObservationResult:

import { categorizeToolName, deriveResultKind } from "@reactive-agents/reasoning";
// Category is automatically derived from tool name
// "file-write" → category: "file-write", resultKind: "side-effect"
// "web-search" → category: "web-search", resultKind: "data"
// "file-read" → category: "file-read", resultKind: "data"
// any error → category: "error", preserveOnCompaction: true

.withAgentTool() now creates real sub-agents with clean context windows:

const coordinator = await ReactiveAgents.create()
.withProvider("anthropic")
.withReasoning()
.withTools()
.withAgentTool("researcher", {
name: "researcher",
description: "Research specialist for web searches",
provider: "anthropic",
model: "claude-haiku-4-5-20251001",
maxIterations: 5,
systemPrompt: "You are a research specialist. Search the web and summarize findings.",
})
.build();
// coordinator can now call "researcher" as a tool
// Sub-agent runs with clean context + focused prompt
// Returns structured: { subAgentName, success, summary, tokensUsed }

Sub-agents are depth-limited to 3 levels (MAX_RECURSION_DEPTH) to prevent infinite delegation.

For ad-hoc delegation where you don’t know ahead of time what sub-tasks the agent will need to delegate, use .withDynamicSubAgents(). This registers the built-in spawn-agent tool, which the model can invoke freely at runtime:

const agent = await ReactiveAgents.create()
.withTools()
.withDynamicSubAgents({ maxIterations: 5 })
.build();

The model calls spawn-agent(task, name?, model?, maxIterations?) whenever it decides a subtask benefits from a clean context window. Sub-agents inherit the parent’s provider and model by default.

Comparison:

ApproachWhen to use
.withAgentTool("name", config)Named, purpose-built sub-agent with a specific role
.withDynamicSubAgents()Ad-hoc delegation at model’s discretion, unknown tasks

Depth is capped at MAX_RECURSION_DEPTH = 3. Spawned sub-agents do not inherit the spawn-agent tool by default, naturally containing recursion.

Prompt templates automatically select tier-specific variants when available:

TemplateAvailable Tiers
reasoning.react-systembase, :local, :frontier
reasoning.react-thoughtbase, :local, :frontier

The system resolves reasoning.react-system:local first, then falls back to reasoning.react-system.

Verified with cogito:14b (Ollama) across 9 scenarios:

CategoryAvg StepsAvg TokensAvg Time
Tool use (S1-S5)6.31,8994.1s
Error recovery (S6)10.02,6305.1s
Compaction stress (S7)13.03,9788.9s
Pure reasoning (S8)1.01,0172.5s
Overall (9 scenarios)6.42,0934.4s

All well within targets: <= 8 steps, <= 5,000 tokens, <= 15s.