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.
The Agent plugin serves two complementary roles:
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.
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.
| 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.
"getUsers", "addToCart") that other components call by name, without importing or prop-drilling. See Cross-Component Messaging pattern."REFRESH" or "TOGGLE_SIDEBAR" commands; any component can handle them independently. See Command-Driven UI pattern.Before using the Agent Plugin, you should be familiar with:
import Eleva from "eleva";
import { Agent } from "eleva/plugins";
const app = new Eleva("App");
app.use(Agent); // Enable agent integration
| 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 viactx.prefix. Use${ctx.property.value}in templates withtemplate: (ctx) => \…``.
| 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 |
| 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 |
| 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 |
# npm
npm install eleva
# yarn
yarn add eleva
# pnpm
pnpm add eleva
# bun
bun add eleva
<!-- 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>
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
});
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");
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
});
// 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"] }
}
});
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.
┌─────────────────────────────────────────────────────────────────┐
│ 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() │
│ │
└─────────────────────────────────────────────────────────────────┘
| ← Back to Plugins | Next: Usage Patterns → |