broods 0.54.1 → 0.55.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/account.d.ts CHANGED
@@ -2,109 +2,54 @@ import { SystemModelMessage, LanguageModelCallOptions, RequestOptions, streamTex
2
2
  import * as convex_values from 'convex/values';
3
3
  import { Infer } from 'convex/values';
4
4
 
5
- /**
6
- * Account-owned code hook upload validation for Convex config-plane sync.
7
- * Mirrors core's account hook upload contract without requiring the Node runtime.
8
- */
9
5
  declare const AGENT_HOOK_EVENT_NAMES: readonly ["agent.started", "agent.step.finished", "agent.finished", "agent.failed", "agent.approval.required", "tool.call.started", "tool.call.finished", "tool.result", "subagent.task.started", "subagent.task.finished", "channel.message.received", "channel.message.sending"];
10
6
  type AgentHookEventName = (typeof AGENT_HOOK_EVENT_NAMES)[number];
11
7
 
12
- /**
13
- * Every Vercel AI SDK provider that ships language models, the community
14
- * providers on the same spec that take an API key (`cloudflare`, `llmgateway`,
15
- * `ollama`, `openrouter`), `custom` (any OpenAI-compatible endpoint), and
16
- * `chatgpt` (OpenAI on a Sign in with ChatGPT login instead of an API key).
17
- * Image-, speech- and transcription-only providers are deliberately absent:
18
- * they cannot back `config.model`.
19
- */
20
8
  declare const ACCOUNT_MODEL_PROVIDER_NAMES: readonly ["alibaba", "anthropic", "azure", "baseten", "bedrock", "cerebras", "chatgpt", "cloudflare", "cohere", "custom", "deepinfra", "deepseek", "fireworks", "google", "groq", "huggingface", "llmgateway", "minimax", "mistral", "moonshotai", "ollama", "openai", "openrouter", "perplexity", "togetherai", "v0", "vercel", "vertex", "xai", "zai"];
21
9
  type AccountModelProviderName = (typeof ACCOUNT_MODEL_PROVIDER_NAMES)[number];
22
10
 
23
- /**
24
- * Agent config validation, the only copy of it: Convex config HTTP checks a
25
- * config on write and core re-checks the stored config on every run. Pure
26
- * module: safe for the default Convex runtime. The public projection lives in
27
- * ./responses.ts.
28
- */
29
-
30
11
  declare const AGENT_HARNESS_TYPES: readonly ["claude-code", "codex", "deepagents", "opencode", "pi"];
31
12
  declare const AGENT_HARNESS_DEBUG_LEVELS: readonly ["error", "warn", "info", "debug", "trace"];
32
13
  declare const AGENT_HARNESS_PERMISSION_MODES: readonly ["allow-reads", "allow-edits", "allow-all"];
33
14
  declare const AGENT_LIFECYCLE_EVENT_NAMES: readonly ["agent.started", "agent.step.finished", "agent.finished", "agent.failed", "agent.approval.required", "tool.call.started", "tool.call.finished", "tool.result", "subagent.task.started", "subagent.task.finished"];
34
15
 
35
- /**
36
- * Shared validation for MCP server registrations (#331). One normalizer
37
- * serves every write path (CLI sync, direct API, dashboard). A `url` makes an "http" row
38
- * core connects to over the stateless 2026-07-28 transport; a `bundle` makes
39
- * a "hosted" row, hashed here so sha256 always travels with the bundle; the
40
- * S3 bundle writer (aws/bundles.ts) marks whether Cloudflare Dynamic Workers
41
- * can run it. Auth header values may carry ${NAME}
42
- * account env refs; they resolve into the encrypted agent config at sync
43
- * time, never on this row, and credential-bearing headers must use one
44
- * instead of an inline secret. `oauth` follows the same rule: clientSecret
45
- * and refreshToken must be ${NAME} refs, so the row never holds a secret.
46
- */
47
-
48
- /**
49
- * OAuth 2.0 refresh-token grant for an external row. Core mints access tokens
50
- * at connect time and sends `Authorization: Bearer <token>`, so a server
51
- * whose tokens expire (Google's Workspace MCP endpoints) still works where a
52
- * static header cannot. Secret fields hold ${NAME} refs on the row.
53
- */
54
16
  interface McpOauth {
55
17
  clientId: string;
56
18
  clientSecret: string;
57
19
  refreshToken: string;
58
- /** Token endpoint, https only; core defaults to https://oauth2.googleapis.com/token. */
59
20
  tokenUrl?: string;
60
21
  }
61
22
 
62
- /**
63
- * Agent configuration: types for the per-agent settings object and the
64
- * runtime projection of a stored config. The validation rules are the config
65
- * plane's (`@broods/convex/model/agentRules`), so a config is judged the same
66
- * on write and on every run. Decrypting the stored blob is
67
- * `../convex/account-keys.ts`.
68
- * Account types and auth live in `./accounts.ts` and `../auth.ts`.
69
- */
70
-
71
23
  interface AgentConfig {
72
24
  agent?: AgentBehaviorConfig;
73
25
  harness?: AgentHarnessConfig;
74
26
  model?: AgentModelConfig;
75
27
  provider?: AgentProviderConfig;
28
+ /** Sandbox record ids. The first is the default for bash, workspaces and a harness. */
76
29
  sandboxes?: string[];
77
30
  workspaces?: AgentWorkspaceRef[];
78
31
  session?: AgentSessionConfig;
79
32
  hooks?: AgentHooksConfig;
80
33
  channels?: AgentChannelsConfig;
81
34
  tools?: AgentToolsConfig;
82
- /** Connected MCP servers, keyed by their config-plane row id (#331). */
83
35
  mcp?: AgentMcpConfig;
84
- /**
85
- * Tool names withheld for this run, applied after the tool set is built.
86
- * Set by a channel record; a channel can take a tool away, never add one.
87
- * Names that are not present are ignored.
88
- */
36
+ /** Withheld after the tool set is built; a channel can take a tool away, never add one. */
89
37
  denyTools?: string[];
90
38
  skills?: AgentSkillsConfig;
91
39
  subagent?: AgentSubagentConfig;
92
40
  scheduler?: AgentSchedulerConfig;
93
- /**
94
- * Registers the `browse` tool, which runs Obscura on the first sandbox. That
95
- * sandbox must be lambda with image "obscura" and network allow-all, or a
96
- * machine; manifest sync refuses anything else it can see.
97
- */
41
+ /** `browse` runs on the first sandbox: a machine, or lambda "obscura" with allow-all. */
98
42
  browser?: {
99
43
  enabled?: boolean;
100
44
  };
101
- /** Policies that gate this agent. Each one carries its own enforcement mode. */
102
45
  policies?: string[];
46
+ /** Opens the runtime-key path; account keys, cron and channel webhooks never need it. */
103
47
  publicAccess?: boolean;
104
48
  allowRunOverrides?: boolean;
105
49
  [key: string]: unknown;
106
50
  }
107
51
  interface AgentBehaviorConfig {
52
+ /** Steps per turn. 0 lifts the cap; unset is the harness default. */
108
53
  maxTurn?: number;
109
54
  system?: string | SystemModelMessage | SystemModelMessage[];
110
55
  [key: string]: unknown;
@@ -130,10 +75,6 @@ interface AgentSkillsConfig {
130
75
  allowed?: string[];
131
76
  [key: string]: unknown;
132
77
  }
133
- /**
134
- * Opt-in for the `schedule` tool. Off by default: a scheduled task starts
135
- * billable agent runs long after the turn that asked for it.
136
- */
137
78
  interface AgentSchedulerConfig {
138
79
  enabled?: boolean;
139
80
  [key: string]: unknown;
@@ -143,33 +84,16 @@ interface AgentSubagentConfig {
143
84
  allowed?: string[];
144
85
  context?: "new" | "inherited";
145
86
  mode?: "ephemeral" | "persistent";
146
- /**
147
- * Publishes child reasoning, text, and tool stream parts to the existing
148
- * WebSocket/JetStream response path. Off by default.
149
- */
150
87
  stream?: boolean;
151
- /**
152
- * Controls what the parent agent sees from a finished subagent (AI SDK
153
- * "controlling what the model sees"): `full` = the child's whole transcript,
154
- * `result` = only its final result (default), `none` = nothing. A
155
- * `subagent.task.finished` code hook overrides this for custom shaping.
156
- */
88
+ /** What the parent sees of a finished child; default `result`. A code hook can override it. */
157
89
  visibility?: "full" | "result" | "none";
158
- /**
159
- * Model for virtual subagents (no `agentId`), laid over the parent's
160
- * `model` key by key. The child keeps the parent's tools, MCP, sandboxes,
161
- * hooks and policies. A registered agent always runs on its own model.
162
- */
90
+ /** Virtual subagents only, merged over the parent's `model`; registered agents use their own. */
163
91
  model?: Partial<AgentModelConfig>;
164
92
  [key: string]: unknown;
165
93
  }
166
94
  interface AgentModelConfig extends LanguageModelCallOptions, Partial<Pick<RequestOptions, "maxRetries" | "timeout">> {
167
95
  provider?: AccountModelProviderName;
168
96
  modelId?: string;
169
- /**
170
- * Speech-to-text model for inbound audio, on the same provider and key as
171
- * `modelId`. Defaults to the widest-container model the provider ships.
172
- */
173
97
  transcriptionModelId?: string;
174
98
  providerOptions?: AgentModelProviderOptions;
175
99
  output?: AgentModelOutputConfig;
@@ -196,14 +120,10 @@ type AgentModelOutputMetadata = {
196
120
  type AgentProviderConfig = Partial<Record<AccountModelProviderName, AgentProviderSettings>>;
197
121
  interface AgentProviderSettings {
198
122
  apiKey?: string;
199
- /** OpenAI-compatible endpoint (`custom`). Snake form, as documented. */
200
123
  base_url?: string;
201
- /** OpenAI-compatible endpoint (`custom`). AI-SDK form; the dashboard writes both. */
202
124
  baseURL?: string;
203
- /** Cloudflare AI Gateway id (`cloudflare`). Set, requests go through the gateway. */
204
125
  gatewayId?: string;
205
126
  headers?: Record<string, string>;
206
- /** Endpoint label; becomes the provider id and the pi harness env prefix. */
207
127
  name?: string;
208
128
  organization?: string;
209
129
  project?: string;
@@ -212,6 +132,7 @@ interface AgentProviderSettings {
212
132
  interface AgentWorkspaceRef {
213
133
  name: string;
214
134
  workspaceId: string;
135
+ /** Unset inherits the default; `null` is read-only, read from S3 without a mount. */
215
136
  sandbox?: string | null;
216
137
  }
217
138
  interface AgentSessionConfig {
@@ -223,35 +144,19 @@ interface AgentSessionPruningConfig {
223
144
  enabled?: boolean;
224
145
  [key: string]: unknown;
225
146
  }
226
- /**
227
- * Compaction after a finished turn, on unless `enabled: false`. It runs once
228
- * the turn's last model call read `maxContextLength` input tokens or more
229
- * (default 500000), or after the provider refused a turn for context length.
230
- * `/compact` works whatever this says.
231
- */
147
+ /** On by default: runs once a turn's last call read `maxContextLength` (500000) tokens. */
232
148
  interface AgentSessionAutoCompactionConfig {
233
149
  enabled?: boolean;
234
150
  maxContextLength?: number;
235
151
  [key: string]: unknown;
236
152
  }
237
153
  interface AgentHooksConfig {
238
- /** Outbound event webhooks. An agent may register several independent endpoints. */
239
154
  webhooks?: AgentWebhookHookConfig[];
240
- /**
241
- * Uploaded code hooks. Each entry references an accountHooks bundle by id; the
242
- * bundle runs in the V8 isolate at the matching fire-points and its validated
243
- * return is folded into mutable harness state.
244
- */
245
155
  code?: AgentCodeHookConfig[];
246
156
  [key: string]: unknown;
247
157
  }
248
158
  interface AgentCodeHookConfig {
249
159
  hookId: string;
250
- /**
251
- * Optional narrowing of the events this reference reacts to. Omitted => the
252
- * bundle's own declared `events` set. Any listed event outside the bundle's
253
- * declared set is ignored at runtime.
254
- */
255
160
  events?: AgentHookEventName[];
256
161
  enabled?: boolean;
257
162
  [key: string]: unknown;
@@ -269,22 +174,14 @@ type AgentToolsConfig = Record<string, AgentToolConfig>;
269
174
  interface AgentToolConfig {
270
175
  enabled?: boolean;
271
176
  needsApproval?: boolean;
272
- async?: boolean;
273
177
  config?: Record<string, unknown>;
274
178
  [key: string]: unknown;
275
179
  }
276
180
  type AgentMcpConfig = Record<string, AgentMcpEntry>;
277
181
  interface AgentMcpEntry {
278
182
  enabled?: boolean;
279
- /** Applies to every tool the server exposes. */
280
183
  needsApproval?: boolean;
281
- /** Extra request headers; values resolved from account env vars at sync. */
282
184
  headers?: Record<string, string>;
283
- /**
284
- * Overrides for the row's oauth credentials; values resolved from account
285
- * env vars at sync, so the row's ${NAME} refs never reach the token
286
- * endpoint. tokenUrl stays on the row, where registration checked it.
287
- */
288
185
  oauth?: Partial<Omit<McpOauth, "tokenUrl">>;
289
186
  [key: string]: unknown;
290
187
  }
@@ -299,17 +196,11 @@ interface AgentChannelsConfig {
299
196
  teams?: AgentTeamsChannelConfig;
300
197
  twilio?: AgentTwilioChannelConfig;
301
198
  zalo?: AgentZaloChannelConfig;
302
- matrix?: AgentMatrixChannelConfig;
303
199
  instagram?: AgentInstagramChannelConfig;
304
200
  messenger?: AgentMessengerChannelConfig;
305
201
  whatsapp?: AgentWhatsAppChannelConfig;
306
202
  [key: string]: unknown;
307
203
  }
308
- /**
309
- * How an attached partitioned workspace splits its folders for runs arriving
310
- * through this door. `shared` mounts the workspace root; `conversation` mounts
311
- * a private child folder per thread, issue or chat under `alias`.
312
- */
313
204
  type ChannelPartition = {
314
205
  by: "shared";
315
206
  alias?: never;
@@ -324,7 +215,6 @@ interface AgentTelegramChannelConfig {
324
215
  webhookSecret?: string;
325
216
  allowedChannelIds?: string[];
326
217
  allowedUserIds?: string[];
327
- /** Bot's @username, e.g. `support_bot`. Set it to answer only when the agent is mentioned. */
328
218
  botUsername?: string;
329
219
  reactionEmoji?: string;
330
220
  trace?: "enabled" | "disabled";
@@ -339,31 +229,20 @@ interface AgentGitHubChannelConfig {
339
229
  privateKey?: string;
340
230
  allowedChannelIds?: string[];
341
231
  allowedUserIds?: string[];
342
- /** Bot username for @-mention detection (e.g. "my-bot" or "my-bot[bot]"). */
343
232
  botUserName?: string;
344
- /** Bot's numeric GitHub user ID for self-message detection. */
345
233
  botUserId?: number;
346
- /** When false, the bot does not auto-trigger on new issues (opened/edited/reopened). Defaults to true. The bot still triggers when assigned to an issue. */
347
234
  triggerOnIssueOpen?: boolean;
348
- /** When false, the bot does not auto-trigger on new PRs (opened/edited/reopened). Defaults to true. The bot still triggers when assigned to a PR. */
349
235
  triggerOnPROpen?: boolean;
350
236
  trace?: "enabled" | "disabled";
351
237
  partition?: ChannelPartition;
352
238
  [key: string]: unknown;
353
239
  }
354
- /**
355
- * A Linear member the agent comments as, through that member's personal API
356
- * key. The agent answers comments that mention `@userName` on issues, and
357
- * `webhookSecret` checks every delivery.
358
- */
359
240
  interface AgentLinearChannelConfig {
360
241
  allowedChannelIds?: string[];
361
242
  allowedUserIds?: string[];
362
243
  id?: string;
363
244
  apiKey?: string;
364
- /** Linear GraphQL endpoint. Defaults to `https://api.linear.app/graphql`. */
365
245
  apiUrl?: string;
366
- /** The member's display name, e.g. `acme-agent`. `@acme-agent` addresses the agent. */
367
246
  userName?: string;
368
247
  webhookSecret?: string;
369
248
  trace?: "enabled" | "disabled";
@@ -389,41 +268,12 @@ interface AgentDiscordChannelConfig {
389
268
  publicKey?: string;
390
269
  allowedChannelIds?: string[];
391
270
  allowedUserIds?: string[];
392
- /** Bot's Discord user id. Set it to answer only when the agent is mentioned. */
393
271
  botUserId?: string;
394
- /** Role ids that count as mentioning the agent, e.g. an on-call role. */
395
272
  mentionRoleIds?: string[];
396
273
  trace?: "enabled" | "disabled";
397
274
  partition?: ChannelPartition;
398
275
  [key: string]: unknown;
399
276
  }
400
- /**
401
- * A Matrix account the agent speaks as. Matrix has no bot concept, so this is
402
- * usually a person's own account: replies carry a per-message profile named
403
- * `botName`, and `mentionText` decides what addresses the agent, because a
404
- * mention of the account would also be a mention of its owner.
405
- */
406
- interface AgentMatrixChannelConfig {
407
- id?: string;
408
- /** Homeserver base URL, e.g. `https://matrix.org`. */
409
- apiUrl?: string;
410
- /** Access token of the account; `apps/matrix-forwarder` syncs with it. */
411
- botToken?: string;
412
- /** Room ids. */
413
- allowedChannelIds?: string[];
414
- /** Matrix user ids, e.g. `@alice:matrix.org`. */
415
- allowedUserIds?: string[];
416
- /** Name replies are shown under. Unset, replies look like the account's own messages. */
417
- botName?: string;
418
- /**
419
- * Text that addresses the agent, e.g. `@georgi-ai`. Unset, a mention of the
420
- * account does. Other messages are stored as context either way.
421
- */
422
- mentionText?: string;
423
- trace?: "enabled" | "disabled";
424
- partition?: ChannelPartition;
425
- [key: string]: unknown;
426
- }
427
277
  interface AgentPancakeChannelConfig {
428
278
  allowedChannelIds?: string[];
429
279
  allowedUserIds?: string[];
@@ -446,73 +296,46 @@ interface AgentZaloChannelConfig {
446
296
  partition?: ChannelPartition;
447
297
  [key: string]: unknown;
448
298
  }
449
- /**
450
- * An Instagram professional account, reached through a Meta app with
451
- * Instagram Login. `accountId` is the account the webhook entries name.
452
- */
453
299
  interface AgentInstagramChannelConfig {
454
300
  allowedChannelIds?: string[];
455
301
  allowedUserIds?: string[];
456
302
  id?: string;
457
- /** Instagram user access token with `instagram_business_manage_messages`. */
458
303
  accessToken?: string;
459
- /** Instagram professional account id. */
460
304
  accountId?: string;
461
- /** Graph API version, e.g. `v26.0`. Defaults to the SDK's. */
462
305
  apiVersion?: string;
463
- /** Meta app secret; signs every webhook POST. */
464
306
  appSecret?: string;
465
307
  userName?: string;
466
- /** The verify token typed into the Meta webhook settings. */
467
308
  verifyToken?: string;
468
309
  trace?: "enabled" | "disabled";
469
310
  partition?: ChannelPartition;
470
311
  [key: string]: unknown;
471
312
  }
472
- /** A Facebook Page the agent answers Messenger DMs for. */
473
313
  interface AgentMessengerChannelConfig {
474
314
  allowedChannelIds?: string[];
475
315
  allowedUserIds?: string[];
476
316
  id?: string;
477
- /** Graph API version, e.g. `v21.0`. Defaults to the SDK's. */
478
317
  apiVersion?: string;
479
- /** Meta app secret; signs every webhook POST. */
480
318
  appSecret?: string;
481
- /** Page access token for the Page the app is subscribed to. */
482
319
  pageAccessToken?: string;
483
320
  userName?: string;
484
- /** The verify token typed into the Meta webhook settings. */
485
321
  verifyToken?: string;
486
322
  trace?: "enabled" | "disabled";
487
323
  partition?: ChannelPartition;
488
324
  [key: string]: unknown;
489
325
  }
490
- /**
491
- * A Google Chat app on the HTTP endpoint connection. It posts as the service
492
- * account in `credentials`, and a webhook is accepted when its Google-signed
493
- * token names `endpointUrl` or `googleChatProjectNumber` as the audience.
494
- */
495
326
  interface AgentGoogleChatChannelConfig {
496
327
  allowedChannelIds?: string[];
497
328
  allowedUserIds?: string[];
498
329
  id?: string;
499
- /** The service-account key JSON, as downloaded from Google Cloud. */
500
330
  credentials?: string;
501
- /** Audience when the app authenticates with "HTTP endpoint URL". */
502
331
  endpointUrl?: string;
503
- /** Audience when the app authenticates with "Project number". */
504
332
  googleChatProjectNumber?: string;
505
- /** `service-{projectNumber}@gcp-sa-gsuiteaddons.iam.gserviceaccount.com`, for an app built as a Workspace add-on. */
506
333
  workspaceAddOnServiceAccountEmail?: string;
507
334
  userName?: string;
508
335
  trace?: "enabled" | "disabled";
509
336
  partition?: ChannelPartition;
510
337
  [key: string]: unknown;
511
338
  }
512
- /**
513
- * A Microsoft Teams bot registered in Azure Bot Service, authenticated with a
514
- * client secret. `appTenantId` is required unless `appType` is `MultiTenant`.
515
- */
516
339
  interface AgentTeamsChannelConfig {
517
340
  allowedChannelIds?: string[];
518
341
  allowedUserIds?: string[];
@@ -527,11 +350,6 @@ interface AgentTeamsChannelConfig {
527
350
  partition?: ChannelPartition;
528
351
  [key: string]: unknown;
529
352
  }
530
- /**
531
- * A Twilio number or Messaging Service for SMS and MMS. `authToken` checks
532
- * Twilio's signature, which covers the exact public URL Twilio called, so
533
- * `webhookUrl` is only set when that URL is not the broods webhook URL.
534
- */
535
353
  interface AgentTwilioChannelConfig {
536
354
  allowedChannelIds?: string[];
537
355
  allowedUserIds?: string[];
@@ -539,22 +357,16 @@ interface AgentTwilioChannelConfig {
539
357
  accountSid?: string;
540
358
  apiUrl?: string;
541
359
  authToken?: string;
542
- /** `MG...`. Replies go through the service instead of the number texted. */
543
360
  messagingServiceSid?: string;
544
- /** E.164 number, e.g. `+15551234567`. Messages to another number go to the agent holding it. */
545
361
  phoneNumber?: string;
546
362
  statusCallbackUrl?: string;
547
363
  userName?: string;
548
- /** The URL entered in the Twilio console, when it is not `{PUBLIC_BASE_URL}/v1/webhooks/...`. */
364
+ /** The URL Twilio calls, when not the broods webhook: its signature covers the exact URL. */
549
365
  webhookUrl?: string;
550
366
  trace?: "enabled" | "disabled";
551
367
  partition?: ChannelPartition;
552
368
  [key: string]: unknown;
553
369
  }
554
- /**
555
- * A WhatsApp Business Cloud API number. `appSecret` signs every delivery and
556
- * `verifyToken` answers Meta's subscription handshake.
557
- */
558
370
  interface AgentWhatsAppChannelConfig {
559
371
  allowedChannelIds?: string[];
560
372
  allowedUserIds?: string[];
@@ -571,18 +383,8 @@ interface AgentWhatsAppChannelConfig {
571
383
  [key: string]: unknown;
572
384
  }
573
385
 
574
- /**
575
- * Cron-job records and patch-merge helpers for the runtime. Input
576
- * normalization lives in the config plane (packages/convex/model/cronRules.ts,
577
- * the single home of those rules).
578
- */
579
-
580
386
  type CronStatus = "active" | "paused";
581
387
  type CronLastStatus = "started" | "completed" | "failed";
582
- /**
583
- * One-of run payload mirroring the agent direct API's AgentRunInput: provide a
584
- * single `input` string (wrapped into one user message) or a full `events` list.
585
- */
586
388
  type CronRunInput = {
587
389
  input: string;
588
390
  events?: never;
@@ -615,20 +417,9 @@ type UpdateCronInput = {
615
417
  input?: never;
616
418
  });
617
419
 
618
- /**
619
- * The sandbox provider list: the one list the schema validator, the config
620
- * rules, core's executor registry and the SDK derive from. A leaf on purpose,
621
- * so `schema.ts` can read it without pulling the rules' import graph.
622
- */
623
420
  declare const SANDBOX_PROVIDERS: readonly ["sandbox", "lambda", "e2b", "daytona", "vercel", "cloudflare", "worker", "machine", "custom"];
624
421
  type SandboxProvider = (typeof SANDBOX_PROVIDERS)[number];
625
422
 
626
- /**
627
- * Sandbox-config validation for the Convex config plane. Ports core's former
628
- * storage/sandbox-config.ts normalizer so the public /v1/sandboxes contract
629
- * is unchanged. The public projection lives in ./responses.ts.
630
- */
631
-
632
423
  declare const SANDBOX_IMAGES: readonly ["browser", "obscura"];
633
424
  declare const SANDBOX_RUNTIMES: readonly ["bash", "python", "node"];
634
425
  declare const SANDBOX_PERMISSION_MODES: readonly ["edit", "ask", "bypass"];
@@ -639,9 +430,6 @@ type PermissionMode = (typeof SANDBOX_PERMISSION_MODES)[number];
639
430
  type NetworkMode = (typeof SANDBOX_NETWORK_MODES)[number];
640
431
  type SandboxSize = (typeof SANDBOX_SIZE_NAMES)[number];
641
432
  type SandboxImage = (typeof SANDBOX_IMAGES)[number];
642
- /**
643
- * Idle and maximum lifetime controls for a persistent sandbox.
644
- */
645
433
  interface SandboxLifecycleConfig {
646
434
  idleTimeoutSeconds?: number;
647
435
  maxLifetimeSeconds?: number;
@@ -651,9 +439,6 @@ interface SandboxNetworkConfig {
651
439
  allowDomains?: string[];
652
440
  allowCidrs?: string[];
653
441
  }
654
- /**
655
- * Account-scoped reusable sandbox configuration referenced by agents.
656
- */
657
442
  interface SandboxConfig {
658
443
  provider: SandboxProvider;
659
444
  fallbackProvider?: SandboxProvider;
@@ -673,47 +458,20 @@ interface SandboxConfig {
673
458
  options?: Record<string, unknown>;
674
459
  }
675
460
 
676
- /**
677
- * Workspace isolation levels, the one list the config plane, core, the
678
- * dashboard and the CLI read. No imports on purpose: the CLI bundles this file
679
- * without the Convex runtime behind workspaceRules (like modelProviders.ts).
680
- */
681
461
  declare const WORKSPACE_ISOLATION_LEVELS: readonly ["conversation", "agent"];
682
- /**
683
- * How a workspace splits its files. "conversation" mounts a folder per channel
684
- * partition, "agent" gives every attached agent its own folder. Unset shares
685
- * one root between every agent and conversation.
686
- */
462
+ /** A folder per channel partition or per agent; unset shares one root. */
687
463
  type WorkspaceIsolation = (typeof WORKSPACE_ISOLATION_LEVELS)[number];
688
464
 
689
- /**
690
- * Workspace-config validation for the Convex config plane. Ports core's
691
- * former storage/workspace-config.ts normalizer so the public /v1/workspaces
692
- * contract is unchanged. Workspace config holds no secrets (a roleArn is not
693
- * a secret, and R2 keys are `${NAME}` env refs), so it is stored and returned
694
- * in plaintext. Pure module, safe
695
- * for the default Convex runtime. The public projection lives in
696
- * ./responses.ts. Core runs the storage access rule too, so it reads the env
697
- * names of both sides.
698
- */
699
-
700
465
  declare const WORKSPACE_STORAGE_PROVIDERS: readonly ["s3"];
701
466
  type WorkspaceStorageProvider = (typeof WORKSPACE_STORAGE_PROVIDERS)[number];
702
467
  type WorkspaceStorageAuth = {
703
468
  type: "managed";
704
- }
705
- /**
706
- * The role's trust policy requires the account's Broods-assigned
707
- * sts:ExternalId (`storageTrust.ts`); a customer never sets one here.
708
- */
709
- | {
469
+ } | {
710
470
  type: "assumeRole";
711
471
  roleArn: string;
712
472
  } | {
713
473
  type: "r2";
714
- /** `${NAME}` ref to the parent R2 token's access key id. */
715
474
  accessKeyId: string;
716
- /** `${NAME}` ref to the parent R2 token's secret access key. */
717
475
  secretAccessKey: string;
718
476
  };
719
477
  interface WorkspaceStorageConfig {
@@ -737,11 +495,6 @@ interface WorkspaceConfig {
737
495
  };
738
496
  }
739
497
 
740
- /**
741
- * Versioned policy document accepted by account-management CRUD, as the
742
- * `agentPolicies` and `accountRoles` tables store it. `mode` says how hard
743
- * the policy bites where it is attached; omitted reads as `audit`.
744
- */
745
498
  declare const policyDocumentValidator: convex_values.VObject<{
746
499
  mode?: "enforce" | "audit" | undefined;
747
500
  version: 1;
@@ -821,7 +574,6 @@ declare const policyDocumentValidator: convex_values.VObject<{
821
574
  resourceIds?: string[] | undefined;
822
575
  } | undefined, {
823
576
  toolNames: convex_values.VArray<string[] | undefined, convex_values.VString<string, "required">, "optional">;
824
- /** MCP registration ids, for scoping tool.call rules per server (#331). */
825
577
  mcpIds: convex_values.VArray<string[] | undefined, convex_values.VString<string, "required">, "optional">;
826
578
  workspaceIds: convex_values.VArray<string[] | undefined, convex_values.VString<string, "required">, "optional">;
827
579
  workspaceNames: convex_values.VArray<string[] | undefined, convex_values.VString<string, "required">, "optional">;
@@ -847,35 +599,15 @@ declare const policyDocumentValidator: convex_values.VObject<{
847
599
  }, "required", "version" | "mode" | "rules">;
848
600
  type PolicyDocument = Infer<typeof policyDocumentValidator>;
849
601
 
850
- /**
851
- * Channel record validation for the config plane, the single home of the
852
- * normalizers core's `shared/domain/channel-record.ts` re-exports. Kept free
853
- * of Convex imports so the rules stay unit-testable; the public projection
854
- * lives in ./responses.ts.
855
- */
856
- /** Where a reply lands: its own thread, or wherever the message came from. */
857
602
  declare const CHANNEL_REPLY_TARGETS: readonly ["thread", "source"];
858
603
  type ChannelReplyIn = (typeof CHANNEL_REPLY_TARGETS)[number];
859
604
 
860
- /**
861
- * The core HTTP contract every handler speaks, plus generic request/response
862
- * helpers. Handlers take a CoreRequest + RequestContext and return a Web
863
- * Response; the transport edge (`src/server.ts`) builds the CoreRequest from
864
- * a real request. Keep route-specific logic out of here.
865
- */
866
605
  declare global {
867
606
  interface BunFetchRequestInit {
868
607
  timeout?: number | boolean;
869
608
  }
870
609
  }
871
610
 
872
- /**
873
- * Wire types for the public account-manage and harness APIs. These mirror
874
- * the deployed API contract (docs/api-reference/openapi.yaml is the source
875
- * of truth); they are intentionally independent of the runtime internals so
876
- * the SDK keeps working when the runtime is ported.
877
- */
878
-
879
611
  interface Cron {
880
612
  accountId: string;
881
613
  cronId: string;
@@ -915,32 +647,19 @@ interface Skill {
915
647
  }>;
916
648
  }
917
649
 
918
- /**
919
- * Connections: external accounts an agent acts through, one of each type per
920
- * Broods account. `broods connect <type>` opens the provider's sign-in; the
921
- * deployment trades the code, checks the ID token and keeps the tokens, and
922
- * core refreshes them from then on. `chatgpt` backs the `chatgpt` model
923
- * provider. Plain data, so the CLI, the config plane, core and the dashboard
924
- * read one copy.
925
- */
926
650
  declare const CONNECTION_TYPE_NAMES: readonly ["chatgpt"];
927
651
  type ConnectionType = (typeof CONNECTION_TYPE_NAMES)[number];
928
- /** Starts a sign-in: `POST /v1/account/connections/{type}/start`. */
929
652
  interface ConnectionStart {
930
- /** The loopback address the provider redirects back to. */
931
653
  redirectUri: string;
932
654
  codeChallenge: string;
933
655
  state: string;
934
656
  nonce: string;
935
657
  }
936
- /** The provider's consent screen, plus the client and host id the PUT echoes back. */
937
658
  interface ConnectionStartResult {
938
659
  authorizeUrl: string;
939
- /** The client the consent runs on; a redirect that signs in again may omit it. */
940
660
  clientId: string;
941
661
  hostId: string;
942
662
  }
943
- /** Finishes a sign-in: `PUT /v1/account/connections/{type}` with the redirect's code. */
944
663
  interface ConnectionCode {
945
664
  code: string;
946
665
  codeVerifier: string;
@@ -950,71 +669,37 @@ interface ConnectionCode {
950
669
  clientId: string;
951
670
  hostId: string;
952
671
  }
953
- /** A connection as the API answers it: never its tokens. */
954
672
  interface Connection {
955
673
  type: ConnectionType;
956
674
  clientId: string;
957
- /** The deployment's `ext_agent_host_id`, kept across sign-ins. */
958
675
  hostId: string;
959
676
  email?: string;
960
677
  scopes: string[];
961
- /** ISO 8601 access-token expiry; Broods refreshes it before then. */
962
678
  expiresAt: string;
963
679
  updatedAt: string;
964
- /** Answered by a sign-in only: the models the plan may call. */
965
680
  models?: string[];
966
681
  }
967
682
 
968
- /**
969
- * Account config-plane client for the broods public account REST API.
970
- *
971
- * This is the DYNAMIC counterpart to the config-first `broods dev` / `broods
972
- * deploy` flow: `broods dev` syncs the predefined resources declared in your
973
- * `broods/` folder, while `BroodsAccountClient` creates and mutates the full
974
- * account config plane at runtime: agents, sandboxes (config + lifecycle),
975
- * workspaces (config + files), tools, policies, skills, crons, and the account
976
- * itself. One caller is a multi-tenant app provisioning one agent per customer
977
- * from its own backend.
978
- *
979
- * Kept intentionally standalone (import from `broods/account`): pure fetch,
980
- * no Node built-ins, no `.env` file loading, so it runs in edge/worker
981
- * runtimes such as Convex actions, Cloudflare Workers, and the browser-less
982
- * server runtimes, as well as Node and Bun.
983
- *
984
- * Auth: every call sends `Authorization: Bearer {accountSecret}` to
985
- * `{baseUrl}/v1/...`, or a short-lived `bsts_` role session token from
986
- * `assumeRole()`, limited to what the role's policy allows. Secrets inside
987
- * agent configs are encrypted at rest by the platform and come back redacted
988
- * (`********`) on reads.
989
- */
990
-
991
- /** A config PATCH body: objects merge key by key, `null` deletes a key, arrays and scalars replace. */
683
+ /** Objects merge key by key, `null` deletes a key, arrays and scalars replace. */
992
684
  type ConfigPatch<T> = T extends readonly unknown[] ? T : T extends object ? {
993
685
  [K in keyof T]?: ConfigPatch<T[K]> | null;
994
686
  } : T;
995
687
  interface BroodsAccountClientOptions {
996
- /** Base URL of the broods gateway. Falls back to `BROODS_BASE_URL`, then `https://gateway.broods.app`. */
997
688
  baseUrl?: string;
998
- /** Account key used as the Bearer token. Falls back to `BROODS_ACCOUNT_SECRET`. */
999
689
  accountSecret?: string;
1000
- /**
1001
- * Short-lived `bsts_` role session token (from {@link BroodsAccountClient.assumeRole})
1002
- * used as the Bearer instead of the account key. The session can only do
1003
- * what its role's policy allows. Falls back to `BROODS_SESSION_TOKEN`.
1004
- */
690
+ /** From {@link BroodsAccountClient.assumeRole}; wins over `accountSecret`. */
1005
691
  sessionToken?: string;
1006
692
  fetch?: typeof fetch;
1007
693
  }
1008
- /** Public account record returned by `GET /v1/account`. */
1009
694
  interface BroodsAccount {
1010
695
  accountId: string;
1011
696
  username: string;
1012
697
  status: string;
1013
- /** Days an audit row is kept; absent means the 90 day default. */
698
+ /** Absent means the 90 day default. */
1014
699
  auditRetentionDays?: number;
1015
700
  [key: string]: unknown;
1016
701
  }
1017
- /** Public agent record; `config` comes back with secret values redacted. */
702
+ /** `config` secrets come back redacted as `********`. */
1018
703
  interface AccountAgent {
1019
704
  accountId: string;
1020
705
  agentId: string;
@@ -1031,20 +716,16 @@ interface CreateAgentResult {
1031
716
  name: string;
1032
717
  description?: string;
1033
718
  }
1034
- /** Write-only account environment variable metadata. */
1035
719
  interface AccountEnvVar {
1036
720
  name: string;
1037
- /** ISO 8601, like every other timestamp in the API. */
1038
721
  updatedAt: string;
1039
722
  }
1040
723
 
1041
- /** Fields accepted by `PATCH /v1/agents/{id}`. `config` is deep-merged; `null` values delete keys. */
1042
724
  interface UpdateAgentInput {
1043
725
  name?: string;
1044
726
  description?: string | null;
1045
727
  config?: ConfigPatch<AgentConfig>;
1046
728
  }
1047
- /** Public workspace record returned by the workspaces routes. */
1048
729
  interface AccountWorkspace {
1049
730
  accountId: string;
1050
731
  workspaceId: string;
@@ -1054,7 +735,6 @@ interface AccountWorkspace {
1054
735
  createdAt: string;
1055
736
  updatedAt: string;
1056
737
  }
1057
- /** One entry of a workspace file listing (`GET /v1/workspaces/{id}/files`). */
1058
738
  interface WorkspaceFileEntry {
1059
739
  path: string;
1060
740
  name: string;
@@ -1062,7 +742,7 @@ interface WorkspaceFileEntry {
1062
742
  sizeBytes?: number;
1063
743
  updatedAt?: string;
1064
744
  }
1065
- /** Public sandbox config record; `config` comes back with secret values (e.g. `envVars`) redacted. */
745
+ /** `config` secrets such as `envVars` come back redacted. */
1066
746
  interface AccountSandbox {
1067
747
  accountId: string;
1068
748
  sandboxId: string;
@@ -1073,7 +753,6 @@ interface AccountSandbox {
1073
753
  updatedAt: string;
1074
754
  [key: string]: unknown;
1075
755
  }
1076
- /** Public agent-policy record returned by the policies routes. */
1077
756
  interface AccountPolicy {
1078
757
  accountId: string;
1079
758
  policyId: string;
@@ -1084,11 +763,7 @@ interface AccountPolicy {
1084
763
  createdAt: string;
1085
764
  updatedAt: string;
1086
765
  }
1087
- /**
1088
- * Public account-role record returned by the roles routes. The policy uses the
1089
- * API action namespace (`"agents:read"`, `"crons:write"`, ...); `projectId` and
1090
- * `stageId` bound which runtime keys may assume the role.
1091
- */
766
+ /** `policy` uses API actions (`agents:read`); `projectId` + `stageId` bound who may assume it. */
1092
767
  interface AccountRole {
1093
768
  accountId: string;
1094
769
  roleId: string;
@@ -1100,7 +775,6 @@ interface AccountRole {
1100
775
  createdAt: string;
1101
776
  updatedAt: string;
1102
777
  }
1103
- /** One link of an agent actor's delegation chain: who asked, or an agent that delegated. */
1104
778
  type AuditPrincipalLink = {
1105
779
  kind: "user";
1106
780
  id: string;
@@ -1114,10 +788,8 @@ type AuditPrincipalLink = {
1114
788
  agentId: string;
1115
789
  };
1116
790
  /**
1117
- * One row of the account's hash-chained audit ledger, as `GET /v1/audit`
1118
- * serves it. `hash` is sha256 over the canonical JSON of every field but
1119
- * `hash` itself (an absent optional field is left out, not null), with
1120
- * `prevHash` linking it to the row before.
791
+ * `hash` is sha256 of the canonical JSON of every other field (an absent optional is left
792
+ * out, not null); `prevHash` is the previous row's `hash`.
1121
793
  */
1122
794
  interface AuditEvent {
1123
795
  accountId: string;
@@ -1147,44 +819,31 @@ interface AuditEvent {
1147
819
  stageId?: string;
1148
820
  traceId?: string;
1149
821
  }
1150
- /** A page of ledger rows plus the chain head to compare the last row against. */
1151
822
  interface AuditPage {
1152
823
  events: AuditEvent[];
1153
- /** Pass as `since` to read the rows after this page. */
1154
824
  nextSince: number;
1155
825
  head: {
1156
826
  seq: number;
1157
827
  hash: string;
1158
828
  } | null;
1159
829
  }
1160
- /** Result of `GET /v1/audit/verify`: the chain recomputed over the checked range. */
1161
830
  interface AuditVerification {
1162
831
  ok: boolean;
1163
832
  brokenAtSeq?: number;
1164
833
  checkedFrom?: number;
1165
834
  checkedTo?: number;
1166
835
  }
1167
- /** The account's audit export target. The signing secret never comes back. */
1168
836
  interface AuditSink {
1169
837
  kind: "webhook";
1170
838
  url: string;
1171
- /** Highest seq the receiver acknowledged. */
1172
839
  exportedSeq: number;
1173
840
  lastError?: string;
1174
841
  updatedAt: string;
1175
842
  }
1176
- /** Short-lived role session minted by `POST /v1/account/assume-role`. */
1177
843
  interface AssumeRoleResult {
1178
- /** `bsts_` bearer token; pass it as `sessionToken` to a new client. */
1179
844
  token: string;
1180
- /** ISO timestamp when the session stops working. */
1181
845
  expiresAt: string;
1182
846
  }
1183
- /**
1184
- * One real place a team talks, bound to an agent: a Slack channel, a Discord
1185
- * channel, a repo. The runtime reads it on the inbound webhook to decide who
1186
- * answers there and with what instructions, workspaces and policies.
1187
- */
1188
847
  interface AccountChannel {
1189
848
  accountId: string;
1190
849
  channelId: string;
@@ -1210,39 +869,26 @@ interface ChannelRecordConfig {
1210
869
  name: string;
1211
870
  workspaceId: string;
1212
871
  }>;
1213
- /** Added to whatever the agent already carries. Each policy holds its own mode. */
1214
872
  policies?: string[];
1215
- /**
1216
- * Tool names withheld in this channel, applied after the tool set is built,
1217
- * so it also covers sandbox tools (`bash`, `read`, …) that `config.tools`
1218
- * cannot name. Narrowing only; unknown names are ignored.
1219
- */
873
+ /** Also covers sandbox tools (`bash`, `read`, …); unknown names are ignored. */
1220
874
  denyTools?: string[];
1221
- /**
1222
- * Where the reply lands. `source` answers wherever the message came from, and
1223
- * threads only when the message already did. Slack only. No other provider
1224
- * gives the runtime a second place to reply.
1225
- */
875
+ /** Slack only. `source` replies where the message came from, threading only if it was. */
1226
876
  replyIn?: ChannelReplyIn;
1227
877
  partition?: ChannelPartition;
1228
- /** Images the agent may stand a sandbox up from for a thread here. */
1229
878
  sandboxImages?: string[];
1230
- /** Named groups of people, readable from policy conditions as `userRoles`. */
879
+ /** Readable from policy conditions as `userRoles`. */
1231
880
  tagRoles?: Array<{
1232
881
  roleId: string;
1233
882
  userIds: string[];
1234
883
  }>;
1235
884
  }
1236
- /** The stage a resource belongs to. Same name in two stages = two resources. */
1237
885
  interface StageScope {
1238
886
  project: string;
1239
887
  stage: string;
1240
888
  }
1241
889
  /**
1242
- * OAuth 2.0 refresh-token grant on an external MCP row. The runtime mints and
1243
- * refreshes access tokens and sends `Authorization: Bearer <token>` itself.
1244
- * `clientSecret` and `refreshToken` must be `${NAME}` account env refs;
1245
- * `tokenUrl` defaults to https://oauth2.googleapis.com/token.
890
+ * Refresh-token grant; the runtime mints the Bearer itself. `clientSecret` and `refreshToken`
891
+ * must be `${NAME}` env refs; `tokenUrl` defaults to https://oauth2.googleapis.com/token.
1246
892
  */
1247
893
  interface McpOauthInput {
1248
894
  clientId: string;
@@ -1250,9 +896,8 @@ interface McpOauthInput {
1250
896
  refreshToken: string;
1251
897
  tokenUrl?: string;
1252
898
  }
1253
- /** Where a hosted MCP server may run. */
899
+ /** `auto` (the default) runs a hosted bundle on Cloudflare Workers when it can, else Lambda. */
1254
900
  type McpRuntime = "auto" | "lambda";
1255
- /** Public MCP server registration returned by the `/v1/mcp` routes (#331). */
1256
901
  interface AccountMcp {
1257
902
  accountId: string;
1258
903
  serverId: string;
@@ -1260,16 +905,12 @@ interface AccountMcp {
1260
905
  stageId: string;
1261
906
  name: string;
1262
907
  description?: string;
908
+ /** `http` sets `url`, `hosted` sets `sha256`/`runtime`, `machine` sets `sandbox`/`command`. */
1263
909
  transport: "http" | "hosted" | "machine";
1264
- /** External servers only; a hosted row has no endpoint of its own. */
1265
910
  url?: string;
1266
- /** Machine servers only: the sandbox (by name) that serves it. */
1267
911
  sandbox?: string;
1268
- /** Machine servers only: argv of the stdio server a lambda sandbox runs. */
1269
912
  command?: string[];
1270
- /** Hosted servers only: content hash of the uploaded bundle. */
1271
913
  sha256?: string;
1272
- /** Hosted servers only: "auto" or "lambda". */
1273
914
  runtime?: McpRuntime;
1274
915
  headers?: Record<string, string>;
1275
916
  oauth?: McpOauthInput;
@@ -1280,11 +921,7 @@ interface AccountMcp {
1280
921
  updatedAt: string;
1281
922
  deletedAt?: string;
1282
923
  }
1283
- /**
1284
- * Fields accepted by `POST /v1/mcp`: `url` connects, `bundle` uploads inline
1285
- * (≤10 MB); a larger bundle goes through `uploadMcpBundle` first; `sandbox`
1286
- * runs it on that sandbox: a machine's daemon, or `command` on a lambda VM.
1287
- */
924
+ /** `bundle` inline is ≤10 MB, a larger one goes through `uploadMcpBundle` first. */
1288
925
  interface CreateMcpInput {
1289
926
  name: string;
1290
927
  description?: string;
@@ -1297,14 +934,8 @@ interface CreateMcpInput {
1297
934
  headers?: Record<string, string>;
1298
935
  oauth?: McpOauthInput;
1299
936
  allowedTools?: string[];
1300
- /**
1301
- * Hosted servers only. "auto" (the default) runs it on Cloudflare Workers
1302
- * when its bundle can run there, on Lambda otherwise; "lambda" always runs
1303
- * it on Lambda.
1304
- */
1305
937
  runtime?: McpRuntime;
1306
938
  }
1307
- /** Fields accepted by `PATCH /v1/mcp/{serverId}`; every field is optional. */
1308
939
  interface UpdateMcpInput {
1309
940
  name?: string;
1310
941
  description?: string;
@@ -1317,19 +948,10 @@ interface UpdateMcpInput {
1317
948
  headers?: Record<string, string>;
1318
949
  oauth?: McpOauthInput;
1319
950
  allowedTools?: string[];
1320
- /**
1321
- * Hosted servers only. "auto" (the default) runs it on Cloudflare Workers
1322
- * when its bundle can run there, on Lambda otherwise; "lambda" always runs
1323
- * it on Lambda.
1324
- */
1325
951
  runtime?: McpRuntime;
1326
952
  disabled?: boolean;
1327
953
  }
1328
- /**
1329
- * Body of a skill upload (`POST /v1/skills`, `PUT /v1/skills/{skillName}`).
1330
- * `json` needs `name`/`description`/`content`; `files` needs base64 `files`
1331
- * including a root `SKILL.md`; `github` needs a tree `url`.
1332
- */
954
+ /** `json` needs name, description, content; `files` a root `SKILL.md`; `github` a tree `url`. */
1333
955
  interface SkillUploadInput {
1334
956
  source: "json" | "files" | "github";
1335
957
  name?: string;
@@ -1342,101 +964,72 @@ interface SkillUploadInput {
1342
964
  }>;
1343
965
  url?: string;
1344
966
  }
1345
- /** Result of `POST /v1/account/rotate-secret`. The returned `secret` is the new account key, shown once; the old key stops working immediately. */
1346
967
  interface RotateSecretResult {
1347
968
  account: BroodsAccount;
1348
969
  secret: string;
1349
970
  }
1350
971
  /**
1351
- * Result of `GET /v1/account/storage-trust`: what a workspace's own AWS role
1352
- * must trust. Broods assigns `externalId` per account and sends it on every
1353
- * AssumeRole of an `assumeRole` workspace's role; it is never set in config.
972
+ * `externalId` is per account and sent on every AssumeRole; it is never set in config.
973
+ * `principalArn` and `trustPolicy` are absent on a deployment with no AWS.
1354
974
  */
1355
975
  interface StorageTrust {
1356
976
  externalId: string;
1357
- /** The Broods AWS principal to trust; absent on a deployment with no AWS. */
1358
977
  principalArn?: string;
1359
- /** A ready-to-paste trust policy JSON; absent on a deployment with no AWS. */
1360
978
  trustPolicy?: string;
1361
979
  }
1362
- /** Result of `DELETE /v1/account`: the account and all account-scoped data are removed; `cleanup` reports per-resource deletion counts. */
1363
980
  interface DeleteAccountResult {
1364
981
  deleted: boolean;
1365
982
  cleanup?: Record<string, number>;
1366
983
  }
1367
- /** Result of a suspend/resume/terminate sandbox lifecycle action. */
1368
984
  interface SandboxLifecycleResult {
1369
985
  status: string;
1370
986
  }
1371
- /** Result of `POST /v1/sandboxes/{id}/snapshot`. */
1372
987
  interface SandboxSnapshotResult {
1373
988
  status: string;
1374
989
  snapshotId?: string;
1375
990
  externalImageId?: string;
1376
991
  }
1377
- /** Sealed ticket from `POST /v1/sandboxes/{id}/terminal`; hand `token` to the gateway terminal WebSocket at `websocketPath`. */
1378
992
  interface SandboxTerminalTicket {
1379
993
  token: string;
1380
994
  expiresAt: number;
1381
995
  websocketPath: string;
1382
996
  }
1383
- /** Non-2xx response from the account API (404s on id routes return null instead). */
1384
997
  declare class BroodsAccountApiError extends Error {
1385
998
  readonly status: number;
1386
999
  readonly body: string;
1387
1000
  constructor(method: string, path: string, status: number, body: string);
1388
1001
  }
1389
- /** Build a validated account env-var reference for use in an agent config. */
1390
1002
  declare function envPlaceholder(name: string): string;
1391
- /**
1392
- * The credential the environment supplies, with a role session winning over
1393
- * the account key. The constructor throws through this same resolution, so
1394
- * callers that can run without an account credential (`broods mcp` with only a
1395
- * stored login) probe here instead of catching the constructor.
1396
- */
1003
+ /** The constructor's env fallback, for callers that must not throw without one. */
1397
1004
  declare function resolveEnvCredential(): string | undefined;
1398
1005
  /**
1399
- * Typed client for the broods account config API. All `get`/`update`/`delete`
1400
- * methods return `null`/`false` when the resource does not exist (HTTP 404) so
1401
- * callers can implement upsert flows without try/catch; every other non-2xx
1402
- * status throws {@link BroodsAccountApiError}.
1006
+ * Lookups, updates and deletes return `null`/`false` on a 404, so upserts need no try/catch.
1007
+ * Any other failure throws {@link BroodsAccountApiError}.
1403
1008
  */
1404
1009
  declare class BroodsAccountClient {
1405
1010
  private readonly baseUrl;
1406
1011
  private readonly bearerToken;
1407
1012
  private readonly fetchImpl;
1408
1013
  constructor(options?: BroodsAccountClientOptions);
1409
- /** The account this secret belongs to. Its `accountId` is the first segment of channel webhook URLs. */
1410
1014
  getAccount(): Promise<BroodsAccount>;
1411
- /** The external id and Broods principal this account's own storage roles must trust. */
1412
1015
  getStorageTrust(): Promise<StorageTrust>;
1413
- /** Update account metadata (username/description). Returns null when the account is gone. Runtime config is managed through the agent endpoints. */
1414
1016
  updateAccount(patch: {
1415
1017
  username?: string;
1416
1018
  description?: string | null;
1417
- /** 1 to 3650 days, or null to return to the 90 day default. */
1019
+ /** 1 to 3650 days, or null for the 90 day default. */
1418
1020
  auditRetentionDays?: number | null;
1419
1021
  }): Promise<BroodsAccount | null>;
1420
1022
  /**
1421
- * Exchange a role for a short-lived `bsts_` session token. Callable with
1422
- * the account key, a CLI login token, or a runtime key (the latter
1423
- * only into roles scoped to the key's own project/stage). Construct a new
1424
- * client with `{ sessionToken: result.token }` to act as the role.
1023
+ * A runtime key may assume only roles scoped to its own project and stage.
1024
+ * Act as the role with `new BroodsAccountClient({ sessionToken: result.token })`.
1425
1025
  */
1426
1026
  assumeRole(roleId: string, options?: {
1427
1027
  ttlSeconds?: number;
1428
1028
  }): Promise<AssumeRoleResult>;
1429
- /** Rotate the account key. The returned `secret` is the new key, shown once, and the current key stops working immediately, so persist it before the process exits. */
1029
+ /** The old key dies at once and `secret` is shown only once: persist it before exiting. */
1430
1030
  rotateSecret(): Promise<RotateSecretResult>;
1431
- /** Delete this account and cascade-clean every account-scoped resource. `cleanup` reports per-resource deletion counts. */
1432
1031
  deleteAccount(): Promise<DeleteAccountResult>;
1433
- /**
1434
- * Provider webhook URL for one of the account's channels. Paste this into the
1435
- * provider's webhook settings (Slack Event Subscriptions, Zalo OA webhook,
1436
- * Pancake page webhook). Routing is per account + channel: the credentials
1437
- * that verify the request pick the receiving agent, and a channel record
1438
- * binds each place to the agent that should answer there.
1439
- */
1032
+ /** One URL per account and channel type; the credentials that verify a request pick the agent. */
1440
1033
  webhookUrl(accountId: string, channelType: string): string;
1441
1034
  listAgents(): Promise<AccountAgent[]>;
1442
1035
  createAgent(input: {
@@ -1445,31 +1038,22 @@ declare class BroodsAccountClient {
1445
1038
  config: AgentConfig;
1446
1039
  }): Promise<CreateAgentResult>;
1447
1040
  getAgent(agentId: string): Promise<AccountAgent | null>;
1448
- /** PATCH an agent. `config` deep-merges into the stored config; `null` leaves delete keys. Returns null when the agent is gone. */
1449
1041
  updateAgent(agentId: string, patch: UpdateAgentInput): Promise<AccountAgent | null>;
1450
1042
  deleteAgent(agentId: string): Promise<boolean>;
1451
- /** List account environment variable names and update timestamps; values are never returned. */
1452
1043
  listEnvVars(): Promise<AccountEnvVar[]>;
1453
- /** Create or replace one write-only account environment variable. */
1454
1044
  setEnvVar(name: string, value: string): Promise<void>;
1455
- /** Delete one account environment variable. Returns false when it is already absent. */
1456
1045
  deleteEnvVar(name: string): Promise<boolean>;
1457
- /** The account's connections (`broods connect`), never their tokens. */
1458
1046
  listConnections(): Promise<Connection[]>;
1459
- /** The account's connection of one type, or null when there is none. */
1460
1047
  getConnection(type: ConnectionType): Promise<Connection | null>;
1461
- /** Starts a sign-in: the provider's consent screen for `broods connect` to open. */
1462
1048
  startConnection(type: ConnectionType, start: ConnectionStart): Promise<ConnectionStartResult>;
1463
- /** Finishes a sign-in with the code the browser brought back; the deployment keeps the tokens. */
1464
1049
  connect(type: ConnectionType, code: ConnectionCode): Promise<Connection>;
1465
- /** Forget a connection and revoke it at the provider. False when there was none. */
1466
1050
  disconnect(type: ConnectionType): Promise<boolean>;
1467
1051
  listCrons(): Promise<Cron[]>;
1468
1052
  createCron(input: CreateCronInput): Promise<Cron>;
1469
1053
  getCron(cronId: string): Promise<Cron | null>;
1470
1054
  updateCron(cronId: string, patch: UpdateCronInput): Promise<Cron | null>;
1471
1055
  deleteCron(cronId: string): Promise<boolean>;
1472
- /** Run history for a cron, newest first. Returns [] when the cron is gone. */
1056
+ /** Newest first. */
1473
1057
  listCronRuns(cronId: string, options?: {
1474
1058
  limit?: number;
1475
1059
  }): Promise<CronRun[]>;
@@ -1486,19 +1070,14 @@ declare class BroodsAccountClient {
1486
1070
  config?: ConfigPatch<WorkspaceConfig>;
1487
1071
  }): Promise<AccountWorkspace | null>;
1488
1072
  deleteWorkspace(workspaceId: string): Promise<boolean>;
1489
- /** Flat listing of every file in the workspace's S3-backed filesystem. Returns [] when the workspace is gone. */
1490
1073
  listWorkspaceFiles(workspaceId: string): Promise<WorkspaceFileEntry[]>;
1491
- /** Short-lived download URL for one workspace file. Returns null when the workspace or file is gone. */
1492
1074
  getWorkspaceFileUrl(workspaceId: string, path: string): Promise<string | null>;
1493
- /** Upload or replace one workspace file from base64 content. Throws when the workspace is gone (404). */
1494
1075
  uploadWorkspaceFile(workspaceId: string, input: {
1495
1076
  path: string;
1496
1077
  contentBase64: string;
1497
1078
  contentType?: string;
1498
1079
  }): Promise<WorkspaceFileEntry>;
1499
- /** Rename a workspace file or folder. Returns how many objects moved; throws when the workspace or source path is gone. */
1500
1080
  renameWorkspaceFile(workspaceId: string, path: string, newPath: string): Promise<number>;
1501
- /** Delete a workspace file or folder. Returns how many objects were deleted, 0 when the workspace or path is gone. */
1502
1081
  deleteWorkspaceFile(workspaceId: string, path: string): Promise<number>;
1503
1082
  listSandboxes(): Promise<AccountSandbox[]>;
1504
1083
  createSandbox(input: {
@@ -1507,30 +1086,24 @@ declare class BroodsAccountClient {
1507
1086
  config?: SandboxConfig;
1508
1087
  }): Promise<AccountSandbox>;
1509
1088
  getSandbox(sandboxId: string): Promise<AccountSandbox | null>;
1510
- /** PATCH a sandbox config. `config` deep-merges into the stored config; `null` leaves delete keys. Returns null when the sandbox is gone. */
1511
1089
  updateSandbox(sandboxId: string, patch: {
1512
1090
  name?: string;
1513
1091
  description?: string | null;
1514
1092
  config?: ConfigPatch<SandboxConfig>;
1515
1093
  }): Promise<AccountSandbox | null>;
1516
1094
  deleteSandbox(sandboxId: string): Promise<boolean>;
1517
- /** Suspend a persistent sandbox reservation. Throws on 404/403/409 (missing sandbox, foreign reservation, or unsupported provider). */
1518
1095
  suspendSandbox(sandboxId: string, reservationKey: string): Promise<SandboxLifecycleResult>;
1519
- /** Resume a persistent sandbox reservation. Throws on 404/403/409. */
1520
1096
  resumeSandbox(sandboxId: string, reservationKey: string): Promise<SandboxLifecycleResult>;
1521
- /** Terminate a persistent sandbox reservation and drop its live-instance row. Throws on 404/403/409. */
1522
1097
  terminateSandbox(sandboxId: string, reservationKey: string): Promise<SandboxLifecycleResult>;
1523
- /** Snapshot a persistent sandbox reservation into an image any sandbox of that provider on the same stage can pin with `snapshot` (`sandbox`, `daytona`, `e2b`, `vercel`, or `lambda`, which answers `building` until its image build lands). The snapshot is locked to the stage of the sandbox it was taken from: pinning it on another stage throws a 400. Throws on 404/403/409. */
1098
+ /**
1099
+ * Providers `sandbox`, `daytona`, `e2b`, `vercel` and `lambda` (`building` until its image
1100
+ * lands). Only the source stage may pin the snapshot; any other stage gets a 400.
1101
+ */
1524
1102
  snapshotSandbox(sandboxId: string, reservationKey: string, name: string): Promise<SandboxSnapshotResult>;
1525
- /** Mint a short-lived sealed ticket for an interactive PTY session on a persistent sandbox (`sandbox`/`lambda`/`cloudflare` providers). Throws on 404/403/409. */
1103
+ /** Providers `sandbox`, `lambda` and `cloudflare` only. */
1526
1104
  openSandboxTerminal(sandboxId: string, reservationKey: string): Promise<SandboxTerminalTicket>;
1527
- /** MCP servers live in one stage, so the collection routes need a scope. */
1528
1105
  listMcp(scope: StageScope): Promise<AccountMcp[]>;
1529
1106
  createMcp(scope: StageScope, input: CreateMcpInput): Promise<AccountMcp>;
1530
- /**
1531
- * Upload a hosted MCP bundle too large for the JSON body; returns the
1532
- * `bundleStorageId` + `sha256` pair `createMcp`/`updateMcp` accept.
1533
- */
1534
1107
  uploadMcpBundle(bundle: string): Promise<{
1535
1108
  bundleStorageId: string;
1536
1109
  sha256: string;
@@ -1545,7 +1118,6 @@ declare class BroodsAccountClient {
1545
1118
  document: PolicyDocument;
1546
1119
  }): Promise<AccountPolicy>;
1547
1120
  getPolicy(policyId: string): Promise<AccountPolicy | null>;
1548
- /** PATCH a policy. `description: null` clears it. Returns null when the policy is gone. */
1549
1121
  updatePolicy(policyId: string, patch: {
1550
1122
  name?: string;
1551
1123
  description?: string | null;
@@ -1553,9 +1125,8 @@ declare class BroodsAccountClient {
1553
1125
  status?: string;
1554
1126
  }): Promise<AccountPolicy | null>;
1555
1127
  deletePolicy(policyId: string): Promise<boolean>;
1556
- /** Roles are account-secret only: a session cannot list, mint, or edit roles. */
1128
+ /** Roles need the account key: a session cannot list, mint, or edit them. */
1557
1129
  listRoles(): Promise<AccountRole[]>;
1558
- /** Create a role whose policy uses the API action namespace. `projectId`/`stageId` must be provided together. */
1559
1130
  createRole(input: {
1560
1131
  name: string;
1561
1132
  policy: PolicyDocument;
@@ -1563,41 +1134,36 @@ declare class BroodsAccountClient {
1563
1134
  stageId?: string;
1564
1135
  }): Promise<AccountRole>;
1565
1136
  getRole(roleId: string): Promise<AccountRole | null>;
1566
- /** PATCH a role. `status: "disabled"` kills every live session of the role. Returns null when the role is gone. */
1137
+ /** `status: "disabled"` kills every live session of the role. */
1567
1138
  updateRole(roleId: string, patch: {
1568
1139
  name?: string;
1569
1140
  policy?: PolicyDocument;
1570
1141
  status?: "active" | "disabled";
1571
1142
  }): Promise<AccountRole | null>;
1572
1143
  deleteRole(roleId: string): Promise<boolean>;
1573
- /** The audit ledger: rows since a seq, chain verification, and the webhook sink. */
1574
1144
  readonly audit: {
1575
- /** Rows with `seq > since`, oldest first, at most `limit` (default 100, max 500). */
1145
+ /** Rows with `seq > since`, oldest first; `limit` defaults to 100, max 500. */
1576
1146
  list: (options?: {
1577
1147
  since?: number;
1578
1148
  limit?: number;
1579
1149
  }) => Promise<AuditPage>;
1580
1150
  /**
1581
- * Recompute the chain over `[fromSeq, toSeq]`, from the oldest kept row by
1582
- * default, at most 1000 rows per call. `ok` covers only `checkedFrom` to
1583
- * `checkedTo`; on a longer ledger call again with `fromSeq: checkedTo + 1`.
1151
+ * At most 1000 rows per call: `ok` covers only `checkedFrom` to `checkedTo`, so on a longer
1152
+ * ledger call again with `fromSeq: checkedTo + 1`.
1584
1153
  */
1585
1154
  verify: (options?: {
1586
1155
  fromSeq?: number;
1587
1156
  toSeq?: number;
1588
1157
  }) => Promise<AuditVerification>;
1589
- /** The account's sink, or null when none is set. */
1590
1158
  getSink: () => Promise<AuditSink | null>;
1591
- /** Set the one webhook sink. `url` must be public https; `secret` signs each batch. */
1159
+ /** `url` must be public https; `secret` signs each batch. */
1592
1160
  setSink: (input: {
1593
1161
  url: string;
1594
1162
  secret: string;
1595
1163
  }) => Promise<AuditSink>;
1596
- /** Remove the sink; exports stop and rows age out on retention alone. Returns whether one existed. */
1597
1164
  deleteSink: () => Promise<boolean>;
1598
1165
  };
1599
1166
  listChannels(): Promise<AccountChannel[]>;
1600
- /** Bind one real chat channel to an agent. One active record per place. */
1601
1167
  createChannel(input: {
1602
1168
  platform: string;
1603
1169
  externalId: string;
@@ -1607,7 +1173,6 @@ declare class BroodsAccountClient {
1607
1173
  config: ChannelRecordConfig;
1608
1174
  }): Promise<AccountChannel>;
1609
1175
  getChannel(channelId: string): Promise<AccountChannel | null>;
1610
- /** PATCH a channel. `description: null` clears it. Returns null when it is gone. */
1611
1176
  updateChannel(channelId: string, patch: {
1612
1177
  name?: string;
1613
1178
  description?: string | null;
@@ -1616,15 +1181,11 @@ declare class BroodsAccountClient {
1616
1181
  status?: "active" | "deleted";
1617
1182
  }): Promise<AccountChannel | null>;
1618
1183
  deleteChannel(channelId: string): Promise<boolean>;
1619
- /** All skills for the account, each with its `<accountId>/<name>` path. */
1620
1184
  listSkills(): Promise<Skill[]>;
1621
- /** Upload a new skill from JSON content, a base64 file bundle, or a GitHub tree URL. Every bundle must include a root `SKILL.md`. */
1622
1185
  createSkill(input: SkillUploadInput): Promise<Skill>;
1623
1186
  getSkill(skillName: string): Promise<Skill | null>;
1624
- /** Replace a skill's bundle in place (`PUT`). Throws when the skill is gone (404). */
1625
1187
  uploadSkill(skillName: string, input: SkillUploadInput): Promise<Skill>;
1626
1188
  deleteSkill(skillName: string): Promise<boolean>;
1627
- /** POST a sandbox lifecycle action, throwing on any non-2xx (including 404, since these are not upsert flows). */
1628
1189
  private sandboxAction;
1629
1190
  private request;
1630
1191
  }