@reactive-agents/runtime
v0.11.1
Published
Runtime for Reactive Agents — ExecutionEngine, ReactiveAgentBuilder, and createRuntime
Readme
@reactive-agents/runtime
Version: 0.10.3 — execution runtime for Reactive Agents.
The runtime package contains the 12-phase ExecutionEngine, the ReactiveAgentBuilder fluent API,
createRuntime() for low-level Effect-TS layer composition, and the agent-level orchestration
surfaces (streaming, debrief, sessions, channels, gateway).
Installation
bun add @reactive-agents/runtimeOr install the umbrella package (recommended for new projects — pulls in core, reasoning, llm-provider, tools, memory, gateway, and channels in one shot):
bun add reactive-agentsWhat this package provides
ReactiveAgentBuilder— chainable builder for assembling agents from optional capabilities (provider, model, memory, reasoning, tools, gateway, channels, observability, …).ExecutionEngine— the 12-phase reactive lifecycle that every task flows through; emits hooks at every phase boundary.createRuntime()/createLightRuntime()— Effect-TS layer factories for embedding the runtime inside larger Effect programs.AgentSession/directChat()— stateless and stateful chat surfaces backed bySessionStore(used by gateway chat mode).AgentStream— streaming event API (deltas, tool calls, phase transitions).synthesizeDebrief()— post-run summary with cost, tools, entropy, verdict.ingestDocuments()— RAG ingestion helper for.withDocuments().
Quick example
import { ReactiveAgents } from "@reactive-agents/runtime";
const agent = await ReactiveAgents.create()
.withName("my-agent")
.withProvider("anthropic")
.withModel("claude-sonnet-4-20250514")
.withMemory("1")
.withReasoning()
.withGuardrails()
.withCostTracking()
.build();
const result = await agent.run("Explain the CAP theorem");
console.log(result.output);
console.log(result.metadata); // { duration, cost, tokensUsed, stepsCount, ... }Effect API
import { Effect } from "effect";
import { ReactiveAgents } from "@reactive-agents/runtime";
const program = Effect.gen(function* () {
const agent = yield* ReactiveAgents.create()
.withName("my-agent")
.withProvider("anthropic")
.withModel("claude-haiku-4-5-20251001")
.buildEffect();
return yield* agent.runEffect("What is the meaning of life?");
});
const result = await Effect.runPromise(program);Low-level createRuntime()
import { createRuntime } from "@reactive-agents/runtime";
const runtime = createRuntime({
agentId: "my-agent",
provider: "anthropic",
enableReasoning: true,
enableGuardrails: true,
enableCostTracking: true,
});The 12-Phase Execution Engine
Every task flows through the following phases. Each phase supports before, after, and
on-error lifecycle hooks via .withHook().
| # | Phase | Purpose |
|---|---|---|
| 1 | bootstrap | Initialize execution context, load memories, prepare state |
| 2 | guardrail | Detect injection, PII, policy violations on input |
| 3 | cost-route | Estimate task complexity and route to a cost-appropriate model |
| 4 | strategy-select | Choose reasoning strategy (ReAct, Reflexion, Plan-Execute, ToT, Adaptive) |
| 5 | think | Multi-step reasoning loop (LLM completions inside the kernel) |
| 6 | act | Execute tool calls produced by think |
| 7 | observe | Process tool results, update kernel context |
| 8 | verify | Semantic verification, evidence grounding, retry-or-pass arbitration |
| 9 | memory-flush | Persist new memories (episodic, procedural, experiences) |
| 10 | cost-track | Record token usage and cost metrics |
| 11 | audit | Emit compliance/observability events |
| 12 | complete | Finalize, assemble output, return result |
The reasoning kernel that powers think / act / observe / verify lives in
@reactive-agents/reasoning under kernel/capabilities/ (act, attend, comprehend, decide, reason,
reflect, sense, verify), kernel/loop/, and kernel/state/. See
reasoning README.
Builder methods
The full set of .with*() methods on ReactiveAgentBuilder:
| Method | Purpose |
|---|---|
| .withName(name) | Human-readable agent name |
| .withAgentId(id) | Stable id for memory + telemetry |
| .withPersona(persona) | Persona/system prompt scaffolding |
| .withSystemPrompt(prompt) | Raw system prompt override |
| .withProvider(name) | "anthropic" \| "openai" \| "gemini" \| "ollama" \| "litellm" \| "test" |
| .withModel(modelOrParams) | Model id string or { model, temperature, thinking, ... } |
| .withReasoning(opts?) | Enable strategies (defaults to ReAct) |
| .withTools(opts?) | Register tools (built-ins + custom) |
| .withTerminalTools(cfg?) | Add shell-execute (opt-in, allowlist-gated) |
| .withDynamicSubAgents(opts?) | Add spawn-agent for runtime sub-agent dispatch |
| .withAgentTool(...) / .withRemoteAgent(...) | Wrap another agent as a callable tool |
| .withMemory(tier) | "1" (FTS5) or "2" (vec) memory |
| .withDocuments(docs) | RAG ingestion at build time |
| .withGuardrails(opts?) | Input/output safety detectors |
| .withVerification(opts?) | Verifier strategies (semantic, evidence, …) |
| .withCostTracking(opts?) | Budget enforcement + cost metadata |
| .withModelPricing(...) / .withDynamicPricing(...) | Custom pricing tables |
| .withCircuitBreaker(...) / .withRateLimiting(...) | Provider-level protection |
| .withFallbacks({...}) | Fallback chain across providers/models |
| .withGateway(opts?) | Persistent harness (heartbeats, crons, webhooks) |
| .withChannels({adapters,triggers?,defaultAgent?}) | Bot/webhook channel adapters |
| .withA2A(opts?) | Agent-to-Agent protocol server |
| .withObservability(opts?) | Verbose live event stream |
| .withTracing({dir?}) / .withTelemetry(cfg?) / .withLogging({...}) | Observability outputs |
| .withCalibration(mode) | Calibration store mode (off / read / write) |
| .withReactiveIntelligence(...) | RI dispatcher (strategy switching) |
| .withSkills({...}) / .withMetaTools(cfg) | Skill system + meta-tools |
| .withMaxIterations(n) | Cap kernel loop iterations |
| .withCustomTermination(fn) | Custom termination predicate |
| .withHook(hook) | Lifecycle hook (phase × timing → fn) |
| .withLayers(layer) | Inject extra Effect layers |
| .withCacheTimeout(ms) | Tool-result cache TTL |
| .withIdentity() | Identity service |
| .withInteraction() | Human-in-the-loop interaction service |
| .withPrompts(opts?) | Prompt manager |
| .withOrchestration() | Orchestration service (multi-agent workflows) |
| .withCortex(url?) | Cortex telemetry endpoint |
| .withStreaming({density?}) | Stream events back to caller |
Build with .build() (Promise) or .buildEffect() (Effect).
Gateway chat mode
When you combine .withGateway() and .withChannels(), incoming messages are routed through the
gateway's chat mode by default. Each (platform, senderId) pair gets a persistent SQLite-backed
session with:
- 40-turn / 8 KiB sliding window
- Episodic memory injection from previous sessions
- Daily compaction (consolidates older turns into a summary)
- TTL-based pruning (
accessControl.sessionTtlDays, default 30 days)
const agent = await ReactiveAgents.create()
.withName("ops-bot")
.withProvider("anthropic")
.withMemory("1")
.withGateway({
accessControl: {
mode: "chat", // 'chat' (default) or 'task'
accessPolicy: "allowlist",
allowedSenders: ["U_TYLER"],
},
})
.withChannels({ adapters: [discordAdapter] })
.build();
await agent.start(); // gateway loop + adapters come up hereSwitch to mode: "task" if you want each inbound message to spawn a fresh one-shot run.
Streaming
const stream = agent.runStream("Summarize the news");
for await (const ev of stream) {
if (ev.type === "delta") process.stdout.write(ev.text);
if (ev.type === "tool-call") console.log("→", ev.name, ev.args);
}StreamDensity controls verbosity: "compact" | "standard" | "verbose".
Common patterns
Sub-agent composition:
import { agentFn, pipe, parallel } from "@reactive-agents/runtime";
const research = agentFn(researchAgent);
const summarize = agentFn(summarizerAgent);
const workflow = pipe(research, summarize);
const out = await workflow.run("Latest LLM evals?");Persistent chat session:
import { AgentSession } from "@reactive-agents/runtime";
const session = new AgentSession(agent, { sessionId: "user-42" });
await session.send("Hi");
await session.send("Remember my favorite color is blue.");Post-run debrief:
import { synthesizeDebrief, formatDebriefMarkdown } from "@reactive-agents/runtime";
const debrief = synthesizeDebrief({ result, steps: result.metadata.steps });
console.log(formatDebriefMarkdown(debrief));Documentation
- Full docs: docs.reactiveagents.dev
- Builder reference: docs.reactiveagents.dev/api/builder/
- Lifecycle hooks: docs.reactiveagents.dev/guides/hooks/
- Related:
@reactive-agents/reasoning,@reactive-agents/llm-provider,@reactive-agents/tools,@reactive-agents/memory,@reactive-agents/gateway,@reactive-agents/channels.
License
MIT
