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