@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.
- package/dist/entrypoint.js +88 -14
- package/dist/index.cjs +87 -13
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +88 -14
- package/docs/entities/agents/horton.md +22 -17
- package/docs/entities/agents/worker.md +13 -6
- package/docs/entities/patterns/blackboard.md +1 -1
- package/docs/entities/patterns/dispatcher.md +1 -1
- package/docs/entities/patterns/manager-worker.md +10 -5
- package/docs/entities/patterns/map-reduce.md +1 -1
- package/docs/entities/patterns/pipeline.md +1 -1
- package/docs/entities/patterns/reactive-observers.md +1 -1
- package/docs/index.md +6 -4
- package/docs/quickstart.md +2 -2
- package/docs/reference/agent-config.md +13 -3
- package/docs/reference/built-in-collections.md +128 -9
- package/docs/reference/cli.md +34 -4
- package/docs/reference/entity-definition.md +39 -7
- package/docs/reference/entity-handle.md +19 -1
- package/docs/reference/handler-context.md +130 -5
- package/docs/reference/runtime-handler.md +42 -14
- package/docs/reference/wake-event.md +29 -1
- package/docs/usage/app-setup.md +38 -7
- package/docs/usage/attachments.md +129 -0
- package/docs/usage/clients-and-react.md +23 -2
- package/docs/usage/configuring-the-agent.md +15 -5
- package/docs/usage/context-composition.md +2 -1
- package/docs/usage/defining-entities.md +9 -5
- package/docs/usage/defining-tools.md +1 -1
- package/docs/usage/embedded-builtins.md +82 -31
- package/docs/usage/managing-state.md +5 -0
- package/docs/usage/mcp-servers.md +16 -8
- package/docs/usage/overview.md +39 -14
- package/docs/usage/permissions-and-principals.md +160 -0
- package/docs/usage/programmatic-runtime-client.md +158 -16
- package/docs/usage/sandboxing.md +162 -0
- package/docs/usage/signals.md +138 -0
- package/docs/usage/spawning-and-coordinating.md +30 -11
- package/docs/usage/testing.md +1 -1
- package/docs/usage/waking-entities.md +34 -6
- package/docs/usage/webhook-sources.md +171 -0
- package/docs/usage/writing-handlers.md +13 -55
- package/docs/walkthrough.md +13 -5
- package/package.json +3 -3
package/docs/usage/overview.md
CHANGED
|
@@ -18,13 +18,13 @@ High level overview of the Electric Agents system and developer APIs.
|
|
|
18
18
|
Agents are entities that handle events, defined as a:
|
|
19
19
|
|
|
20
20
|
- `handler(ctx, wake)` with
|
|
21
|
-
- `state` and [built in collections](#
|
|
21
|
+
- `state` and [built in collections](#_9-built-in-collections)
|
|
22
22
|
|
|
23
23
|
And schemas:
|
|
24
24
|
|
|
25
25
|
- `creationSchema` -- validated spawn args
|
|
26
26
|
- `inboxSchemas` -- typed message contracts
|
|
27
|
-
- `
|
|
27
|
+
- `stateSchemas` -- additional registered state schemas
|
|
28
28
|
|
|
29
29
|
See [Defining entities](/docs/agents/usage/defining-entities) and [EntityDefinition reference](/docs/agents/reference/entity-definition).
|
|
30
30
|
|
|
@@ -35,10 +35,13 @@ The context API passed into the handler:
|
|
|
35
35
|
| Property/Method | Purpose |
|
|
36
36
|
| ----------------------------------- | --------------------------------------------------------------------- |
|
|
37
37
|
| `ctx.firstWake` | Boolean -- initial setup pass while no manifest entries exist |
|
|
38
|
+
| `ctx.wake` | Current wake, also passed as the second handler argument |
|
|
39
|
+
| `ctx.slashCommands` | Read/register structured composer slash commands |
|
|
38
40
|
| `ctx.entityUrl` | Identity -- `/type/id` |
|
|
39
41
|
| `ctx.entityType` | Type name string |
|
|
40
42
|
| `ctx.args` | Readonly spawn arguments |
|
|
41
43
|
| `ctx.tags` | Entity tags -- key/value metadata |
|
|
44
|
+
| `ctx.principal` | Principal that caused the current wake, when supplied by the server |
|
|
42
45
|
| `ctx.db` | Full TanStack DB: `db.actions` for writes, `db.collections` for reads |
|
|
43
46
|
| `ctx.state` | Proxy object keyed by collection name |
|
|
44
47
|
| `ctx.events` | Change events that triggered this wake |
|
|
@@ -49,14 +52,17 @@ The context API passed into the handler:
|
|
|
49
52
|
| `ctx.agent.run()` | Execute the agent loop |
|
|
50
53
|
| `ctx.electricTools` | Runtime-provided tools to spread into agent config |
|
|
51
54
|
| `ctx.spawn(type, id, args, opts)` | Create child entity |
|
|
52
|
-
| `ctx.
|
|
55
|
+
| `ctx.fork(url, id, opts)` / `ctx.forkSelf(id, opts)` | Branch an entity at its latest completed run |
|
|
56
|
+
| `ctx.observe(source, opts)` | Subscribe to a source via `entity()`, `cron()`, `entities()`, `db()`, `webhook()`, or `pgSync()` |
|
|
53
57
|
| `ctx.send(url, payload, opts)` | Send message to an entity |
|
|
54
58
|
| `ctx.sleep()` | Return to idle |
|
|
55
59
|
| `ctx.mkdb(id, schema)` | Create cross-entity shared state |
|
|
56
60
|
| `ctx.observe(db(id, schema), opts)` | Join existing shared state |
|
|
57
61
|
| `ctx.recordRun()` | Record non-LLM work as a run for `runFinished` observers |
|
|
62
|
+
| `ctx.replyText(text)` | Emit a synthetic assistant text reply without invoking the LLM |
|
|
63
|
+
| `ctx.setGoal(input)` / `ctx.getGoal()` | Manage the active goal for long-running agents |
|
|
58
64
|
| `ctx.setTag(key, value)` | Set a tag on this entity |
|
|
59
|
-
| `ctx.
|
|
65
|
+
| `ctx.deleteTag(key)` | Delete a tag from this entity |
|
|
60
66
|
|
|
61
67
|
See [Writing handlers](/docs/agents/usage/writing-handlers) and [HandlerContext reference](/docs/agents/reference/handler-context).
|
|
62
68
|
|
|
@@ -65,12 +71,14 @@ See [Writing handlers](/docs/agents/usage/writing-handlers) and [HandlerContext
|
|
|
65
71
|
```ts
|
|
66
72
|
ctx.useAgent({
|
|
67
73
|
systemPrompt: string,
|
|
68
|
-
model: string | Model<any>, // e.g. 'claude-sonnet-4-
|
|
69
|
-
provider?:
|
|
74
|
+
model: string | Model<any>, // e.g. 'claude-sonnet-4-6'
|
|
75
|
+
provider?: Provider, // defaults to 'anthropic' for string models
|
|
70
76
|
tools: AgentTool[], // [...ctx.electricTools, ...custom]
|
|
71
77
|
streamFn?: StreamFn, // optional streaming callback
|
|
72
78
|
getApiKey?: (provider: string) => string | Promise<string> | undefined,
|
|
73
79
|
onPayload?: SimpleStreamOptions["onPayload"],
|
|
80
|
+
modelTimeoutMs?: number,
|
|
81
|
+
modelMaxRetries?: number,
|
|
74
82
|
testResponses?: string[] | TestResponseFn // for testing without LLM
|
|
75
83
|
})
|
|
76
84
|
await ctx.agent.run() // blocks until agent finishes
|
|
@@ -177,8 +185,10 @@ See [Managing state](/docs/agents/usage/managing-state).
|
|
|
177
185
|
|
|
178
186
|
- **`spawn(type, id, args, opts)`** -> `EntityHandle` -- create child
|
|
179
187
|
- `opts.initialMessage` -- first message to deliver
|
|
188
|
+
- `opts.initialMessageType` -- optional inbox message type for the initial message
|
|
180
189
|
- `opts.wake` -- `'runFinished'`, `{ on: 'runFinished', includeResponse? }`, or `{ on: 'change', collections?, debounceMs?, timeoutMs? }`
|
|
181
|
-
- **`
|
|
190
|
+
- **`fork(sourceEntityUrl, id, opts)` / `forkSelf(id, opts)`** -> `EntityHandle` -- branch an entity at its latest completed run
|
|
191
|
+
- **`observe(source, opts)`** -> `EntityHandle | ObservationHandle` -- subscribe via `entity()`, `cron()`, `entities()`, `db()`, `webhook()`, or `pgSync()`
|
|
182
192
|
- **`send(url, payload, opts)`** -- fire-and-forget message
|
|
183
193
|
- **`recordRun()`** -> `RunHandle` -- publish run lifecycle for external work
|
|
184
194
|
- **`sleep()`** -- go idle
|
|
@@ -192,7 +202,17 @@ See [Managing state](/docs/agents/usage/managing-state).
|
|
|
192
202
|
|
|
193
203
|
See [Spawning & coordinating](/docs/agents/usage/spawning-and-coordinating) and [EntityHandle reference](/docs/agents/reference/entity-handle).
|
|
194
204
|
|
|
195
|
-
## 7.
|
|
205
|
+
## 7. Runtime capabilities
|
|
206
|
+
|
|
207
|
+
Use the dedicated guides for runtime features that cut across handlers, clients, and hosted built-ins:
|
|
208
|
+
|
|
209
|
+
- [Permissions & principals](/docs/agents/usage/permissions-and-principals) — principal-scoped access to types and entities.
|
|
210
|
+
- [Sandboxing](/docs/agents/usage/sandboxing) — filesystem, process, and network isolation for LLM-driven tools.
|
|
211
|
+
- [Attachments](/docs/agents/usage/attachments) — upload, read, and hydrate files and images.
|
|
212
|
+
- [Signals](/docs/agents/usage/signals) — interrupt, pause, resume, kill, and notify entities.
|
|
213
|
+
- [Webhook sources](/docs/agents/usage/webhook-sources) — subscribe entities to external webhook-backed feeds.
|
|
214
|
+
|
|
215
|
+
## 8. Shared state (cross-entity)
|
|
196
216
|
|
|
197
217
|
Define a schema map, then create/connect:
|
|
198
218
|
|
|
@@ -213,9 +233,9 @@ shared.findings.insert({ key: "f1", text: "..." })
|
|
|
213
233
|
|
|
214
234
|
See [Shared state](/docs/agents/usage/shared-state) and [SharedStateHandle reference](/docs/agents/reference/shared-state-handle).
|
|
215
235
|
|
|
216
|
-
##
|
|
236
|
+
## 9. Built-in collections
|
|
217
237
|
|
|
218
|
-
Every entity automatically has
|
|
238
|
+
Every entity automatically has 20 `ctx.db.collections`:
|
|
219
239
|
|
|
220
240
|
| Collection | Purpose | Key fields |
|
|
221
241
|
| ------------------ | ------------------------- | ---------------------------------------------------------------------- |
|
|
@@ -225,13 +245,16 @@ Every entity automatically has 17 `ctx.db.collections`:
|
|
|
225
245
|
| `textDeltas` | Incremental text chunks | `text_id, delta` |
|
|
226
246
|
| `toolCalls` | Tool invocation lifecycle | `tool_name, status, args, result` |
|
|
227
247
|
| `reasoning` | Extended thinking blocks | `status: streaming/completed` |
|
|
248
|
+
| `reasoningDeltas` | Incremental reasoning chunks | `reasoning_id, delta` |
|
|
228
249
|
| `errors` | Diagnostic errors | `error_code, message` |
|
|
229
250
|
| `inbox` | Received messages | `from, payload, message_type` |
|
|
230
251
|
| `wakes` | Wake event history | `source, timeout, changes` |
|
|
231
252
|
| `entityCreated` | Bootstrap metadata | `entity_type, args, parent_url` |
|
|
232
253
|
| `entityStopped` | Shutdown signal | `timestamp, reason` |
|
|
254
|
+
| `signals` | Lifecycle signal records | `signal, status, outcome` |
|
|
233
255
|
| `childStatus` | Child entity status | `entity_url, status` |
|
|
234
|
-
| `
|
|
256
|
+
| `slashCommands` | Composer slash commands | `name, description, args` |
|
|
257
|
+
| `manifests` | Wiring declarations | discriminated union: child/source/shared-state/effect/attachment/context/schedule |
|
|
235
258
|
| `replayWatermarks` | Replay offset tracking | `source_id, offset` |
|
|
236
259
|
| `tags` | Entity tags/labels | `key, value` |
|
|
237
260
|
| `contextInserted` | Context additions | `id, name, attrs, content, timestamp` |
|
|
@@ -239,7 +262,7 @@ Every entity automatically has 17 `ctx.db.collections`:
|
|
|
239
262
|
|
|
240
263
|
See [Built-in collections](/docs/agents/reference/built-in-collections).
|
|
241
264
|
|
|
242
|
-
##
|
|
265
|
+
## 10. CLI (`electric agents`)
|
|
243
266
|
|
|
244
267
|
Interact with the system using the Electric Agents CLI:
|
|
245
268
|
|
|
@@ -250,6 +273,8 @@ Interact with the system using the Electric Agents CLI:
|
|
|
250
273
|
| `electric agents spawn /type/id --args '{...}'` | Create entity |
|
|
251
274
|
| `electric agents send /type/id 'message'` | Send message |
|
|
252
275
|
| `electric agents observe /type/id` | Stream entity events |
|
|
276
|
+
| `electric agents view /type/id` | Print entity conversation once |
|
|
277
|
+
| `electric agents signal /type/id SIGINT` | Send a lifecycle signal |
|
|
253
278
|
| `electric agents inspect /type/id` | Show entity state |
|
|
254
279
|
| `electric agents ps [--type --status --parent]` | List entities |
|
|
255
280
|
| `electric agents kill /type/id` | Delete entity |
|
|
@@ -261,7 +286,7 @@ Interact with the system using the Electric Agents CLI:
|
|
|
261
286
|
|
|
262
287
|
See [CLI reference](/docs/agents/reference/cli).
|
|
263
288
|
|
|
264
|
-
##
|
|
289
|
+
## 11. App setup
|
|
265
290
|
|
|
266
291
|
```ts
|
|
267
292
|
const registry = createEntityRegistry()
|
|
@@ -279,7 +304,7 @@ await runtime.registerTypes() // register all types with runtime server
|
|
|
279
304
|
|
|
280
305
|
See [App setup](/docs/agents/usage/app-setup) and [RuntimeHandler reference](/docs/agents/reference/runtime-handler).
|
|
281
306
|
|
|
282
|
-
##
|
|
307
|
+
## 12. App clients and embedded built-ins
|
|
283
308
|
|
|
284
309
|
Use the client and embedding APIs when you need to work with agents outside an entity handler:
|
|
285
310
|
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Permissions & principals
|
|
3
|
+
titleTemplate: "... - Electric Agents"
|
|
4
|
+
description: >-
|
|
5
|
+
Control who can spawn, read, write, signal, fork, schedule, and manage Electric Agents entities using principals and grants.
|
|
6
|
+
outline: [2, 3]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Permissions & principals
|
|
10
|
+
|
|
11
|
+
Electric Agents servers authorize requests using a **principal** and permission grants. A principal identifies the caller; grants decide what that caller can do to entity types and entity instances.
|
|
12
|
+
|
|
13
|
+
## Principals
|
|
14
|
+
|
|
15
|
+
Pass a principal key as the `Electric-Principal` header. The key shape is:
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
<kind>:<id>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Supported principal kinds are `user`, `agent`, `service`, and `system`. The server turns a key such as `user:sam` into the canonical principal URL `/principal/user%3Asam`.
|
|
22
|
+
|
|
23
|
+
From clients, use `principalKey`:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { createRuntimeServerClient } from "@electric-ax/agents-runtime"
|
|
27
|
+
|
|
28
|
+
const client = createRuntimeServerClient({
|
|
29
|
+
baseUrl: "http://localhost:4437",
|
|
30
|
+
principalKey: "user:sam",
|
|
31
|
+
})
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The CLI can pass the same value through the environment:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
ELECTRIC_AGENTS_PRINCIPAL=user:sam electric agents ps
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Servers may also accept additional auth headers through `ELECTRIC_AGENTS_SERVER_HEADERS` or `serverHeaders`, depending on the host.
|
|
41
|
+
|
|
42
|
+
## Entity type permissions
|
|
43
|
+
|
|
44
|
+
Entity type grants control who can spawn or manage entities of a type. Type-level permissions are:
|
|
45
|
+
|
|
46
|
+
| Permission | Allows |
|
|
47
|
+
| ---------- | ------ |
|
|
48
|
+
| `spawn` | Spawn entities of this type |
|
|
49
|
+
| `manage` | Manage the entity type and acts as the broader type-level permission |
|
|
50
|
+
|
|
51
|
+
Declare initial type grants in an entity definition:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
registry.define("worker", {
|
|
55
|
+
description: "Internal worker",
|
|
56
|
+
permissionGrants: [
|
|
57
|
+
{
|
|
58
|
+
subject_kind: "principal_kind",
|
|
59
|
+
subject_value: "user",
|
|
60
|
+
permission: "spawn",
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
async handler(ctx) {
|
|
64
|
+
// ...
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`subject_kind` can be `principal` for one principal URL/key or `principal_kind` for every principal of a kind.
|
|
70
|
+
|
|
71
|
+
Built-in Horton and Worker registrations grant all `user` principals both `spawn` and `manage` on those entity types. This makes local and hosted user principals able to create built-in sessions and see the type metadata needed by creation UIs. Custom entity types should choose their own `permissionGrants`.
|
|
72
|
+
|
|
73
|
+
## Entity permissions
|
|
74
|
+
|
|
75
|
+
Entity grants control access to existing entities. Entity-level permissions are:
|
|
76
|
+
|
|
77
|
+
| Permission | Allows |
|
|
78
|
+
| ---------- | ------ |
|
|
79
|
+
| `read` | Read entity metadata and streams |
|
|
80
|
+
| `write` | Send messages and write entity-owned resources |
|
|
81
|
+
| `delete` | Delete or kill the entity |
|
|
82
|
+
| `signal` | Send lifecycle signals |
|
|
83
|
+
| `fork` | Fork from entity history |
|
|
84
|
+
| `schedule` | Create, update, or delete schedules |
|
|
85
|
+
| `spawn` | Spawn children from this entity |
|
|
86
|
+
| `manage` | Manage grants and acts as the broader entity-level permission |
|
|
87
|
+
|
|
88
|
+
Server spawn routes can include initial entity grants:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
await fetch("http://localhost:4437/_electric/entities/assistant/support-ticket-42", {
|
|
92
|
+
method: "PUT",
|
|
93
|
+
headers: {
|
|
94
|
+
"content-type": "application/json",
|
|
95
|
+
"electric-principal": "user:sam",
|
|
96
|
+
},
|
|
97
|
+
body: JSON.stringify({
|
|
98
|
+
grants: [
|
|
99
|
+
{
|
|
100
|
+
subject_kind: "principal",
|
|
101
|
+
subject_value: "/principal/user%3Asam",
|
|
102
|
+
permission: "read",
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
}),
|
|
106
|
+
})
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
When spawning from a parent, broad delegation requires `manage` on the parent. This applies to grants such as `manage`, principal-kind grants, descendant propagation, and `copy_to_children`.
|
|
110
|
+
|
|
111
|
+
## Sharing roles
|
|
112
|
+
|
|
113
|
+
The server stores granular grants, but the UI presents common sharing roles:
|
|
114
|
+
|
|
115
|
+
| Role | Grants |
|
|
116
|
+
| -------- | ------ |
|
|
117
|
+
| `view` | `read`, `fork` |
|
|
118
|
+
| `chat` | `read`, `write`, `signal`, `fork`, `schedule`, `spawn` |
|
|
119
|
+
| `manage` | `manage`, `delete` |
|
|
120
|
+
|
|
121
|
+
These are presets for entity grants. They do not change the underlying permission model, and deployments can still grant individual permissions directly.
|
|
122
|
+
|
|
123
|
+
The server also exposes principal and effective-permission data through Electric shapes for sharing UIs. Point authorization still uses server-side permission checks; Electric visibility is derived from materialized effective permissions.
|
|
124
|
+
|
|
125
|
+
## Grant propagation
|
|
126
|
+
|
|
127
|
+
Entity grants may include propagation options:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
{
|
|
131
|
+
subject_kind: "principal",
|
|
132
|
+
subject_value: "/principal/user%3Asam",
|
|
133
|
+
permission: "read",
|
|
134
|
+
propagation: "descendants",
|
|
135
|
+
copy_to_children: true,
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
- `propagation: "self"` applies to the entity itself.
|
|
140
|
+
- `propagation: "descendants"` applies through descendant entities.
|
|
141
|
+
- `copy_to_children: true` copies the grant when children are spawned.
|
|
142
|
+
- `expires_at` can set a grant expiry timestamp.
|
|
143
|
+
|
|
144
|
+
## Claim-scoped write tokens
|
|
145
|
+
|
|
146
|
+
Some low-level writes are protected by claim-scoped write tokens. Handler APIs such as `ctx.setTag()` and `ctx.deleteTag()` already have the active claim context. External clients should usually send messages instead of directly mutating entity-owned state.
|
|
147
|
+
|
|
148
|
+
If a host reserves the `Authorization` header for server auth, configure write token transport with `writeTokenHeader` or `claimTokenHeader`:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
const client = createRuntimeServerClient({
|
|
152
|
+
baseUrl: "http://localhost:4437",
|
|
153
|
+
headers: { authorization: `Bearer ${serverToken}` },
|
|
154
|
+
writeTokenHeader: "electric-claim-token",
|
|
155
|
+
})
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Development fallback
|
|
159
|
+
|
|
160
|
+
Local development servers can use a development principal fallback. Production deployments should authenticate requests and provide an explicit `Electric-Principal` header for every request.
|
|
@@ -25,15 +25,21 @@ const client = createRuntimeServerClient({
|
|
|
25
25
|
interface RuntimeServerClientConfig {
|
|
26
26
|
baseUrl: string
|
|
27
27
|
fetch?: typeof globalThis.fetch
|
|
28
|
+
headers?: HeadersProvider
|
|
29
|
+
writeTokenHeader?: ClaimTokenHeader
|
|
28
30
|
track?: <T>(promise: Promise<T>) => Promise<T>
|
|
31
|
+
principalKey?: string
|
|
29
32
|
}
|
|
30
33
|
```
|
|
31
34
|
|
|
32
|
-
| Field
|
|
33
|
-
|
|
|
34
|
-
| `baseUrl`
|
|
35
|
-
| `fetch`
|
|
36
|
-
| `
|
|
35
|
+
| Field | Description |
|
|
36
|
+
| ------------------ | --------------------------------------------------------------------------- |
|
|
37
|
+
| `baseUrl` | Base URL for the Electric Agents server. |
|
|
38
|
+
| `fetch` | Optional fetch implementation, useful in tests or non-standard runtimes. |
|
|
39
|
+
| `headers` | Static or async headers added to requests, useful for auth or tenant scope. |
|
|
40
|
+
| `writeTokenHeader` | Header transport for claim-scoped write tokens: `authorization`, `electric-claim-token`, or `both`. |
|
|
41
|
+
| `track` | Optional wrapper for all requests, useful for telemetry or pending state. |
|
|
42
|
+
| `principalKey` | Principal key sent as `Electric-Principal` on requests. |
|
|
37
43
|
|
|
38
44
|
## Entity Lifecycle
|
|
39
45
|
|
|
@@ -46,6 +52,7 @@ const info = await client.spawnEntity({
|
|
|
46
52
|
args: { timezone: "Europe/London" },
|
|
47
53
|
initialMessage: "Help me get started.",
|
|
48
54
|
tags: { project: "docs" },
|
|
55
|
+
sandbox: { profile: "local", scope: "entity" },
|
|
49
56
|
})
|
|
50
57
|
|
|
51
58
|
console.log(info.entityUrl) // "/horton/onboarding"
|
|
@@ -60,7 +67,17 @@ interface SpawnEntityOptions {
|
|
|
60
67
|
args?: Record<string, unknown>
|
|
61
68
|
parentUrl?: string
|
|
62
69
|
initialMessage?: unknown
|
|
70
|
+
initialMessageType?: string
|
|
63
71
|
tags?: Record<string, string>
|
|
72
|
+
sandbox?: {
|
|
73
|
+
profile?: string
|
|
74
|
+
key?: string
|
|
75
|
+
scope?: "entity" | "wake"
|
|
76
|
+
persistent?: boolean
|
|
77
|
+
owner?: boolean
|
|
78
|
+
inherit?: boolean
|
|
79
|
+
}
|
|
80
|
+
dispatch_policy?: DispatchPolicy
|
|
64
81
|
wake?: {
|
|
65
82
|
subscriberUrl: string
|
|
66
83
|
condition:
|
|
@@ -73,14 +90,50 @@ interface SpawnEntityOptions {
|
|
|
73
90
|
debounceMs?: number
|
|
74
91
|
timeoutMs?: number
|
|
75
92
|
includeResponse?: boolean
|
|
93
|
+
manifestKey?: string
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### forkEntity
|
|
99
|
+
|
|
100
|
+
`forkEntity()` wraps `POST /_electric/entities/<type>/<id>/fork` and creates a new entity from a source entity's latest completed run:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
const fork = await client.forkEntity({
|
|
104
|
+
sourceEntityUrl: "/horton/onboarding",
|
|
105
|
+
instanceId: "onboarding-variant",
|
|
106
|
+
initialMessage: { text: "Try a different approach." },
|
|
107
|
+
tags: { branch: "variant" },
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
console.log(fork.entityUrl)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
interface ForkEntityOptions {
|
|
115
|
+
sourceEntityUrl: string
|
|
116
|
+
instanceId?: string
|
|
117
|
+
parent?: string
|
|
118
|
+
wake?: {
|
|
119
|
+
subscriberUrl: string
|
|
120
|
+
condition: RegisterWakeOptions["condition"]
|
|
121
|
+
debounceMs?: number
|
|
122
|
+
timeoutMs?: number
|
|
123
|
+
includeResponse?: boolean
|
|
124
|
+
manifestKey?: string
|
|
76
125
|
}
|
|
126
|
+
initialMessage?: unknown
|
|
127
|
+
tags?: Record<string, string>
|
|
77
128
|
}
|
|
78
129
|
```
|
|
79
130
|
|
|
80
|
-
|
|
131
|
+
`initialMessage` is sent after the fork has been created and dispatch subscriptions are linked, so a partial failure can leave an idle fork. Handler code should prefer `ctx.fork()` or `ctx.forkSelf()`.
|
|
132
|
+
|
|
133
|
+
### getEntity
|
|
81
134
|
|
|
82
135
|
```ts
|
|
83
|
-
const info = await client.
|
|
136
|
+
const info = await client.getEntity("/horton/onboarding")
|
|
84
137
|
// { entityUrl, entityType, streamPath }
|
|
85
138
|
```
|
|
86
139
|
|
|
@@ -98,8 +151,8 @@ Deleting an already-missing entity is treated as success.
|
|
|
98
151
|
await client.sendEntityMessage({
|
|
99
152
|
targetUrl: "/horton/onboarding",
|
|
100
153
|
payload: "What changed since last time?",
|
|
101
|
-
from: "support-ui",
|
|
102
154
|
type: "user_message",
|
|
155
|
+
mode: "queued",
|
|
103
156
|
})
|
|
104
157
|
```
|
|
105
158
|
|
|
@@ -107,13 +160,57 @@ await client.sendEntityMessage({
|
|
|
107
160
|
interface SendEntityMessageOptions {
|
|
108
161
|
targetUrl: string
|
|
109
162
|
payload: unknown
|
|
110
|
-
from?: string
|
|
111
163
|
type?: string
|
|
112
164
|
afterMs?: number
|
|
165
|
+
mode?: "immediate" | "queued" | "paused" | "steer"
|
|
166
|
+
position?: string
|
|
167
|
+
fromPrincipal?: string
|
|
168
|
+
fromAgent?: string
|
|
169
|
+
writeToken?: string
|
|
113
170
|
}
|
|
114
171
|
```
|
|
115
172
|
|
|
116
|
-
`afterMs` asks the server to deliver the message later.
|
|
173
|
+
`afterMs` asks the server to deliver the message later. `mode` controls how the server queues or applies the message. `fromPrincipal`, `fromAgent`, and `writeToken` are advanced fields for claim-scoped runtime writes.
|
|
174
|
+
|
|
175
|
+
## Signals
|
|
176
|
+
|
|
177
|
+
Send lifecycle signals to an entity:
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
await client.signalEntity({
|
|
181
|
+
entityUrl: "/horton/onboarding",
|
|
182
|
+
signal: "SIGINT",
|
|
183
|
+
reason: "User stopped the current run",
|
|
184
|
+
})
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
`deleteEntity()` sends `SIGKILL` and treats an already-missing entity as success:
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
await client.deleteEntity("/horton/onboarding")
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Attachments
|
|
194
|
+
|
|
195
|
+
Attachments are uploaded through entity routes, stored in private attachment streams, and referenced by manifest entries:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
const { attachment } = await client.createAttachment({
|
|
199
|
+
entityUrl: "/horton/onboarding",
|
|
200
|
+
attachment: {
|
|
201
|
+
bytes: imageBytes,
|
|
202
|
+
mimeType: "image/png",
|
|
203
|
+
filename: "diagram.png",
|
|
204
|
+
subject: { type: "inbox", key: "message-1" },
|
|
205
|
+
role: "input",
|
|
206
|
+
},
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
const bytes = await client.readAttachment({
|
|
210
|
+
entityUrl: "/horton/onboarding",
|
|
211
|
+
id: attachment.id,
|
|
212
|
+
})
|
|
213
|
+
```
|
|
117
214
|
|
|
118
215
|
## Shared State
|
|
119
216
|
|
|
@@ -156,24 +253,69 @@ await client.registerWake({
|
|
|
156
253
|
})
|
|
157
254
|
```
|
|
158
255
|
|
|
159
|
-
###
|
|
256
|
+
### ensureCronStream
|
|
160
257
|
|
|
161
258
|
```ts
|
|
162
|
-
const streamUrl = await client.
|
|
259
|
+
const streamUrl = await client.ensureCronStream(
|
|
163
260
|
"0 9 * * *",
|
|
164
261
|
"Europe/London"
|
|
165
262
|
)
|
|
166
263
|
```
|
|
167
264
|
|
|
168
|
-
###
|
|
265
|
+
### ensureEntitiesMembershipStream
|
|
169
266
|
|
|
170
267
|
```ts
|
|
171
|
-
const source = await client.
|
|
268
|
+
const source = await client.ensureEntitiesMembershipStream({ project: "docs" })
|
|
172
269
|
// { streamUrl, sourceRef }
|
|
173
270
|
```
|
|
174
271
|
|
|
175
272
|
This is the lower-level operation behind observing `entities({ tags })`.
|
|
176
273
|
|
|
274
|
+
### registerPgSyncSource
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
const source = await client.registerPgSyncSource({
|
|
278
|
+
url: "http://localhost:3000/v1/shape",
|
|
279
|
+
table: "todos",
|
|
280
|
+
where: "project_id = $1",
|
|
281
|
+
params: ["docs"],
|
|
282
|
+
})
|
|
283
|
+
// { streamUrl, sourceRef }
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
This is the lower-level operation behind observing `pgSync({ url, table, where, params })` sources. The server turns the Postgres shape into an Electric Agents observation stream.
|
|
287
|
+
|
|
288
|
+
Remove an entity's pg-sync observation by source reference:
|
|
289
|
+
|
|
290
|
+
```ts
|
|
291
|
+
await client.removePgSyncObservation({
|
|
292
|
+
entityUrl: "/horton/onboarding",
|
|
293
|
+
sourceRef: source.sourceRef,
|
|
294
|
+
})
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Webhook sources
|
|
298
|
+
|
|
299
|
+
Webhook-source APIs expose webhook-backed feeds that agents can subscribe to:
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
const sources = await client.listWebhookSources()
|
|
303
|
+
|
|
304
|
+
await client.subscribeToWebhookSource({
|
|
305
|
+
entityUrl: "/horton/onboarding",
|
|
306
|
+
id: "github-main",
|
|
307
|
+
webhookKey: "github",
|
|
308
|
+
bucketKey: "repo",
|
|
309
|
+
params: { repo: "electric-sql/electric" },
|
|
310
|
+
lifetime: { kind: "until_entity_stopped" },
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
await client.unsubscribeFromWebhookSource({
|
|
314
|
+
entityUrl: "/horton/onboarding",
|
|
315
|
+
id: "github-main",
|
|
316
|
+
})
|
|
317
|
+
```
|
|
318
|
+
|
|
177
319
|
## Schedules
|
|
178
320
|
|
|
179
321
|
Schedules are stored on an entity manifest and return the write transaction id.
|
|
@@ -202,11 +344,11 @@ await client.deleteSchedule({
|
|
|
202
344
|
|
|
203
345
|
## Tags
|
|
204
346
|
|
|
205
|
-
`setTag()` and `
|
|
347
|
+
`setTag()` and `deleteTag()` are primarily for handler/runtime-owned flows that already hold the current claim-scoped write token. External clients should prefer `sendEntityMessage()` and write only to an entity's inbox rather than writing entity state directly.
|
|
206
348
|
|
|
207
349
|
```ts
|
|
208
350
|
await client.setTag("/horton/onboarding", "title", "Onboarding", writeToken)
|
|
209
|
-
await client.
|
|
351
|
+
await client.deleteTag("/horton/onboarding", "title", writeToken)
|
|
210
352
|
```
|
|
211
353
|
|
|
212
354
|
## Choosing a Client
|