@electric-ax/agents 0.4.18 → 0.6.0

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 (45) hide show
  1. package/dist/entrypoint.js +88 -14
  2. package/dist/index.cjs +87 -13
  3. package/dist/index.d.cts +1 -1
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.js +88 -14
  6. package/docs/entities/agents/horton.md +22 -17
  7. package/docs/entities/agents/worker.md +13 -6
  8. package/docs/entities/patterns/blackboard.md +1 -1
  9. package/docs/entities/patterns/dispatcher.md +1 -1
  10. package/docs/entities/patterns/manager-worker.md +10 -5
  11. package/docs/entities/patterns/map-reduce.md +1 -1
  12. package/docs/entities/patterns/pipeline.md +1 -1
  13. package/docs/entities/patterns/reactive-observers.md +1 -1
  14. package/docs/index.md +6 -4
  15. package/docs/quickstart.md +2 -2
  16. package/docs/reference/agent-config.md +13 -3
  17. package/docs/reference/built-in-collections.md +128 -9
  18. package/docs/reference/cli.md +34 -4
  19. package/docs/reference/entity-definition.md +39 -7
  20. package/docs/reference/entity-handle.md +19 -1
  21. package/docs/reference/handler-context.md +130 -5
  22. package/docs/reference/runtime-handler.md +42 -14
  23. package/docs/reference/wake-event.md +29 -1
  24. package/docs/usage/app-setup.md +38 -7
  25. package/docs/usage/attachments.md +129 -0
  26. package/docs/usage/clients-and-react.md +23 -2
  27. package/docs/usage/configuring-the-agent.md +15 -5
  28. package/docs/usage/context-composition.md +2 -1
  29. package/docs/usage/defining-entities.md +9 -5
  30. package/docs/usage/defining-tools.md +1 -1
  31. package/docs/usage/embedded-builtins.md +82 -31
  32. package/docs/usage/managing-state.md +5 -0
  33. package/docs/usage/mcp-servers.md +16 -8
  34. package/docs/usage/overview.md +39 -14
  35. package/docs/usage/permissions-and-principals.md +160 -0
  36. package/docs/usage/programmatic-runtime-client.md +158 -16
  37. package/docs/usage/sandboxing.md +162 -0
  38. package/docs/usage/signals.md +138 -0
  39. package/docs/usage/spawning-and-coordinating.md +30 -11
  40. package/docs/usage/testing.md +1 -1
  41. package/docs/usage/waking-entities.md +34 -6
  42. package/docs/usage/webhook-sources.md +171 -0
  43. package/docs/usage/writing-handlers.md +13 -55
  44. package/docs/walkthrough.md +13 -5
  45. package/package.json +3 -3
@@ -26,31 +26,36 @@ npx electric-ax agents observe /horton/my-horton
26
26
 
27
27
  Horton is configured with `ctx.electricTools` plus the base Horton tool set:
28
28
 
29
- | Tool | Purpose |
30
- | -------------- | -------------------------------------------------------- |
31
- | `bash` | Run shell commands in the working directory. |
32
- | `read` | Read a file. Tracked in a per-wake `readSet`. |
33
- | `write` | Create or overwrite a file. |
34
- | `edit` | Targeted string replacement (file must be `read` first). |
35
- | `brave_search` | Web search via the Brave Search API. |
36
- | `fetch_url` | Fetch a URL and return it as markdown. |
37
- | `spawn_worker` | Dispatch a subagent for an isolated subtask. |
38
-
39
- `brave_search` requires `BRAVE_SEARCH_API_KEY` in the environment; without it the tool errors at call time.
40
-
41
- When docs support or skills are available, Horton also adds the docs search tool and skill tools during bootstrap.
29
+ | Tool | Purpose |
30
+ | ----------------- | -------------------------------------------------------- |
31
+ | `bash` | Run shell commands in the working directory. |
32
+ | `read` | Read a file. Tracked in a per-wake `readSet`. |
33
+ | `write` | Create or overwrite a file. |
34
+ | `edit` | Targeted string replacement (file must be `read` first). |
35
+ | `web_search` | Web search via the configured search provider. |
36
+ | `fetch_url` | Fetch a URL and return it as markdown. |
37
+ | `spawn_worker` | Dispatch a subagent for an isolated subtask. |
38
+ | `fork` | Branch a session at its latest completed response. |
39
+ | `observe_pg_sync` | Observe an Electric Postgres shape and wake on changes. |
40
+ | `unobserve_pg_sync` | Remove an existing pg-sync observation. |
41
+ | `send` | Send a message to another entity. |
42
+ | `set_title` | Rename the current chat session title. |
43
+
44
+ `web_search` uses the search provider configured by the built-in runtime; Brave search requires `BRAVE_SEARCH_API_KEY`.
45
+
46
+ When docs support or skills are available, Horton also adds the docs search tool and skill tools during bootstrap. Built-in runtimes also provide `ctx.electricTools`, including schedule tools and webhook-source tools when configured.
42
47
 
43
48
  ## Title generation
44
49
 
45
- After the first agent run completes, Horton calls `generateTitle()` (Haiku) to summarise the user's first message into a 3-5 word session title and stores it via `ctx.setTag('title', title)`. Failures are logged and ignored — the entity continues without a title.
50
+ After the first agent run completes, Horton calls `generateTitle()` using the configured low-cost model to summarise the user's first message into a 3-5 word session title and stores it via `ctx.setTag('title', title)`. Failures are logged and ignored — the entity continues without a title.
46
51
 
47
52
  ## Details
48
53
 
49
54
  | Property | Value |
50
55
  | ----------------- | ------------------------------------------------- |
51
56
  | Type name | `horton` |
52
- | Model | `HORTON_MODEL` (`claude-sonnet-4-5-20250929`) |
53
- | Title model | `claude-haiku-4-5-20251001` |
57
+ | Model | `HORTON_MODEL` (`claude-sonnet-4-6` by default) |
58
+ | Title model | Configured low-cost model |
54
59
  | Tools | `ctx.electricTools` + base Horton tool set, plus docs/skill tools when configured |
55
60
  | Working directory | Passed at bootstrap (defaults to `process.cwd()`) |
56
61
  | Title generation | Yes, after the first run if no title tag exists |
@@ -75,7 +80,7 @@ registry.define("my-assistant", {
75
80
  model: HORTON_MODEL,
76
81
  tools: [
77
82
  ...ctx.electricTools,
78
- ...createHortonTools(process.cwd(), ctx, readSet),
83
+ ...createHortonTools(ctx.sandbox, ctx, readSet),
79
84
  myCustomTool,
80
85
  ],
81
86
  })
@@ -20,6 +20,9 @@ interface WorkerArgs {
20
20
  tools?: Array<WorkerToolName>
21
21
  sharedDb?: { id: string; schema: SharedStateSchemaMap }
22
22
  sharedDbToolMode?: "full" | "write-only"
23
+ model?: string
24
+ provider?: string
25
+ reasoningEffort?: string
23
26
  }
24
27
  ```
25
28
 
@@ -29,8 +32,11 @@ interface WorkerArgs {
29
32
  | `tools` | No | Subset of valid tool names (see below). Unknown names throw at parse time. |
30
33
  | `sharedDb` | No | Shared state stream id and schema to connect to. |
31
34
  | `sharedDbToolMode` | No | Shared state tool mode: `"full"` (default) or `"write-only"`. |
35
+ | `model` | No | Model id override. Usually inherited from `spawn_worker` / Horton model config. |
36
+ | `provider` | No | Model provider override paired with `model`. |
37
+ | `reasoningEffort` | No | Reasoning effort override for compatible reasoning models. |
32
38
 
33
- `registerWorker(registry, { workingDirectory, streamFn? })` is called by the dev server during bootstrap; you don't usually call it yourself.
39
+ `registerWorker(registry, { workingDirectory, modelCatalog, streamFn? })` is called by the dev server during bootstrap; you don't usually call it yourself. The bootstrap path supplies the required `modelCatalog`.
34
40
 
35
41
  ## Valid tool names
36
42
 
@@ -40,9 +46,10 @@ type WorkerToolName =
40
46
  | "read"
41
47
  | "write"
42
48
  | "edit"
43
- | "brave_search"
49
+ | "web_search"
44
50
  | "fetch_url"
45
51
  | "spawn_worker"
52
+ | "send"
46
53
  ```
47
54
 
48
55
  These are the same primitives Horton uses. Pick the smallest subset the worker needs — tools are the worker's permission set.
@@ -57,7 +64,7 @@ The canonical way to spawn a worker is the `spawn_worker` tool, which Horton cal
57
64
  spawn_worker({
58
65
  systemPrompt:
59
66
  "You are a focused researcher. Find the three most-cited papers on X and return their titles, authors, and DOIs as a markdown table.",
60
- tools: ["brave_search", "fetch_url"],
67
+ tools: ["web_search", "fetch_url"],
61
68
  initialMessage: "Begin research now.",
62
69
  })
63
70
  ```
@@ -75,7 +82,7 @@ The spawn uses `wake: { on: 'runFinished', includeResponse: true }`, so the spaw
75
82
  1. Parses `ctx.args` into `WorkerArgs`. Throws if `systemPrompt` is empty, if `tools` contains an unknown name, or if neither `tools` nor `sharedDb` is provided.
76
83
  2. Builds the requested tool instances against the worker's `workingDirectory` (and a fresh per-wake `readSet` for the read-first-then-edit guard).
77
84
  3. If `sharedDb` is present, connects with `ctx.observe(db(id, schema))` and exposes generated `read_*`, `write_*`, `update_*`, and `delete_*` tools (`write_*` only in `"write-only"` mode).
78
- 4. Configures the agent with `HORTON_MODEL` (`claude-sonnet-4-5-20250929`), the provided system prompt (with a brief reporting-back footer appended), and the assembled tool list.
85
+ 4. Configures the agent with `HORTON_MODEL` (`claude-sonnet-4-6` by default), the provided system prompt (with a brief reporting-back footer appended), and the assembled tool list.
79
86
  5. Runs the agent until the LLM stops.
80
87
 
81
88
  ::: warning Least-privilege sandbox
@@ -96,7 +103,7 @@ When you finish, respond with a concise report covering what was done and any ke
96
103
  | Property | Value |
97
104
  | ----------------- | --------------------------------------------------------------------- |
98
105
  | Type name | `worker` |
99
- | Model | `HORTON_MODEL` (`claude-sonnet-4-5-20250929`) |
100
- | Tools | Subset of 7 primitives plus optional shared-state tools. **No `ctx.electricTools`.** |
106
+ | Model | `HORTON_MODEL` (`claude-sonnet-4-6` by default) |
107
+ | Tools | Subset of 8 primitives plus optional shared-state tools. **No `ctx.electricTools`.** |
101
108
  | Working directory | Provided to `registerWorker` at bootstrap |
102
109
  | Description | `Internal — generic worker spawned by other agents. Configure via spawn args (systemPrompt + tools + optional sharedDb).` |
@@ -58,7 +58,7 @@ export function registerDebate(registry: EntityRegistry) {
58
58
 
59
59
  ctx.useAgent({
60
60
  systemPrompt: DEBATE_SYSTEM_PROMPT,
61
- model: `claude-sonnet-4-5-20250929`,
61
+ model: `claude-sonnet-4-6`,
62
62
  tools: [...ctx.electricTools, startTool, checkTool, endTool],
63
63
  })
64
64
  await ctx.agent.run()
@@ -24,7 +24,7 @@ export function registerDispatcher(registry: EntityRegistry) {
24
24
 
25
25
  ctx.useAgent({
26
26
  systemPrompt: DISPATCHER_SYSTEM_PROMPT,
27
- model: `claude-sonnet-4-5-20250929`,
27
+ model: `claude-sonnet-4-6`,
28
28
  tools: [...ctx.electricTools, dispatchTool],
29
29
  })
30
30
  await ctx.agent.run()
@@ -27,7 +27,7 @@ export function registerManagerWorker(registry: EntityRegistry) {
27
27
 
28
28
  ctx.useAgent({
29
29
  systemPrompt: MANAGER_SYSTEM_PROMPT,
30
- model: `claude-sonnet-4-5-20250929`,
30
+ model: `claude-sonnet-4-6`,
31
31
  tools: [...ctx.electricTools, analyzeTool],
32
32
  })
33
33
  await ctx.agent.run()
@@ -92,10 +92,15 @@ Do not wait for worker output inside the same wake. Spawn workers with `wake: {
92
92
  ```ts
93
93
  const finished = wake.payload?.finished_child
94
94
  if (finished) {
95
- ctx.state.workers.update(finished.url, (draft) => {
96
- draft.status = finished.run_status
97
- draft.output = finished.response ?? ""
98
- })
95
+ const child = ctx.state.children.toArray.find(
96
+ (entry) => entry.url === finished.url
97
+ )
98
+ if (child) {
99
+ ctx.state.children.update(child.key, (draft) => {
100
+ draft.status = finished.run_status
101
+ draft.output = finished.response ?? ""
102
+ })
103
+ }
99
104
  }
100
105
  ```
101
106
 
@@ -25,7 +25,7 @@ export function registerMapReduce(registry: EntityRegistry) {
25
25
  async handler(ctx) {
26
26
  ctx.useAgent({
27
27
  systemPrompt: MAP_REDUCE_SYSTEM_PROMPT,
28
- model: `claude-sonnet-4-5-20250929`,
28
+ model: `claude-sonnet-4-6`,
29
29
  tools: [...ctx.electricTools, createMapChunksTool(ctx)],
30
30
  })
31
31
  await ctx.agent.run()
@@ -25,7 +25,7 @@ export function registerPipeline(registry: EntityRegistry) {
25
25
  async handler(ctx) {
26
26
  ctx.useAgent({
27
27
  systemPrompt: PIPELINE_SYSTEM_PROMPT,
28
- model: `claude-sonnet-4-5-20250929`,
28
+ model: `claude-sonnet-4-6`,
29
29
  tools: [...ctx.electricTools, createRunStageTool(ctx)],
30
30
  })
31
31
  await ctx.agent.run()
@@ -50,7 +50,7 @@ export function registerMonitor(registry: EntityRegistry) {
50
50
 
51
51
  ctx.useAgent({
52
52
  systemPrompt: MONITOR_SYSTEM_PROMPT,
53
- model: `claude-sonnet-4-5-20250929`,
53
+ model: `claude-sonnet-4-6`,
54
54
  tools: [...ctx.electricTools, observeTool],
55
55
  })
56
56
  await ctx.agent.run()
package/docs/index.md CHANGED
@@ -44,7 +44,7 @@ The runtime SDK is a layer over three foundations:
44
44
  - **[TanStack&nbsp;DB](https://tanstack.com/db)** — typed local reads and writes via collections.
45
45
  - **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.
46
46
 
47
- **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.
47
+ **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](/docs/agents/usage/managing-state) collections per entity type.
48
48
 
49
49
  **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.
50
50
 
@@ -75,7 +75,7 @@ registry.define("support", {
75
75
  if (wake.type === "inbox") {
76
76
  ctx.useAgent({
77
77
  systemPrompt: "You are a support agent.",
78
- model: "claude-sonnet-4-5-20250929",
78
+ model: "claude-sonnet-4-6",
79
79
  tools: [...ctx.electricTools, searchKbTool],
80
80
  })
81
81
  await ctx.agent.run()
@@ -110,7 +110,7 @@ The core pattern is [`ctx.useAgent()`](/docs/agents/reference/agent-config) foll
110
110
  ```ts
111
111
  ctx.useAgent({
112
112
  systemPrompt: "You are a helpful assistant.",
113
- model: "claude-sonnet-4-5-20250929",
113
+ model: "claude-sonnet-4-6",
114
114
  tools: [...ctx.electricTools, myCustomTool],
115
115
  })
116
116
 
@@ -228,5 +228,7 @@ See [Managing state](/docs/agents/usage/managing-state) for more information.
228
228
  - [Writing handlers](/docs/agents/usage/writing-handlers) — handler lifecycle and the `ctx` API.
229
229
  - [Configuring the agent](/docs/agents/usage/configuring-the-agent) — `useAgent`, models, tools, and streaming.
230
230
  - [Spawning & coordinating](/docs/agents/usage/spawning-and-coordinating) — multi-entity topologies and shared state.
231
- - [Built-in agents](/docs/agents/entities/agents/horton) — Horton, Worker, and Coder, the agents that ship with the runtime.
231
+ - [Permissions & principals](/docs/agents/usage/permissions-and-principals) — entity access control and principal-scoped clients.
232
+ - [Sandboxing](/docs/agents/usage/sandboxing), [Attachments](/docs/agents/usage/attachments), [Signals](/docs/agents/usage/signals), and [Webhook sources](/docs/agents/usage/webhook-sources) — newer runtime capabilities for hosted agents.
233
+ - [Built-in agents](/docs/agents/entities/agents/horton) — Horton and Worker, the agents that ship with the runtime.
232
234
  - [Examples](/docs/agents/examples/playground) — pattern walkthroughs and demo apps.
@@ -121,7 +121,7 @@ registry.define("assistant", {
121
121
  async handler(ctx) {
122
122
  ctx.useAgent({
123
123
  systemPrompt: "You are a helpful assistant.",
124
- model: "claude-sonnet-4-5-20250929",
124
+ model: "claude-sonnet-4-6",
125
125
  tools: [...ctx.electricTools],
126
126
  })
127
127
  await ctx.agent.run()
@@ -202,4 +202,4 @@ See the [CLI reference](./reference/cli#start) for the full set of commands.
202
202
  - [Defining entities](./usage/defining-entities) — entity types, schemas, and configuration.
203
203
  - [Writing handlers](./usage/writing-handlers) — handler lifecycle and the `ctx` API.
204
204
  - [Configuring the agent](./usage/configuring-the-agent) — `useAgent`, models, tools, and streaming.
205
- - [Built-in agents](./entities/agents/horton) — Horton, Worker, and Coder, the agents that ship with the runtime.
205
+ - [Built-in agents](./entities/agents/horton) — Horton and Worker, the agents that ship with the runtime.
@@ -16,13 +16,20 @@ Configuration for the LLM agent loop. Passed to `ctx.useAgent()`.
16
16
  interface AgentConfig {
17
17
  systemPrompt: string
18
18
  model: string | Model<any>
19
- provider?: KnownProvider
19
+ provider?: Provider
20
20
  tools: AgentTool[]
21
21
  streamFn?: StreamFn
22
22
  getApiKey?: (
23
23
  provider: string
24
24
  ) => Promise<string | undefined> | string | undefined
25
25
  onPayload?: SimpleStreamOptions["onPayload"]
26
+ onStepEnd?: (stats: {
27
+ input: number
28
+ uncachedInput: number
29
+ output: number
30
+ }) => void
31
+ modelTimeoutMs?: number
32
+ modelMaxRetries?: number
26
33
  testResponses?: string[] | TestResponseFn
27
34
  }
28
35
  ```
@@ -32,12 +39,15 @@ interface AgentConfig {
32
39
  | Field | Type | Required | Description |
33
40
  | --------------- | ---------------------------- | -------- | --------------------------------------------------------------------------------------------------- |
34
41
  | `systemPrompt` | `string` | Yes | System prompt sent to the LLM on each step. |
35
- | `model` | `string \| Model<any>` | Yes | Model identifier (e.g. `"claude-sonnet-4-5-20250929"`) or a resolved model object. |
36
- | `provider` | `KnownProvider` | No | Provider to use when `model` is a string. Defaults to `"anthropic"`. |
42
+ | `model` | `string \| Model<any>` | Yes | Model identifier (e.g. `"claude-sonnet-4-6"`) or a resolved model object. |
43
+ | `provider` | `Provider` | No | pi-ai provider to use when `model` is a string. Defaults to `"anthropic"`. |
37
44
  | `tools` | `AgentTool[]` | Yes | Tools available to the LLM. Spread `ctx.electricTools` when your runtime host provides runtime-level tools. See [`AgentTool`](./agent-tool). |
38
45
  | `streamFn` | `StreamFn` | No | Optional streaming callback passed to the underlying agent. |
39
46
  | `getApiKey` | `(provider) => string \| Promise<string> \| undefined` | No | Optional API-key resolver passed through to the model layer. |
40
47
  | `onPayload` | `SimpleStreamOptions["onPayload"]` | No | Optional callback for raw streaming payloads from the model layer. |
48
+ | `onStepEnd` | `(stats) => void` | No | Callback after each model step with provider-reported token counts. |
49
+ | `modelTimeoutMs` | `number` | No | Timeout for individual model calls, in milliseconds. |
50
+ | `modelMaxRetries` | `number` | No | Maximum retry count for model calls. |
41
51
  | `testResponses` | `string[] \| TestResponseFn` | No | Mock LLM responses for testing. When set, no real LLM calls are made. |
42
52
 
43
53
  ## TestResponseFn
@@ -2,13 +2,13 @@
2
2
  title: Built-in collections
3
3
  titleTemplate: "... - Electric Agents"
4
4
  description: >-
5
- Reference for the 17 runtime-managed collections: runs, steps, texts, toolCalls, inbox, errors, and more.
5
+ Reference for the 20 runtime-managed collections: runs, steps, texts, toolCalls, inbox, signals, errors, slashCommands, and more.
6
6
  outline: [2, 3]
7
7
  ---
8
8
 
9
9
  # Built-in collections
10
10
 
11
- Every entity automatically has these 17 collections, populated by the runtime as the agent operates. Custom state collections defined in `EntityDefinition.state` are merged with these at creation time.
11
+ Every entity automatically has these 20 collections, populated by the runtime as the agent operates. Custom state collections defined in `EntityDefinition.state` are merged with these at creation time.
12
12
 
13
13
  **Source:** `@electric-ax/agents-runtime` -- `entity-schema.ts`
14
14
 
@@ -22,19 +22,22 @@ Every entity automatically has these 17 collections, populated by the runtime as
22
22
  | `textDeltas` | `text_delta` | `TextDelta` | Incremental text content |
23
23
  | `toolCalls` | `tool_call` | `ToolCall` | Tool call lifecycle |
24
24
  | `reasoning` | `reasoning` | `Reasoning` | Reasoning block lifecycle |
25
+ | `reasoningDeltas` | `reasoning_delta` | `ReasoningDelta` | Incremental reasoning content |
25
26
  | `errors` | `error` | `ErrorEvent` | Diagnostic errors |
26
27
  | `inbox` | `inbox` | `MessageReceived` | Inbound messages |
27
28
  | `wakes` | `wake` | `WakeEntry` | Wake delivery records |
28
29
  | `entityCreated` | `entity_created` | `EntityCreated` | Entity bootstrap metadata |
29
30
  | `entityStopped` | `entity_stopped` | `EntityStopped` | Entity shutdown signal |
31
+ | `signals` | `signal` | `Signal` | Lifecycle signal records |
30
32
  | `childStatus` | `child_status` | `ChildStatusEntry` | Child/observed entity status |
31
33
  | `tags` | `tags` | `TagEntry` | Entity tags |
34
+ | `slashCommands` | `slash_command` | `SlashCommandEntry` | Composer slash commands |
35
+ | `manifests` | `manifest` | `Manifest` | Durable resource manifests |
32
36
  | `contextInserted` | `context_inserted` | `ContextInserted` | Context additions |
33
37
  | `contextRemoved` | `context_removed` | `ContextRemoved` | Context removals |
34
- | `manifests` | `manifest` | `Manifest` | Durable resource manifests |
35
38
  | `replayWatermarks` | `replay_watermark` | `ReplayWatermark` | Replay progress tracking |
36
39
 
37
- All collections use `key` as the primary key.
40
+ All collections use `key` as the primary key. Runtime-managed timeline rows may also include `_timeline_order` for stable timeline sorting.
38
41
 
39
42
  ## Type definitions
40
43
 
@@ -60,6 +63,8 @@ interface Step {
60
63
  model_provider?: string
61
64
  model_id?: string
62
65
  duration_ms?: number
66
+ input_tokens?: number
67
+ output_tokens?: number
63
68
  }
64
69
  ```
65
70
 
@@ -90,6 +95,7 @@ interface TextDelta {
90
95
  interface ToolCall {
91
96
  key: string
92
97
  run_id?: string
98
+ tool_call_id?: string
93
99
  tool_name: string
94
100
  status: "started" | "args_complete" | "executing" | "completed" | "failed"
95
101
  args?: unknown
@@ -104,7 +110,21 @@ interface ToolCall {
104
110
  ```ts
105
111
  interface Reasoning {
106
112
  key: string
113
+ run_id?: string
107
114
  status: "streaming" | "completed"
115
+ encrypted?: string
116
+ summary_title?: string
117
+ }
118
+ ```
119
+
120
+ ### ReasoningDelta
121
+
122
+ ```ts
123
+ interface ReasoningDelta {
124
+ key: string
125
+ reasoning_id: string
126
+ run_id: string
127
+ delta: string
108
128
  }
109
129
  ```
110
130
 
@@ -126,10 +146,15 @@ interface ErrorEvent {
126
146
  ```ts
127
147
  interface MessageReceived {
128
148
  key: string
129
- from: string
149
+ from?: string
130
150
  payload?: unknown
131
- timestamp: string
151
+ timestamp?: string
132
152
  message_type?: string
153
+ mode?: "immediate" | "queued" | "paused" | "steer"
154
+ status?: "pending" | "processed" | "cancelled"
155
+ position?: string
156
+ processed_at?: string
157
+ cancelled_at?: string
133
158
  }
134
159
  ```
135
160
 
@@ -150,6 +175,10 @@ interface WakeChangeEntry {
150
175
  collection: string
151
176
  kind: "insert" | "update" | "delete"
152
177
  key: string
178
+ from?: string
179
+ payload?: unknown
180
+ timestamp?: string
181
+ message_type?: string
153
182
  }
154
183
 
155
184
  interface WakeFinishedChildEntry {
@@ -163,7 +192,7 @@ interface WakeFinishedChildEntry {
163
192
  interface WakeOtherChildEntry {
164
193
  url: string
165
194
  type: string
166
- status: "spawning" | "running" | "idle" | "stopped"
195
+ status: "spawning" | "running" | "idle" | "paused" | "stopping" | "stopped" | "killed"
167
196
  }
168
197
  ```
169
198
 
@@ -189,6 +218,25 @@ interface EntityStopped {
189
218
  }
190
219
  ```
191
220
 
221
+ ### Signal
222
+
223
+ ```ts
224
+ interface Signal {
225
+ key: string
226
+ signal: "SIGINT" | "SIGHUP" | "SIGTERM" | "SIGKILL" | "SIGSTOP" | "SIGCONT" | "SIGUSR"
227
+ status: "unhandled" | "handled"
228
+ sender?: string
229
+ reason?: string
230
+ payload?: unknown
231
+ timestamp: string
232
+ handled_at?: string
233
+ handled_by?: string
234
+ outcome?: "transitioned" | "ignored" | "invalid_for_state" | "delivered" | "aborted" | "shutdown_requested" | "failed"
235
+ previous_state?: ChildStatusEntry["status"]
236
+ new_state?: ChildStatusEntry["status"]
237
+ }
238
+ ```
239
+
192
240
  ### ChildStatusEntry
193
241
 
194
242
  ```ts
@@ -196,7 +244,7 @@ interface ChildStatusEntry {
196
244
  key: string
197
245
  entity_url: string
198
246
  entity_type: string
199
- status: "spawning" | "running" | "idle" | "stopped"
247
+ status: "spawning" | "running" | "idle" | "paused" | "stopping" | "stopped" | "killed"
200
248
  }
201
249
  ```
202
250
 
@@ -209,6 +257,39 @@ interface TagEntry {
209
257
  }
210
258
  ```
211
259
 
260
+ ### SlashCommandEntry
261
+
262
+ ```ts
263
+ interface SlashCommandEntry {
264
+ key: string
265
+ name: string
266
+ description?: string
267
+ arguments?: Array<{
268
+ name: string
269
+ type: "string" | "number" | "boolean"
270
+ required?: boolean
271
+ description?: string
272
+ }>
273
+ source: "static" | "dynamic"
274
+ owner?: string
275
+ version?: string
276
+ updated_at: string
277
+ dynamic_layers?: Array<{
278
+ name: string
279
+ description?: string
280
+ arguments?: Array<{
281
+ name: string
282
+ type: "string" | "number" | "boolean"
283
+ required?: boolean
284
+ description?: string
285
+ }>
286
+ owner?: string
287
+ version?: string
288
+ updated_at: string
289
+ }>
290
+ }
291
+ ```
292
+
212
293
  ### ContextInserted
213
294
 
214
295
  ```ts
@@ -243,9 +324,11 @@ type Manifest =
243
324
  | ManifestSourceEntry
244
325
  | ManifestSharedStateEntry
245
326
  | ManifestEffectEntry
327
+ | ManifestAttachmentEntry
246
328
  | ManifestContextEntry
247
329
  | ManifestCronScheduleEntry
248
330
  | ManifestFutureSendScheduleEntry
331
+ | ManifestGoalEntry
249
332
 
250
333
  interface ManifestChildEntry {
251
334
  key: string
@@ -260,7 +343,7 @@ interface ManifestChildEntry {
260
343
  interface ManifestSourceEntry {
261
344
  key: string
262
345
  kind: "source"
263
- sourceType: string
346
+ sourceType: "entity" | "cron" | "entities" | "db" | "webhook" | "pgSync" | string
264
347
  sourceRef: string
265
348
  wake?: WakeConfig
266
349
  config: Record<string, unknown>
@@ -283,6 +366,27 @@ interface ManifestEffectEntry {
283
366
  config: unknown
284
367
  }
285
368
 
369
+ interface ManifestAttachmentEntry {
370
+ key: string
371
+ kind: "attachment"
372
+ id: string
373
+ streamPath: string
374
+ status: "pending" | "complete" | "failed"
375
+ subject: {
376
+ type: "inbox" | "run" | "text" | "tool_call" | "context"
377
+ key: string
378
+ }
379
+ role: "input" | "output"
380
+ mimeType: string
381
+ filename?: string
382
+ byteLength?: number
383
+ sha256?: string
384
+ createdAt: string
385
+ createdBy?: string
386
+ error?: string
387
+ meta?: Record<string, JsonValue>
388
+ }
389
+
286
390
  interface ManifestContextEntry {
287
391
  key: string
288
392
  kind: "context"
@@ -320,8 +424,23 @@ interface ManifestFutureSendScheduleEntry {
320
424
  failedAt?: string
321
425
  lastError?: string
322
426
  }
427
+
428
+ interface ManifestGoalEntry {
429
+ key: string
430
+ kind: "goal"
431
+ id: string
432
+ objective: string
433
+ status: "active" | "complete" | "budget_limited"
434
+ tokenBudget: number | null
435
+ tokensUsed: number
436
+ summary?: string
437
+ createdAt: string
438
+ updatedAt: string
439
+ }
323
440
  ```
324
441
 
442
+ `pgSync()` observations are stored as `sourceType: "pgSync"` manifest rows and project matching Postgres shape changes into the observed source's `changes` collection.
443
+
325
444
  ### ReplayWatermark
326
445
 
327
446
  ```ts
@@ -23,7 +23,8 @@ npm install -g electric-ax
23
23
  | `ELECTRIC_AGENTS_PRINCIPAL` | - | Optional principal key sent as `Electric-Principal` |
24
24
  | `ELECTRIC_AGENTS_SERVER_HEADERS` | - | Optional JSON object of additional server headers |
25
25
  | `ELECTRIC_AGENTS_PORT` | `4437` | Port used by `start` / `quickstart` |
26
- | `ELECTRIC_AGENTS_BUILTIN_PORT` | `4448` | Webhook port for `start-builtin` |
26
+ | `ELECTRIC_AGENTS_PULL_WAKE_RUNNER_ID` | `builtin-{identity}` | Pull-wake runner id for `start-builtin` |
27
+ | `PULL_WAKE_RUNNER_ID` | - | Legacy alias for `ELECTRIC_AGENTS_PULL_WAKE_RUNNER_ID` |
27
28
  | `ELECTRIC_AGENTS_COMPOSE_PROJECT` | `electric-agents` | Docker Compose project name |
28
29
  | `ANTHROPIC_API_KEY` | - | Required for `start-builtin` and `quickstart` |
29
30
 
@@ -94,6 +95,19 @@ electric agents observe /chat/my-convo --from 0
94
95
  | ----------------- | -------------------------------- |
95
96
  | `--from <offset>` | Start streaming from this offset |
96
97
 
98
+ ### <span class="cli-command"><code>view &lt;url&gt; [--from &lt;offset&gt;]</code></span> {#view-url-from-offset}
99
+
100
+ Print an entity conversation once.
101
+
102
+ ```bash
103
+ electric agents view /chat/my-convo
104
+ electric agents view /chat/my-convo --from 0
105
+ ```
106
+
107
+ | Option | Description |
108
+ | ----------------- | --------------------------- |
109
+ | `--from <offset>` | Start reading from this offset |
110
+
97
111
  ### <span class="cli-command"><code>inspect &lt;url&gt;</code></span> {#inspect-url}
98
112
 
99
113
  Show entity details. Outputs JSON.
@@ -120,9 +134,23 @@ electric agents ps --parent /manager/my-manager
120
134
 
121
135
  Output shows `URL`, `STATUS`, `CREATED`, and `LAST ACTIVE` columns with human-readable relative timestamps. Results are sorted by most recently active first.
122
136
 
137
+ ### <span class="cli-command"><code>signal &lt;url&gt; &lt;signal&gt; [--reason &lt;text&gt;] [--payload &lt;json&gt;]</code></span> {#signal-url-signal}
138
+
139
+ Send a lifecycle signal to an entity.
140
+
141
+ ```bash
142
+ electric agents signal /chat/my-convo SIGINT --reason "stop current run"
143
+ electric agents signal /chat/my-convo SIGUSR --payload '{"refresh":true}'
144
+ ```
145
+
146
+ | Option | Description |
147
+ | ------------------ | ----------------------------------- |
148
+ | `--reason <text>` | Human-readable signal reason |
149
+ | `--payload <json>` | JSON payload to attach to the signal |
150
+
123
151
  ### <span class="cli-command"><code>kill &lt;url&gt;</code></span> {#kill-url}
124
152
 
125
- Delete an entity.
153
+ Send `SIGKILL` to an entity.
126
154
 
127
155
  ```bash
128
156
  electric agents kill /chat/my-convo
@@ -138,7 +166,7 @@ electric agents start
138
166
 
139
167
  ### <span class="cli-command"><code>start-builtin [--anthropic-api-key &lt;key&gt;]</code></span> {#start-builtin}
140
168
 
141
- Start the built-in Horton runtime and register built-in agent types with the coordinator server.
169
+ Start the built-in Horton and worker runtime, register built-in agent types, and run a pull-wake runner.
142
170
 
143
171
  ```bash
144
172
  electric agents start-builtin --anthropic-api-key sk-ant-...
@@ -216,8 +244,10 @@ import {
216
244
  } from "electric-ax"
217
245
 
218
246
  const env = getElectricCliEnv({
247
+ ...process.env,
219
248
  ELECTRIC_AGENTS_URL: "http://localhost:4437",
220
249
  ELECTRIC_AGENTS_IDENTITY: "docs@example.com",
250
+ ELECTRIC_AGENTS_PRINCIPAL: "user:docs@example.com",
221
251
  })
222
252
 
223
253
  const handlers = createElectricCliHandlers(env, "electric agents")
@@ -234,7 +264,7 @@ await program.parseAsync(["node", "electric", "agents", "types"])
234
264
  | Export | Purpose |
235
265
  | --------------------------------- | ------------------------------------------------------------------------ |
236
266
  | `DEFAULT_ELECTRIC_AGENTS_URL` | Default server URL (`"http://localhost:4437"`). |
237
- | `getElectricCliEnv(env?)` | Reads `ELECTRIC_AGENTS_URL` and `ELECTRIC_AGENTS_IDENTITY`. |
267
+ | `getElectricCliEnv(env?)` | Reads `ELECTRIC_AGENTS_URL`, `ELECTRIC_AGENTS_IDENTITY`, `ELECTRIC_AGENTS_PRINCIPAL`, and `ELECTRIC_AGENTS_SERVER_HEADERS`. |
238
268
  | `createElectricCliHandlers()` | Creates the default command handlers. |
239
269
  | `createElectricProgram()` | Creates the Commander program. |
240
270
  | `resolveCommandPrefix(argv, env?)` | Resolves help text examples for direct or package-manager invocation. |