@electric-ax/agents-server 0.4.15 → 0.4.17

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.
@@ -0,0 +1,100 @@
1
+ CREATE TABLE "entity_type_permission_grants" (
2
+ "id" bigserial PRIMARY KEY NOT NULL,
3
+ "tenant_id" text DEFAULT 'default' NOT NULL,
4
+ "entity_type" text NOT NULL,
5
+ "permission" text NOT NULL,
6
+ "subject_kind" text NOT NULL,
7
+ "subject_value" text NOT NULL,
8
+ "created_by" text,
9
+ "expires_at" timestamp with time zone,
10
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
11
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
12
+ CONSTRAINT "chk_type_permission_grants_permission" CHECK ("entity_type_permission_grants"."permission" IN ('spawn', 'manage')),
13
+ CONSTRAINT "chk_type_permission_grants_subject_kind" CHECK ("entity_type_permission_grants"."subject_kind" IN ('principal', 'principal_kind'))
14
+ );
15
+ --> statement-breakpoint
16
+ CREATE TABLE "entity_lineage" (
17
+ "tenant_id" text DEFAULT 'default' NOT NULL,
18
+ "ancestor_url" text NOT NULL,
19
+ "descendant_url" text NOT NULL,
20
+ "depth" integer NOT NULL,
21
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
22
+ CONSTRAINT "entity_lineage_pkey" PRIMARY KEY ("tenant_id", "ancestor_url", "descendant_url"),
23
+ CONSTRAINT "chk_entity_lineage_depth" CHECK ("entity_lineage"."depth" >= 0)
24
+ );
25
+ --> statement-breakpoint
26
+ CREATE TABLE "entity_permission_grants" (
27
+ "id" bigserial PRIMARY KEY NOT NULL,
28
+ "tenant_id" text DEFAULT 'default' NOT NULL,
29
+ "entity_url" text NOT NULL,
30
+ "permission" text NOT NULL,
31
+ "subject_kind" text NOT NULL,
32
+ "subject_value" text NOT NULL,
33
+ "propagation" text DEFAULT 'self' NOT NULL,
34
+ "copy_to_children" boolean DEFAULT false NOT NULL,
35
+ "created_by" text,
36
+ "expires_at" timestamp with time zone,
37
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
38
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
39
+ CONSTRAINT "chk_entity_permission_grants_permission" CHECK ("entity_permission_grants"."permission" IN ('read', 'write', 'delete', 'signal', 'fork', 'schedule', 'spawn', 'manage')),
40
+ CONSTRAINT "chk_entity_permission_grants_subject_kind" CHECK ("entity_permission_grants"."subject_kind" IN ('principal', 'principal_kind')),
41
+ CONSTRAINT "chk_entity_permission_grants_propagation" CHECK ("entity_permission_grants"."propagation" IN ('self', 'descendants'))
42
+ );
43
+ --> statement-breakpoint
44
+ CREATE TABLE "entity_effective_permissions" (
45
+ "id" bigserial PRIMARY KEY NOT NULL,
46
+ "tenant_id" text DEFAULT 'default' NOT NULL,
47
+ "entity_url" text NOT NULL,
48
+ "source_entity_url" text NOT NULL,
49
+ "source_grant_id" bigint NOT NULL,
50
+ "permission" text NOT NULL,
51
+ "subject_kind" text NOT NULL,
52
+ "subject_value" text NOT NULL,
53
+ "expires_at" timestamp with time zone,
54
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
55
+ CONSTRAINT "uq_entity_effective_permission" UNIQUE ("tenant_id", "entity_url", "source_grant_id"),
56
+ CONSTRAINT "chk_entity_effective_permissions_permission" CHECK ("entity_effective_permissions"."permission" IN ('read', 'write', 'delete', 'signal', 'fork', 'schedule', 'spawn', 'manage')),
57
+ CONSTRAINT "chk_entity_effective_permissions_subject_kind" CHECK ("entity_effective_permissions"."subject_kind" IN ('principal', 'principal_kind'))
58
+ );
59
+ --> statement-breakpoint
60
+ CREATE TABLE "shared_state_links" (
61
+ "tenant_id" text DEFAULT 'default' NOT NULL,
62
+ "shared_state_id" text NOT NULL,
63
+ "owner_entity_url" text NOT NULL,
64
+ "manifest_key" text NOT NULL,
65
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
66
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
67
+ CONSTRAINT "shared_state_links_pkey" PRIMARY KEY ("tenant_id", "owner_entity_url", "manifest_key")
68
+ );
69
+ --> statement-breakpoint
70
+ CREATE INDEX "idx_type_permission_grants_lookup" ON "entity_type_permission_grants" USING btree ("tenant_id", "entity_type", "permission", "subject_kind", "subject_value");
71
+ --> statement-breakpoint
72
+ CREATE INDEX "idx_type_permission_grants_expiry" ON "entity_type_permission_grants" USING btree ("tenant_id", "expires_at");
73
+ --> statement-breakpoint
74
+ CREATE INDEX "idx_entity_lineage_descendant" ON "entity_lineage" USING btree ("tenant_id", "descendant_url");
75
+ --> statement-breakpoint
76
+ CREATE INDEX "idx_entity_permission_grants_entity" ON "entity_permission_grants" USING btree ("tenant_id", "entity_url");
77
+ --> statement-breakpoint
78
+ CREATE INDEX "idx_entity_permission_grants_subject" ON "entity_permission_grants" USING btree ("tenant_id", "permission", "subject_kind", "subject_value");
79
+ --> statement-breakpoint
80
+ CREATE INDEX "idx_entity_permission_grants_expiry" ON "entity_permission_grants" USING btree ("tenant_id", "expires_at");
81
+ --> statement-breakpoint
82
+ CREATE INDEX "idx_entity_effective_permissions_lookup" ON "entity_effective_permissions" USING btree ("tenant_id", "permission", "subject_kind", "subject_value", "entity_url");
83
+ --> statement-breakpoint
84
+ CREATE INDEX "idx_entity_effective_permissions_entity" ON "entity_effective_permissions" USING btree ("tenant_id", "entity_url");
85
+ --> statement-breakpoint
86
+ CREATE INDEX "idx_entity_effective_permissions_expiry" ON "entity_effective_permissions" USING btree ("tenant_id", "expires_at");
87
+ --> statement-breakpoint
88
+ CREATE INDEX "idx_shared_state_links_shared_state" ON "shared_state_links" USING btree ("tenant_id", "shared_state_id");
89
+ --> statement-breakpoint
90
+ CREATE INDEX "idx_shared_state_links_owner" ON "shared_state_links" USING btree ("tenant_id", "owner_entity_url");
91
+ --> statement-breakpoint
92
+ -- Pre-permission entity bridge rows do not carry principal attribution. Drop them
93
+ -- so observation bridges are rebuilt with principal_url/principal_kind scoping.
94
+ DELETE FROM "entity_bridges";
95
+ --> statement-breakpoint
96
+ ALTER TABLE "entity_bridges" ADD COLUMN "principal_url" text;
97
+ --> statement-breakpoint
98
+ ALTER TABLE "entity_bridges" ADD COLUMN "principal_kind" text;
99
+ --> statement-breakpoint
100
+ CREATE INDEX "idx_entity_bridges_principal" ON "entity_bridges" USING btree ("tenant_id", "principal_kind", "principal_url");
@@ -0,0 +1,25 @@
1
+ INSERT INTO "entity_type_permission_grants" (
2
+ "tenant_id",
3
+ "entity_type",
4
+ "permission",
5
+ "subject_kind",
6
+ "subject_value"
7
+ )
8
+ SELECT
9
+ "entity_types"."tenant_id",
10
+ "entity_types"."name",
11
+ 'manage',
12
+ 'principal_kind',
13
+ 'user'
14
+ FROM "entity_types"
15
+ WHERE "entity_types"."name" = 'horton'
16
+ AND NOT EXISTS (
17
+ SELECT 1
18
+ FROM "entity_type_permission_grants"
19
+ WHERE "entity_type_permission_grants"."tenant_id" = "entity_types"."tenant_id"
20
+ AND "entity_type_permission_grants"."entity_type" = "entity_types"."name"
21
+ AND "entity_type_permission_grants"."permission" = 'manage'
22
+ AND "entity_type_permission_grants"."subject_kind" = 'principal_kind'
23
+ AND "entity_type_permission_grants"."subject_value" = 'user'
24
+ AND "entity_type_permission_grants"."expires_at" IS NULL
25
+ );
@@ -0,0 +1,25 @@
1
+ INSERT INTO "entity_type_permission_grants" (
2
+ "tenant_id",
3
+ "entity_type",
4
+ "permission",
5
+ "subject_kind",
6
+ "subject_value"
7
+ )
8
+ SELECT
9
+ "entity_types"."tenant_id",
10
+ "entity_types"."name",
11
+ 'manage',
12
+ 'principal_kind',
13
+ 'user'
14
+ FROM "entity_types"
15
+ WHERE "entity_types"."name" = 'worker'
16
+ AND NOT EXISTS (
17
+ SELECT 1
18
+ FROM "entity_type_permission_grants"
19
+ WHERE "entity_type_permission_grants"."tenant_id" = "entity_types"."tenant_id"
20
+ AND "entity_type_permission_grants"."entity_type" = "entity_types"."name"
21
+ AND "entity_type_permission_grants"."permission" = 'manage'
22
+ AND "entity_type_permission_grants"."subject_kind" = 'principal_kind'
23
+ AND "entity_type_permission_grants"."subject_value" = 'user'
24
+ AND "entity_type_permission_grants"."expires_at" IS NULL
25
+ );
@@ -0,0 +1 @@
1
+ ALTER TABLE "entity_types" ADD COLUMN "slash_commands" jsonb;
@@ -78,6 +78,34 @@
78
78
  "when": 1779062400000,
79
79
  "tag": "0010_sandbox_profiles",
80
80
  "breakpoints": true
81
+ },
82
+ {
83
+ "idx": 11,
84
+ "version": "7",
85
+ "when": 1779050000000,
86
+ "tag": "0011_entity_permissions",
87
+ "breakpoints": true
88
+ },
89
+ {
90
+ "idx": 12,
91
+ "version": "7",
92
+ "when": 1780584581000,
93
+ "tag": "0012_horton_user_manage_permission",
94
+ "breakpoints": true
95
+ },
96
+ {
97
+ "idx": 13,
98
+ "version": "7",
99
+ "when": 1780588695000,
100
+ "tag": "0013_worker_user_manage_permission",
101
+ "breakpoints": true
102
+ },
103
+ {
104
+ "idx": 14,
105
+ "version": "7",
106
+ "when": 1780600000000,
107
+ "tag": "0014_entity_type_slash_commands",
108
+ "breakpoints": true
81
109
  }
82
110
  ]
83
111
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electric-ax/agents-server",
3
- "version": "0.4.15",
3
+ "version": "0.4.17",
4
4
  "description": "Electric Agents entity runtime server",
5
5
  "author": "Durable Stream contributors",
6
6
  "bin": {
@@ -37,8 +37,8 @@
37
37
  "dependencies": {
38
38
  "@anthropic-ai/sdk": "^0.78.0",
39
39
  "@durable-streams/client": "^0.2.6",
40
- "@durable-streams/server": "^0.3.5",
41
- "@durable-streams/state": "^0.2.9",
40
+ "@durable-streams/server": "^0.3.7",
41
+ "@durable-streams/state": "^0.3.1",
42
42
  "@electric-sql/client": "^1.5.20",
43
43
  "@mariozechner/pi-agent-core": "^0.70.2",
44
44
  "@opentelemetry/api": "^1.9.1",
@@ -54,7 +54,7 @@
54
54
  "pino-pretty": "^13.0.0",
55
55
  "postgres": "^3.4.0",
56
56
  "undici": "^7.24.7",
57
- "@electric-ax/agents-runtime": "0.3.8"
57
+ "@electric-ax/agents-runtime": "0.3.10"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@types/node": "^22.19.15",
@@ -65,9 +65,9 @@
65
65
  "tsx": "^4.19.0",
66
66
  "typescript": "^5.0.0",
67
67
  "vitest": "^4.1.0",
68
- "@electric-ax/agents": "0.4.12",
69
- "@electric-ax/agents-server-conformance-tests": "0.1.10",
70
- "@electric-ax/agents-server-ui": "0.4.15"
68
+ "@electric-ax/agents": "0.4.14",
69
+ "@electric-ax/agents-server-ui": "0.4.17",
70
+ "@electric-ax/agents-server-conformance-tests": "0.1.11"
71
71
  },
72
72
  "files": [
73
73
  "dist",
package/src/db/schema.ts CHANGED
@@ -24,6 +24,7 @@ export const entityTypes = pgTable(
24
24
  creationSchema: jsonb(`creation_schema`),
25
25
  inboxSchemas: jsonb(`inbox_schemas`),
26
26
  stateSchemas: jsonb(`state_schemas`),
27
+ slashCommands: jsonb(`slash_commands`),
27
28
  serveEndpoint: text(`serve_endpoint`),
28
29
  defaultDispatchPolicy: jsonb(`default_dispatch_policy`),
29
30
  revision: integer(`revision`).notNull().default(1),
@@ -72,6 +73,197 @@ export const entities = pgTable(
72
73
  ]
73
74
  )
74
75
 
76
+ export const entityTypePermissionGrants = pgTable(
77
+ `entity_type_permission_grants`,
78
+ {
79
+ id: bigserial(`id`, { mode: `number` }).primaryKey(),
80
+ tenantId: text(`tenant_id`).notNull().default(`default`),
81
+ entityType: text(`entity_type`).notNull(),
82
+ permission: text(`permission`).notNull(),
83
+ subjectKind: text(`subject_kind`).notNull(),
84
+ subjectValue: text(`subject_value`).notNull(),
85
+ createdBy: text(`created_by`),
86
+ expiresAt: timestamp(`expires_at`, { withTimezone: true }),
87
+ createdAt: timestamp(`created_at`, { withTimezone: true })
88
+ .notNull()
89
+ .defaultNow(),
90
+ updatedAt: timestamp(`updated_at`, { withTimezone: true })
91
+ .notNull()
92
+ .defaultNow(),
93
+ },
94
+ (table) => [
95
+ index(`idx_type_permission_grants_lookup`).on(
96
+ table.tenantId,
97
+ table.entityType,
98
+ table.permission,
99
+ table.subjectKind,
100
+ table.subjectValue
101
+ ),
102
+ index(`idx_type_permission_grants_expiry`).on(
103
+ table.tenantId,
104
+ table.expiresAt
105
+ ),
106
+ check(
107
+ `chk_type_permission_grants_permission`,
108
+ sql`${table.permission} IN ('spawn', 'manage')`
109
+ ),
110
+ check(
111
+ `chk_type_permission_grants_subject_kind`,
112
+ sql`${table.subjectKind} IN ('principal', 'principal_kind')`
113
+ ),
114
+ ]
115
+ )
116
+
117
+ export const entityLineage = pgTable(
118
+ `entity_lineage`,
119
+ {
120
+ tenantId: text(`tenant_id`).notNull().default(`default`),
121
+ ancestorUrl: text(`ancestor_url`).notNull(),
122
+ descendantUrl: text(`descendant_url`).notNull(),
123
+ depth: integer(`depth`).notNull(),
124
+ createdAt: timestamp(`created_at`, { withTimezone: true })
125
+ .notNull()
126
+ .defaultNow(),
127
+ },
128
+ (table) => [
129
+ primaryKey({
130
+ columns: [table.tenantId, table.ancestorUrl, table.descendantUrl],
131
+ }),
132
+ index(`idx_entity_lineage_descendant`).on(
133
+ table.tenantId,
134
+ table.descendantUrl
135
+ ),
136
+ check(`chk_entity_lineage_depth`, sql`${table.depth} >= 0`),
137
+ ]
138
+ )
139
+
140
+ export const entityPermissionGrants = pgTable(
141
+ `entity_permission_grants`,
142
+ {
143
+ id: bigserial(`id`, { mode: `number` }).primaryKey(),
144
+ tenantId: text(`tenant_id`).notNull().default(`default`),
145
+ entityUrl: text(`entity_url`).notNull(),
146
+ permission: text(`permission`).notNull(),
147
+ subjectKind: text(`subject_kind`).notNull(),
148
+ subjectValue: text(`subject_value`).notNull(),
149
+ propagation: text(`propagation`).notNull().default(`self`),
150
+ copyToChildren: boolean(`copy_to_children`).notNull().default(false),
151
+ createdBy: text(`created_by`),
152
+ expiresAt: timestamp(`expires_at`, { withTimezone: true }),
153
+ createdAt: timestamp(`created_at`, { withTimezone: true })
154
+ .notNull()
155
+ .defaultNow(),
156
+ updatedAt: timestamp(`updated_at`, { withTimezone: true })
157
+ .notNull()
158
+ .defaultNow(),
159
+ },
160
+ (table) => [
161
+ index(`idx_entity_permission_grants_entity`).on(
162
+ table.tenantId,
163
+ table.entityUrl
164
+ ),
165
+ index(`idx_entity_permission_grants_subject`).on(
166
+ table.tenantId,
167
+ table.permission,
168
+ table.subjectKind,
169
+ table.subjectValue
170
+ ),
171
+ index(`idx_entity_permission_grants_expiry`).on(
172
+ table.tenantId,
173
+ table.expiresAt
174
+ ),
175
+ check(
176
+ `chk_entity_permission_grants_permission`,
177
+ sql`${table.permission} IN ('read', 'write', 'delete', 'signal', 'fork', 'schedule', 'spawn', 'manage')`
178
+ ),
179
+ check(
180
+ `chk_entity_permission_grants_subject_kind`,
181
+ sql`${table.subjectKind} IN ('principal', 'principal_kind')`
182
+ ),
183
+ check(
184
+ `chk_entity_permission_grants_propagation`,
185
+ sql`${table.propagation} IN ('self', 'descendants')`
186
+ ),
187
+ ]
188
+ )
189
+
190
+ export const entityEffectivePermissions = pgTable(
191
+ `entity_effective_permissions`,
192
+ {
193
+ id: bigserial(`id`, { mode: `number` }).primaryKey(),
194
+ tenantId: text(`tenant_id`).notNull().default(`default`),
195
+ entityUrl: text(`entity_url`).notNull(),
196
+ sourceEntityUrl: text(`source_entity_url`).notNull(),
197
+ sourceGrantId: bigint(`source_grant_id`, { mode: `number` }).notNull(),
198
+ permission: text(`permission`).notNull(),
199
+ subjectKind: text(`subject_kind`).notNull(),
200
+ subjectValue: text(`subject_value`).notNull(),
201
+ expiresAt: timestamp(`expires_at`, { withTimezone: true }),
202
+ createdAt: timestamp(`created_at`, { withTimezone: true })
203
+ .notNull()
204
+ .defaultNow(),
205
+ },
206
+ (table) => [
207
+ unique(`uq_entity_effective_permission`).on(
208
+ table.tenantId,
209
+ table.entityUrl,
210
+ table.sourceGrantId
211
+ ),
212
+ index(`idx_entity_effective_permissions_lookup`).on(
213
+ table.tenantId,
214
+ table.permission,
215
+ table.subjectKind,
216
+ table.subjectValue,
217
+ table.entityUrl
218
+ ),
219
+ index(`idx_entity_effective_permissions_entity`).on(
220
+ table.tenantId,
221
+ table.entityUrl
222
+ ),
223
+ index(`idx_entity_effective_permissions_expiry`).on(
224
+ table.tenantId,
225
+ table.expiresAt
226
+ ),
227
+ check(
228
+ `chk_entity_effective_permissions_permission`,
229
+ sql`${table.permission} IN ('read', 'write', 'delete', 'signal', 'fork', 'schedule', 'spawn', 'manage')`
230
+ ),
231
+ check(
232
+ `chk_entity_effective_permissions_subject_kind`,
233
+ sql`${table.subjectKind} IN ('principal', 'principal_kind')`
234
+ ),
235
+ ]
236
+ )
237
+
238
+ export const sharedStateLinks = pgTable(
239
+ `shared_state_links`,
240
+ {
241
+ tenantId: text(`tenant_id`).notNull().default(`default`),
242
+ sharedStateId: text(`shared_state_id`).notNull(),
243
+ ownerEntityUrl: text(`owner_entity_url`).notNull(),
244
+ manifestKey: text(`manifest_key`).notNull(),
245
+ createdAt: timestamp(`created_at`, { withTimezone: true })
246
+ .notNull()
247
+ .defaultNow(),
248
+ updatedAt: timestamp(`updated_at`, { withTimezone: true })
249
+ .notNull()
250
+ .defaultNow(),
251
+ },
252
+ (table) => [
253
+ primaryKey({
254
+ columns: [table.tenantId, table.ownerEntityUrl, table.manifestKey],
255
+ }),
256
+ index(`idx_shared_state_links_shared_state`).on(
257
+ table.tenantId,
258
+ table.sharedStateId
259
+ ),
260
+ index(`idx_shared_state_links_owner`).on(
261
+ table.tenantId,
262
+ table.ownerEntityUrl
263
+ ),
264
+ ]
265
+ )
266
+
75
267
  export const users = pgTable(
76
268
  `users`,
77
269
  {
@@ -436,6 +628,8 @@ export const entityBridges = pgTable(
436
628
  sourceRef: text(`source_ref`).notNull(),
437
629
  tags: jsonb(`tags`).notNull(),
438
630
  streamUrl: text(`stream_url`).notNull(),
631
+ principalUrl: text(`principal_url`),
632
+ principalKind: text(`principal_kind`),
439
633
  shapeHandle: text(`shape_handle`),
440
634
  shapeOffset: text(`shape_offset`),
441
635
  lastObserverActivityAt: timestamp(`last_observer_activity_at`, {
@@ -453,6 +647,11 @@ export const entityBridges = pgTable(
453
647
  (table) => [
454
648
  primaryKey({ columns: [table.tenantId, table.sourceRef] }),
455
649
  unique(`uq_entity_bridges_stream_url`).on(table.tenantId, table.streamUrl),
650
+ index(`idx_entity_bridges_principal`).on(
651
+ table.tenantId,
652
+ table.principalKind,
653
+ table.principalUrl
654
+ ),
456
655
  ]
457
656
  )
458
657
 
@@ -4,6 +4,7 @@
4
4
 
5
5
  import type {
6
6
  PullWakeRunnerHealth,
7
+ SlashCommandDefinition,
7
8
  WebhookNotification,
8
9
  } from '@electric-ax/agents-runtime'
9
10
  import type { Principal } from './principal.js'
@@ -67,6 +68,78 @@ export type RunnerKind = `local` | `cloud-worker` | `sandbox` | `ci` | `server`
67
68
  export type RunnerAdminStatus = `enabled` | `disabled`
68
69
  export type RunnerLiveness = `online` | `offline`
69
70
 
71
+ export type PermissionSubjectKind = `principal` | `principal_kind`
72
+ export type PermissionSubject = {
73
+ subject_kind: PermissionSubjectKind
74
+ subject_value: string
75
+ }
76
+ export type EntityPermission =
77
+ | `read`
78
+ | `write`
79
+ | `delete`
80
+ | `signal`
81
+ | `fork`
82
+ | `schedule`
83
+ | `spawn`
84
+ | `manage`
85
+ export type EntityTypePermission = `spawn` | `manage`
86
+ export type EntityPermissionPropagation = `self` | `descendants`
87
+
88
+ export interface EntityPermissionGrant extends PermissionSubject {
89
+ id: number
90
+ entity_url: string
91
+ permission: EntityPermission
92
+ propagation: EntityPermissionPropagation
93
+ copy_to_children: boolean
94
+ created_by?: string
95
+ expires_at?: string
96
+ created_at: string
97
+ updated_at: string
98
+ }
99
+
100
+ export interface EntityTypePermissionGrant extends PermissionSubject {
101
+ id: number
102
+ entity_type: string
103
+ permission: EntityTypePermission
104
+ created_by?: string
105
+ expires_at?: string
106
+ created_at: string
107
+ updated_at: string
108
+ }
109
+
110
+ export interface EntityTypePermissionGrantInput extends PermissionSubject {
111
+ permission: EntityTypePermission
112
+ expires_at?: string
113
+ }
114
+
115
+ export type AuthorizationResource =
116
+ | { kind: `entity`; entity: ElectricAgentsEntity }
117
+ | { kind: `entity_type`; entityType: ElectricAgentsEntityType }
118
+ | { kind: `entity_type_registration`; entityTypeName: string }
119
+ | {
120
+ kind: `shared_state`
121
+ sharedStateId: string
122
+ linkedEntityUrls: Array<string>
123
+ }
124
+
125
+ export type AuthorizationDecision = {
126
+ decision: `allow` | `deny`
127
+ expires_at?: string
128
+ }
129
+
130
+ export type AuthorizeRequest = (input: {
131
+ tenant: string
132
+ principal: Principal
133
+ verb: EntityPermission | EntityTypePermission
134
+ resource: AuthorizationResource
135
+ request?: {
136
+ method: string
137
+ url: string
138
+ headers: Record<string, string>
139
+ }
140
+ builtInAllowed: boolean
141
+ }) => Promise<AuthorizationDecision> | AuthorizationDecision
142
+
70
143
  const VALID_RUNNER_KINDS = new Set<string>([
71
144
  `local`,
72
145
  `cloud-worker`,
@@ -356,7 +429,6 @@ export interface ElectricAgentsEntity {
356
429
  status: EntityStatus
357
430
  streams: {
358
431
  main: string
359
- error: string
360
432
  }
361
433
  subscription_id: string
362
434
  dispatch_policy?: DispatchPolicy
@@ -385,7 +457,7 @@ export interface PublicElectricAgentsEntity {
385
457
  url: string
386
458
  type: string
387
459
  status: EntityStatus
388
- streams: { main: string; error: string }
460
+ streams: { main: string }
389
461
  dispatch_policy?: DispatchPolicy
390
462
  tags: Record<string, string>
391
463
  spawn_args?: Record<string, unknown>
@@ -428,6 +500,7 @@ export interface ElectricAgentsEntityType {
428
500
  creation_schema?: Record<string, unknown>
429
501
  inbox_schemas?: Record<string, Record<string, unknown>>
430
502
  state_schemas?: Record<string, Record<string, unknown>>
503
+ slash_commands?: Array<SlashCommandDefinition>
431
504
  serve_endpoint?: string
432
505
  default_dispatch_policy?: DispatchPolicy
433
506
  revision: number
@@ -441,8 +514,10 @@ export interface RegisterEntityTypeRequest {
441
514
  creation_schema?: Record<string, unknown>
442
515
  inbox_schemas?: Record<string, Record<string, unknown>>
443
516
  state_schemas?: Record<string, Record<string, unknown>>
517
+ slash_commands?: Array<SlashCommandDefinition>
444
518
  serve_endpoint?: string
445
519
  default_dispatch_policy?: DispatchPolicy
520
+ permission_grants?: Array<EntityTypePermissionGrantInput>
446
521
  }
447
522
 
448
523
  export interface TypedSpawnRequest {
@@ -458,6 +533,7 @@ export interface TypedSpawnRequest {
458
533
  */
459
534
  sandbox?: SandboxChoice
460
535
  initialMessage?: unknown
536
+ initialMessageType?: string
461
537
  created_by?: string
462
538
  wake?: {
463
539
  subscriberUrl: string
@@ -477,6 +553,8 @@ export interface TypedSpawnRequest {
477
553
 
478
554
  export interface SendRequest {
479
555
  from?: string
556
+ from_principal?: string
557
+ from_agent?: string
480
558
  payload?: unknown
481
559
  key?: string
482
560
  type?: string