@electric-ax/agents 0.2.3 → 0.2.4
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 +40 -12
- package/dist/index.cjs +40 -12
- package/dist/index.js +40 -12
- package/docs/entities/agents/coder.md +99 -0
- package/docs/entities/agents/horton.md +16 -13
- package/docs/entities/agents/worker.md +18 -18
- package/docs/entities/patterns/blackboard.md +6 -6
- package/docs/entities/patterns/dispatcher.md +1 -1
- package/docs/entities/patterns/manager-worker.md +1 -1
- package/docs/entities/patterns/map-reduce.md +1 -1
- package/docs/entities/patterns/pipeline.md +1 -1
- package/docs/entities/patterns/reactive-observers.md +2 -2
- package/docs/examples/playground.md +42 -26
- package/docs/index.md +23 -23
- package/docs/quickstart.md +13 -13
- package/docs/reference/agent-config.md +20 -12
- package/docs/reference/agent-tool.md +1 -1
- package/docs/reference/built-in-collections.md +21 -21
- package/docs/reference/cli.md +39 -30
- package/docs/reference/entity-definition.md +9 -9
- package/docs/reference/entity-handle.md +2 -2
- package/docs/reference/entity-registry.md +1 -1
- package/docs/reference/handler-context.md +69 -18
- package/docs/reference/runtime-handler.md +25 -23
- package/docs/reference/shared-state-handle.md +7 -7
- package/docs/reference/state-collection-proxy.md +1 -1
- package/docs/reference/wake-event.md +23 -23
- package/docs/usage/app-setup.md +24 -23
- package/docs/usage/clients-and-react.md +44 -36
- package/docs/usage/configuring-the-agent.md +25 -19
- package/docs/usage/context-composition.md +12 -12
- package/docs/usage/defining-entities.md +36 -36
- package/docs/usage/defining-tools.md +45 -45
- package/docs/usage/embedded-builtins.md +48 -47
- package/docs/usage/managing-state.md +12 -12
- package/docs/usage/overview.md +52 -45
- package/docs/usage/programmatic-runtime-client.md +50 -47
- package/docs/usage/shared-state.md +32 -32
- package/docs/usage/spawning-and-coordinating.md +9 -9
- package/docs/usage/testing.md +14 -14
- package/docs/usage/waking-entities.md +13 -13
- package/docs/usage/writing-handlers.md +57 -26
- package/package.json +4 -1
- package/scripts/sync-docs.mjs +42 -0
- package/docs/examples/mega-draw.md +0 -106
package/docs/usage/app-setup.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: App setup
|
|
3
|
-
titleTemplate:
|
|
3
|
+
titleTemplate: "... - Electric Agents"
|
|
4
4
|
description: >-
|
|
5
5
|
Connect your app to the Electric Agents runtime with createRuntimeHandler, webhooks, and type registration.
|
|
6
6
|
outline: [2, 3]
|
|
@@ -18,14 +18,14 @@ Creates a runtime with a Node HTTP adapter:
|
|
|
18
18
|
import {
|
|
19
19
|
createEntityRegistry,
|
|
20
20
|
createRuntimeHandler,
|
|
21
|
-
} from
|
|
21
|
+
} from "@electric-ax/agents-runtime"
|
|
22
22
|
|
|
23
23
|
const registry = createEntityRegistry()
|
|
24
24
|
// ... register entity types ...
|
|
25
25
|
|
|
26
26
|
const runtime = createRuntimeHandler({
|
|
27
|
-
baseUrl:
|
|
28
|
-
serveEndpoint:
|
|
27
|
+
baseUrl: "http://localhost:4437",
|
|
28
|
+
serveEndpoint: "http://localhost:3000/webhook",
|
|
29
29
|
registry,
|
|
30
30
|
})
|
|
31
31
|
```
|
|
@@ -37,6 +37,7 @@ interface RuntimeRouterConfig {
|
|
|
37
37
|
baseUrl: string // Electric Agents server URL
|
|
38
38
|
serveEndpoint?: string // Webhook callback URL
|
|
39
39
|
webhookPath?: string // Path to match (default: derived from serveEndpoint)
|
|
40
|
+
handlerUrl?: string // legacy alias for serveEndpoint
|
|
40
41
|
registry?: EntityRegistry
|
|
41
42
|
subscriptionPathForType?: (typeName: string) => string
|
|
42
43
|
idleTimeout?: number // ms before closing idle wake (default: 20000)
|
|
@@ -75,10 +76,10 @@ interface RuntimeRouterConfig {
|
|
|
75
76
|
Your app needs an HTTP server to receive webhook callbacks from the Electric Agents runtime server. Forward webhook POSTs to the runtime handler:
|
|
76
77
|
|
|
77
78
|
```ts
|
|
78
|
-
import http from
|
|
79
|
+
import http from "node:http"
|
|
79
80
|
|
|
80
81
|
const server = http.createServer(async (req, res) => {
|
|
81
|
-
if (req.url ===
|
|
82
|
+
if (req.url === "/webhook" && req.method === "POST") {
|
|
82
83
|
await runtime.onEnter(req, res)
|
|
83
84
|
return
|
|
84
85
|
}
|
|
@@ -131,24 +132,24 @@ interface RuntimeDebugState {
|
|
|
131
132
|
}
|
|
132
133
|
```
|
|
133
134
|
|
|
134
|
-
| Method | Description
|
|
135
|
-
| ---------------------- |
|
|
136
|
-
| `onEnter` | Node HTTP adapter — reads the request body and delegates to `handleWebhookRequest`
|
|
137
|
-
| `handleRequest` | Fetch-native router — returns `null` if the path does not match `webhookPath`
|
|
138
|
-
| `handleWebhookRequest` | Processes a webhook POST directly, without path matching
|
|
139
|
-
| `dispatchWebhookWake` | Dispatches a pre-parsed notification (fire-and-forget)
|
|
140
|
-
| `drainWakes` | Waits for all in-flight wake handlers to settle; throws on errors
|
|
141
|
-
| `waitForSettled` | Waits for all in-flight wakes; throws on errors
|
|
142
|
-
| `abortWakes` | Cancels all in-flight wake handlers immediately
|
|
143
|
-
| `debugState` | Returns a snapshot of internal runtime state for diagnostics
|
|
144
|
-
| `registerTypes` | Registers entity types and webhook subscriptions with the Electric Agents runtime server
|
|
135
|
+
| Method | Description |
|
|
136
|
+
| ---------------------- | ---------------------------------------------------------------------------------- |
|
|
137
|
+
| `onEnter` | Node HTTP adapter — reads the request body and delegates to `handleWebhookRequest` |
|
|
138
|
+
| `handleRequest` | Fetch-native router — returns `null` if the path does not match `webhookPath` |
|
|
139
|
+
| `handleWebhookRequest` | Processes a webhook POST directly, without path matching |
|
|
140
|
+
| `dispatchWebhookWake` | Dispatches a pre-parsed notification (fire-and-forget) |
|
|
141
|
+
| `drainWakes` | Waits for all in-flight wake handlers to settle; throws on errors |
|
|
142
|
+
| `waitForSettled` | Waits for all in-flight wakes; throws on errors |
|
|
143
|
+
| `abortWakes` | Cancels all in-flight wake handlers immediately |
|
|
144
|
+
| `debugState` | Returns a snapshot of internal runtime state for diagnostics |
|
|
145
|
+
| `registerTypes` | Registers entity types and webhook subscriptions with the Electric Agents runtime server |
|
|
145
146
|
|
|
146
147
|
## createRuntimeRouter
|
|
147
148
|
|
|
148
149
|
Fetch-native alternative with no Node HTTP dependency:
|
|
149
150
|
|
|
150
151
|
```ts
|
|
151
|
-
import { createRuntimeRouter } from
|
|
152
|
+
import { createRuntimeRouter } from "@electric-ax/agents-runtime"
|
|
152
153
|
|
|
153
154
|
const router = createRuntimeRouter(config)
|
|
154
155
|
const response = await router.handleRequest(request)
|
|
@@ -158,8 +159,8 @@ Use this when integrating with non-Node frameworks or edge runtimes.
|
|
|
158
159
|
|
|
159
160
|
## Environment variables
|
|
160
161
|
|
|
161
|
-
| Variable
|
|
162
|
-
|
|
|
163
|
-
| `ELECTRIC_AGENTS_URL`
|
|
164
|
-
| `PORT`
|
|
165
|
-
| `ANTHROPIC_API_KEY`
|
|
162
|
+
| Variable | Default | Purpose |
|
|
163
|
+
| ------------------- | ----------------------- | ------------------------ |
|
|
164
|
+
| `ELECTRIC_AGENTS_URL` | `http://localhost:4437` | Electric Agents runtime server URL |
|
|
165
|
+
| `PORT` | `3000` | Your app's HTTP port |
|
|
166
|
+
| `ANTHROPIC_API_KEY` | — | Claude API key |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Clients & React
|
|
3
|
-
titleTemplate:
|
|
3
|
+
titleTemplate: "... - Electric Agents"
|
|
4
4
|
description: >-
|
|
5
5
|
Observe Electric Agents entities from app code, build reactive StreamDB handles,
|
|
6
6
|
and render chat timelines with the React useChat hook.
|
|
@@ -17,20 +17,27 @@ Use the client APIs when you need to observe agents from application code rather
|
|
|
17
17
|
|
|
18
18
|
```ts
|
|
19
19
|
import {
|
|
20
|
+
codingSession,
|
|
20
21
|
createAgentsClient,
|
|
21
22
|
entity,
|
|
22
23
|
entities,
|
|
23
|
-
} from
|
|
24
|
+
} from "@electric-ax/agents-runtime"
|
|
24
25
|
|
|
25
|
-
const client = createAgentsClient({ baseUrl:
|
|
26
|
+
const client = createAgentsClient({ baseUrl: "http://localhost:4437" })
|
|
26
27
|
|
|
27
28
|
// Observe a single entity stream.
|
|
28
|
-
const entityDb = await client.observe(entity(
|
|
29
|
+
const entityDb = await client.observe(entity("/horton/onboarding"))
|
|
29
30
|
console.log(entityDb.collections.texts.toArray)
|
|
30
31
|
|
|
31
32
|
// Observe the entity membership stream for a tag query.
|
|
32
|
-
const membersDb = await client.observe(
|
|
33
|
+
const membersDb = await client.observe(
|
|
34
|
+
entities({ tags: { project: "alpha" } })
|
|
35
|
+
)
|
|
33
36
|
console.log(membersDb.collections.members.toArray)
|
|
37
|
+
|
|
38
|
+
// Observe a built-in coder session by id.
|
|
39
|
+
const coderDb = await client.observe(codingSession("feature-work"))
|
|
40
|
+
console.log(coderDb.collections.events.toArray)
|
|
34
41
|
```
|
|
35
42
|
|
|
36
43
|
### Types
|
|
@@ -58,17 +65,18 @@ interface AgentsClient {
|
|
|
58
65
|
|
|
59
66
|
The same source helpers used by `ctx.observe()` can be used with `AgentsClient`.
|
|
60
67
|
|
|
61
|
-
| Helper
|
|
62
|
-
|
|
|
63
|
-
| `entity(url)`
|
|
68
|
+
| Helper | Use case |
|
|
69
|
+
| ------------------- | ---------------------------------------------------- |
|
|
70
|
+
| `entity(url)` | Observe one entity by URL. |
|
|
71
|
+
| `codingSession(id)` | Observe a built-in `coder` entity by session id. |
|
|
64
72
|
| `entities({ tags })` | Observe the entity membership stream matching tags. |
|
|
65
|
-
| `db(id, schema)`
|
|
66
|
-
| `cron(expression)`
|
|
73
|
+
| `db(id, schema)` | Observe a shared-state stream. |
|
|
74
|
+
| `cron(expression)` | Build a cron source for wake subscriptions. |
|
|
67
75
|
|
|
68
76
|
```ts
|
|
69
|
-
import { db } from
|
|
77
|
+
import { db } from "@electric-ax/agents-runtime"
|
|
70
78
|
|
|
71
|
-
const shared = await client.observe(db(
|
|
79
|
+
const shared = await client.observe(db("research-123", researchSchema))
|
|
72
80
|
```
|
|
73
81
|
|
|
74
82
|
## React useChat
|
|
@@ -76,12 +84,12 @@ const shared = await client.observe(db('research-123', researchSchema))
|
|
|
76
84
|
`@electric-ax/agents-runtime/react` exports `useChat()`, a React hook that turns an `EntityStreamDB` into sections suitable for a chat UI.
|
|
77
85
|
|
|
78
86
|
```tsx
|
|
79
|
-
import { useEffect, useState } from
|
|
80
|
-
import { createAgentsClient, entity } from
|
|
81
|
-
import { useChat } from
|
|
82
|
-
import type { EntityStreamDB } from
|
|
87
|
+
import { useEffect, useState } from "react"
|
|
88
|
+
import { createAgentsClient, entity } from "@electric-ax/agents-runtime"
|
|
89
|
+
import { useChat } from "@electric-ax/agents-runtime/react"
|
|
90
|
+
import type { EntityStreamDB } from "@electric-ax/agents-runtime"
|
|
83
91
|
|
|
84
|
-
const client = createAgentsClient({ baseUrl:
|
|
92
|
+
const client = createAgentsClient({ baseUrl: "http://localhost:4437" })
|
|
85
93
|
|
|
86
94
|
export function AgentConversation({ entityUrl }: { entityUrl: string }) {
|
|
87
95
|
const [db, setDb] = useState<EntityStreamDB | null>(null)
|
|
@@ -109,10 +117,10 @@ export function AgentConversation({ entityUrl }: { entityUrl: string }) {
|
|
|
109
117
|
<ol>
|
|
110
118
|
{chat.sections.map((section, index) => (
|
|
111
119
|
<li key={index}>
|
|
112
|
-
{section.kind ===
|
|
120
|
+
{section.kind === "user_message"
|
|
113
121
|
? section.text
|
|
114
122
|
: section.items.map((item) =>
|
|
115
|
-
item.kind ===
|
|
123
|
+
item.kind === "text" ? item.text : item.toolName
|
|
116
124
|
)}
|
|
117
125
|
</li>
|
|
118
126
|
))}
|
|
@@ -126,7 +134,7 @@ export function AgentConversation({ entityUrl }: { entityUrl: string }) {
|
|
|
126
134
|
```ts
|
|
127
135
|
interface UseChatResult {
|
|
128
136
|
sections: EntityTimelineSection[]
|
|
129
|
-
state:
|
|
137
|
+
state: "pending" | "queued" | "working" | "idle" | "error"
|
|
130
138
|
runs: IncludesRun[]
|
|
131
139
|
inbox: IncludesInboxMessage[]
|
|
132
140
|
wakes: IncludesWakeMessage[]
|
|
@@ -151,34 +159,34 @@ import {
|
|
|
151
159
|
normalizeEntityTimelineData,
|
|
152
160
|
timelineMessages,
|
|
153
161
|
timelineToMessages,
|
|
154
|
-
} from
|
|
162
|
+
} from "@electric-ax/agents-runtime"
|
|
155
163
|
```
|
|
156
164
|
|
|
157
165
|
Use these when you already have an `EntityStreamDB` and want to build your own UI integration.
|
|
158
166
|
|
|
159
|
-
| Helper
|
|
160
|
-
|
|
|
161
|
-
| `createEntityIncludesQuery(db)`
|
|
162
|
-
| `normalizeEntityTimelineData()`
|
|
163
|
-
| `getEntityState(runs, inbox)`
|
|
164
|
-
| `buildSections(runs, inbox)`
|
|
165
|
-
| `buildTimelineEntries(runs, inbox)` | Builds keyed timeline entries with response timestamps.
|
|
166
|
-
| `materializeTimeline(data)`
|
|
167
|
-
| `defaultProjection(item)`
|
|
168
|
-
| `timelineMessages(db, opts?)`
|
|
169
|
-
| `timelineToMessages(db)`
|
|
167
|
+
| Helper | Purpose |
|
|
168
|
+
| ------------------------------ | ------------------------------------------------------------- |
|
|
169
|
+
| `createEntityIncludesQuery(db)` | Builds the TanStack DB query used by `useChat`. |
|
|
170
|
+
| `normalizeEntityTimelineData()` | Normalizes and sorts nested run, text, tool, wake, and entity data. |
|
|
171
|
+
| `getEntityState(runs, inbox)` | Computes `pending`, `queued`, `working`, `idle`, or `error`. |
|
|
172
|
+
| `buildSections(runs, inbox)` | Builds chat-friendly user/agent sections. |
|
|
173
|
+
| `buildTimelineEntries(runs, inbox)` | Builds keyed timeline entries with response timestamps. |
|
|
174
|
+
| `materializeTimeline(data)` | Converts normalized timeline data into prompt-oriented timeline items. |
|
|
175
|
+
| `defaultProjection(item)` | Projects one timeline item into LLM messages. |
|
|
176
|
+
| `timelineMessages(db, opts?)` | Reads an entity DB and returns timestamped LLM messages. |
|
|
177
|
+
| `timelineToMessages(db)` | Convenience wrapper returning plain LLM messages. |
|
|
170
178
|
|
|
171
179
|
## CLI Entity Stream DB
|
|
172
180
|
|
|
173
181
|
The `electric-ax/entity-stream-db` subpath exposes a convenience loader used by CLI and UI code:
|
|
174
182
|
|
|
175
183
|
```ts
|
|
176
|
-
import { createEntityStreamDB } from
|
|
184
|
+
import { createEntityStreamDB } from "electric-ax/entity-stream-db"
|
|
177
185
|
|
|
178
186
|
const { db, close } = await createEntityStreamDB({
|
|
179
|
-
baseUrl:
|
|
180
|
-
entityUrl:
|
|
181
|
-
initialOffset:
|
|
187
|
+
baseUrl: "http://localhost:4437",
|
|
188
|
+
entityUrl: "/horton/onboarding",
|
|
189
|
+
initialOffset: "0",
|
|
182
190
|
})
|
|
183
191
|
|
|
184
192
|
try {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Configuring the agent
|
|
3
|
-
titleTemplate:
|
|
3
|
+
titleTemplate: "... - Electric Agents"
|
|
4
4
|
description: >-
|
|
5
5
|
Set up LLM agents with ctx.useAgent(), including model selection, system prompts, tools, and test responses.
|
|
6
6
|
outline: [2, 3]
|
|
@@ -19,18 +19,22 @@ interface AgentConfig {
|
|
|
19
19
|
provider?: KnownProvider
|
|
20
20
|
tools: AgentTool[]
|
|
21
21
|
streamFn?: StreamFn
|
|
22
|
+
getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined
|
|
23
|
+
onPayload?: SimpleStreamOptions["onPayload"]
|
|
22
24
|
testResponses?: string[] | TestResponseFn
|
|
23
25
|
}
|
|
24
26
|
```
|
|
25
27
|
|
|
26
|
-
| Field | Required | Description
|
|
27
|
-
| --------------- | -------- |
|
|
28
|
-
| `systemPrompt` | Yes | The system prompt passed to the LLM.
|
|
29
|
-
| `model` | Yes | Model identifier string or resolved model object.
|
|
30
|
-
| `provider` | No | Provider to use when `model` is a string. Defaults to `"anthropic"`.
|
|
28
|
+
| Field | Required | Description |
|
|
29
|
+
| --------------- | -------- | ----------------------------------------------------------------------- |
|
|
30
|
+
| `systemPrompt` | Yes | The system prompt passed to the LLM. |
|
|
31
|
+
| `model` | Yes | Model identifier string or resolved model object. |
|
|
32
|
+
| `provider` | No | Provider to use when `model` is a string. Defaults to `"anthropic"`. |
|
|
31
33
|
| `tools` | Yes | Array of tools available to the agent. Spread `ctx.electricTools` when your runtime host provides runtime-level tools. |
|
|
32
|
-
| `streamFn` | No | Optional streaming callback passed to the underlying agent.
|
|
33
|
-
| `
|
|
34
|
+
| `streamFn` | No | Optional streaming callback passed to the underlying agent. |
|
|
35
|
+
| `getApiKey` | No | Optional API-key resolver passed through to the model layer. |
|
|
36
|
+
| `onPayload` | No | Optional callback for raw streaming payloads from the model layer. |
|
|
37
|
+
| `testResponses` | No | Mock responses for testing without calling the LLM. |
|
|
34
38
|
|
|
35
39
|
## Basic usage
|
|
36
40
|
|
|
@@ -71,16 +75,18 @@ Returns an `AgentRunResult`:
|
|
|
71
75
|
|
|
72
76
|
```ts
|
|
73
77
|
type AgentRunResult = {
|
|
78
|
+
result?: unknown
|
|
74
79
|
writes: ChangeEvent[]
|
|
75
80
|
toolCalls: Array<{ name: string; args: unknown; result: unknown }>
|
|
76
81
|
usage: { tokens: number; duration: number }
|
|
77
82
|
}
|
|
78
83
|
```
|
|
79
84
|
|
|
80
|
-
| Field | Description
|
|
81
|
-
| ----------- |
|
|
82
|
-
| `
|
|
83
|
-
| `
|
|
85
|
+
| Field | Description |
|
|
86
|
+
| ----------- | --------------------------------------------------------------------------- |
|
|
87
|
+
| `result` | Optional final result from the underlying agent adapter. |
|
|
88
|
+
| `writes` | Currently returned as an empty array placeholder. |
|
|
89
|
+
| `toolCalls` | Currently returned as an empty array placeholder. |
|
|
84
90
|
| `usage` | Currently returned as `{ tokens: 0, duration: 0 }` until usage aggregation is wired in. |
|
|
85
91
|
|
|
86
92
|
## AgentHandle
|
|
@@ -100,8 +106,8 @@ You must call `useAgent` before calling `run()`. Calling `ctx.agent.run()` witho
|
|
|
100
106
|
When `model` is a string, the runtime resolves it through the configured `provider` (default `"anthropic"`). You can also pass a resolved `Model` object directly.
|
|
101
107
|
|
|
102
108
|
```ts
|
|
103
|
-
model:
|
|
104
|
-
provider:
|
|
109
|
+
model: "claude-sonnet-4-5-20250929"
|
|
110
|
+
provider: "anthropic"
|
|
105
111
|
```
|
|
106
112
|
|
|
107
113
|
## Test responses
|
|
@@ -112,10 +118,10 @@ For testing handlers without making LLM calls, pass `testResponses`. Two forms a
|
|
|
112
118
|
|
|
113
119
|
```ts
|
|
114
120
|
ctx.useAgent({
|
|
115
|
-
systemPrompt:
|
|
116
|
-
model:
|
|
121
|
+
systemPrompt: "...",
|
|
122
|
+
model: "claude-sonnet-4-5-20250929",
|
|
117
123
|
tools: [...ctx.electricTools],
|
|
118
|
-
testResponses: [
|
|
124
|
+
testResponses: ["Hello! How can I help?", "Sure, I can do that."],
|
|
119
125
|
})
|
|
120
126
|
```
|
|
121
127
|
|
|
@@ -125,8 +131,8 @@ ctx.useAgent({
|
|
|
125
131
|
ctx.useAgent({
|
|
126
132
|
// ...
|
|
127
133
|
testResponses: async (message, bridge) => {
|
|
128
|
-
if (message.includes(
|
|
129
|
-
return
|
|
134
|
+
if (message.includes("calculate")) {
|
|
135
|
+
return "The answer is 42."
|
|
130
136
|
}
|
|
131
137
|
return undefined // emits no automatic text response
|
|
132
138
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Context composition
|
|
3
|
-
titleTemplate:
|
|
3
|
+
titleTemplate: "... - Electric Agents"
|
|
4
4
|
description: >-
|
|
5
5
|
Control what goes into the agent's context window using ctx.useContext() with token-budgeted sources, cache tiers, and imperative context entries.
|
|
6
6
|
outline: [2, 3]
|
|
@@ -25,14 +25,14 @@ ctx.useContext({
|
|
|
25
25
|
sourceBudget: 18_000,
|
|
26
26
|
sources: {
|
|
27
27
|
docs: {
|
|
28
|
-
content: () =>
|
|
28
|
+
content: () => "# Reference docs\n...",
|
|
29
29
|
max: 6_000,
|
|
30
|
-
cache:
|
|
30
|
+
cache: "stable",
|
|
31
31
|
},
|
|
32
32
|
conversation: {
|
|
33
33
|
content: () => ctx.timelineMessages(),
|
|
34
34
|
max: 12_000,
|
|
35
|
-
cache:
|
|
35
|
+
cache: "volatile",
|
|
36
36
|
},
|
|
37
37
|
},
|
|
38
38
|
})
|
|
@@ -82,7 +82,7 @@ const messages = ctx.timelineMessages()
|
|
|
82
82
|
const messages = ctx.timelineMessages({
|
|
83
83
|
since: 42,
|
|
84
84
|
projection: (item) => {
|
|
85
|
-
if (item.kind ===
|
|
85
|
+
if (item.kind === "run") return [{ role: "assistant", content: "..." }]
|
|
86
86
|
return null // use default projection
|
|
87
87
|
},
|
|
88
88
|
})
|
|
@@ -102,7 +102,7 @@ ctx.useContext({
|
|
|
102
102
|
conversation: {
|
|
103
103
|
content: () => ctx.timelineMessages(),
|
|
104
104
|
max: 15_000,
|
|
105
|
-
cache:
|
|
105
|
+
cache: "volatile",
|
|
106
106
|
},
|
|
107
107
|
},
|
|
108
108
|
})
|
|
@@ -117,10 +117,10 @@ Use context entries for information the agent discovers during a run that should
|
|
|
117
117
|
### insertContext
|
|
118
118
|
|
|
119
119
|
```ts
|
|
120
|
-
ctx.insertContext(
|
|
121
|
-
name:
|
|
122
|
-
content:
|
|
123
|
-
attrs: { priority:
|
|
120
|
+
ctx.insertContext("user-prefs", {
|
|
121
|
+
name: "User preferences",
|
|
122
|
+
content: "Prefers concise responses. Timezone: PST.",
|
|
123
|
+
attrs: { priority: "high" },
|
|
124
124
|
})
|
|
125
125
|
```
|
|
126
126
|
|
|
@@ -129,13 +129,13 @@ Inserting with an existing `id` replaces the previous entry.
|
|
|
129
129
|
### removeContext
|
|
130
130
|
|
|
131
131
|
```ts
|
|
132
|
-
ctx.removeContext(
|
|
132
|
+
ctx.removeContext("user-prefs")
|
|
133
133
|
```
|
|
134
134
|
|
|
135
135
|
### getContext / listContext
|
|
136
136
|
|
|
137
137
|
```ts
|
|
138
|
-
const entry = ctx.getContext(
|
|
138
|
+
const entry = ctx.getContext("user-prefs")
|
|
139
139
|
// { id: "user-prefs", name: "User preferences", content: "...", insertedAt: 1234 }
|
|
140
140
|
|
|
141
141
|
const all = ctx.listContext()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Defining entities
|
|
3
|
-
titleTemplate:
|
|
3
|
+
titleTemplate: "... - Electric Agents"
|
|
4
4
|
description: >-
|
|
5
5
|
Register entity types with the EntityRegistry, define custom state collections, typed schemas, and handler functions.
|
|
6
6
|
outline: [2, 3]
|
|
@@ -15,16 +15,16 @@ An entity type is registered with an `EntityRegistry`. The registry maps type na
|
|
|
15
15
|
`createEntityRegistry()` returns an `EntityRegistry`. Register types with `registry.define(name, definition)`.
|
|
16
16
|
|
|
17
17
|
```ts
|
|
18
|
-
import { createEntityRegistry } from
|
|
18
|
+
import { createEntityRegistry } from "@electric-ax/agents-runtime"
|
|
19
19
|
|
|
20
20
|
const registry = createEntityRegistry()
|
|
21
21
|
|
|
22
|
-
registry.define(
|
|
23
|
-
description:
|
|
22
|
+
registry.define("assistant", {
|
|
23
|
+
description: "A general-purpose AI assistant",
|
|
24
24
|
async handler(ctx) {
|
|
25
25
|
ctx.useAgent({
|
|
26
|
-
systemPrompt:
|
|
27
|
-
model:
|
|
26
|
+
systemPrompt: "You are a helpful assistant.",
|
|
27
|
+
model: "claude-sonnet-4-5-20250929",
|
|
28
28
|
tools: [...ctx.electricTools],
|
|
29
29
|
})
|
|
30
30
|
await ctx.agent.run()
|
|
@@ -50,15 +50,15 @@ interface EntityDefinition {
|
|
|
50
50
|
}
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
| Field | Purpose
|
|
54
|
-
| ---------------- |
|
|
55
|
-
| `description` | Human-readable description. Shown in the Electric Agents UI and CLI.
|
|
53
|
+
| Field | Purpose |
|
|
54
|
+
| ---------------- | ------------------------------------------------------------------------------------- |
|
|
55
|
+
| `description` | Human-readable description. Shown in the Electric Agents UI and CLI. |
|
|
56
56
|
| `state` | Custom persistent collections accessed via `ctx.state`, `ctx.db.actions`, and `ctx.db.collections`. |
|
|
57
|
-
| `actions` | Factory that returns custom non-CRUD action functions exposed on `ctx.actions`.
|
|
58
|
-
| `creationSchema` | JSON Schema for arguments passed when the entity is spawned.
|
|
59
|
-
| `inboxSchemas` | JSON Schemas for typed inbox message categories.
|
|
60
|
-
| `outputSchemas` | JSON Schemas for typed output message categories.
|
|
61
|
-
| `handler` | The function that runs each time the entity wakes. Required.
|
|
57
|
+
| `actions` | Factory that returns custom non-CRUD action functions exposed on `ctx.actions`. |
|
|
58
|
+
| `creationSchema` | JSON Schema for arguments passed when the entity is spawned. |
|
|
59
|
+
| `inboxSchemas` | JSON Schemas for typed inbox message categories. |
|
|
60
|
+
| `outputSchemas` | JSON Schemas for typed output message categories. |
|
|
61
|
+
| `handler` | The function that runs each time the entity wakes. Required. |
|
|
62
62
|
|
|
63
63
|
## Custom state
|
|
64
64
|
|
|
@@ -81,7 +81,7 @@ interface CollectionDefinition {
|
|
|
81
81
|
Declared collections become available via `ctx.state` proxies and the lower-level `ctx.db.actions` / `ctx.db.collections` APIs:
|
|
82
82
|
|
|
83
83
|
```ts
|
|
84
|
-
import { z } from
|
|
84
|
+
import { z } from "zod"
|
|
85
85
|
|
|
86
86
|
const childSchema = z.object({
|
|
87
87
|
key: z.string(),
|
|
@@ -89,22 +89,22 @@ const childSchema = z.object({
|
|
|
89
89
|
kind: z.string(),
|
|
90
90
|
})
|
|
91
91
|
|
|
92
|
-
registry.define(
|
|
93
|
-
description:
|
|
92
|
+
registry.define("coordinator", {
|
|
93
|
+
description: "Spawns and tracks child entities",
|
|
94
94
|
state: {
|
|
95
|
-
status: { primaryKey:
|
|
96
|
-
children: { schema: childSchema, primaryKey:
|
|
95
|
+
status: { primaryKey: "key" },
|
|
96
|
+
children: { schema: childSchema, primaryKey: "key" },
|
|
97
97
|
},
|
|
98
98
|
|
|
99
99
|
async handler(ctx) {
|
|
100
|
-
if (ctx.
|
|
101
|
-
ctx.db.actions.status_insert({ row: { key:
|
|
100
|
+
if (!ctx.db.collections.status.get("current")) {
|
|
101
|
+
ctx.db.actions.status_insert({ row: { key: "current", value: "idle" } })
|
|
102
102
|
}
|
|
103
103
|
// Convenience proxy:
|
|
104
104
|
ctx.state.children.insert({
|
|
105
|
-
key:
|
|
106
|
-
url:
|
|
107
|
-
kind:
|
|
105
|
+
key: "child-1",
|
|
106
|
+
url: "/worker/child-1",
|
|
107
|
+
kind: "worker",
|
|
108
108
|
})
|
|
109
109
|
|
|
110
110
|
// Lower-level APIs:
|
|
@@ -126,9 +126,9 @@ For projects with multiple entity types, keep a separate registry file and impor
|
|
|
126
126
|
|
|
127
127
|
```ts
|
|
128
128
|
// entities/registry.ts
|
|
129
|
-
import { createEntityRegistry } from
|
|
130
|
-
import { registerAssistant } from
|
|
131
|
-
import { registerWorker } from
|
|
129
|
+
import { createEntityRegistry } from "@electric-ax/agents-runtime"
|
|
130
|
+
import { registerAssistant } from "./assistant"
|
|
131
|
+
import { registerWorker } from "./worker"
|
|
132
132
|
|
|
133
133
|
export const registry = createEntityRegistry()
|
|
134
134
|
registerAssistant(registry)
|
|
@@ -137,15 +137,15 @@ registerWorker(registry)
|
|
|
137
137
|
|
|
138
138
|
```ts
|
|
139
139
|
// entities/assistant.ts
|
|
140
|
-
import type { EntityRegistry } from
|
|
140
|
+
import type { EntityRegistry } from "@electric-ax/agents-runtime"
|
|
141
141
|
|
|
142
142
|
export function registerAssistant(registry: EntityRegistry) {
|
|
143
|
-
registry.define(
|
|
144
|
-
description:
|
|
143
|
+
registry.define("assistant", {
|
|
144
|
+
description: "General-purpose assistant",
|
|
145
145
|
async handler(ctx) {
|
|
146
146
|
ctx.useAgent({
|
|
147
|
-
systemPrompt:
|
|
148
|
-
model:
|
|
147
|
+
systemPrompt: "You are a helpful assistant.",
|
|
148
|
+
model: "claude-sonnet-4-5-20250929",
|
|
149
149
|
tools: [...ctx.electricTools],
|
|
150
150
|
})
|
|
151
151
|
await ctx.agent.run()
|
|
@@ -161,12 +161,12 @@ This keeps each entity type isolated and the registry composition explicit.
|
|
|
161
161
|
`creationSchema`, `inboxSchemas`, and `outputSchemas` accept [`StandardJSONSchemaV1`](https://github.com/standard-schema/standard-schema) objects. Any schema library implementing the Standard JSON Schema interface works (e.g. Zod v4). These schemas are used for validation and for generating UI and documentation in the Electric Agents dashboard.
|
|
162
162
|
|
|
163
163
|
```ts
|
|
164
|
-
import { z } from
|
|
164
|
+
import { z } from "zod/v4"
|
|
165
165
|
|
|
166
|
-
registry.define(
|
|
167
|
-
description:
|
|
166
|
+
registry.define("processor", {
|
|
167
|
+
description: "Processes structured tasks",
|
|
168
168
|
creationSchema: z.object({
|
|
169
|
-
priority: z.enum([
|
|
169
|
+
priority: z.enum(["low", "medium", "high"]).default("medium"),
|
|
170
170
|
}),
|
|
171
171
|
inboxSchemas: {
|
|
172
172
|
task: z.object({
|