Skip to content

Layer System

Last updated 2 days ago · d13fa3c

Updated 2 days ago

"fix(debt): Wave 3 (round 1) — delete orchestration package + dead RA_ flags" · d13fa3c · 2026-07-20

The layer system is the core architectural pattern of Reactive Agents. Every capability is an independent Effect Layer that can be enabled or disabled.

In Effect-TS, a Layer is a recipe for constructing services. Think of it as a factory:

// Layer<AgentService, never, EventBus>
// "I provide AgentService, never fail, and need EventBus"

Layers compose through two operations:

  • Layer.merge(a, b) — Provides services from both layers
  • Layer.provide(dep) — Satisfies a layer’s requirements

When you call createRuntime(), it composes layers based on your configuration:

const runtime = createRuntime({
agentId: "my-agent",
provider: "anthropic",
enableGuardrails: true,
enableReasoning: true,
});

Internally, this produces:

CoreServicesLive → provides EventBus, AgentService, TaskService
+ EventBusLive → provides EventBus (for optional layers)
+ LLMProviderLayer → provides LLMService
+ MemoryLayer → provides MemoryService
+ HookRegistryLive → provides LifecycleHookRegistry
+ ExecutionEngineLive → provides ExecutionEngine
+ GuardrailsLayer → provides GuardrailService
+ ReasoningLayer → provides ReasoningService, StrategyRegistry

Each layer declares what it provides and what it requires:

LayerProvidesRequires
CoreEventBus, AgentService, TaskServiceNothing
LLM ProviderLLMServiceNothing
MemoryMemoryService, MemoryDatabaseNothing
ReasoningReasoningService, StrategyRegistryLLMService
ToolsToolServiceEventBus
InteractionInteractionManager, ModeSwitcher, …EventBus
GuardrailsGuardrailServiceNothing
VerificationVerificationServiceNothing
CostCostServiceNothing
IdentityIdentityServiceNothing
ObservabilityObservabilityServiceNothing
PromptsPromptServiceNothing
GatewayGatewayService, SchedulerService, WebhookService, PolicyEngineEventBus
A2AA2A server/client helpersCore (+ tools when serving)
Reactive IntelligenceEntropySensor, ReactiveController, learning hooksEventBus, reasoning kernel integration
EvalEvalService, EvalStoreLLMService (for judges)

The runtime automatically satisfies dependencies when composing layers.

Add your own layers using .withLayers():

import { Layer, Context, Effect } from "effect";
class MyAnalytics extends Context.Tag("MyAnalytics")<
MyAnalytics,
{ readonly track: (event: string) => Effect.Effect<void> }
>() {}
const MyAnalyticsLive = Layer.succeed(MyAnalytics, {
track: (event) => Effect.sync(() => console.log(`[analytics] ${event}`)),
});
const agent = await ReactiveAgents.create()
.withLayers(MyAnalyticsLive)
.build();

Replace any layer with a test implementation:

import { TestLLMServiceLayer } from "@reactive-agents/llm-provider";
// The test provider is a Layer that returns canned responses. Each turn can
// gate on a `match` substring so a specific prompt yields a specific reply.
const testLLM = TestLLMServiceLayer([
{ text: "Paris", match: "capital of France" },
]);

This is the power of the layer system — any service can be swapped at the composition boundary without changing application code.