@electric-ax/agents 0.2.2 → 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.
Files changed (49) hide show
  1. package/dist/entrypoint.js +40 -12
  2. package/dist/index.cjs +40 -12
  3. package/dist/index.js +40 -12
  4. package/docs/entities/agents/coder.md +99 -0
  5. package/docs/entities/agents/horton.md +16 -13
  6. package/docs/entities/agents/worker.md +18 -18
  7. package/docs/entities/patterns/blackboard.md +6 -6
  8. package/docs/entities/patterns/dispatcher.md +1 -1
  9. package/docs/entities/patterns/manager-worker.md +1 -1
  10. package/docs/entities/patterns/map-reduce.md +1 -1
  11. package/docs/entities/patterns/pipeline.md +1 -1
  12. package/docs/entities/patterns/reactive-observers.md +2 -2
  13. package/docs/examples/playground.md +42 -26
  14. package/docs/index.md +23 -23
  15. package/docs/quickstart.md +13 -13
  16. package/docs/reference/agent-config.md +20 -12
  17. package/docs/reference/agent-tool.md +1 -1
  18. package/docs/reference/built-in-collections.md +21 -21
  19. package/docs/reference/cli.md +39 -30
  20. package/docs/reference/entity-definition.md +9 -9
  21. package/docs/reference/entity-handle.md +2 -2
  22. package/docs/reference/entity-registry.md +1 -1
  23. package/docs/reference/handler-context.md +69 -18
  24. package/docs/reference/runtime-handler.md +25 -23
  25. package/docs/reference/shared-state-handle.md +7 -7
  26. package/docs/reference/state-collection-proxy.md +1 -1
  27. package/docs/reference/wake-event.md +23 -23
  28. package/docs/usage/app-setup.md +24 -23
  29. package/docs/usage/clients-and-react.md +44 -36
  30. package/docs/usage/configuring-the-agent.md +25 -19
  31. package/docs/usage/context-composition.md +12 -12
  32. package/docs/usage/defining-entities.md +36 -36
  33. package/docs/usage/defining-tools.md +45 -45
  34. package/docs/usage/embedded-builtins.md +48 -47
  35. package/docs/usage/managing-state.md +12 -12
  36. package/docs/usage/overview.md +52 -45
  37. package/docs/usage/programmatic-runtime-client.md +50 -47
  38. package/docs/usage/shared-state.md +32 -32
  39. package/docs/usage/spawning-and-coordinating.md +9 -9
  40. package/docs/usage/testing.md +14 -14
  41. package/docs/usage/waking-entities.md +13 -13
  42. package/docs/usage/writing-handlers.md +57 -26
  43. package/package.json +5 -2
  44. package/scripts/sync-docs.mjs +42 -0
  45. package/skills/quickstart/scaffold/package.json +1 -0
  46. package/skills/quickstart/scaffold-ui/index.html +1 -1
  47. package/skills/quickstart/scaffold-ui/main.tsx +221 -16
  48. package/skills/quickstart.md +49 -94
  49. package/docs/examples/mega-draw.md +0 -106
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Defining tools
3
- titleTemplate: '... - Electric Agents'
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: 'text'; text: string }>
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 '@sinclair/typebox'
46
+ import { Type } from "@sinclair/typebox"
47
47
 
48
48
  parameters: Type.Object({
49
- expression: Type.String({ description: 'Math expression to evaluate' }),
50
- precision: Type.Optional(Type.Number({ description: 'Decimal places' })),
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 '@sinclair/typebox'
60
- import type { AgentTool } from '@electric-ax/agents-runtime'
59
+ import { Type } from "@sinclair/typebox"
60
+ import type { AgentTool } from "@electric-ax/agents-runtime"
61
61
 
62
62
  const calculatorTool: AgentTool = {
63
- name: 'calculator',
64
- label: 'Calculator',
65
- description: 'Evaluate mathematical expressions.',
63
+ name: "calculator",
64
+ label: "Calculator",
65
+ description: "Evaluate mathematical expressions.",
66
66
  parameters: Type.Object({
67
- expression: Type.String({ description: 'The expression to evaluate' }),
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: 'text', text: String(result) }],
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 '@sinclair/typebox'
86
- import type { AgentTool, HandlerContext } from '@electric-ax/agents-runtime'
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: 'memory_store',
91
- label: 'Memory Store',
92
- description: 'Persistent key-value store.',
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('get'),
96
- Type.Literal('set'),
97
- Type.Literal('delete'),
98
- Type.Literal('list'),
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 === 'set') {
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: 'text', text: `Stored "${key}"` }],
122
+ content: [{ type: "text", text: `Stored "${key}"` }],
123
123
  details: {},
124
124
  }
125
125
  }
126
- if (operation === 'get') {
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: 'text', text }], details: {} }
129
+ return { content: [{ type: "text", text }], details: {} }
130
130
  }
131
- if (operation === 'delete') {
131
+ if (operation === "delete") {
132
132
  ctx.db.actions.kv_delete({ key: key! })
133
133
  return {
134
- content: [{ type: 'text', text: `Deleted "${key}"` }],
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('\n')
140
+ const text = entries.map((e) => `${e.key}: ${e.value}`).join("\n")
141
141
  return {
142
- content: [{ type: 'text', text: text || '(empty)' }],
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 '@sinclair/typebox'
166
- import type { AgentTool, HandlerContext } from '@electric-ax/agents-runtime'
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: 'dispatch',
171
- label: 'Dispatch',
172
- description: 'Spawn a child agent and wait for its response.',
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: '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' }),
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: 'runFinished',
190
+ wake: "runFinished",
191
191
  }
192
192
  )
193
- const text = (await child.text()).join('\n\n')
193
+ const text = (await child.text()).join("\n\n")
194
194
  return {
195
- content: [{ type: 'text', text }],
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('assistant', {
211
- description: 'An assistant with memory and delegation',
210
+ registry.define("assistant", {
211
+ description: "An assistant with memory and delegation",
212
212
  state: {
213
- kv: { primaryKey: 'key' },
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: 'You are a helpful assistant with persistent memory.',
221
- model: 'claude-sonnet-4-5-20250929',
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: '... - Electric Agents'
3
+ titleTemplate: "... - Electric Agents"
4
4
  description: >-
5
- Embed the built-in Horton and worker runtime in your own process using
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 worker runtime for you. If you need to host those built-ins inside your own process, use the exported APIs from `@electric-ax/agents`.
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 `worker`, and forwards Electric Agents webhook wakes to the built-in handler.
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 '@electric-ax/agents'
19
+ import { BuiltinAgentsServer } from "@electric-ax/agents"
20
20
 
21
21
  const server = new BuiltinAgentsServer({
22
- agentServerUrl: 'http://localhost:4437',
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 '@electric-ax/agents-runtime'
39
+ import type { RuntimeRouterConfig } from "@electric-ax/agents-runtime"
40
40
 
41
- type CreateElectricTools = RuntimeRouterConfig['createElectricTools']
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 and worker file tools. 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. |
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 '@electric-ax/agents'
76
+ } from "@electric-ax/agents"
77
77
 
78
78
  const bootstrap = await createBuiltinAgentHandler({
79
- agentServerUrl: 'http://localhost:4437',
80
- serveEndpoint: 'https://example.com/_electric/builtin-agent-handler',
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('ANTHROPIC_API_KEY is required for built-in agents')
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 '@sinclair/typebox'
111
+ import { Type } from "@sinclair/typebox"
112
112
 
113
113
  const server = new BuiltinAgentsServer({
114
- agentServerUrl: 'http://localhost:4437',
114
+ agentServerUrl: "http://localhost:4437",
115
115
  port: 4448,
116
116
  createElectricTools: ({ entityUrl, upsertCronSchedule }) => [
117
117
  {
118
- name: 'schedule_daily_summary',
119
- label: 'Schedule daily summary',
120
- description: 'Schedule a daily summary wake for this entity.',
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: 'daily-summary',
127
+ id: "daily-summary",
128
128
  expression: `0 ${hour} * * *`,
129
129
  payload: `Run daily summary for ${entityUrl}`,
130
130
  })
131
- return { content: [{ type: 'text', text: 'Scheduled.' }], details: {} }
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 '@electric-ax/agents'
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 | 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. |
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 | Purpose |
170
- | --------------------------- | ----------------------------------------------------- |
171
- | `registerHorton()` | Register the `horton` type on an `EntityRegistry`. |
172
- | `registerWorker()` | Register the `worker` type on an `EntityRegistry`. |
173
- | `HORTON_MODEL` | Default model id used by Horton and worker. |
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()` | Create Horton's base shell/file/search/worker tools. |
176
- | `createSpawnWorkerTool()` | Create the `spawn_worker` tool for another agent. |
177
- | `WORKER_TOOL_NAMES` | Valid primitive tool names for workers. |
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 `worker`, see [Horton](../entities/agents/horton) and [Worker](../entities/agents/worker).
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: '... - Electric Agents'
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('my-entity', {
18
+ registry.define("my-entity", {
19
19
  state: {
20
- status: { primaryKey: 'key' },
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: 'key',
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: 'item-1', name: 'Widget', count: 5 })
63
- const itemViaState = ctx.state.items.get('item-1')
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('item-1', (draft) => {
65
+ ctx.state.items.update("item-1", (draft) => {
66
66
  draft.count += 1
67
67
  })
68
- ctx.state.items.delete('item-1')
68
+ ctx.state.items.delete("item-1")
69
69
 
70
70
  // Lower-level insert
71
71
  ctx.db.actions.items_insert({
72
- row: { key: 'item-1', name: 'Widget', count: 5 },
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('item-1')
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: 'item-1',
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: 'item-1' })
88
+ ctx.db.actions.items_delete({ key: "item-1" })
89
89
  ```
90
90
 
91
91
  ## Built-in collections