@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Defining tools
|
|
3
|
-
titleTemplate:
|
|
3
|
+
titleTemplate: "... - Electric Agents"
|
|
4
4
|
description: >-
|
|
5
5
|
Create stateless, stateful, and handler-scoped tools for the LLM agent loop.
|
|
6
6
|
outline: [2, 3]
|
|
@@ -33,7 +33,7 @@ The return type:
|
|
|
33
33
|
|
|
34
34
|
```ts
|
|
35
35
|
interface AgentToolResult<T = any> {
|
|
36
|
-
content: Array<{ type:
|
|
36
|
+
content: Array<{ type: "text"; text: string }>
|
|
37
37
|
details: T
|
|
38
38
|
}
|
|
39
39
|
```
|
|
@@ -43,11 +43,11 @@ interface AgentToolResult<T = any> {
|
|
|
43
43
|
Defined using [TypeBox](https://github.com/sinclairzx81/typebox) (`@sinclair/typebox`). The schema is used for LLM function calling and argument validation.
|
|
44
44
|
|
|
45
45
|
```ts
|
|
46
|
-
import { Type } from
|
|
46
|
+
import { Type } from "@sinclair/typebox"
|
|
47
47
|
|
|
48
48
|
parameters: Type.Object({
|
|
49
|
-
expression: Type.String({ description:
|
|
50
|
-
precision: Type.Optional(Type.Number({ description:
|
|
49
|
+
expression: Type.String({ description: "Math expression to evaluate" }),
|
|
50
|
+
precision: Type.Optional(Type.Number({ description: "Decimal places" })),
|
|
51
51
|
})
|
|
52
52
|
```
|
|
53
53
|
|
|
@@ -56,21 +56,21 @@ parameters: Type.Object({
|
|
|
56
56
|
Pure functions with no side effects beyond what they compute. Define directly as an `AgentTool` object.
|
|
57
57
|
|
|
58
58
|
```ts
|
|
59
|
-
import { Type } from
|
|
60
|
-
import type { AgentTool } from
|
|
59
|
+
import { Type } from "@sinclair/typebox"
|
|
60
|
+
import type { AgentTool } from "@electric-ax/agents-runtime"
|
|
61
61
|
|
|
62
62
|
const calculatorTool: AgentTool = {
|
|
63
|
-
name:
|
|
64
|
-
label:
|
|
65
|
-
description:
|
|
63
|
+
name: "calculator",
|
|
64
|
+
label: "Calculator",
|
|
65
|
+
description: "Evaluate mathematical expressions.",
|
|
66
66
|
parameters: Type.Object({
|
|
67
|
-
expression: Type.String({ description:
|
|
67
|
+
expression: Type.String({ description: "The expression to evaluate" }),
|
|
68
68
|
}),
|
|
69
69
|
execute: async (_toolCallId, params) => {
|
|
70
70
|
const { expression } = params as { expression: string }
|
|
71
71
|
const result = evaluate(expression)
|
|
72
72
|
return {
|
|
73
|
-
content: [{ type:
|
|
73
|
+
content: [{ type: "text", text: String(result) }],
|
|
74
74
|
details: {},
|
|
75
75
|
}
|
|
76
76
|
},
|
|
@@ -82,20 +82,20 @@ const calculatorTool: AgentTool = {
|
|
|
82
82
|
Use a factory function that receives the `HandlerContext`. The state persists across wakes -- it is backed by the entity's durable stream. Reads go through `ctx.db.collections` and writes go through `ctx.db.actions`.
|
|
83
83
|
|
|
84
84
|
```ts
|
|
85
|
-
import { Type } from
|
|
86
|
-
import type { AgentTool, HandlerContext } from
|
|
85
|
+
import { Type } from "@sinclair/typebox"
|
|
86
|
+
import type { AgentTool, HandlerContext } from "@electric-ax/agents-runtime"
|
|
87
87
|
|
|
88
88
|
function createMemoryStoreTool(ctx: HandlerContext): AgentTool {
|
|
89
89
|
return {
|
|
90
|
-
name:
|
|
91
|
-
label:
|
|
92
|
-
description:
|
|
90
|
+
name: "memory_store",
|
|
91
|
+
label: "Memory Store",
|
|
92
|
+
description: "Persistent key-value store.",
|
|
93
93
|
parameters: Type.Object({
|
|
94
94
|
operation: Type.Union([
|
|
95
|
-
Type.Literal(
|
|
96
|
-
Type.Literal(
|
|
97
|
-
Type.Literal(
|
|
98
|
-
Type.Literal(
|
|
95
|
+
Type.Literal("get"),
|
|
96
|
+
Type.Literal("set"),
|
|
97
|
+
Type.Literal("delete"),
|
|
98
|
+
Type.Literal("list"),
|
|
99
99
|
]),
|
|
100
100
|
key: Type.Optional(Type.String()),
|
|
101
101
|
value: Type.Optional(Type.String()),
|
|
@@ -106,7 +106,7 @@ function createMemoryStoreTool(ctx: HandlerContext): AgentTool {
|
|
|
106
106
|
key?: string
|
|
107
107
|
value?: string
|
|
108
108
|
}
|
|
109
|
-
if (operation ===
|
|
109
|
+
if (operation === "set") {
|
|
110
110
|
const existing = ctx.db.collections.kv?.get(key!)
|
|
111
111
|
if (existing) {
|
|
112
112
|
ctx.db.actions.kv_update({
|
|
@@ -119,27 +119,27 @@ function createMemoryStoreTool(ctx: HandlerContext): AgentTool {
|
|
|
119
119
|
ctx.db.actions.kv_insert({ row: { key: key!, value: value! } })
|
|
120
120
|
}
|
|
121
121
|
return {
|
|
122
|
-
content: [{ type:
|
|
122
|
+
content: [{ type: "text", text: `Stored "${key}"` }],
|
|
123
123
|
details: {},
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
-
if (operation ===
|
|
126
|
+
if (operation === "get") {
|
|
127
127
|
const entry = ctx.db.collections.kv?.get(key!)
|
|
128
128
|
const text = entry ? entry.value : `No value found for "${key}"`
|
|
129
|
-
return { content: [{ type:
|
|
129
|
+
return { content: [{ type: "text", text }], details: {} }
|
|
130
130
|
}
|
|
131
|
-
if (operation ===
|
|
131
|
+
if (operation === "delete") {
|
|
132
132
|
ctx.db.actions.kv_delete({ key: key! })
|
|
133
133
|
return {
|
|
134
|
-
content: [{ type:
|
|
134
|
+
content: [{ type: "text", text: `Deleted "${key}"` }],
|
|
135
135
|
details: {},
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
// list
|
|
139
139
|
const entries = ctx.db.collections.kv?.toArray ?? []
|
|
140
|
-
const text = entries.map((e) => `${e.key}: ${e.value}`).join(
|
|
140
|
+
const text = entries.map((e) => `${e.key}: ${e.value}`).join("\n")
|
|
141
141
|
return {
|
|
142
|
-
content: [{ type:
|
|
142
|
+
content: [{ type: "text", text: text || "(empty)" }],
|
|
143
143
|
details: {},
|
|
144
144
|
}
|
|
145
145
|
},
|
|
@@ -162,18 +162,18 @@ The entity state API:
|
|
|
162
162
|
Use a factory that receives the `HandlerContext`. These tools can spawn entities, observe streams, send messages, and use any other `ctx` primitive.
|
|
163
163
|
|
|
164
164
|
```ts
|
|
165
|
-
import { Type } from
|
|
166
|
-
import type { AgentTool, HandlerContext } from
|
|
165
|
+
import { Type } from "@sinclair/typebox"
|
|
166
|
+
import type { AgentTool, HandlerContext } from "@electric-ax/agents-runtime"
|
|
167
167
|
|
|
168
168
|
function createDispatchTool(ctx: HandlerContext): AgentTool {
|
|
169
169
|
return {
|
|
170
|
-
name:
|
|
171
|
-
label:
|
|
172
|
-
description:
|
|
170
|
+
name: "dispatch",
|
|
171
|
+
label: "Dispatch",
|
|
172
|
+
description: "Spawn a child agent and wait for its response.",
|
|
173
173
|
parameters: Type.Object({
|
|
174
|
-
type: Type.String({ description:
|
|
175
|
-
systemPrompt: Type.String({ description:
|
|
176
|
-
task: Type.String({ description:
|
|
174
|
+
type: Type.String({ description: "Entity type to spawn" }),
|
|
175
|
+
systemPrompt: Type.String({ description: "System prompt for the child" }),
|
|
176
|
+
task: Type.String({ description: "Task to send to the child" }),
|
|
177
177
|
}),
|
|
178
178
|
execute: async (_, params) => {
|
|
179
179
|
const { type, systemPrompt, task } = params as {
|
|
@@ -187,12 +187,12 @@ function createDispatchTool(ctx: HandlerContext): AgentTool {
|
|
|
187
187
|
{ systemPrompt },
|
|
188
188
|
{
|
|
189
189
|
initialMessage: task,
|
|
190
|
-
wake:
|
|
190
|
+
wake: "runFinished",
|
|
191
191
|
}
|
|
192
192
|
)
|
|
193
|
-
const text = (await child.text()).join(
|
|
193
|
+
const text = (await child.text()).join("\n\n")
|
|
194
194
|
return {
|
|
195
|
-
content: [{ type:
|
|
195
|
+
content: [{ type: "text", text }],
|
|
196
196
|
details: {},
|
|
197
197
|
}
|
|
198
198
|
},
|
|
@@ -207,18 +207,18 @@ function createDispatchTool(ctx: HandlerContext): AgentTool {
|
|
|
207
207
|
Tools are constructed in the handler and passed to `useAgent`. Include `ctx.electricTools` when your runtime host provides runtime-level tools that the LLM should be able to call:
|
|
208
208
|
|
|
209
209
|
```ts
|
|
210
|
-
registry.define(
|
|
211
|
-
description:
|
|
210
|
+
registry.define("assistant", {
|
|
211
|
+
description: "An assistant with memory and delegation",
|
|
212
212
|
state: {
|
|
213
|
-
kv: { primaryKey:
|
|
213
|
+
kv: { primaryKey: "key" },
|
|
214
214
|
},
|
|
215
215
|
async handler(ctx) {
|
|
216
216
|
const memoryTool = createMemoryStoreTool(ctx)
|
|
217
217
|
const dispatchTool = createDispatchTool(ctx)
|
|
218
218
|
|
|
219
219
|
ctx.useAgent({
|
|
220
|
-
systemPrompt:
|
|
221
|
-
model:
|
|
220
|
+
systemPrompt: "You are a helpful assistant with persistent memory.",
|
|
221
|
+
model: "claude-sonnet-4-5-20250929",
|
|
222
222
|
tools: [...ctx.electricTools, memoryTool, dispatchTool, calculatorTool],
|
|
223
223
|
})
|
|
224
224
|
await ctx.agent.run()
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Embedded built-ins
|
|
3
|
-
titleTemplate:
|
|
3
|
+
titleTemplate: "... - Electric Agents"
|
|
4
4
|
description: >-
|
|
5
|
-
Embed the built-in Horton and
|
|
5
|
+
Embed the built-in Horton, worker, and coder runtime in your own process using
|
|
6
6
|
@electric-ax/agents, BuiltinAgentsServer, or the entrypoint helpers.
|
|
7
7
|
outline: [2, 3]
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Embedded built-ins
|
|
11
11
|
|
|
12
|
-
The CLI commands `electric agents start-builtin` and `electric agents quickstart` run the built-in Horton and
|
|
12
|
+
The CLI commands `electric agents start-builtin` and `electric agents quickstart` run the built-in Horton, worker, and coder runtime for you. If you need to host those built-ins inside your own process, use the exported APIs from `@electric-ax/agents`.
|
|
13
13
|
|
|
14
14
|
## BuiltinAgentsServer
|
|
15
15
|
|
|
16
|
-
`BuiltinAgentsServer` starts an HTTP webhook server, registers `horton` and `
|
|
16
|
+
`BuiltinAgentsServer` starts an HTTP webhook server, registers `horton`, `worker`, and `coder`, and forwards Electric Agents webhook wakes to the built-in handler.
|
|
17
17
|
|
|
18
18
|
```ts
|
|
19
|
-
import { BuiltinAgentsServer } from
|
|
19
|
+
import { BuiltinAgentsServer } from "@electric-ax/agents"
|
|
20
20
|
|
|
21
21
|
const server = new BuiltinAgentsServer({
|
|
22
|
-
agentServerUrl:
|
|
22
|
+
agentServerUrl: "http://localhost:4437",
|
|
23
23
|
port: 4448,
|
|
24
24
|
workingDirectory: process.cwd(),
|
|
25
25
|
})
|
|
@@ -36,9 +36,9 @@ await server.stop()
|
|
|
36
36
|
### Options
|
|
37
37
|
|
|
38
38
|
```ts
|
|
39
|
-
import type { RuntimeRouterConfig } from
|
|
39
|
+
import type { RuntimeRouterConfig } from "@electric-ax/agents-runtime"
|
|
40
40
|
|
|
41
|
-
type CreateElectricTools = RuntimeRouterConfig[
|
|
41
|
+
type CreateElectricTools = RuntimeRouterConfig["createElectricTools"]
|
|
42
42
|
|
|
43
43
|
interface BuiltinAgentsServerOptions {
|
|
44
44
|
agentServerUrl: string
|
|
@@ -52,16 +52,16 @@ interface BuiltinAgentsServerOptions {
|
|
|
52
52
|
}
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
| Field | Description
|
|
56
|
-
| --------------------- |
|
|
57
|
-
| `agentServerUrl` | Electric Agents coordinator server URL.
|
|
58
|
-
| `baseUrl` | Public base URL used when registering the webhook. Defaults to local URL.
|
|
59
|
-
| `port` | Local webhook server port.
|
|
60
|
-
| `host` | Bind host. Defaults to `127.0.0.1`.
|
|
61
|
-
| `workingDirectory` | Directory used by Horton
|
|
62
|
-
| `mockStreamFn` | Optional test stream function. Lets you run without `ANTHROPIC_API_KEY`.
|
|
63
|
-
| `webhookPath` | Webhook path. Defaults to `/_electric/builtin-agent-handler`.
|
|
64
|
-
| `createElectricTools` | Optional factory for extra tools injected into built-in agent handlers.
|
|
55
|
+
| Field | Description |
|
|
56
|
+
| --------------------- | --------------------------------------------------------------------------- |
|
|
57
|
+
| `agentServerUrl` | Electric Agents coordinator server URL. |
|
|
58
|
+
| `baseUrl` | Public base URL used when registering the webhook. Defaults to local URL. |
|
|
59
|
+
| `port` | Local webhook server port. |
|
|
60
|
+
| `host` | Bind host. Defaults to `127.0.0.1`. |
|
|
61
|
+
| `workingDirectory` | Directory used by Horton, worker file tools, and the default coder cwd. Defaults to `process.cwd()`. |
|
|
62
|
+
| `mockStreamFn` | Optional test stream function. Lets you run without `ANTHROPIC_API_KEY`. |
|
|
63
|
+
| `webhookPath` | Webhook path. Defaults to `/_electric/builtin-agent-handler`. |
|
|
64
|
+
| `createElectricTools` | Optional factory for extra tools injected into built-in agent handlers. |
|
|
65
65
|
|
|
66
66
|
Without `mockStreamFn`, `ANTHROPIC_API_KEY` must be present before the built-in handler starts.
|
|
67
67
|
|
|
@@ -73,16 +73,16 @@ Use `createBuiltinAgentHandler()` when you already have an HTTP server and only
|
|
|
73
73
|
import {
|
|
74
74
|
createBuiltinAgentHandler,
|
|
75
75
|
registerBuiltinAgentTypes,
|
|
76
|
-
} from
|
|
76
|
+
} from "@electric-ax/agents"
|
|
77
77
|
|
|
78
78
|
const bootstrap = await createBuiltinAgentHandler({
|
|
79
|
-
agentServerUrl:
|
|
80
|
-
serveEndpoint:
|
|
79
|
+
agentServerUrl: "http://localhost:4437",
|
|
80
|
+
serveEndpoint: "https://example.com/_electric/builtin-agent-handler",
|
|
81
81
|
workingDirectory: process.cwd(),
|
|
82
82
|
})
|
|
83
83
|
|
|
84
84
|
if (!bootstrap) {
|
|
85
|
-
throw new Error(
|
|
85
|
+
throw new Error("ANTHROPIC_API_KEY is required for built-in agents")
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
await registerBuiltinAgentTypes(bootstrap)
|
|
@@ -108,27 +108,27 @@ interface AgentHandlerResult {
|
|
|
108
108
|
Both `BuiltinAgentsServer` and `createBuiltinAgentHandler()` accept `createElectricTools`. The factory receives the same context shape as `RuntimeRouterConfig.createElectricTools` and can add host-specific tools to Horton.
|
|
109
109
|
|
|
110
110
|
```ts
|
|
111
|
-
import { Type } from
|
|
111
|
+
import { Type } from "@sinclair/typebox"
|
|
112
112
|
|
|
113
113
|
const server = new BuiltinAgentsServer({
|
|
114
|
-
agentServerUrl:
|
|
114
|
+
agentServerUrl: "http://localhost:4437",
|
|
115
115
|
port: 4448,
|
|
116
116
|
createElectricTools: ({ entityUrl, upsertCronSchedule }) => [
|
|
117
117
|
{
|
|
118
|
-
name:
|
|
119
|
-
label:
|
|
120
|
-
description:
|
|
118
|
+
name: "schedule_daily_summary",
|
|
119
|
+
label: "Schedule daily summary",
|
|
120
|
+
description: "Schedule a daily summary wake for this entity.",
|
|
121
121
|
parameters: Type.Object({
|
|
122
122
|
hour: Type.Number(),
|
|
123
123
|
}),
|
|
124
124
|
execute: async (_id, params) => {
|
|
125
125
|
const { hour } = params as { hour: number }
|
|
126
126
|
await upsertCronSchedule({
|
|
127
|
-
id:
|
|
127
|
+
id: "daily-summary",
|
|
128
128
|
expression: `0 ${hour} * * *`,
|
|
129
129
|
payload: `Run daily summary for ${entityUrl}`,
|
|
130
130
|
})
|
|
131
|
-
return { content: [{ type:
|
|
131
|
+
return { content: [{ type: "text", text: "Scheduled." }], details: {} }
|
|
132
132
|
},
|
|
133
133
|
},
|
|
134
134
|
],
|
|
@@ -143,7 +143,7 @@ const server = new BuiltinAgentsServer({
|
|
|
143
143
|
import {
|
|
144
144
|
resolveBuiltinAgentsEntrypointOptions,
|
|
145
145
|
runBuiltinAgentsEntrypoint,
|
|
146
|
-
} from
|
|
146
|
+
} from "@electric-ax/agents"
|
|
147
147
|
|
|
148
148
|
const options = resolveBuiltinAgentsEntrypointOptions(process.env)
|
|
149
149
|
const { server, url } = await runBuiltinAgentsEntrypoint()
|
|
@@ -154,27 +154,28 @@ await server.stop()
|
|
|
154
154
|
|
|
155
155
|
Environment variables:
|
|
156
156
|
|
|
157
|
-
| Variable
|
|
158
|
-
|
|
|
159
|
-
| `ELECTRIC_AGENTS_SERVER_URL`
|
|
160
|
-
| `ELECTRIC_AGENTS_BUILTIN_BASE_URL`
|
|
161
|
-
| `ELECTRIC_AGENTS_BUILTIN_HOST`
|
|
162
|
-
| `ELECTRIC_AGENTS_BUILTIN_PORT`
|
|
163
|
-
| `ELECTRIC_AGENTS_WORKING_DIRECTORY` | Working directory for file tools.
|
|
157
|
+
| Variable | Description |
|
|
158
|
+
| -------------------------------- | ----------------------------------------------------- |
|
|
159
|
+
| `ELECTRIC_AGENTS_SERVER_URL` | Required coordinator server URL. |
|
|
160
|
+
| `ELECTRIC_AGENTS_BUILTIN_BASE_URL` | Public webhook base URL for the built-in server. |
|
|
161
|
+
| `ELECTRIC_AGENTS_BUILTIN_HOST` | Bind host. |
|
|
162
|
+
| `ELECTRIC_AGENTS_BUILTIN_PORT` | Built-in server port. Defaults to `4448`. |
|
|
163
|
+
| `ELECTRIC_AGENTS_WORKING_DIRECTORY` | Working directory for file tools and default coder sessions. |
|
|
164
164
|
|
|
165
165
|
## Built-in Agent APIs
|
|
166
166
|
|
|
167
167
|
The built-in agent exports are also available if you want to compose your own runtime:
|
|
168
168
|
|
|
169
|
-
| Export
|
|
170
|
-
|
|
|
171
|
-
| `registerHorton()`
|
|
172
|
-
| `registerWorker()`
|
|
173
|
-
| `
|
|
169
|
+
| Export | Purpose |
|
|
170
|
+
| ------------------------- | --------------------------------------------------- |
|
|
171
|
+
| `registerHorton()` | Register the `horton` type on an `EntityRegistry`. |
|
|
172
|
+
| `registerWorker()` | Register the `worker` type on an `EntityRegistry`. |
|
|
173
|
+
| `registerCodingSession()` | Register the `coder` type on an `EntityRegistry`. |
|
|
174
|
+
| `HORTON_MODEL` | Default model id used by Horton and worker. |
|
|
174
175
|
| `buildHortonSystemPrompt()` | Build Horton's system prompt for a working directory. |
|
|
175
|
-
| `createHortonTools()`
|
|
176
|
-
| `createSpawnWorkerTool()`
|
|
177
|
-
| `WORKER_TOOL_NAMES`
|
|
178
|
-
| `createHortonDocsSupport()` | Create Horton's docs knowledge-base support.
|
|
176
|
+
| `createHortonTools()` | Create Horton's base shell/file/search/worker tools. |
|
|
177
|
+
| `createSpawnWorkerTool()` | Create the `spawn_worker` tool for another agent. |
|
|
178
|
+
| `WORKER_TOOL_NAMES` | Valid primitive tool names for workers. |
|
|
179
|
+
| `createHortonDocsSupport()` | Create Horton's docs knowledge-base support. |
|
|
179
180
|
|
|
180
|
-
For the behavior of `horton` and `
|
|
181
|
+
For the behavior of `horton`, `worker`, and `coder`, see [Horton](../entities/agents/horton), [Worker](../entities/agents/worker), and [Coder](../entities/agents/coder).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Managing state
|
|
3
|
-
titleTemplate:
|
|
3
|
+
titleTemplate: "... - Electric Agents"
|
|
4
4
|
description: >-
|
|
5
5
|
Declare and manage persistent entity state using custom collections with typed CRUD operations.
|
|
6
6
|
outline: [2, 3]
|
|
@@ -15,16 +15,16 @@ Entities can declare custom persistent collections. The convenience API is `ctx.
|
|
|
15
15
|
Define collections in the `state` field of the entity definition:
|
|
16
16
|
|
|
17
17
|
```ts
|
|
18
|
-
registry.define(
|
|
18
|
+
registry.define("my-entity", {
|
|
19
19
|
state: {
|
|
20
|
-
status: { primaryKey:
|
|
20
|
+
status: { primaryKey: "key" },
|
|
21
21
|
items: {
|
|
22
22
|
schema: z.object({
|
|
23
23
|
key: z.string(),
|
|
24
24
|
name: z.string(),
|
|
25
25
|
count: z.number(),
|
|
26
26
|
}),
|
|
27
|
-
primaryKey:
|
|
27
|
+
primaryKey: "key",
|
|
28
28
|
},
|
|
29
29
|
},
|
|
30
30
|
async handler(ctx) {
|
|
@@ -59,33 +59,33 @@ Write helpers return a Transaction. Reads query the underlying TanStack DB colle
|
|
|
59
59
|
|
|
60
60
|
```ts
|
|
61
61
|
// Convenience API
|
|
62
|
-
ctx.state.items.insert({ key:
|
|
63
|
-
const itemViaState = ctx.state.items.get(
|
|
62
|
+
ctx.state.items.insert({ key: "item-1", name: "Widget", count: 5 })
|
|
63
|
+
const itemViaState = ctx.state.items.get("item-1")
|
|
64
64
|
const allViaState = ctx.state.items.toArray
|
|
65
|
-
ctx.state.items.update(
|
|
65
|
+
ctx.state.items.update("item-1", (draft) => {
|
|
66
66
|
draft.count += 1
|
|
67
67
|
})
|
|
68
|
-
ctx.state.items.delete(
|
|
68
|
+
ctx.state.items.delete("item-1")
|
|
69
69
|
|
|
70
70
|
// Lower-level insert
|
|
71
71
|
ctx.db.actions.items_insert({
|
|
72
|
-
row: { key:
|
|
72
|
+
row: { key: "item-1", name: "Widget", count: 5 },
|
|
73
73
|
})
|
|
74
74
|
|
|
75
75
|
// Lower-level read
|
|
76
|
-
const item = ctx.db.collections.items?.get(
|
|
76
|
+
const item = ctx.db.collections.items?.get("item-1")
|
|
77
77
|
const all = ctx.db.collections.items?.toArray
|
|
78
78
|
|
|
79
79
|
// Lower-level update (Immer-style draft)
|
|
80
80
|
ctx.db.actions.items_update({
|
|
81
|
-
key:
|
|
81
|
+
key: "item-1",
|
|
82
82
|
updater: (draft) => {
|
|
83
83
|
draft.count += 1
|
|
84
84
|
},
|
|
85
85
|
})
|
|
86
86
|
|
|
87
87
|
// Lower-level delete
|
|
88
|
-
ctx.db.actions.items_delete({ key:
|
|
88
|
+
ctx.db.actions.items_delete({ key: "item-1" })
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
## Built-in collections
|