broods 0.2.0 → 0.3.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.
@@ -0,0 +1,799 @@
1
+ import { SystemModelMessage, LanguageModelCallOptions, RequestOptions, streamText, JSONSchema7, ModelMessage } from 'ai';
2
+ import { DiscordAdapterConfig } from '@chat-adapter/discord';
3
+ import { GitHubAdapterConfig } from '@chat-adapter/github';
4
+ import { SlackAdapterConfig } from '@chat-adapter/slack';
5
+ import { TelegramAdapterConfig } from '@chat-adapter/telegram';
6
+
7
+ /**
8
+ * Agent policy contracts and validation.
9
+ * Runtime decisions are made by OPA using the same document/input shape.
10
+ */
11
+ declare const AGENT_POLICY_ACTIONS: readonly ["tool.call", "workspace.read", "workspace.write", "workspace.exec", "subagent.run", "skill.load"];
12
+ type AgentPolicyAction = (typeof AGENT_POLICY_ACTIONS)[number];
13
+ type AgentPolicyEffect = "allow" | "deny";
14
+ type AgentPolicyMode = "enforce" | "audit";
15
+ type AgentPolicyConditionOperator = "equals" | "notEquals" | "in" | "notIn" | "prefix" | "contains";
16
+ interface AgentPolicyCondition {
17
+ attribute: string;
18
+ operator: AgentPolicyConditionOperator;
19
+ value: string | number | boolean | string[] | number[] | boolean[];
20
+ }
21
+ interface AgentPolicyResourceSelector {
22
+ toolNames?: string[];
23
+ toolIds?: string[];
24
+ workspaceIds?: string[];
25
+ workspaceNames?: string[];
26
+ filePaths?: string[];
27
+ subagentIds?: string[];
28
+ skillPaths?: string[];
29
+ }
30
+ interface AgentPolicyRule {
31
+ id: string;
32
+ effect: AgentPolicyEffect;
33
+ actions: AgentPolicyAction[];
34
+ resources?: AgentPolicyResourceSelector;
35
+ conditions?: AgentPolicyCondition[];
36
+ }
37
+ interface AgentPolicyDocument {
38
+ version: 1;
39
+ rules: AgentPolicyRule[];
40
+ }
41
+ interface AgentPolicyConfig {
42
+ policyIds?: string[];
43
+ mode?: AgentPolicyMode;
44
+ }
45
+
46
+ /**
47
+ * Supported account model provider names.
48
+ * Keep provider identifiers here so config validation and model resolution share one source.
49
+ */
50
+ declare const ACCOUNT_MODEL_PROVIDERS: {
51
+ readonly google: true;
52
+ readonly openai: true;
53
+ readonly anthropic: true;
54
+ readonly bedrock: true;
55
+ readonly gateway: true;
56
+ readonly minimax: true;
57
+ readonly custom: true;
58
+ };
59
+ type AccountModelProviderName = keyof typeof ACCOUNT_MODEL_PROVIDERS;
60
+
61
+ /**
62
+ * Agent configuration: types for the per-agent settings object, input
63
+ * normalization, encryption helpers, patch-merge, and redaction.
64
+ * Account types and auth live in `./accounts.ts` and `../auth.ts`.
65
+ */
66
+
67
+ interface AgentConfig {
68
+ agent?: AgentBehaviorConfig;
69
+ model?: AgentModelConfig;
70
+ provider?: AgentProviderConfig;
71
+ sandbox?: string;
72
+ workspaces?: AgentWorkspaceRef[];
73
+ session?: AgentSessionConfig;
74
+ hooks?: AgentHooksConfig;
75
+ channels?: AgentChannelsConfig;
76
+ tools?: AgentToolsConfig;
77
+ skills?: AgentSkillsConfig;
78
+ subagent?: AgentSubagentConfig;
79
+ policy?: AgentPolicyConfig;
80
+ publicAccess?: boolean;
81
+ [key: string]: unknown;
82
+ }
83
+ interface AgentBehaviorConfig {
84
+ maxTurn?: number;
85
+ system?: string | SystemModelMessage | SystemModelMessage[];
86
+ [key: string]: unknown;
87
+ }
88
+ type StreamTextOptions = Parameters<typeof streamText>[0];
89
+ type AgentModelProviderOptions = StreamTextOptions["providerOptions"];
90
+ interface AgentSkillsConfig {
91
+ enabled?: boolean;
92
+ allowed?: string[];
93
+ [key: string]: unknown;
94
+ }
95
+ interface AgentSubagentConfig {
96
+ enabled?: boolean;
97
+ allowed?: string[];
98
+ context?: "new" | "inherited";
99
+ mode?: "ephemeral" | "persistent";
100
+ /**
101
+ * Controls what the parent agent sees from a finished subagent (AI SDK
102
+ * "controlling what the model sees"): `full` = the child's whole transcript,
103
+ * `result` = only its final result (default), `none` = nothing. A
104
+ * `subagent.task.finished` code hook overrides this for custom shaping.
105
+ */
106
+ visibility?: "full" | "result" | "none";
107
+ [key: string]: unknown;
108
+ }
109
+ interface AgentModelConfig extends LanguageModelCallOptions, Pick<RequestOptions, "maxRetries" | "timeout"> {
110
+ provider?: AccountModelProviderName;
111
+ modelId?: string;
112
+ providerOptions?: AgentModelProviderOptions;
113
+ output?: AgentModelOutputConfig;
114
+ }
115
+ type AgentModelOutputConfig = ({
116
+ type: "text";
117
+ } & AgentModelOutputMetadata) | ({
118
+ type: "object";
119
+ schema: JSONSchema7;
120
+ } & AgentModelOutputMetadata) | ({
121
+ type: "array";
122
+ element: JSONSchema7;
123
+ } & AgentModelOutputMetadata) | ({
124
+ type: "choice";
125
+ options: string[];
126
+ } & AgentModelOutputMetadata) | ({
127
+ type: "json";
128
+ } & AgentModelOutputMetadata);
129
+ type AgentModelOutputMetadata = {
130
+ name?: string;
131
+ description?: string;
132
+ [key: string]: unknown;
133
+ };
134
+ type AgentProviderConfig = Partial<Record<AccountModelProviderName, AgentProviderSettings>>;
135
+ /**
136
+ * Constructor settings for a model provider. The keys are an explicit allow-list
137
+ * (no open index signature) so a misspelled option — most commonly the camel
138
+ * `baseUrl` instead of the canonical `base_url`/`baseURL` — is a compile-time
139
+ * error in the SDK and is caught by `normalizeProviderSettings` at runtime.
140
+ * Keep this list in sync with `normalizeProviderSettings` and the SDK's
141
+ * `KNOWN_PROVIDER_SETTING_KEYS`.
142
+ */
143
+ interface AgentProviderSettings {
144
+ apiKey?: string;
145
+ /** OpenAI-compatible endpoint (`custom`). Snake form, as documented. */
146
+ base_url?: string;
147
+ /** OpenAI-compatible endpoint (`custom`). AI-SDK form; the dashboard writes both. */
148
+ baseURL?: string;
149
+ headers?: Record<string, string>;
150
+ organization?: string;
151
+ project?: string;
152
+ name?: string;
153
+ region?: string;
154
+ accessKeyId?: string;
155
+ secretAccessKey?: string;
156
+ sessionToken?: string;
157
+ }
158
+ interface AgentWorkspaceRef {
159
+ name: string;
160
+ workspaceId: string;
161
+ sandbox?: string | null;
162
+ }
163
+ interface AgentSessionConfig {
164
+ pruning?: AgentSessionPruningConfig;
165
+ compaction?: AgentSessionCompactionConfig;
166
+ [key: string]: unknown;
167
+ }
168
+ interface AgentSessionPruningConfig {
169
+ enabled?: boolean;
170
+ [key: string]: unknown;
171
+ }
172
+ interface AgentSessionCompactionConfig {
173
+ enabled?: boolean;
174
+ maxContextLength?: number;
175
+ [key: string]: unknown;
176
+ }
177
+ interface AgentHooksConfig {
178
+ /** Outbound event webhooks. An agent may register several independent endpoints. */
179
+ webhooks?: AgentWebhookHookConfig[];
180
+ /**
181
+ * Uploaded code hooks. Each entry references an accountHooks bundle by id; the
182
+ * bundle runs in the V8 isolate at the matching fire-points and its validated
183
+ * return is folded into mutable harness state.
184
+ */
185
+ code?: AgentCodeHookConfig[];
186
+ [key: string]: unknown;
187
+ }
188
+ interface AgentCodeHookConfig {
189
+ hookId: string;
190
+ /**
191
+ * Optional narrowing of the events this reference reacts to. Omitted => the
192
+ * bundle's own declared `events` set. Any listed event outside the bundle's
193
+ * declared set is ignored at runtime.
194
+ */
195
+ events?: AgentHookEventName[];
196
+ enabled?: boolean;
197
+ [key: string]: unknown;
198
+ }
199
+ interface AgentWebhookHookConfig {
200
+ enabled?: boolean;
201
+ url?: string;
202
+ secret?: string;
203
+ events?: AgentLifecycleEventName[];
204
+ [key: string]: unknown;
205
+ }
206
+ type AgentLifecycleEventName = "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";
207
+ type AgentChannelHookEventName = "channel.message.received" | "channel.message.sending";
208
+ type AgentHookEventName = AgentLifecycleEventName | AgentChannelHookEventName;
209
+ type AgentToolsConfig = Record<string, AgentToolConfig>;
210
+ interface AgentToolConfig {
211
+ enabled?: boolean;
212
+ needsApproval?: boolean;
213
+ async?: boolean;
214
+ config?: Record<string, unknown>;
215
+ [key: string]: unknown;
216
+ }
217
+ interface AgentChannelsConfig {
218
+ telegram?: AgentTelegramChannelConfig;
219
+ github?: AgentGitHubChannelConfig;
220
+ slack?: AgentSlackChannelConfig;
221
+ discord?: AgentDiscordChannelConfig;
222
+ pancake?: AgentPancakeChannelConfig;
223
+ zalo?: AgentZaloChannelConfig;
224
+ [key: string]: unknown;
225
+ }
226
+ type AgentChannelWorkspaceScope = {
227
+ level: "channel";
228
+ alias?: never;
229
+ } | {
230
+ level: "conversation";
231
+ alias: string;
232
+ };
233
+ interface AgentTelegramChannelConfig {
234
+ id?: string;
235
+ apiUrl?: TelegramAdapterConfig["apiUrl"];
236
+ botToken?: TelegramAdapterConfig["botToken"];
237
+ webhookSecret?: TelegramAdapterConfig["secretToken"];
238
+ allowedChatIds?: number[];
239
+ reactionEmoji?: string;
240
+ workspaceScope?: AgentChannelWorkspaceScope;
241
+ [key: string]: unknown;
242
+ }
243
+ interface AgentGitHubChannelConfig {
244
+ id?: string;
245
+ apiUrl?: Extract<GitHubAdapterConfig, {
246
+ appId: string;
247
+ }>["apiUrl"];
248
+ webhookSecret?: Extract<GitHubAdapterConfig, {
249
+ appId: string;
250
+ }>["webhookSecret"];
251
+ appId?: Extract<GitHubAdapterConfig, {
252
+ appId: string;
253
+ }>["appId"];
254
+ privateKey?: Extract<GitHubAdapterConfig, {
255
+ appId: string;
256
+ }>["privateKey"];
257
+ allowedRepos?: string[];
258
+ /** Bot username for @-mention detection (e.g. "my-bot" or "my-bot[bot]"). */
259
+ userName?: string;
260
+ /** Bot's numeric GitHub user ID for self-message detection. */
261
+ botUserId?: number;
262
+ /** 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. */
263
+ triggerOnIssueOpen?: boolean;
264
+ /** 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. */
265
+ triggerOnPROpen?: boolean;
266
+ workspaceScope?: AgentChannelWorkspaceScope;
267
+ [key: string]: unknown;
268
+ }
269
+ interface AgentSlackChannelConfig {
270
+ id?: string;
271
+ apiUrl?: SlackAdapterConfig["apiUrl"];
272
+ botToken?: string;
273
+ signingSecret?: SlackAdapterConfig["signingSecret"];
274
+ allowedChannelIds?: string[];
275
+ reactionEmoji?: string;
276
+ workspaceScope?: AgentChannelWorkspaceScope;
277
+ [key: string]: unknown;
278
+ }
279
+ interface AgentDiscordChannelConfig {
280
+ id?: string;
281
+ apiUrl?: DiscordAdapterConfig["apiUrl"];
282
+ botToken?: DiscordAdapterConfig["botToken"];
283
+ publicKey?: DiscordAdapterConfig["publicKey"];
284
+ allowedGuildIds?: string[];
285
+ workspaceScope?: AgentChannelWorkspaceScope;
286
+ [key: string]: unknown;
287
+ }
288
+ interface AgentPancakeChannelConfig {
289
+ id?: string;
290
+ pageId?: string;
291
+ pageAccessToken?: string;
292
+ webhookSecret?: string;
293
+ senderId?: string;
294
+ workspaceScope?: AgentChannelWorkspaceScope;
295
+ [key: string]: unknown;
296
+ }
297
+ interface AgentZaloChannelConfig {
298
+ id?: string;
299
+ botToken?: string;
300
+ webhookSecret?: string;
301
+ allowedUserIds?: string[];
302
+ workspaceScope?: AgentChannelWorkspaceScope;
303
+ [key: string]: unknown;
304
+ }
305
+
306
+ /**
307
+ * Cron-job types, input normalization, and patch-merge helpers.
308
+ * Provider-agnostic — both the DynamoDB and Convex stores import the
309
+ * normalizer at their create/update entry points so behaviour is
310
+ * symmetric across modes.
311
+ */
312
+
313
+ type CronStatus = "active" | "paused";
314
+ type CronLastStatus = "started" | "completed" | "failed";
315
+ /**
316
+ * One-of run payload mirroring the agent direct API's AgentRunInput: provide a
317
+ * single `input` string (wrapped into one user message) or a full `events` list.
318
+ */
319
+ type CronRunInput = {
320
+ input: string;
321
+ events?: never;
322
+ } | {
323
+ events: ModelMessage[];
324
+ input?: never;
325
+ };
326
+ type CreateCronInput = {
327
+ name: string;
328
+ description?: string;
329
+ agentId: string;
330
+ conversationKey?: string;
331
+ scheduleExpression: string;
332
+ timezone?: string;
333
+ status?: CronStatus;
334
+ } & CronRunInput;
335
+ type UpdateCronInput = {
336
+ name?: string;
337
+ description?: string | null;
338
+ agentId?: string;
339
+ conversationKey?: string | null;
340
+ scheduleExpression?: string;
341
+ timezone?: string | null;
342
+ status?: CronStatus;
343
+ } & ({
344
+ input?: string;
345
+ events?: never;
346
+ } | {
347
+ events?: ModelMessage[];
348
+ input?: never;
349
+ });
350
+
351
+ /**
352
+ * Predefined sandbox sizes — the canonical (vcpu, memoryMb, storageGb) catalog
353
+ * shared by sandbox config validation, the workdir resource mapping, and the
354
+ * Convex `sandboxInstances` mirror. Sizes are the user-facing knob (`config.size`)
355
+ * that reconciles issue #78's tiers with each backend's real limits.
356
+ *
357
+ * The specs are canonical/advisory: workdir applies them as create-time resources
358
+ * (clamping vcpu to its allowed set); MicroVM bakes size into the image so the
359
+ * specs are display-only there; daytona/e2b/vercel size natively. The control-plane
360
+ * mirror type lives here too so the Convex writer and the executors share one shape
361
+ * without importing across the _shared/harness boundary.
362
+ */
363
+
364
+ type SandboxSize = "tiny" | "xsmall" | "small" | "medium" | "large";
365
+
366
+ /**
367
+ * Sandbox config: account-scoped, reusable sandbox definitions referenced by
368
+ * agents via `config.sandbox`. A sandbox is a collection of Claude-Code-style
369
+ * tools (bash/read/write/edit/glob/grep) backed by a provider. Validation +
370
+ * the public projection live here; the
371
+ * DynamoDB / Convex stores call these at their create/update entry points.
372
+ * Stored encrypted at rest because `envVars`/`options` may hold secrets.
373
+ */
374
+
375
+ type SandboxProvider = "sandbox" | "lambda" | "e2b" | "daytona" | "vercel";
376
+ type SandboxRuntimeName = "bash" | "python" | "node";
377
+ type SandboxPermissionMode = "edit" | "ask" | "bypass";
378
+ type SandboxNetworkMode = "allow-all" | "deny-all" | "restricted";
379
+ interface SandboxLifecycleConfig {
380
+ idleTimeoutSeconds?: number;
381
+ maxLifetimeSeconds?: number;
382
+ }
383
+ interface SandboxNetworkConfig {
384
+ mode: SandboxNetworkMode;
385
+ allowDomains?: string[];
386
+ allowCidrs?: string[];
387
+ }
388
+ interface SandboxConfig {
389
+ provider: SandboxProvider;
390
+ size?: SandboxSize;
391
+ snapshot?: string;
392
+ runtimes?: SandboxRuntimeName[];
393
+ network?: SandboxNetworkConfig;
394
+ permissionMode?: SandboxPermissionMode;
395
+ persistent?: boolean;
396
+ lifecycle?: SandboxLifecycleConfig;
397
+ onCreate?: string[];
398
+ onResume?: string[];
399
+ timeout?: number;
400
+ memoryLimit?: number;
401
+ outputLimitBytes?: number;
402
+ envVars?: Record<string, undefined | string>;
403
+ options?: Record<string, unknown>;
404
+ }
405
+
406
+ /**
407
+ * Workspace config: account-scoped, reusable workspace definitions referenced by
408
+ * agents via `config.workspaces[].workspaceId`. A workspace is the persistent
409
+ * S3-backed filesystem mounted into a sandbox; agents referencing the same
410
+ * workspaceId share the same files. Holds no secrets, so it is stored in
411
+ * plaintext (unlike sandbox config). Validation + the public projection live
412
+ * here; the DynamoDB / Convex stores call these at create/update.
413
+ */
414
+ declare const WORKSPACE_STORAGE_PROVIDERS: readonly ["s3"];
415
+ type WorkspaceStorageProvider = (typeof WORKSPACE_STORAGE_PROVIDERS)[number];
416
+ type WorkspaceStorageAuth = {
417
+ type: "managed";
418
+ } | {
419
+ type: "assumeRole";
420
+ roleArn: string;
421
+ externalId?: string;
422
+ };
423
+ interface WorkspaceStorageConfig {
424
+ provider: WorkspaceStorageProvider;
425
+ bucket?: string;
426
+ region?: string;
427
+ endpoint?: string;
428
+ prefix?: string;
429
+ auth?: WorkspaceStorageAuth;
430
+ }
431
+ interface WorkspaceConfig {
432
+ storage: WorkspaceStorageConfig;
433
+ isolation?: boolean;
434
+ harness?: {
435
+ enabled?: boolean;
436
+ };
437
+ }
438
+
439
+ /**
440
+ * Wire types for the public account-manage and harness APIs. These mirror
441
+ * the deployed API contract (docs/api-reference/openapi.yaml is the source
442
+ * of truth); they are intentionally independent of the runtime internals so
443
+ * the SDK keeps working when the runtime is ported.
444
+ */
445
+
446
+ interface Cron {
447
+ accountId: string;
448
+ cronId: string;
449
+ name: string;
450
+ description?: string;
451
+ agentId: string;
452
+ events: ModelMessage[];
453
+ conversationKey?: string;
454
+ scheduleExpression: string;
455
+ timezone?: string;
456
+ status: CronStatus;
457
+ createdAt: string;
458
+ updatedAt: string;
459
+ lastInvokedAt?: string;
460
+ lastStatus?: CronLastStatus;
461
+ lastError?: string;
462
+ }
463
+ interface CronRun {
464
+ accountId: string;
465
+ cronId: string;
466
+ runId: string;
467
+ eventId: string;
468
+ conversationKey: string;
469
+ status: CronLastStatus;
470
+ result?: unknown;
471
+ error?: string;
472
+ startedAt: string;
473
+ completedAt?: string;
474
+ }
475
+ interface Skill {
476
+ path: string;
477
+ name: string;
478
+ description: string;
479
+ files?: Array<{
480
+ path: string;
481
+ size?: number;
482
+ }>;
483
+ }
484
+
485
+ /**
486
+ * Account config-plane client for the broods public account REST API.
487
+ *
488
+ * This is the DYNAMIC counterpart to the config-first `broods dev` / `broods
489
+ * deploy` flow: `broods dev` syncs the predefined resources declared in your
490
+ * `broods/` folder, while `BroodsAccountClient` creates and mutates the full
491
+ * account config plane at runtime — agents, sandboxes (config + lifecycle),
492
+ * workspaces (config + files), tools, policies, skills, crons, and the account
493
+ * itself — e.g. a multi-tenant app provisioning one agent per customer from its
494
+ * own backend.
495
+ *
496
+ * Kept intentionally standalone (import from `broods/account`): pure fetch,
497
+ * no Node built-ins, no `.env` file loading — so it runs in edge/worker
498
+ * runtimes such as Convex actions, Cloudflare Workers, and the browser-less
499
+ * server runtimes, as well as Node and Bun.
500
+ *
501
+ * Auth: every call sends `Authorization: Bearer {accountSecret}` to
502
+ * `{baseUrl}/v1/...`. Secrets inside agent configs are encrypted at rest by
503
+ * the platform and come back redacted (`********`) on reads.
504
+ */
505
+
506
+ interface BroodsAccountClientOptions {
507
+ /** Base URL of the broods gateway. Falls back to `BROODS_BASE_URL`, then `https://gateway.broods.app`. */
508
+ baseUrl?: string;
509
+ /** Account secret used as the Bearer token. Falls back to `BROODS_ACCOUNT_SECRET`. */
510
+ accountSecret?: string;
511
+ fetch?: typeof fetch;
512
+ }
513
+ /** Public account record returned by `GET /v1/account`. */
514
+ interface BroodsAccount {
515
+ accountId: string;
516
+ username: string;
517
+ status: string;
518
+ [key: string]: unknown;
519
+ }
520
+ /** Public agent record; `config` comes back with secret values redacted. */
521
+ interface AccountAgent {
522
+ accountId: string;
523
+ agentId: string;
524
+ name: string;
525
+ description?: string;
526
+ status: string;
527
+ config: AgentConfig;
528
+ createdAt: string;
529
+ updatedAt: string;
530
+ }
531
+ interface CreateAgentResult {
532
+ accountId: string;
533
+ agentId: string;
534
+ name: string;
535
+ description?: string;
536
+ }
537
+ /** Fields accepted by `PATCH /v1/agents/{id}`. `config` is deep-merged; `null` values delete keys. */
538
+ interface UpdateAgentInput {
539
+ name?: string;
540
+ description?: string | null;
541
+ config?: unknown;
542
+ }
543
+ /** Public workspace record returned by the workspaces routes. */
544
+ interface AccountWorkspace {
545
+ accountId: string;
546
+ workspaceId: string;
547
+ name: string;
548
+ description?: string;
549
+ config: WorkspaceConfig;
550
+ createdAt: string;
551
+ updatedAt: string;
552
+ }
553
+ /** One entry of a workspace file listing (`GET /v1/workspaces/{id}/files`). */
554
+ interface WorkspaceFileEntry {
555
+ path: string;
556
+ name: string;
557
+ isFolder: boolean;
558
+ sizeBytes?: number;
559
+ updatedAt?: string;
560
+ }
561
+ /** Public sandbox config record; `config` comes back with secret values (e.g. `envVars`) redacted. */
562
+ interface AccountSandbox {
563
+ accountId: string;
564
+ sandboxId: string;
565
+ name: string;
566
+ description?: string;
567
+ config: SandboxConfig;
568
+ createdAt: string;
569
+ updatedAt: string;
570
+ [key: string]: unknown;
571
+ }
572
+ /** Public agent-policy record returned by the policies routes. */
573
+ interface AccountPolicy {
574
+ accountId: string;
575
+ policyId: string;
576
+ name: string;
577
+ description?: string;
578
+ document: AgentPolicyDocument;
579
+ status: string;
580
+ createdAt: string;
581
+ updatedAt: string;
582
+ }
583
+ /** Public uploaded-tool record returned by the tools routes. */
584
+ interface AccountTool {
585
+ accountId: string;
586
+ toolId: string;
587
+ name: string;
588
+ description: string;
589
+ inputSchema: unknown;
590
+ sha256: string;
591
+ runtime: "isolate" | "sandbox";
592
+ defaultConfig?: unknown;
593
+ status: string;
594
+ createdAt: string;
595
+ updatedAt: string;
596
+ deletedAt?: string;
597
+ }
598
+ /** Fields accepted by `POST /v1/tools`. `bundle` is already-bundled JavaScript module source. */
599
+ interface CreateToolInput {
600
+ name: string;
601
+ description: string;
602
+ inputSchema: unknown;
603
+ bundle: string;
604
+ runtime?: "isolate" | "sandbox";
605
+ defaultConfig?: unknown;
606
+ }
607
+ /** Fields accepted by `PATCH /v1/tools/{toolId}`; every field is optional. Omitting `bundle` keeps the stored one. */
608
+ interface UpdateToolInput {
609
+ name?: string;
610
+ description?: string;
611
+ inputSchema?: unknown;
612
+ bundle?: string;
613
+ runtime?: "isolate" | "sandbox";
614
+ defaultConfig?: unknown;
615
+ }
616
+ /**
617
+ * Body of a skill upload (`POST /v1/skills`, `PUT /v1/skills/{skillName}`).
618
+ * `json` needs `name`/`description`/`content`; `files` needs base64 `files`
619
+ * including a root `SKILL.md`; `github` needs a tree `url`.
620
+ */
621
+ interface SkillUploadInput {
622
+ source: "json" | "files" | "github";
623
+ name?: string;
624
+ description?: string;
625
+ content?: string;
626
+ files?: Array<{
627
+ path: string;
628
+ contentBase64: string;
629
+ contentType?: string;
630
+ }>;
631
+ url?: string;
632
+ }
633
+ /** Result of `POST /v1/account/rotate-secret`. The returned `secret` is shown once; the old secret stops working immediately. */
634
+ interface RotateSecretResult {
635
+ account: BroodsAccount;
636
+ secret: string;
637
+ }
638
+ /** Result of `DELETE /v1/account`: the account and all account-scoped data are removed; `cleanup` reports per-resource deletion counts. */
639
+ interface DeleteAccountResult {
640
+ deleted: boolean;
641
+ cleanup?: Record<string, number>;
642
+ }
643
+ /** Result of a suspend/resume/terminate sandbox lifecycle action. */
644
+ interface SandboxLifecycleResult {
645
+ status: string;
646
+ }
647
+ /** Result of `POST /v1/sandboxes/{id}/snapshot`. */
648
+ interface SandboxSnapshotResult {
649
+ status: string;
650
+ snapshotId?: string;
651
+ externalImageId?: string;
652
+ }
653
+ /** Sealed ticket from `POST /v1/sandboxes/{id}/terminal`; hand `token` to the gateway terminal WebSocket at `websocketPath`. */
654
+ interface SandboxTerminalTicket {
655
+ token: string;
656
+ expiresAt: number;
657
+ websocketPath: string;
658
+ }
659
+ /** Non-2xx response from the account API (404s on id routes return null instead). */
660
+ declare class BroodsAccountApiError extends Error {
661
+ readonly status: number;
662
+ readonly body: string;
663
+ constructor(method: string, path: string, status: number, body: string);
664
+ }
665
+ /**
666
+ * Typed client for the broods account config API. All `get`/`update`/`delete`
667
+ * methods return `null`/`false` when the resource does not exist (HTTP 404) so
668
+ * callers can implement upsert flows without try/catch; every other non-2xx
669
+ * status throws {@link BroodsAccountApiError}.
670
+ */
671
+ declare class BroodsAccountClient {
672
+ private readonly baseUrl;
673
+ private readonly accountSecret;
674
+ private readonly fetchImpl;
675
+ constructor(options?: BroodsAccountClientOptions);
676
+ /** The account this secret belongs to. Its `accountId` is the first segment of channel webhook URLs. */
677
+ getAccount(): Promise<BroodsAccount>;
678
+ /** Update account metadata (username/description). Returns null when the account is gone. Runtime config is managed through the agent endpoints. */
679
+ updateAccount(patch: {
680
+ username?: string;
681
+ description?: string | null;
682
+ }): Promise<BroodsAccount | null>;
683
+ /** Rotate the account secret. The returned `secret` is shown once and the current secret stops working immediately, so persist it before the process exits. */
684
+ rotateSecret(): Promise<RotateSecretResult>;
685
+ /** Delete this account and cascade-clean every account-scoped resource. `cleanup` reports per-resource deletion counts. */
686
+ deleteAccount(): Promise<DeleteAccountResult>;
687
+ /**
688
+ * Provider webhook URL for one of an agent's channels. Paste this into the
689
+ * provider's webhook settings (Slack Event Subscriptions, Zalo OA webhook,
690
+ * Pancake page webhook). Routing is per account + agent, so each agent's
691
+ * channels are isolated from every other agent's.
692
+ */
693
+ webhookUrl(accountId: string, agentId: string, channelType: string): string;
694
+ listAgents(): Promise<AccountAgent[]>;
695
+ createAgent(input: {
696
+ name: string;
697
+ description?: string;
698
+ config: unknown;
699
+ }): Promise<CreateAgentResult>;
700
+ getAgent(agentId: string): Promise<AccountAgent | null>;
701
+ /** PATCH an agent. `config` deep-merges into the stored config; `null` leaves delete keys. Returns null when the agent is gone. */
702
+ updateAgent(agentId: string, patch: UpdateAgentInput): Promise<AccountAgent | null>;
703
+ deleteAgent(agentId: string): Promise<boolean>;
704
+ listCrons(): Promise<Cron[]>;
705
+ createCron(input: CreateCronInput): Promise<Cron>;
706
+ getCron(cronId: string): Promise<Cron | null>;
707
+ updateCron(cronId: string, patch: UpdateCronInput): Promise<Cron | null>;
708
+ deleteCron(cronId: string): Promise<boolean>;
709
+ /** Run history for a cron, newest first. Returns [] when the cron is gone. */
710
+ listCronRuns(cronId: string, options?: {
711
+ limit?: number;
712
+ }): Promise<CronRun[]>;
713
+ listWorkspaces(): Promise<AccountWorkspace[]>;
714
+ createWorkspace(input: {
715
+ name: string;
716
+ description?: string;
717
+ config?: unknown;
718
+ }): Promise<AccountWorkspace>;
719
+ getWorkspace(workspaceId: string): Promise<AccountWorkspace | null>;
720
+ updateWorkspace(workspaceId: string, patch: {
721
+ name?: string;
722
+ description?: string | null;
723
+ config?: unknown;
724
+ }): Promise<AccountWorkspace | null>;
725
+ deleteWorkspace(workspaceId: string): Promise<boolean>;
726
+ /** Flat listing of every file in the workspace's S3-backed filesystem. Returns [] when the workspace is gone. */
727
+ listWorkspaceFiles(workspaceId: string): Promise<WorkspaceFileEntry[]>;
728
+ /** Short-lived download URL for one workspace file. Returns null when the workspace or file is gone. */
729
+ getWorkspaceFileUrl(workspaceId: string, path: string): Promise<string | null>;
730
+ /** Upload or replace one workspace file from base64 content. Throws when the workspace is gone (404). */
731
+ uploadWorkspaceFile(workspaceId: string, input: {
732
+ path: string;
733
+ contentBase64: string;
734
+ contentType?: string;
735
+ }): Promise<WorkspaceFileEntry>;
736
+ /** Rename a workspace file or folder. Returns false when the workspace or source path is gone. */
737
+ renameWorkspaceFile(workspaceId: string, path: string, newPath: string): Promise<boolean>;
738
+ /** Delete a workspace file or folder. Returns false when the workspace or path is gone. */
739
+ deleteWorkspaceFile(workspaceId: string, path: string): Promise<boolean>;
740
+ listSandboxes(): Promise<AccountSandbox[]>;
741
+ createSandbox(input: {
742
+ name: string;
743
+ description?: string;
744
+ config?: unknown;
745
+ }): Promise<AccountSandbox>;
746
+ getSandbox(sandboxId: string): Promise<AccountSandbox | null>;
747
+ /** PATCH a sandbox config. `config` fully replaces the stored config. Returns null when the sandbox is gone. */
748
+ updateSandbox(sandboxId: string, patch: {
749
+ name?: string;
750
+ description?: string | null;
751
+ config?: unknown;
752
+ }): Promise<AccountSandbox | null>;
753
+ deleteSandbox(sandboxId: string): Promise<boolean>;
754
+ /** Suspend a persistent sandbox reservation. Throws on 404/403/409 (missing sandbox, foreign reservation, or unsupported provider). */
755
+ suspendSandbox(sandboxId: string, reservationKey: string): Promise<SandboxLifecycleResult>;
756
+ /** Resume a persistent sandbox reservation. Throws on 404/403/409. */
757
+ resumeSandbox(sandboxId: string, reservationKey: string): Promise<SandboxLifecycleResult>;
758
+ /** Terminate a persistent sandbox reservation and drop its live-instance row. Throws on 404/403/409. */
759
+ terminateSandbox(sandboxId: string, reservationKey: string): Promise<SandboxLifecycleResult>;
760
+ /** Snapshot a persistent sandbox reservation into a reusable image (self-hosted `sandbox` provider). Throws on 404/403/409. */
761
+ snapshotSandbox(sandboxId: string, reservationKey: string, name: string): Promise<SandboxSnapshotResult>;
762
+ /** Mint a short-lived sealed ticket for an interactive PTY session on a persistent sandbox (`sandbox`/`lambda` providers). Throws on 404/403/409. */
763
+ openSandboxTerminal(sandboxId: string, reservationKey: string): Promise<SandboxTerminalTicket>;
764
+ listTools(): Promise<AccountTool[]>;
765
+ createTool(input: CreateToolInput): Promise<AccountTool>;
766
+ getTool(toolId: string): Promise<AccountTool | null>;
767
+ /** PATCH an uploaded tool. Omitting `bundle` keeps the stored bundle and runtime. Returns null when the tool is gone. */
768
+ updateTool(toolId: string, patch: UpdateToolInput): Promise<AccountTool | null>;
769
+ deleteTool(toolId: string): Promise<boolean>;
770
+ listPolicies(): Promise<AccountPolicy[]>;
771
+ createPolicy(input: {
772
+ name: string;
773
+ description?: string;
774
+ document: AgentPolicyDocument;
775
+ }): Promise<AccountPolicy>;
776
+ getPolicy(policyId: string): Promise<AccountPolicy | null>;
777
+ /** PATCH a policy. `description: null` clears it. Returns null when the policy is gone. */
778
+ updatePolicy(policyId: string, patch: {
779
+ name?: string;
780
+ description?: string | null;
781
+ document?: AgentPolicyDocument;
782
+ status?: string;
783
+ }): Promise<AccountPolicy | null>;
784
+ deletePolicy(policyId: string): Promise<boolean>;
785
+ /** All skills for the account, each with its `<accountId>/<name>` path. */
786
+ listSkills(): Promise<Skill[]>;
787
+ /** Upload a new skill from JSON content, a base64 file bundle, or a GitHub tree URL. Every bundle must include a root `SKILL.md`. */
788
+ createSkill(input: SkillUploadInput): Promise<Skill>;
789
+ getSkill(skillName: string): Promise<Skill | null>;
790
+ /** Replace a skill's bundle in place (`PUT`). Throws when the skill is gone (404). */
791
+ uploadSkill(skillName: string, input: SkillUploadInput): Promise<Skill>;
792
+ deleteSkill(skillName: string): Promise<boolean>;
793
+ /** POST a sandbox lifecycle action, throwing on any non-2xx (including 404, since these are not upsert flows). */
794
+ private sandboxAction;
795
+ private request;
796
+ }
797
+
798
+ export { BroodsAccountApiError, BroodsAccountClient };
799
+ export type { AccountAgent, AccountPolicy, AccountSandbox, AccountTool, AccountWorkspace, BroodsAccount, BroodsAccountClientOptions, CreateAgentResult, CreateToolInput, DeleteAccountResult, RotateSecretResult, SandboxLifecycleResult, SandboxSnapshotResult, SandboxTerminalTicket, SkillUploadInput, UpdateAgentInput, UpdateToolInput, WorkspaceFileEntry };