Reactive Agents
A harness you fully control for agent loops that actually finish, on any model, with proof.
Most agent frameworks pick one model tier, hide the loop behind an opaque runtime, and hand you back prose you have to take on faith. Reactive Agents is built around four things instead:
- 🔍 Transparent harness. A deterministic 12-phase execution engine with
before/after/on-errorhooks on every phase. Every prompt, tool call, and reasoning step is a typed event you can inspect, steer, and replay, all locally, no SaaS dashboard required. Not a black box you debug by reading logs. - 🛡️ Reliable on every model tier. Model-adaptive context profiles, tool-call healing, output verification, durable crash-resume, and a single-owner termination oracle let the same code finish the agent loop on a local 4B Ollama model and on Claude / GPT / Gemini, with no per-model rewrites.
- 🧩 Composable and controllable. A typed builder of opt-in layers. Start with a model; add reasoning, memory, guardrails, cost routing, and durability one
.with()call at a time. You own the loop; nothing runs that you didn't ask for. - 🧾 Accountable. Every run returns a signed
receipt: a claim→evidence record with a verdict and confidence, not just an answer you have to trust.
Built on Effect-TS: schema-validated boundaries, tagged errors, no untyped throws.
| One import to start | Everything else (reasoning, memory, guardrails, cost routing) is opt-in, added one .with() call at a time |
| 8 LLM providers | Anthropic, OpenAI, Gemini, Groq, xAI, Ollama (local), LiteLLM 40+, Test |
| 8 reasoning strategies | ReAct · Blueprint · Reflexion · Plan-Execute · Tree-of-Thought · Adaptive · Direct · Code-Action (@exp) |
| 8,920 tests | Verified with bun test on every PR |
| 12-phase execution | Deterministic lifecycle with before/after/error hooks per phase |
| Cortex Studio | Live agent canvas, entropy charts, debrief UI, agent builder |
| Effect-TS end to end | Compile-time type safety, schema-validated boundaries, tagged errors |
Documentation · Discord · Quick Start · Features · Comparison · Architecture · Packages
Reliable on every tier — see it for yourself
The same agent investigates an incident, calls two tools, correlates the data, and recommends a fix — and finishes the job on a 4B local model just like on Claude. One builder, the only line that changes is the model. Demo source.
…and survives a crash mid-run
Durable execution: kill the process mid-run, and a fresh process reconstructs the run from its last on-disk checkpoint and finishes the job — completed tools never re-run. Demo source.
Why Reactive Agents?
Most AI agent frameworks pick a lane and make you live with it: dynamically typed, monolithic, opaque about what the model actually did, and tuned for one model tier. Reactive Agents is organized around four pillars instead, each one a direct answer to a specific way those frameworks fall short.
🔍 Transparent harness: nothing happens off the record
| Where it falls short elsewhere | How Reactive Agents answers it |
|---|---|
| Opaque decisions, debugged by reading logs | 12-phase execution engine with before/after/error hooks on every phase |
| No type safety at service boundaries | Effect-TS schemas validate every boundary at compile time |
🛡️ Reliable on every model tier: same code, any model
| Where it falls short elsewhere | How Reactive Agents answers it |
|---|---|
| Model lock-in, assumes GPT-4-class | Model-adaptive context profiles (4 tiers: local, mid, large, frontier) help smaller models punch above their weight |
| Single reasoning mode | 8 strategies (ReAct, Blueprint, Reflexion, Plan-Execute, Tree-of-Thought, Adaptive, Direct, Code-Action @experimental) |
🧩 Composable and controllable: you own the loop
| Where it falls short elsewhere | How Reactive Agents answers it |
|---|---|
| Monolithic, all-or-nothing | 15 independent layers: enable only what you need, one .with() call at a time |
| Unsafe by default | Guardrails block injection/PII/toxicity before the LLM sees input |
| No cost control | Complexity router picks the cheapest capable model; budget enforcement at 4 levels |
🧾 Accountable: an answer you can check, not just trust
| Where it falls short elsewhere | How Reactive Agents answers it |
|---|---|
| "Trust me" prose output | result.receipt: signed claim→evidence record with verdict and confidence, generated every run |
Cortex Studio
A full-featured local studio for live debugging — start it with .withCortex() or rax run --cortex:
→ Full Cortex documentation with more screenshots
Features
Grouped by capability. Every layer is opt-in — call .with*() only for what you need.
🧠 Reasoning & Cognition
- 8 reasoning strategies — ReAct, Blueprint (efficient static-decomposable), Reflexion, Plan-Execute, Tree-of-Thought, Adaptive (meta-strategy), Direct, Code-Action (@experimental)
- Intelligent context synthesis — fast-template or deep-LLM transcript shaping per iteration (
ContextSynthesizedon EventBus) - Reactive intelligence — detects when a run is going off the rails and intervenes: stalls, loops, and context pressure trigger corrective actions like early-stop, compression, or a strategy switch (under the hood: a multi-source entropy sensor, a reactive controller, and a Thompson Sampling bandit — docs)
- Adaptive calibration — three-tier live learning (shipped prior → community profile → local posterior) with per-run observations and classifier bypass
💾 Memory & Skills
- 4-layer memory — working, episodic, semantic (vector + FTS5), procedural — backed by
bun:sqlitewith background consolidation + decay - ExperienceStore — cross-agent learning loop closed by
ToolCallObservation - Living Skills System — agentskills.io
SKILL.mdcompatible, SQLite-backed, LLM-refined evolution, 5-stage compression, context-aware injection guard - Agent debrief + chat —
agent.chat()for one-shot Q&A,agent.session()for multi-turn (optional SQLite persistence), post-runDebriefSynthesizer
🔌 Providers & Models
- 8 LLM providers — Anthropic, OpenAI, Google Gemini, Groq, xAI (Grok), Ollama (local), LiteLLM (40+ models), Test (deterministic)
- Model-adaptive context profiles — 4 tiers (local / mid / large / frontier) with tier-aware prompts, compaction, and truncation; 4B+ Ollama models work with the same code
- Adaptive tool calling — FC dialect probe routes to
NativeFCDriveror 3-tierTextParseDriver(XML / JSON / pseudo-code) - HealingPipeline — normalizes tool-name aliases, param aliases, paths, and type coercion before every execution, so malformed tool calls from smaller models get repaired instead of failing
- Provider fallback chains —
withFallbacks()for graceful degradation across providers and models - Native thinking mode —
.withThinking({ effort, budgetTokens })opts into provider-native reasoning across all four cloud/local adapters (off unless enabled);.withModel({ thinking: true })is the quick boolean - Cost-aware model routing —
.withModelRouting()(opt-in, off by default) routes each run to the cheapest capable model of the configured provider by task complexity, degrading to the configured model on any error
🛡️ Production Safety
- Guardrails — pre-LLM injection detection, PII filtering, toxicity blocking, kill switch, behavioral contracts
- Ed25519 identity — real cryptographic agent certificates, RBAC, delegation chains, audit trails
- Verification — semantic entropy, fact decomposition, NLI hallucination detection
- Fabrication guard —
.withFabricationGuard()is on by default; rejects invented empirical performance measurements (benchmark timings, % speed-ups) absent from the tool-observation corpus. Soften to"warn"or disable with"off" - Stall / no-progress policy —
.withStallPolicy()bounds wasted iterations when the model ignores required-tool nudges: fast-escalate after N ignored nudges instead of looping to the full cap (progress resets the streak) - Harness-forced abstention — when grounding is structurally impossible (a required tool is missing, or synthesis is repeatedly rejected as ungrounded), the run ends honestly with
terminatedBy: "abstained"andresult.abstention { reason, missing }instead of fabricating or grinding tomax_iterations - Cost controls — multi-factor complexity router (task length, code presence, multi-step markers, tool-reliability escalation), semantic cache, budget enforcement (persists across restarts), dynamic pricing via OpenRouter
- Required tools guard — ensure critical tools are called before answering, with
maxCallsPerToolbudgets to prevent research loops - Deliverable-truth — the run tells you exactly which promised outputs never landed:
result.receipt.deliverables[]names each declared output as produced or missing, so a partial multi-file run reports what's incomplete instead of claiming success. Default-on in a reasoning run - Evidence ledger — the receipt is backed by an append-only ledger of what actually happened (tool invocations, written artifacts with path + content digest, verifier verdicts, the answer's evidence claims) that survives crash-resume
🔭 Observability
- 12-phase execution engine — deterministic lifecycle with
before/after/on-errorhooks per phase - Professional metrics dashboard — EventBus-driven execution timeline, tool-call summary, cost estimation, smart alerts (zero manual instrumentation)
- Distributed tracing (OTLP) + structured logging via
withLogging({ level, format, filePath }) - Cortex Studio live reporting —
.withCortex(url?)streams runtime telemetry over WebSocket - Streaming + SSE —
agent.runStream()withAbortSignalcancellation; one-line SSE endpoint viaAgentStream.toSSE() - Per-iteration run assessment — every iteration emits an
assessmenttrace event (requirements satisfied/outstanding, deliverables, evidence delta, run phase — orient/gather/execute/synthesize/verify — pace band, health), visible inrax diagnose replay. The measurement is always on; its consumption by adaptive pacing is behind the opt-in flags below
🧩 Composition & Multi-Agent
- Builder API — chains capabilities in one place; Agent-as-data via
toConfig()/fromJSON()for save/share/restore - Two-line entry point —
ReactiveAgents.quick()resolves provider, model, and iteration defaults from the environment and returns a ready-to-run agent - Functional combinators —
agentFn(),pipe(),parallel(),race()for declarative agent pipelines - A2A protocol — Agent Cards, JSON-RPC 2.0 server/client, SSE streaming, agent-as-tool
- Orchestration — sequential, parallel, pipeline, map-reduce; dynamic sub-agent spawning with depth limits
- Persistent gateway — adaptive heartbeats, cron scheduling, webhook ingestion (GitHub adapter), composable policy engine, chat mode with per-sender SQLite session history
⚙️ Builder Hardening
withStrictValidation(),withTimeout(),withLlmTimeout()(per-LLM-call timeout for local/Ollama providers — tolerate cold model loads without loosening the run-level timeout),withRetryPolicy(),withErrorHandler(),withFallbacks(),withLogging(),withHealthCheck(),withMinIterations(),withVerificationStep(),withOutputValidator(),withCustomTermination(),withTaskContext()defineTooltyped tool authoring — Standard Schema input (Effect Schema / Zod / Valibot / ArkType) + a plain async handler with arg types inferred from the schema; malformed options (parameters/executeinstead ofinput/handler) fail fast with a typed error- ToolBuilder fluent API — define tools without raw schema objects
- Dynamic tool registration —
agent.registerTool()/agent.unregisterTool()at runtime .withLongHorizon()(opt-in, off by default) — scales the guard thresholds (stall, consecutive-thoughts, redirect/nudge budgets) proportionally tomaxIterationsso a 40+ iteration research run isn't tripped by guards tuned for short runs. Verified to let a long-horizon task run to completion; not yet lift-gated for default-on. When not called, behavior is byte-identical to the default.withAdaptiveHarness()(opt-in, experimental) — a policy compiler derives the run's harness (strategy, guard depth, horizon profile) from model tier + task classification + horizon at run-start, and recompiles mid-run on progress evidence; explicit.withX()withers override the compiled plan. Experimental and opt-in — not yet validated for default-on
🌐 Frontend Integration
@reactive-agents/ui-core— headless, framework-agnostic core: versioned wire protocol, resumable stream client (cursor reconnect), run state machine, safe generative-UI trees, durable human-in-the-loop rails, and zero-token fixture testing. The engine the bindings share.@reactive-agents/react— React 18+ hooks + components:useRun,useResumableRun,useInteractions,useTaskInbox,useRunCost/useRunSteps,AgentSurface,AgentDevtools, and theuseAgentStream/useAgentclassics@reactive-agents/vue— Vue 3 composables with reactive refs@reactive-agents/svelte— Svelte 4/5 stores (createRun,createResumableRun,createInteractions,createAgentStream, …)- All build on
ui-coreand consumeAgentStream.toSSE()+ the durable endpoint helpers from Next.js, SvelteKit, Nuxt, or any SSE-capable server
✅ Confidence
- 8,920 tests across 1158 files, verified
bun teston every PR - Strict TypeScript — Effect-TS schemas validate every service boundary; explicit tagged errors, no untyped throws
Quick Start
Install and run your first TypeScript AI agent in under 60 seconds.
Recommended: Bun ≥1.0.0 — optimal performance with native SQLite, subprocess, and HTTP APIs. Node.js 22.5+ is now also supported via
@reactive-agents/runtime-shim— same code, both runtimes. Install Bun:curl -fsSL https://bun.sh/install | bash
# Bun (recommended)
bun add reactive-agents
# Node.js 22.5+
npm install reactive-agents
Note:
effectis included as a dependency ofreactive-agentsand installed automatically. If you import fromeffectdirectly in your own code (e.g.import { Effect } from "effect"), add it to your project explicitly:bun add effect(ornpm install effect).
Set your provider key first (each provider's variable is listed in Environment Variables below):
export ANTHROPIC_API_KEY=sk-ant-... # or put it in .env
createAgent(config) is the front door — one declarative config object, the
shape you already know from the Vercel AI SDK and OpenAI SDK. This is the 90%
case:
import { createAgent } from 'reactive-agents'
const agent = await createAgent({
name: 'assistant',
provider: 'anthropic',
model: 'claude-sonnet-4-6',
})
const result = await agent.run('Explain quantum entanglement')
console.log(result.output)
console.log(result.metadata) // { duration, cost, tokensUsed, stepsCount }
Add Capabilities
Add capabilities as config keys — grouped by domain, so autocomplete reads like
a menu. Start from a profile preset ("lean", "balanced", "intelligent")
and override individual keys:
import { createAgent } from 'reactive-agents'
const agent = await createAgent({
name: 'research-agent',
provider: 'anthropic',
model: 'claude-sonnet-4-6',
profile: 'balanced', // memory + RI + verifier + strategy switching
tools: { allowedTools: ['web-search', 'file-write'] },
budget: { tokenLimit: 100_000 }, // canonical budget killswitch
})
Pick the profile that matches the workload:
"lean"— model + nothing else. Latency- and cost-sensitive paths; benchmark ablations."balanced"— today's production defaults (memory + reactive intelligence + verifier + strategy switching)."intelligent"— balanced + skill persistence for cross-session compounding learning.
Advanced: the fluent builder
createAgent(config) and the fluent builder are the same API in two
syntaxes — same names, same nesting. Reach for the builder when construction
is conditional or imperative (branch on runtime state, inject code-only
escape hatches like hooks/layers, or compose a precise chokepoint) — things
that read awkwardly as static data:
import { ReactiveAgents, HarnessProfile } from 'reactive-agents'
let builder = ReactiveAgents.create()
.withName('research-agent')
.withProvider('anthropic')
.withProfile(HarnessProfile.intelligent()) // cross-session skills
.withMemory({ tier: 'enhanced' }) // upgrade memory to vector embeddings
.withTools({ builtins: true })
if (process.env.AUTONOMOUS) {
builder = builder.withGateway({ // persistent autonomous harness
heartbeat: { intervalMs: 1_800_000, policy: 'adaptive' },
crons: [{ schedule: '0 9 * * MON', instruction: 'Weekly review' }],
policies: { dailyTokenBudget: 50_000 },
})
}
const agent = await builder
.compose((h) => h.before('act', (ctx) => { console.log(ctx.phase) })) // precise chokepoint
.build()
The full builder / config reference is generated from the schema (the single source of truth): builder-api · configuration.
Conversational Chat
Use agent.chat() for single-turn Q&A or agent.session() for multi-turn conversations with adaptive routing -- direct LLM for simple questions, full ReAct loop for tool-capable queries:
// Single-turn chat
const answer = await agent.chat("What's the status of the deployment?")
// Multi-turn session
const session = agent.session()
await session.chat("Summarize yesterday's logs")
await session.chat('Which errors were most frequent?')
Agent Config (Agent as Data)
Define agents as JSON-serializable config objects. Save, share, and reconstruct agents without code:
import { agentConfigToJSON, ReactiveAgents } from 'reactive-agents'
// Builder → Config → JSON
const builder = ReactiveAgents.create()
.withName('researcher')
.withProvider('anthropic')
.withReasoning({ defaultStrategy: 'plan-execute-reflect' })
.withTools({ adaptive: true })
.withMemory({ tier: 'enhanced' })
const config = builder.toConfig()
const json = agentConfigToJSON(config)
// Save to file, database, or send over the wire
// JSON → Builder → Agent
const restored = await ReactiveAgents.fromJSON(json)
const agent = await restored.build()
const result = await agent.run('Research quantum computing advances')
Composition API
Build agent pipelines with functional combinators:
import { agentFn, pipe, parallel, race } from 'reactive-agents'
// Create lazy agent functions
const researcher = agentFn({ name: 'researcher', provider: 'anthropic' }, (b) =>
b.withReasoning().withTools({ builtins: true })
)
const summarizer = agentFn({ name: 'summarizer', provider: 'anthropic' })
// Sequential pipeline: research → summarize
const pipeline = pipe(researcher, summarizer)
const result = await pipeline('What are the latest AI breakthroughs?')
// Parallel fan-out: run multiple analyses concurrently
const multiAnalysis = parallel(
agentFn({ name: 'sentiment', provider: 'anthropic' }),
agentFn({ name: 'keywords', provider: 'anthropic' }),
agentFn({ name: 'summary', provider: 'anthropic' })
)
const combined = await multiAnalysis('Article text here...')
// combined.output contains labeled results from all 3 agents
// Race: fastest agent wins
const fastest = race(
agentFn({ name: 'claude', provider: 'anthropic' }),
agentFn({ name: 'gpt4', provider: 'openai' })
)
const winner = await fastest('Quick answer needed')
// Clean up
await pipeline.dispose()
await multiAnalysis.dispose()
await fastest.dispose()
Streaming
Tokens arrive as they're generated via AsyncGenerator. Pass an AbortSignal to cancel mid-stream:
const controller = new AbortController()
for await (const event of agent.runStream('Analyze this dataset', {
signal: controller.signal,
})) {
if (event._tag === 'TextDelta') process.stdout.write(event.text)
if (event._tag === 'IterationProgress')
console.log(`Step ${event.iteration}/${event.maxIterations}`)
if (event._tag === 'StreamCancelled') console.log('Stream cancelled')
if (event._tag === 'StreamCompleted') {
console.log('\nDone!')
// event.toolSummary: Array<{ toolName, calls, successRate }>
}
}
// Cancel from elsewhere (e.g., HTTP request abort)
controller.abort()
Agents are processes
A durable run behaves like an OS process: inspect it live, fork it from a checkpoint, and read a graded evidence receipt on completion.
const handle = agent.runStream(task) // needs .withReasoning() + .withDurableRuns()
handle.inspect() // live: { iteration, stepsCount, lastThought, pendingToolCalls }
handle.pause(); handle.resume()
const result = await agent.run(task)
result.receipt // { verdict: "tool-grounded", toolsUsed: ["calculator"], … }
// graded evidence about HOW the answer was produced — not a truth certificate
// optional Ed25519 signing via .withReceiptSigning() certifies provenance
await agent.fork(runId, { at: 1 }) // counterfactual restart from iteration 1's checkpoint —
// live LLM calls after the fork point, never "time-travel"
From the terminal: rax ps lists durable runs, rax attach <runId> tails one. Recorded runs re-execute with zero tokens via exact replay (makeReplayLLMLayer — unchanged prompts only; drift misses loudly). → The Process Model docs · demo
Lifecycle Hooks
Intercept any of the 12 execution phases with before, after, or error hooks:
import { Effect } from 'effect'
import { ReactiveAgents } from 'reactive-agents'
const agent = await ReactiveAgents.create()
.withProvider('anthropic')
.withReasoning()
.withTools({ builtins: true })
.withHook({
phase: 'think',
timing: 'after',
handler: (ctx) => {
console.log(
`Step ${ctx.metadata.stepsCount}: ${ctx.metadata.strategyUsed}`
)
return Effect.succeed(ctx)
},
})
.withHook({
phase: 'act',
timing: 'after',
handler: (ctx) => {
const last = ctx.toolResults.at(-1) as
| { toolName?: string }
| undefined
if (last?.toolName) console.log(`Tool called: ${last.toolName}`)
return Effect.succeed(ctx)
},
})
.build()
Available phases (12): bootstrap, guardrail, cost-route, strategy-select, think, act, observe, verify, memory-flush, cost-track, audit, complete. Each supports before, after, and on-error timing.
Comparison
We'd rather ship a short, defensible comparison than a long one where a single wrong row undermines the rest. This is scoped to where Reactive Agents is structurally different, not a feature-count contest: most of these frameworks ship token streaming, tool calling, and multi-agent orchestration too.
| Capability | Reactive Agents | LangChain JS | Vercel AI SDK | Mastra |
|---|---|---|---|---|
| Full type safety (Effect-TS) | Yes | -- | Partial | Partial |
| Typed per-phase lifecycle hooks | 12 phases, before/after/error |
Callbacks | Middleware | -- |
| Model-adaptive context by tier | 4 tiers | -- | -- | -- |
| Signed run receipt (claim→evidence) | Yes | -- | -- | -- |
| Production guardrails | Yes | -- | -- | Partial (processors) |
| Durable crash-resume | Yes | -- | -- | Partial (Temporal-backed workflows) |
Reflects our understanding of each framework's first-party, shipped features as of 2026-08. -- means we found no first-party equivalent, not that none exists; these move fast. Corrections welcome: open a PR.
Use Cases
- Autonomous engineering agents with tool execution and code generation
- Research and reporting workflows with verifiable reasoning steps
- Scheduled background agents using heartbeats, cron jobs, and webhooks
- Secure enterprise copilots with RBAC, audit trails, and policy controls
- Hybrid local/cloud AI deployments with adaptive context profiles
- Multi-agent teams with A2A protocol and dynamic sub-agent delegation
Architecture
ReactiveAgentBuilder
-> createRuntime()
-> Core Services EventBus, AgentService, TaskService
-> LLM Provider Anthropic, OpenAI, Gemini, Groq, xAI, Ollama, LiteLLM, Test
-> Memory Working, Semantic, Episodic, Procedural
-> Reasoning ReAct, Blueprint, Reflexion, Plan-Execute, ToT, Adaptive, Direct, Code-Action
-> Tools Registry, Sandbox, MCP Client
-> Guardrails Injection, PII, Toxicity, Kill Switch, Behavioral Contracts
-> Verification Semantic Entropy, Fact Decomposition, NLI
-> Cost Complexity Router, Budget Enforcer, Cache
-> Identity Certificates, RBAC, Delegation, Audit
-> Observability Tracing, Metrics, Structured Logging
-> Interaction 5 Modes, Checkpoints, Preference Learning
-> Orchestration Sequential, Parallel, Pipeline, Map-Reduce
-> Prompts Template Engine, Version Control
-> Gateway Heartbeats, Crons, Webhooks, Policy Engine
-> ExecutionEngine 12-phase lifecycle with hooks
Every layer is an Effect Layer -- composable, independently testable, and tree-shakeable.
12-Phase Execution Engine
Every task flows through a deterministic lifecycle. Each phase calls its corresponding service when enabled:
Bootstrap --> Guardrail --> Cost Route --> Strategy Select
|
+--------------------+
| Think -> Act -> Observe | <-- loop
+--------------------+
|
Verify --> Memory Flush --> Cost Track --> Audit --> Complete
| Phase | Service Called | What It Does |
|---|---|---|
| Bootstrap | MemoryService | Load context from semantic/episodic memory |
| Guardrail | GuardrailService | Block unsafe input before LLM sees it |
| Cost Route | CostService | Select optimal model tier by complexity |
| Strategy Select | ReasoningService | Pick reasoning strategy (or direct LLM) |
| Think/Act/Observe | LLMService + ToolService | Reasoning loop with real tool execution |
| Verify | VerificationService | Fact-check output (entropy, decomposition, NLI) |
| Memory Flush | MemoryService | Persist session + episodic memories |
| Cost Track | CostService | Record spend against budget |
| Audit | ObservabilityService | Log audit trail (tokens, cost, strategy, duration) |
| Complete | -- | Build final result with metadata |
Every phase supports before, after, and on-error lifecycle hooks. When observability is enabled, every phase emits trace spans and metrics.
Reasoning Strategies
| Strategy | How It Works | Best For |
|---|---|---|
| ReAct | Think -> Act -> Observe loop | Tool use, step-by-step tasks |
| Blueprint | ReWOO-style: plan once -> execute in parallel -> solve (alias rewoo) |
Cheap runs on decomposable, tool-heavy tasks |
| Reflexion | Generate -> Critique -> Improve | Quality-critical output |
| Plan-Execute | Plan steps -> Execute -> Reflect -> Refine | Structured multi-step work |
| Tree-of-Thought | Branch -> Score -> Prune -> Synthesize | Creative, open-ended problems |
| Adaptive | Analyze task -> Auto-select best strategy | Mixed workloads |
| Direct | Single LLM call, no reasoning loop | Simple questions, minimal latency |
Code-Action @exp |
LLM generates a TypeScript IIFE run in a Worker sandbox; tools exposed as async functions | Multi-tool orchestration, pure computation |
// Auto-select the best strategy per task
const agent = await ReactiveAgents.create()
.withProvider('anthropic')
.withReasoning({ defaultStrategy: 'adaptive' })
.build()
// Strategy switching is on by default — customize or disable explicitly
const agent2 = await ReactiveAgents.create()
.withProvider('anthropic')
.withReasoning({
// enableStrategySwitching defaults to true
maxStrategySwitches: 1,
fallbackStrategy: 'plan-execute-reflect',
})
.build()
Multi-Provider Support
| Provider | Models | Tool Calling | Streaming |
|---|---|---|---|
| Anthropic | Claude Haiku, Sonnet, Opus | Yes | Yes |
| OpenAI | GPT-4o, GPT-4o-mini | Yes | Yes |
| Google Gemini | Gemini Flash, Pro | Yes | Yes |
| Groq | Llama, Qwen, and more (hosted) | Yes | Yes |
| xAI | Grok models | Yes | Yes |
| Ollama | Any local model | Yes | Yes |
| LiteLLM | 40+ models via LiteLLM proxy | Yes | Yes |
| Test | Mock (deterministic) | -- | -- |
Switch providers with one line -- agent code stays the same.
openai/groq/xai/litellm all speak the OpenAI-compatible wire protocol,
so .withProvider(provider, { baseUrl, apiKey, headers }) can point any of
them at any OpenAI-compatible endpoint at runtime -- a llama.cpp server,
Deepseek, a LiteLLM proxy on a non-default host -- without predefining env
vars. See LLM Providers for details.
Model-Adaptive Context
Optimize prompt construction and context compaction for your model tier:
const agent = await ReactiveAgents.create()
.withProvider('ollama')
.withModel('qwen3:4b')
.withReasoning()
.withTools({ builtins: true })
.withContextProfile({ tier: 'local' }) // Lean prompts, aggressive compaction
.build()
| Tier | Models | Context Strategy |
|---|---|---|
"local" |
Ollama small models (<=14b) | Lean prompts, aggressive compaction after 6 steps, 800-char truncation |
"mid" |
Mid-range models | Balanced prompts, moderate compaction |
"large" |
Anthropic, OpenAI, Gemini | Full context, standard compaction |
"frontier" |
Flagship models | Maximum context, minimal compaction |
Context Window Override (numCtx)
Pin the exact context window the provider is given, instead of relying on the
model's assumed maximum. Pass it via the .withModel() object form:
const agent = await ReactiveAgents.create()
.withProvider('ollama')
.withModel({ model: 'qwen3:4b', numCtx: 32768 }) // exact num_ctx sent to Ollama
.withReasoning()
.build()
numCtx is also a first-class AgentConfig field, so it round-trips through
toConfig() / fromJSON() and the Cortex Studio agent builder:
{ "provider": "ollama", "model": "qwen3:4b", "numCtx": 32768 }
Provider applicability: honored by providers that expose a context-window knob
(Ollama maps it to num_ctx). Cloud providers that don't expose one ignore the
field. When set, it becomes the authoritative denominator for the context-usage
gauge in Cortex Studio.
Packages
| Package | Description |
|---|---|
@reactive-agents/core |
EventBus pub/sub, AgentService lifecycle, TaskService state machine, canonical types |
@reactive-agents/runtime |
12-phase ExecutionEngine, ReactiveAgentBuilder, createRuntime() layer composer |
@reactive-agents/llm-provider |
Unified LLM interface for Anthropic, OpenAI, Gemini, Groq, xAI, Ollama, LiteLLM, and Test providers |
@reactive-agents/memory |
4-layer memory (working, semantic, episodic, procedural) on bun:sqlite; ExperienceStore cross-agent learning; background consolidation + decay |
@reactive-agents/reasoning |
8 strategies (ReAct, Blueprint, Reflexion, Plan-Execute, ToT, Adaptive, Direct, Code-Action @experimental) with composable kernel architecture |
@reactive-agents/tools |
Tool registry with sandboxed execution, MCP client, agent-as-tool adapter, dynamic sub-agent spawning |
@reactive-agents/guardrails |
Pre-LLM safety: injection detection, PII filtering, toxicity blocking |
@reactive-agents/verification |
Post-LLM quality: semantic entropy, fact decomposition, NLI hallucination detection |
No comments yet
Be the first to share your take.