eleva

Agent Plugin — Agent Experience (AX)

Version: 1.0.0 Type: AI/Agent Integration Plugin Dependencies: Eleva core

Eleva’s Agent plugin is the AX (Agent Experience) layer — a first-class integration surface for LLMs, AI agents, and automation scripts.

The Agent plugin gives your Eleva app a structured way to register callable actions, dispatch commands between components, and record everything that happens in an audit log — so that AI models, automation scripts, or other components can discover and invoke functionality without tight coupling.

Think of it as a service layer between your components: instead of components calling each other directly, they register actions and dispatch commands through the Agent, which handles permissions, logging, and introspection automatically.


Why Use Agent?

The Agent plugin serves two complementary roles:

1. AI / LLM Integration Layer

If you’re building applications that interact with language models or AI agents, the Agent plugin provides exactly what LLMs need to operate: a discoverable action registry with typed schemas. An LLM can call listActions() to see what’s available, describeAction() to understand inputs and outputs, and execute() to invoke them — all with automatic audit logging.

2. General-Purpose Command Bus

Even without any AI involvement, the Agent plugin is useful as a decoupled communication layer between components. Instead of passing callbacks through props or managing complex emitter chains, components register actions and dispatch commands through a shared bus. This is especially valuable in larger apps where components need to interact without knowing about each other.

When Would I Use Agent vs. Emitter Events?

Scenario Use Emitter Use Agent
Simple parent-child communication Yes Overkill
Fire-and-forget notifications Yes Optional
Actions that return values No (events are void) Yes (execute() returns results)
Typed schemas for discoverability No Yes (describeAction())
Permission-controlled access No Yes (scope-based permissions)
Automatic audit trail No Yes (built-in logging)
LLM/AI tool integration No Yes (primary use case)

Rule of thumb: If you need return values, permissions, or audit logging — use Agent. If you just need to notify other components that something happened — emitter events are simpler.


When to Use


Prerequisites

Before using the Agent Plugin, you should be familiar with:


TL;DR - Quick Reference

30-Second Setup

import Eleva from "eleva";
import { Agent } from "eleva/plugins";

const app = new Eleva("App");
app.use(Agent);  // Enable agent integration

API Cheatsheet

Feature Method Description
Register Action agent.register(name, handler, schema?) Add a callable action
Execute Action agent.execute(name, payload?, scope?) Run a registered action
Batch Execute agent.executeBatch(actions, scope?) Run multiple actions in parallel
Sequence Execute agent.executeSequence(actions, scope?) Run actions sequentially (piped)
Has Action agent.hasAction(name) Check if action exists
Describe Action agent.describeAction(name) Get action schema
List Actions agent.listActions() List all registered actions
Describe All agent.describe(scope?) Get full capability manifest
Unregister agent.unregister(name) Remove an action
Dispatch Command agent.dispatch(command, scope?) Send a structured command
Handle Command agent.onCommand(type, handler) Listen for commands
Get Log agent.getLog(filter?) Query the audit log
Clear Log agent.clearLog() Clear all log entries
Inspect agent.inspect() View component registry
Snapshot agent.snapshot() Capture application state
Diff agent.diff(snapA, snapB) Compare two snapshots

Context Rule: Inside ${}, access properties via ctx. prefix. Use ${ctx.property.value} in templates with template: (ctx) => \…``.

Configuration Options

Option Type Default Description
maxLogSize number 100 Maximum audit log entries before rotation
enableInspection boolean true Enable inspect/snapshot/diff methods
onError function null Custom error handler (error, context) => void
actions object {} Pre-registered action handlers
permissions object {} Capability-based access control per scope
emitterEvents string[] [] Emitter event prefixes to capture in audit log
strictPermissions boolean false Require scope for all execute/dispatch calls
validateSchemas boolean false Enforce schema.input validation on execute

Documentation

Section Description
Usage Patterns Action registry, command bus, cross-component, and AI agent examples
Machine-Readable Manifest Structured JSON for AI tool-calling integrations
API Reference Complete API, troubleshooting, TypeScript types, and migration guide

Features

Feature Description
Action Registry Register, execute, and introspect callable actions with typed schemas
Composition executeBatch() for parallel and executeSequence() for piped execution
Command Bus Structured agent-to-component communication with typed commands
Audit Log Actions/commands logged with outcomes (result, error, durationMs) and rotation
Permissions Capability-based access control per scope with strict mode option
Schema Validation Opt-in payload validation against schema.input on execute
Error Codes All errors have machine-readable error.code for programmatic handling
Capability Discovery describe(scope?) returns full manifest of actions, commands, and permissions
State Inspection Component tree inspection, serializable snapshots, and snapshot diffing
Emitter Capture Optionally capture cross-plugin emitter events in the audit log
Emitter Events Emits agent:register, agent:execute, agent:dispatch (and more) via eleva.emitter for cross-plugin observability
Reactive Signals agent.actionCount and agent.lastActivity signals for template-driven monitoring of agent activity
Auto-cleanup Component-scoped actions and command handlers are automatically cleaned up on unmount
Zero Config Works out of the box with sensible defaults
Idempotent Safe to call install multiple times; warns and no-ops on double install

Installation

Via Package Manager

# npm
npm install eleva

# yarn
yarn add eleva

# pnpm
pnpm add eleva

# bun
bun add eleva

Via CDN

<!-- Option 1: Bundled plugins -->
<script src="https://cdn.jsdelivr.net/npm/eleva"></script>
<script src="https://cdn.jsdelivr.net/npm/eleva/dist/eleva-plugins.umd.min.js"></script>
<script>
  const app = new Eleva("MyApp");
  app.use(ElevaPlugins.Agent);
</script>

<!-- Option 2: Individual plugin -->
<script src="https://cdn.jsdelivr.net/npm/eleva"></script>
<script src="https://cdn.jsdelivr.net/npm/eleva/dist/plugins/agent.umd.min.js"></script>
<script>
  const app = new Eleva("MyApp");
  app.use(ElevaAgent);
</script>

Getting Started

Basic Setup

import Eleva from "eleva";
import { Agent } from "eleva/plugins";

const app = new Eleva("MyApp");

// Default options — no configuration needed
app.use(Agent);

Or with custom configuration:

import Eleva from "eleva";
import { Agent } from "eleva/plugins";

const app = new Eleva("MyApp");

app.use(Agent, {
  maxLogSize: 200,
  enableInspection: true,
  onError: (err, ctx) => console.error(`[Agent Error] ${ctx.method} ${ctx.code}:`, err),
  actions: {
    ping: () => "pong"
  },
  permissions: {
    "ui-agent": { actions: ["ping"], commands: ["UPDATE_UI"] }
  },
  emitterEvents: ["router:", "store:"],
  strictPermissions: false
});

First Component with Agent

app.component("SmartComponent", {
  setup({ agent, emitter }) {
    // Register an action with a typed schema
    agent.register("calculate", (payload) => payload.a + payload.b, {
      input: { a: "number", b: "number" },
      output: "number"
    });

    // Listen for commands
    const unsubscribe = agent.onCommand("REFRESH", async (cmd) => {
      console.log("Refresh requested:", cmd.payload);
    });

    // Execute an action
    const doCalculation = async () => {
      const result = await agent.execute("calculate", { a: 2, b: 3 });
      console.log("Result:", result); // 5
    };

    // Use emitter for event observation (not agent)
    emitter.on("router:afterEach", (to, from) => {
      console.log("Route changed:", to.path);
    });

    return { doCalculation };
  },
  template: (ctx) => `
    <div>
      <button @click="doCalculation">Calculate</button>
    </div>
  `
});

app.mount(document.getElementById("app"), "SmartComponent");

Configuration

Plugin Options

app.use(Agent, {
  maxLogSize: 200,           // Audit log capacity (default: 100)
  enableInspection: true,    // Enable inspect/snapshot/diff (default: true)
  onError: null,             // Custom error handler
  actions: {},               // Pre-registered actions
  permissions: {},           // Access control rules
  emitterEvents: [],         // Emitter prefixes to capture (e.g., ["router:", "store:"])
  strictPermissions: false,  // Default permissive mode; set true to require scope
  validateSchemas: false     // Set true to enforce schema.input on execute
});

Permission Modes

// Default mode (strictPermissions: false)
// - No permissions configured = everything allowed
// - No scope provided = unrestricted
// - Scope provided = checked against rules
app.use(Agent, {
  permissions: {
    "ui-agent": { actions: ["render"], commands: ["UPDATE_UI"] }
  }
});

// Strict mode (strictPermissions: true)
// - No permissions configured = everything denied
// - No scope provided = denied
// - Scope provided = checked against rules
app.use(Agent, {
  strictPermissions: true,
  permissions: {
    "admin": {
      actions: ["readData", "writeData", "deleteData"],
      commands: ["SHUTDOWN", "RESTART", "NOTIFY"]
    },
    "ui-agent": { actions: ["render"], commands: ["UPDATE_UI"] }
  }
});

Emitter Event Capture

Capture events emitted via eleva.emitter in the audit log. Both the Router (router:*) and Store (store:*) plugins emit events through the shared emitter automatically.

// Capture both Router and Store events in the audit log
app.use(Agent, {
  emitterEvents: ["router:", "store:"]
});

// Later, query captured events
const allEvents = app.agent.getLog({ type: "event" });

Store events: store:dispatch (before action), store:mutate (after action), store:error (on failure), store:register, store:unregister.


Data Flow

┌─────────────────────────────────────────────────────────────────┐
│                        Agent Plugin                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Component / AI Agent                                          │
│        │                                                        │
│        ├── register(name, handler, schema)                      │
│        │       └──► Action Registry ──► _actions Map            │
│        │                                                        │
│        ├── execute(name, payload, scope?)                       │
│        │       ├──► Permission Check                            │
│        │       ├──► Audit Log Entry                             │
│        │       └──► Handler Invocation ──► Result               │
│        │                                                        │
│        ├── dispatch({ type, target?, payload? }, scope?)        │
│        │       ├──► Permission Check                            │
│        │       ├──► Audit Log Entry                             │
│        │       └──► Command Handlers ──► Execution              │
│        │                                                        │
│        ├── onCommand(type, handler) ──► Unsubscribe fn          │
│        │                                                        │
│        ├── getLog(filter?) ──► Filtered Log Entries             │
│        │                                                        │
│        └── snapshot() ──► { components, plugins, timestamp }    │
│                                                                 │
│   Emitter (cross-plugin)                                        │
│        └── emit(event, data)                                    │
│                ├──► Prefix Match?                               │
│                │       └── Yes ──► Audit Log Entry              │
│                └──► Original emit()                             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Next Steps



← Back to Plugins Next: Usage Patterns →