@electric-ax/agents 0.1.5 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entrypoint.js +653 -408
- package/dist/index.cjs +671 -419
- package/dist/index.d.cts +36 -3
- package/dist/index.d.ts +36 -3
- package/dist/index.js +656 -411
- package/docs/entities/agents/horton.md +89 -0
- package/docs/entities/agents/worker.md +102 -0
- package/docs/entities/patterns/blackboard.md +111 -0
- package/docs/entities/patterns/dispatcher.md +77 -0
- package/docs/entities/patterns/manager-worker.md +127 -0
- package/docs/entities/patterns/map-reduce.md +81 -0
- package/docs/entities/patterns/pipeline.md +101 -0
- package/docs/entities/patterns/reactive-observers.md +125 -0
- package/docs/examples/mega-draw.md +106 -0
- package/docs/examples/playground.md +46 -0
- package/docs/index.md +208 -0
- package/docs/quickstart.md +201 -0
- package/docs/reference/agent-config.md +82 -0
- package/docs/reference/agent-tool.md +58 -0
- package/docs/reference/built-in-collections.md +334 -0
- package/docs/reference/cli.md +238 -0
- package/docs/reference/entity-definition.md +57 -0
- package/docs/reference/entity-handle.md +63 -0
- package/docs/reference/entity-registry.md +73 -0
- package/docs/reference/handler-context.md +108 -0
- package/docs/reference/runtime-handler.md +136 -0
- package/docs/reference/shared-state-handle.md +74 -0
- package/docs/reference/state-collection-proxy.md +41 -0
- package/docs/reference/wake-event.md +132 -0
- package/docs/usage/app-setup.md +165 -0
- package/docs/usage/clients-and-react.md +191 -0
- package/docs/usage/configuring-the-agent.md +136 -0
- package/docs/usage/context-composition.md +204 -0
- package/docs/usage/defining-entities.md +181 -0
- package/docs/usage/defining-tools.md +229 -0
- package/docs/usage/embedded-builtins.md +180 -0
- package/docs/usage/managing-state.md +93 -0
- package/docs/usage/overview.md +284 -0
- package/docs/usage/programmatic-runtime-client.md +216 -0
- package/docs/usage/shared-state.md +169 -0
- package/docs/usage/spawning-and-coordinating.md +165 -0
- package/docs/usage/testing.md +76 -0
- package/docs/usage/waking-entities.md +148 -0
- package/docs/usage/writing-handlers.md +267 -0
- package/package.json +6 -9
- package/skills/init.md +71 -0
- package/skills/quickstart/scaffold/package.json +30 -0
- package/skills/{tutorial → quickstart}/scaffold/tsconfig.json +8 -3
- package/skills/quickstart/scaffold/vite.config.ts +21 -0
- package/skills/quickstart/scaffold-ui/index.html +12 -0
- package/skills/quickstart/scaffold-ui/main.tsx +235 -0
- package/skills/quickstart.md +582 -0
- package/skills/tutorial/scaffold/package.json +0 -17
- package/skills/tutorial.md +0 -282
- /package/skills/{tutorial → quickstart}/scaffold/entities/.gitkeep +0 -0
- /package/skills/{tutorial → quickstart}/scaffold/lib/electric-tools.ts +0 -0
- /package/skills/{tutorial → quickstart}/scaffold/server.ts +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Reactive observers
|
|
3
|
+
titleTemplate: '... - Electric Agents'
|
|
4
|
+
description: >-
|
|
5
|
+
Pattern for entities that watch others and react to changes using ctx.observe() with wake conditions.
|
|
6
|
+
outline: [2, 3]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Reactive observers
|
|
10
|
+
|
|
11
|
+
Pattern: entities that watch other entities and react to changes.
|
|
12
|
+
|
|
13
|
+
**Source:** [`packages/agents-runtime/skills/designing-entities/references/patterns/reactive-observers.md`](https://github.com/electric-sql/electric/blob/main/packages/agents-runtime/skills/designing-entities/references/patterns/reactive-observers.md)
|
|
14
|
+
|
|
15
|
+
## Core mechanism
|
|
16
|
+
|
|
17
|
+
An entity calls `ctx.observe(entity(entityUrl), { wake: { on: 'change', collections: [...] } })` to start watching another entity. The `entity()` helper (imported from `@electric-ax/agents-runtime`) wraps a raw URL into the correct observe target. When the observed entity has new activity in the specified collections, the observer is woken.
|
|
18
|
+
|
|
19
|
+
## Monitor example
|
|
20
|
+
|
|
21
|
+
The monitor watches multiple entities and reports status changes.
|
|
22
|
+
|
|
23
|
+
**Source:** [`packages/agents-runtime/skills/designing-entities/references/patterns/reactive-observers.md`](https://github.com/electric-sql/electric/blob/main/packages/agents-runtime/skills/designing-entities/references/patterns/reactive-observers.md)
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
export function registerMonitor(registry: EntityRegistry) {
|
|
27
|
+
registry.define(`monitor`, {
|
|
28
|
+
description: `Health dashboard agent that watches multiple entities and reports status changes and anomalies`,
|
|
29
|
+
state: {
|
|
30
|
+
status: { primaryKey: `key` },
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
async handler(ctx) {
|
|
34
|
+
if (ctx.firstWake) {
|
|
35
|
+
ctx.db.actions.status_insert({ row: { key: `current`, value: `idle` } })
|
|
36
|
+
}
|
|
37
|
+
const baseObserveTool = createObserveTool(ctx)
|
|
38
|
+
const observeTool = {
|
|
39
|
+
...baseObserveTool,
|
|
40
|
+
execute: async (toolCallId: string, params: unknown) => {
|
|
41
|
+
ctx.db.actions.status_update({
|
|
42
|
+
key: `current`,
|
|
43
|
+
updater: (draft) => {
|
|
44
|
+
draft.value = `observing`
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
return baseObserveTool.execute(toolCallId, params)
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
ctx.useAgent({
|
|
52
|
+
systemPrompt: MONITOR_SYSTEM_PROMPT,
|
|
53
|
+
model: `claude-sonnet-4-5-20250929`,
|
|
54
|
+
tools: [...ctx.electricTools, observeTool],
|
|
55
|
+
})
|
|
56
|
+
await ctx.agent.run()
|
|
57
|
+
},
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The monitor wraps the base observe tool to also transition its own state to `observing`.
|
|
63
|
+
|
|
64
|
+
## The observe tool
|
|
65
|
+
|
|
66
|
+
The `observe_entity` tool lets the LLM decide what to watch:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { entity } from '@electric-ax/agents-runtime'
|
|
70
|
+
|
|
71
|
+
export function createObserveTool(ctx: HandlerContext): AgentTool {
|
|
72
|
+
return {
|
|
73
|
+
name: `observe_entity`,
|
|
74
|
+
label: `Observe Entity`,
|
|
75
|
+
description: `Start observing another entity by its URL. The current entity will wake with a change payload when the observed entity has new activity.`,
|
|
76
|
+
parameters: Type.Object({
|
|
77
|
+
entity_url: Type.String({
|
|
78
|
+
description: `The URL of the entity to observe`,
|
|
79
|
+
}),
|
|
80
|
+
collections: Type.Optional(
|
|
81
|
+
Type.Array(Type.String(), {
|
|
82
|
+
description: `Which collections to watch (default: all). Options: texts, textDeltas, runs, toolCalls, childStatus`,
|
|
83
|
+
})
|
|
84
|
+
),
|
|
85
|
+
}),
|
|
86
|
+
execute: async (_toolCallId, params) => {
|
|
87
|
+
const { entity_url, collections } = params as {
|
|
88
|
+
entity_url: string
|
|
89
|
+
collections?: string[]
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
await ctx.observe(entity(entity_url), {
|
|
93
|
+
wake: { on: `change`, collections },
|
|
94
|
+
})
|
|
95
|
+
return {
|
|
96
|
+
content: [
|
|
97
|
+
{
|
|
98
|
+
type: `text`,
|
|
99
|
+
text: `Now observing entity: ${entity_url}. You will be woken when new activity is detected.`,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
details: {},
|
|
103
|
+
}
|
|
104
|
+
} catch (err) {
|
|
105
|
+
return {
|
|
106
|
+
content: [
|
|
107
|
+
{
|
|
108
|
+
type: `text`,
|
|
109
|
+
text: `Error observing entity: ${err instanceof Error ? err.message : `Unknown error`}`,
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
details: {},
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Other reactive variants
|
|
121
|
+
|
|
122
|
+
- **Summarizer** -- observes an entity's `texts` and `textDeltas` collections and produces progressive summaries of its output.
|
|
123
|
+
- **Guardian** -- observes an entity's `texts` and `toolCalls` collections and evaluates output quality, checking for hallucination signals, safety issues, and formatting problems.
|
|
124
|
+
|
|
125
|
+
All three follow the same structure: register an entity, wrap `createObserveTool` with a state transition, configure the agent with the observe tool, and run.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Mega Draw
|
|
3
|
+
titleTemplate: '... - Electric Agents'
|
|
4
|
+
description: >-
|
|
5
|
+
Multi-agent collaborative drawing example with coordinator-worker patterns and 100 tile agents.
|
|
6
|
+
outline: [2, 3]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Mega Draw
|
|
10
|
+
|
|
11
|
+
A collaborative multi-agent drawing app where 100 AI agents each own a tile of a shared 1000x1000 pixel canvas and work together to produce a drawing from a single text prompt. Located at `examples/mega-draw/` in the repository.
|
|
12
|
+
|
|
13
|
+
## What it demonstrates
|
|
14
|
+
|
|
15
|
+
- **Coordinator + worker pattern** at scale (1 coordinator spawning 100 tile agents)
|
|
16
|
+
- **Custom drawing tools** --- `fill_rect`, `draw_line`, `draw_circle`, `fill_gradient`, `set_pixels`
|
|
17
|
+
- **Shared canvas** --- in-memory pixel buffer flushed to PNG, served via a live viewer
|
|
18
|
+
- **Follow-up instructions** --- send a new prompt and only affected tiles get re-instructed
|
|
19
|
+
- **Two-pass workflow** --- coordinator does a quick first pass for backgrounds, then a detail pass
|
|
20
|
+
|
|
21
|
+
## Architecture
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
User
|
|
25
|
+
│
|
|
26
|
+
│ spawn /coordinator/my-drawing
|
|
27
|
+
│ send "Draw a sunset over mountains"
|
|
28
|
+
▼
|
|
29
|
+
┌────────────────────────────────┐
|
|
30
|
+
│ Coordinator Agent │
|
|
31
|
+
│ - Receives prompt │
|
|
32
|
+
│ - Plans composition + palette │
|
|
33
|
+
│ - Spawns 100 tile agents │
|
|
34
|
+
│ - Can re-instruct tiles │
|
|
35
|
+
└──────────┬─────────────────────┘
|
|
36
|
+
│ spawn tile-agent (10×10 grid)
|
|
37
|
+
▼
|
|
38
|
+
┌────────┐ ┌────────┐
|
|
39
|
+
│Tile 0,0│ │Tile 1,0│ ... (10 columns)
|
|
40
|
+
└────────┘ └────────┘
|
|
41
|
+
┌────────┐ ┌────────┐
|
|
42
|
+
│Tile 0,1│ │Tile 1,1│ ...
|
|
43
|
+
└────────┘ └────────┘
|
|
44
|
+
... ... (10 rows = 100 tiles)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Each tile agent:
|
|
48
|
+
|
|
49
|
+
- Owns a 100x100 pixel region
|
|
50
|
+
- Can **see** 50px beyond its borders (200x200 viewport) for edge coordination
|
|
51
|
+
- Can only **draw** within its own tile
|
|
52
|
+
- Receives drawing instructions from the coordinator
|
|
53
|
+
|
|
54
|
+
## Key files
|
|
55
|
+
|
|
56
|
+
### `src/server.ts`
|
|
57
|
+
|
|
58
|
+
Entry point. Creates the registry, runtime handler, and two HTTP servers (one for the Electric Agents webhook, one for the canvas viewer).
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
const registry = createEntityRegistry()
|
|
62
|
+
registerCoordinator(registry, WEB_PORT)
|
|
63
|
+
registerTileAgent(registry)
|
|
64
|
+
|
|
65
|
+
const runtime = createRuntimeHandler({
|
|
66
|
+
baseUrl: ELECTRIC_AGENTS_URL,
|
|
67
|
+
serveEndpoint: `${SERVE_URL}/webhook`,
|
|
68
|
+
registry,
|
|
69
|
+
})
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### `src/coordinator.ts`
|
|
73
|
+
|
|
74
|
+
The coordinator entity. Defines two custom tools:
|
|
75
|
+
|
|
76
|
+
- `set_drawing_plan` --- sets the composition description and color palette
|
|
77
|
+
- `instruct_tile` --- spawns or re-instructs a tile agent with drawing directions
|
|
78
|
+
|
|
79
|
+
### `src/tile-agent.ts`
|
|
80
|
+
|
|
81
|
+
The tile agent entity. Each instance gets drawing tools scoped to its tile:
|
|
82
|
+
|
|
83
|
+
- `read_viewport` --- see current pixel state (own tile + neighbors)
|
|
84
|
+
- `fill_rect`, `draw_line`, `draw_circle`, `fill_gradient`, `set_pixels`
|
|
85
|
+
|
|
86
|
+
All coordinates are tile-relative (0--99) and automatically clipped to tile bounds.
|
|
87
|
+
|
|
88
|
+
## Running it
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
cd examples/mega-draw
|
|
92
|
+
pnpm install
|
|
93
|
+
cp ../../.env.template .env # Set ANTHROPIC_API_KEY
|
|
94
|
+
pnpm dev
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Requires a running Electric Agents runtime server at `http://localhost:4437`.
|
|
98
|
+
|
|
99
|
+
Then in another terminal:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npx electric-ax agents spawn /coordinator/my-drawing
|
|
103
|
+
npx electric-ax agents send /coordinator/my-drawing 'Draw a sunset over mountains'
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
View the canvas live at `http://localhost:3000/my-drawing` --- it auto-refreshes as tiles draw.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pattern references
|
|
3
|
+
titleTemplate: '... - Electric Agents'
|
|
4
|
+
description: >-
|
|
5
|
+
Electric Agents pattern references for standalone, coordination, blackboard, and reactive designs.
|
|
6
|
+
outline: [2, 3]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Pattern references
|
|
10
|
+
|
|
11
|
+
Electric Agents pattern references live in the monorepo under `packages/agents-runtime/skills/designing-entities/references/patterns/`.
|
|
12
|
+
|
|
13
|
+
## What it includes
|
|
14
|
+
|
|
15
|
+
The patterns are organized into four categories.
|
|
16
|
+
|
|
17
|
+
### Standalone
|
|
18
|
+
|
|
19
|
+
- `single-agent` --- one entity handles the full task itself
|
|
20
|
+
|
|
21
|
+
### Coordination
|
|
22
|
+
|
|
23
|
+
- `manager-worker` --- multi-perspective analysis (optimist/pessimist/pragmatist)
|
|
24
|
+
- `dispatcher` --- routes tasks to the appropriate agent type
|
|
25
|
+
- `pipeline` --- sequential worker stages
|
|
26
|
+
- `map-reduce` --- parallel chunk processing
|
|
27
|
+
|
|
28
|
+
### Blackboard (shared state)
|
|
29
|
+
|
|
30
|
+
- `blackboard` --- multiple workers coordinate through shared state
|
|
31
|
+
|
|
32
|
+
### Reactive
|
|
33
|
+
|
|
34
|
+
- `reactive-observers` --- observes entity streams and reacts to changes
|
|
35
|
+
|
|
36
|
+
## Source references
|
|
37
|
+
|
|
38
|
+
- [`single-agent`](https://github.com/electric-sql/electric/blob/main/packages/agents-runtime/skills/designing-entities/references/patterns/single-agent.md)
|
|
39
|
+
- [`manager-worker`](https://github.com/electric-sql/electric/blob/main/packages/agents-runtime/skills/designing-entities/references/patterns/manager-worker.md)
|
|
40
|
+
- [`dispatcher`](https://github.com/electric-sql/electric/blob/main/packages/agents-runtime/skills/designing-entities/references/patterns/dispatcher.md)
|
|
41
|
+
- [`pipeline`](https://github.com/electric-sql/electric/blob/main/packages/agents-runtime/skills/designing-entities/references/patterns/pipeline.md)
|
|
42
|
+
- [`map-reduce`](https://github.com/electric-sql/electric/blob/main/packages/agents-runtime/skills/designing-entities/references/patterns/map-reduce.md)
|
|
43
|
+
- [`blackboard`](https://github.com/electric-sql/electric/blob/main/packages/agents-runtime/skills/designing-entities/references/patterns/blackboard.md)
|
|
44
|
+
- [`reactive-observers`](https://github.com/electric-sql/electric/blob/main/packages/agents-runtime/skills/designing-entities/references/patterns/reactive-observers.md)
|
|
45
|
+
|
|
46
|
+
See [Agents & Patterns](../usage/spawning-and-coordinating.md) for detailed documentation of each pattern.
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Electric Agents
|
|
3
|
+
titleTemplate: '... - Electric Agents'
|
|
4
|
+
description: >-
|
|
5
|
+
The durable runtime for long-lived agents — entities, handlers, wakes, agent loops, and coordination, built on Electric Streams, TanStack DB, and pi.
|
|
6
|
+
outline: [2, 3]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<script setup>
|
|
10
|
+
import EntityOverviewDiagram from '../../src/components/agents-home/EntityOverviewDiagram.vue'
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
# Electric Agents
|
|
14
|
+
|
|
15
|
+
Electric Agents is **the durable runtime for long-lived agents**. It's a runtime and communication fabric for spawning and scaling collaborative agents on serverless compute, using your existing web and AI frameworks.
|
|
16
|
+
|
|
17
|
+
Each agent is an **entity** — an addressable, schema-typed unit of state at `/{type}/{id}`. An entity's session and state live on a durable [Electric Stream](/streams/) of events.
|
|
18
|
+
|
|
19
|
+
Entities **wake** when something happens — a message arrives, a child finishes, state changes, or a scheduled time elapses. When woken, the entity's handler runs. It can configure an LLM agent loop, update state, spawn children, and coordinate with other entities.
|
|
20
|
+
|
|
21
|
+
Every step — runs, tool calls, text deltas, state changes — is appended to the entity's stream as it happens. Agents scale to zero and survive restarts. Any session can be replayed or [forked](/blog/2026/04/15/fork-branching-for-durable-streams) from any point, and observed in real time by any number of users and entities, both inside the system and from external apps.
|
|
22
|
+
|
|
23
|
+
<EntityOverviewDiagram />
|
|
24
|
+
|
|
25
|
+
Start with the [Quickstart](/docs/agents/quickstart) to run the built-in `horton` agent and connect your own app in a few minutes. The [Usage overview](/docs/agents/usage/overview) summarises the full developer surface in a single page.
|
|
26
|
+
|
|
27
|
+
## How it works
|
|
28
|
+
|
|
29
|
+
The runtime SDK is a layer over three foundations:
|
|
30
|
+
|
|
31
|
+
- **[Electric Streams](/streams/)** — durable, ordered event log per entity.
|
|
32
|
+
- **[TanStack DB](https://tanstack.com/db)** — typed local reads and writes via collections.
|
|
33
|
+
- **Mario Zechner's [pi](https://github.com/badlogic/pi-mono) toolkit** — `pi-ai` (unified multi-provider LLM API) and `pi-agent-core` (agent runtime) for the LLM agent loop.
|
|
34
|
+
|
|
35
|
+
**One stream per entity.** The runtime projects that stream into a typed local DB of collections — an `EntityStreamDB`. Inside a handler, that DB is `ctx.db`: writes go through `ctx.db.actions` (which append events to the stream), reads come from `ctx.db.collections`. The runtime ships [built-in collections](#built-in-collections) for runs, tool calls, text deltas, errors, inbox, and more, and you add your own typed [state](#state) collections per entity type.
|
|
36
|
+
|
|
37
|
+
**Inside a handler.** When a handler calls `ctx.useAgent()`, the runtime configures the agent on its behalf and routes every step — model call, text delta, tool invocation, error — through the same projection, so the agent loop becomes durable events on the entity's stream.
|
|
38
|
+
|
|
39
|
+
**Outside the handler.** Any app or other entity can call [`createAgentsClient().observe(entity('/type/id'))`](/docs/agents/usage/clients-and-react) to load an entity's stream into a local DB and react to changes in real time, with the same schemas and types as the handler.
|
|
40
|
+
|
|
41
|
+
## Entities
|
|
42
|
+
|
|
43
|
+
Use entities to model anything long-lived and addressable — an agent session, a chat thread, a research job, a coordinator, a worker. You register a **type** with [`registry.define()`](/docs/agents/reference/entity-registry) and spawn **instances** at `/{type}/{id}`. Each instance has its own state, handler, and event stream. See [Defining entities](/docs/agents/usage/defining-entities).
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
const registry = createEntityRegistry()
|
|
47
|
+
|
|
48
|
+
registry.define('assistant', {
|
|
49
|
+
description: 'A general-purpose AI assistant',
|
|
50
|
+
async handler(ctx) {
|
|
51
|
+
// ...
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Handlers
|
|
57
|
+
|
|
58
|
+
The function that runs when an entity wakes. Receives a [`HandlerContext`](/docs/agents/reference/handler-context) (`ctx`) and a [`WakeEvent`](/docs/agents/reference/wake-event) (`wake`). The handler decides how to respond: configure an agent, update state, spawn children, or any combination. See [Writing handlers](/docs/agents/usage/writing-handlers).
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
registry.define('support', {
|
|
62
|
+
async handler(ctx, wake) {
|
|
63
|
+
if (wake.type === 'message_received') {
|
|
64
|
+
ctx.useAgent({
|
|
65
|
+
systemPrompt: 'You are a support agent.',
|
|
66
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
67
|
+
tools: [...ctx.electricTools, searchKbTool],
|
|
68
|
+
})
|
|
69
|
+
await ctx.agent.run()
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Wakes
|
|
76
|
+
|
|
77
|
+
Events that trigger a handler invocation. Wake sources include incoming messages, child completion, state changes, and timers (scheduled sends, cron, timeouts). The [`WakeEvent`](/docs/agents/reference/wake-event) tells the handler why it was woken. See [Waking entities](/docs/agents/usage/waking-entities).
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
async handler(ctx, wake) {
|
|
81
|
+
// wake.type — "message_received", "wake", etc.
|
|
82
|
+
// wake.source — who triggered the wake
|
|
83
|
+
// wake.payload — message content or wake data
|
|
84
|
+
|
|
85
|
+
if (wake.type === "message_received") {
|
|
86
|
+
const userMessage = wake.payload
|
|
87
|
+
// handle incoming message
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## State
|
|
93
|
+
|
|
94
|
+
Custom persistent collections on the entity. Defined as part of the [entity definition](/docs/agents/reference/entity-definition) and accessed through `ctx.db` alongside the [built-in collections](#built-in-collections). State is local to the entity, typed, and survives restarts. Use it for things that belong to the entity but aren't part of the agent's event stream — an order's items, a research job's findings, a chat session's TODOs. See [Managing state](/docs/agents/usage/managing-state).
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
registry.define('tracker', {
|
|
98
|
+
state: {
|
|
99
|
+
items: {
|
|
100
|
+
schema: z.object({
|
|
101
|
+
key: z.string(),
|
|
102
|
+
name: z.string(),
|
|
103
|
+
done: z.boolean(),
|
|
104
|
+
}),
|
|
105
|
+
primaryKey: 'key',
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
async handler(ctx) {
|
|
109
|
+
// read
|
|
110
|
+
const item = ctx.db.collections.items.get('item-1')
|
|
111
|
+
|
|
112
|
+
// write
|
|
113
|
+
ctx.db.actions.items_insert({
|
|
114
|
+
row: { key: 'item-2', name: 'New', done: false },
|
|
115
|
+
})
|
|
116
|
+
},
|
|
117
|
+
})
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Agent loop
|
|
121
|
+
|
|
122
|
+
The core pattern is [`ctx.useAgent()`](/docs/agents/reference/agent-config) followed by `ctx.agent.run()`. This runs the LLM in a loop — it generates text, calls tools, and continues until it has nothing left to do. All activity is automatically persisted to the entity's stream. See [Configuring the agent](/docs/agents/usage/configuring-the-agent).
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
ctx.useAgent({
|
|
126
|
+
systemPrompt: 'You are a helpful assistant.',
|
|
127
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
128
|
+
tools: [...ctx.electricTools, myCustomTool],
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
await ctx.agent.run()
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Tools
|
|
135
|
+
|
|
136
|
+
Functions the LLM can call during the agent loop. Each tool has a name, description, parameters (defined with [TypeBox](https://github.com/sinclairzx81/typebox) or any [Standard Schema](https://standardschema.dev) validator), and an execute function. Tools run in the handler's context and have access to the entity's state and coordination primitives. See [Defining tools](/docs/agents/usage/defining-tools) and the [`AgentTool` reference](/docs/agents/reference/agent-tool).
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
const searchKbTool: AgentTool = {
|
|
140
|
+
name: 'search_kb',
|
|
141
|
+
label: 'Search knowledge base',
|
|
142
|
+
description: 'Search the knowledge base',
|
|
143
|
+
parameters: Type.Object({
|
|
144
|
+
query: Type.String({ description: 'Search query' }),
|
|
145
|
+
}),
|
|
146
|
+
execute: async (_toolCallId, params) => {
|
|
147
|
+
const { query } = params as { query: string }
|
|
148
|
+
const results = await searchKnowledgeBase(query)
|
|
149
|
+
return {
|
|
150
|
+
content: [{ type: 'text', text: JSON.stringify(results) }],
|
|
151
|
+
details: {},
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Coordination
|
|
158
|
+
|
|
159
|
+
Entities interact through structured primitives. An entity can `spawn` children, `observe` other entities, `send` messages, and [share state](/docs/agents/usage/shared-state). These operations are all durable — they survive restarts and are tracked in the event stream. See [Spawning and coordinating](/docs/agents/usage/spawning-and-coordinating).
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
async handler(ctx) {
|
|
163
|
+
// spawn a child entity — wake parent when it finishes
|
|
164
|
+
const child = await ctx.spawn(
|
|
165
|
+
"worker",
|
|
166
|
+
"task-1",
|
|
167
|
+
{
|
|
168
|
+
systemPrompt: "Analyse the report",
|
|
169
|
+
tools: ["read"],
|
|
170
|
+
},
|
|
171
|
+
{ initialMessage: "Find the top three issues", wake: "runFinished" }
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
// send a message to another entity
|
|
175
|
+
ctx.send("/notify/alerts", { level: "info", text: "Task started" })
|
|
176
|
+
|
|
177
|
+
// observe another entity's state changes
|
|
178
|
+
await ctx.observe(entity("/order/99"), {
|
|
179
|
+
wake: { on: "change", collections: ["status"] },
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Built-in collections
|
|
185
|
+
|
|
186
|
+
Every entity automatically has collections for runs, steps, texts, tool calls, errors, inbox, and more. These are populated by the runtime as the agent operates and give you live observability into every step of the agent loop — useful for chat UIs, debugging tools, dashboards, and analytics. Query them from the handler or observe them externally. See the [Built-in collections reference](/docs/agents/reference/built-in-collections).
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
// from inside a handler
|
|
190
|
+
const allRuns = ctx.db.collections.runs.toArray
|
|
191
|
+
const lastError = ctx.db.collections.errors.toArray.at(-1)
|
|
192
|
+
|
|
193
|
+
// from outside — load an entity's stream into a local DB
|
|
194
|
+
const client = createAgentsClient({ baseUrl: 'http://localhost:4437' })
|
|
195
|
+
const db = await client.observe(entity('/support/ticket-42'))
|
|
196
|
+
console.log(db.collections.texts.toArray)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Next steps
|
|
200
|
+
|
|
201
|
+
- [Quickstart](/docs/agents/quickstart) — run the built-in `horton` agent and connect your own app.
|
|
202
|
+
- [Usage overview](/docs/agents/usage/overview) — the full developer surface on one page.
|
|
203
|
+
- [Defining entities](/docs/agents/usage/defining-entities) — entity types, schemas, and configuration.
|
|
204
|
+
- [Writing handlers](/docs/agents/usage/writing-handlers) — handler lifecycle and the `ctx` API.
|
|
205
|
+
- [Configuring the agent](/docs/agents/usage/configuring-the-agent) — `useAgent`, models, tools, and streaming.
|
|
206
|
+
- [Spawning & coordinating](/docs/agents/usage/spawning-and-coordinating) — multi-entity topologies and shared state.
|
|
207
|
+
- [Built-in agents](/docs/agents/entities/agents/horton) — Horton and Worker, the agents that ship with the runtime.
|
|
208
|
+
- [Examples](/docs/agents/examples/playground) — pattern walkthroughs and demo apps.
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Quickstart
|
|
3
|
+
titleTemplate: '... - Electric Agents'
|
|
4
|
+
description: >-
|
|
5
|
+
Run the Electric Agents runtime and the built-in Horton assistant with a single CLI command, then connect from the web UI or define your own entities.
|
|
6
|
+
outline: [2, 3]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Quickstart
|
|
10
|
+
|
|
11
|
+
One command starts the Electric Agents runtime, the web UI, and a local [Horton](./entities/agents/horton) assistant you can chat with right away. From there, define your own [entities](./usage/defining-entities) in your own app.
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npx electric-ax agents quickstart
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## What you'll need
|
|
18
|
+
|
|
19
|
+
- **Node.js 18+**.
|
|
20
|
+
- **[Docker](https://docs.docker.com/get-docker/)**. The runtime server, Postgres, and Electric run as containers.
|
|
21
|
+
- **An [Anthropic API key](https://console.anthropic.com/settings/keys)**. Used by the built-in Horton agent.
|
|
22
|
+
- _(Optional)_ A **[Brave Search API key](https://brave.com/search/api/)** if you want Horton to be able to search the web.
|
|
23
|
+
|
|
24
|
+
## Set your API key
|
|
25
|
+
|
|
26
|
+
Either export it in your shell:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Or persist it in a `.env` file in the directory you run the CLI from (this creates or overwrites `.env` in the current directory):
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
cat <<'EOF' > .env
|
|
36
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
37
|
+
# BRAVE_SEARCH_API_KEY=BS...
|
|
38
|
+
EOF
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The CLI also accepts `--anthropic-api-key <key>` if you'd rather pass it inline.
|
|
42
|
+
|
|
43
|
+
## Start the runtime
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
npx electric-ax agents quickstart
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This:
|
|
50
|
+
|
|
51
|
+
1. Starts Postgres, Electric, and the Electric Agents runtime server in Docker (the runtime serves both the API and the web UI on `http://localhost:4437`).
|
|
52
|
+
2. Starts a built-in **Horton** runtime in the foreground that registers the `horton` and `worker` entity types.
|
|
53
|
+
3. Prints onboarding commands you can copy into a second terminal.
|
|
54
|
+
|
|
55
|
+
Leave this terminal running. Press `Ctrl-C` to stop the built-in Horton runtime — the runtime server containers keep running in the background until you call [`electric agents stop`](#stop-the-dev-environment).
|
|
56
|
+
|
|
57
|
+
## Chat with Horton
|
|
58
|
+
|
|
59
|
+
### From the web UI
|
|
60
|
+
|
|
61
|
+
Open [http://localhost:4437](http://localhost:4437). Spawn a `horton` entity from the dashboard and send it a message — its timeline updates live as the agent thinks, calls tools, and responds.
|
|
62
|
+
|
|
63
|
+
### From the CLI
|
|
64
|
+
|
|
65
|
+
In a separate terminal:
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
npx electric-ax agents spawn /horton/onboarding
|
|
69
|
+
npx electric-ax agents send /horton/onboarding 'Walk me through Electric Agents'
|
|
70
|
+
npx electric-ax agents observe /horton/onboarding
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
- `spawn` creates a new entity instance at the given path.
|
|
74
|
+
- `send` delivers a message to the entity's inbox, waking its handler.
|
|
75
|
+
- `observe` streams the entity's events to your terminal in real time, with reasoning, tool calls, and text deltas rendered inline.
|
|
76
|
+
|
|
77
|
+
See the [CLI reference](./reference/cli) for the full command surface.
|
|
78
|
+
|
|
79
|
+
## Define your own entity types
|
|
80
|
+
|
|
81
|
+
Once you're chatting with Horton, the next step is to define your own entity types in your own app. Your app is just a process that registers entity types with the runtime server and receives webhook callbacks when they wake.
|
|
82
|
+
|
|
83
|
+
### 1. Install the runtime SDK
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
mkdir my-agents-app && cd my-agents-app
|
|
87
|
+
npm init -y
|
|
88
|
+
npm install @electric-ax/agents-runtime
|
|
89
|
+
npm install --save-dev tsx
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 2. Create a server
|
|
93
|
+
|
|
94
|
+
Create `server.ts`:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import http from 'node:http'
|
|
98
|
+
import {
|
|
99
|
+
createEntityRegistry,
|
|
100
|
+
createRuntimeHandler,
|
|
101
|
+
} from '@electric-ax/agents-runtime'
|
|
102
|
+
|
|
103
|
+
const ELECTRIC_AGENTS_URL =
|
|
104
|
+
process.env.ELECTRIC_AGENTS_URL ?? 'http://localhost:4437'
|
|
105
|
+
const PORT = Number(process.env.PORT ?? 3000)
|
|
106
|
+
const SERVE_URL = process.env.SERVE_URL ?? `http://localhost:${PORT}`
|
|
107
|
+
|
|
108
|
+
const registry = createEntityRegistry()
|
|
109
|
+
|
|
110
|
+
registry.define('assistant', {
|
|
111
|
+
description: 'A general-purpose AI assistant',
|
|
112
|
+
async handler(ctx) {
|
|
113
|
+
ctx.useAgent({
|
|
114
|
+
systemPrompt: 'You are a helpful assistant.',
|
|
115
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
116
|
+
tools: [...ctx.electricTools],
|
|
117
|
+
})
|
|
118
|
+
await ctx.agent.run()
|
|
119
|
+
},
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
const runtime = createRuntimeHandler({
|
|
123
|
+
baseUrl: ELECTRIC_AGENTS_URL,
|
|
124
|
+
serveEndpoint: `${SERVE_URL}/webhook`,
|
|
125
|
+
registry,
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
const server = http.createServer(async (req, res) => {
|
|
129
|
+
if (req.url === '/webhook' && req.method === 'POST') {
|
|
130
|
+
await runtime.onEnter(req, res)
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
res.writeHead(404)
|
|
134
|
+
res.end()
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
server.listen(PORT, async () => {
|
|
138
|
+
await runtime.registerTypes()
|
|
139
|
+
console.log(`App server ready on port ${PORT}`)
|
|
140
|
+
})
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
This does four things:
|
|
144
|
+
|
|
145
|
+
1. **Defines an entity type** called `assistant` with a handler that configures and runs an LLM agent.
|
|
146
|
+
2. **Creates a runtime handler** that connects to the runtime server.
|
|
147
|
+
3. **Starts an HTTP server** to receive webhook callbacks from the runtime.
|
|
148
|
+
4. **Registers entity types** with the runtime server on startup.
|
|
149
|
+
|
|
150
|
+
See [App setup](./usage/app-setup) for the full `createRuntimeHandler` configuration.
|
|
151
|
+
|
|
152
|
+
### 3. Run your app
|
|
153
|
+
|
|
154
|
+
With the runtime server already running (from `electric agents quickstart` or `electric agents start`), start your app:
|
|
155
|
+
|
|
156
|
+
```sh
|
|
157
|
+
npx tsx server.ts
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Your handler calls `ctx.useAgent()` in this process, so make sure `ANTHROPIC_API_KEY` is exported in this shell (or copy your `.env` into `my-agents-app`).
|
|
161
|
+
|
|
162
|
+
### 4. Interact with your entity
|
|
163
|
+
|
|
164
|
+
Spawn an instance, send it a message, and observe the timeline:
|
|
165
|
+
|
|
166
|
+
```sh
|
|
167
|
+
npx electric-ax agents spawn /assistant/my-assistant
|
|
168
|
+
npx electric-ax agents send /assistant/my-assistant 'Hello!'
|
|
169
|
+
npx electric-ax agents observe /assistant/my-assistant
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Or open the web UI at `http://localhost:4437` and pick `/assistant/my-assistant` from the entity list.
|
|
173
|
+
|
|
174
|
+
## Stop the dev environment
|
|
175
|
+
|
|
176
|
+
`Ctrl-C` in the quickstart terminal stops the built-in Horton runtime. The runtime server containers keep running. To stop them:
|
|
177
|
+
|
|
178
|
+
```sh
|
|
179
|
+
npx electric-ax agents stop # stop containers, keep data
|
|
180
|
+
npx electric-ax agents stop --remove-volumes # stop containers and wipe data
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Run pieces independently
|
|
184
|
+
|
|
185
|
+
`quickstart` runs `start` then `start-builtin` for you. Run them yourself if you want the runtime server up across multiple sessions, or to run your own agent process instead of the built-ins:
|
|
186
|
+
|
|
187
|
+
```sh
|
|
188
|
+
npx electric-ax agents start # runtime server + UI (background, Docker)
|
|
189
|
+
npx electric-ax agents start-builtin # built-in Horton + worker (foreground)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
See the [CLI reference](./reference/cli#start) for the full set of commands.
|
|
193
|
+
|
|
194
|
+
## Next steps
|
|
195
|
+
|
|
196
|
+
- [Overview](./) — the mental model behind entities, handlers, and wakes.
|
|
197
|
+
- [Usage overview](./usage/overview) — the full developer surface on one page.
|
|
198
|
+
- [Defining entities](./usage/defining-entities) — entity types, schemas, and configuration.
|
|
199
|
+
- [Writing handlers](./usage/writing-handlers) — handler lifecycle and the `ctx` API.
|
|
200
|
+
- [Configuring the agent](./usage/configuring-the-agent) — `useAgent`, models, tools, and streaming.
|
|
201
|
+
- [Built-in agents](./entities/agents/horton) — Horton and Worker, the agents that ship with the runtime.
|