broods 0.25.0 → 0.27.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/index.d.ts CHANGED
@@ -1,5 +1,12 @@
1
1
  import { SystemModelMessage, LanguageModelCallOptions, RequestOptions, streamText, JSONSchema7, ModelMessage, TextStreamPart, ToolSet } from 'ai';
2
2
 
3
+ /**
4
+ * Account-owned code hook upload validation for Convex config-plane sync.
5
+ * Mirrors core's account hook upload contract without requiring the Node runtime.
6
+ */
7
+ 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"];
8
+ type AgentHookEventName = (typeof AGENT_HOOK_EVENT_NAMES)[number];
9
+
3
10
  /**
4
11
  * Every Vercel AI SDK provider that ships language models, plus `custom`
5
12
  * (any OpenAI-compatible endpoint) and `minimax`. Image-, speech- and
@@ -114,6 +121,8 @@ interface AgentConfig {
114
121
  hooks?: AgentHooksConfig;
115
122
  channels?: AgentChannelsConfig;
116
123
  tools?: AgentToolsConfig;
124
+ /** Connected MCP servers, keyed by their config-plane row id (#331). */
125
+ mcpServers?: AgentMcpServersConfig;
117
126
  /**
118
127
  * Tool names withheld for this run, applied after the tool set is built.
119
128
  * Set by a channel record; a channel can take a tool away, never add one.
@@ -269,8 +278,7 @@ interface AgentWebhookHookConfig {
269
278
  [key: string]: unknown;
270
279
  }
271
280
  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";
272
- type AgentChannelHookEventName = "channel.message.received" | "channel.message.sending";
273
- type AgentHookEventName = AgentLifecycleEventName | AgentChannelHookEventName;
281
+
274
282
  type AgentToolsConfig = Record<string, AgentToolConfig>;
275
283
  interface AgentToolConfig {
276
284
  enabled?: boolean;
@@ -279,6 +287,15 @@ interface AgentToolConfig {
279
287
  config?: Record<string, unknown>;
280
288
  [key: string]: unknown;
281
289
  }
290
+ type AgentMcpServersConfig = Record<string, AgentMcpServerConfig>;
291
+ interface AgentMcpServerConfig {
292
+ enabled?: boolean;
293
+ /** Applies to every tool the server exposes. */
294
+ needsApproval?: boolean;
295
+ /** Extra request headers; values resolved from account env vars at sync. */
296
+ headers?: Record<string, string>;
297
+ [key: string]: unknown;
298
+ }
282
299
  interface AgentChannelsConfig {
283
300
  telegram?: AgentTelegramChannelConfig;
284
301
  github?: AgentGitHubChannelConfig;
@@ -385,7 +402,9 @@ interface AgentZaloChannelConfig {
385
402
  }
386
403
 
387
404
  /**
388
- * Cron-job records, input normalization, and patch-merge helpers.
405
+ * Cron-job records and patch-merge helpers for the runtime. Input
406
+ * normalization lives in the config plane (packages/convex/model/cronRules.ts,
407
+ * the single home of those rules).
389
408
  */
390
409
 
391
410
  type CronStatus = "active" | "paused";
@@ -427,48 +446,45 @@ type UpdateCronInput = {
427
446
  });
428
447
 
429
448
  /**
430
- * Predefined sandbox sizes — the canonical (vcpu, memoryMb, storageGb) catalog
431
- * shared by sandbox config validation, the workdir resource mapping, and the
432
- * Convex `sandboxInstances` mirror. Sizes are the user-facing knob (`config.size`)
433
- * that reconciles issue #78's tiers with each backend's real limits.
434
- *
435
- * The specs are canonical/advisory: workdir applies them as create-time resources
436
- * (clamping vcpu to its allowed set); MicroVM bakes size into the image so the
437
- * specs are display-only there; daytona/e2b/vercel size natively. The control-plane
438
- * mirror type lives here too so the Convex writer and the executors share one shape
439
- * without importing across the _shared/harness boundary.
449
+ * Sandbox-config validation for the Convex config plane. Ports core's former
450
+ * storage/sandbox-config.ts normalizer so the public /v1/sandboxes contract
451
+ * is unchanged. The public projection lives in ./responses.ts.
440
452
  */
441
-
442
- type SandboxSize = "tiny" | "xsmall" | "small" | "medium" | "large";
443
-
453
+ declare const SANDBOX_PROVIDERS: readonly ["sandbox", "lambda", "e2b", "daytona", "vercel"];
454
+ declare const SANDBOX_RUNTIMES: readonly ["bash", "python", "node"];
455
+ declare const SANDBOX_PERMISSION_MODES: readonly ["edit", "ask", "bypass"];
456
+ declare const SANDBOX_NETWORK_MODES: readonly ["allow-all", "deny-all", "restricted"];
457
+ declare const SANDBOX_SIZE_NAMES: readonly ["tiny", "xsmall", "small", "medium", "large"];
458
+ type SandboxProvider = (typeof SANDBOX_PROVIDERS)[number];
459
+ type RuntimeName = (typeof SANDBOX_RUNTIMES)[number];
460
+ type PermissionMode = (typeof SANDBOX_PERMISSION_MODES)[number];
461
+ type NetworkMode = (typeof SANDBOX_NETWORK_MODES)[number];
462
+ type SandboxSize = (typeof SANDBOX_SIZE_NAMES)[number];
444
463
  /**
445
- * Sandbox config: account-scoped, reusable sandbox definitions referenced by
446
- * agents via `config.sandbox`. A sandbox is a collection of Claude-Code-style
447
- * tools (bash/read/write/edit/glob/grep) backed by a provider. Validation and
448
- * the public projection live here.
449
- * Stored encrypted at rest because `envVars`/`options` may hold secrets.
464
+ * Idle and maximum lifetime controls for a persistent sandbox.
450
465
  */
451
-
452
- type SandboxProvider = "sandbox" | "lambda" | "e2b" | "daytona" | "vercel";
453
- type SandboxRuntimeName = "bash" | "python" | "node";
454
- type SandboxPermissionMode = "edit" | "ask" | "bypass";
455
- type SandboxNetworkMode = "allow-all" | "deny-all" | "restricted";
456
466
  interface SandboxLifecycleConfig {
457
467
  idleTimeoutSeconds?: number;
458
468
  maxLifetimeSeconds?: number;
459
469
  }
470
+ /**
471
+ * Provider-normalized sandbox network policy.
472
+ */
460
473
  interface SandboxNetworkConfig {
461
- mode: SandboxNetworkMode;
474
+ mode: NetworkMode;
462
475
  allowDomains?: string[];
463
476
  allowCidrs?: string[];
464
477
  }
478
+ /**
479
+ * Account-scoped reusable sandbox configuration referenced by agents.
480
+ */
465
481
  interface SandboxConfig {
466
482
  provider: SandboxProvider;
467
483
  size?: SandboxSize;
468
484
  snapshot?: string;
469
- runtimes?: SandboxRuntimeName[];
485
+ runtimes?: RuntimeName[];
470
486
  network?: SandboxNetworkConfig;
471
- permissionMode?: SandboxPermissionMode;
487
+ permissionMode?: PermissionMode;
472
488
  persistent?: boolean;
473
489
  lifecycle?: SandboxLifecycleConfig;
474
490
  onCreate?: string[];
@@ -481,12 +497,12 @@ interface SandboxConfig {
481
497
  }
482
498
 
483
499
  /**
484
- * Workspace config: account-scoped, reusable workspace definitions referenced by
485
- * agents via `config.workspaces[].workspaceId`. A workspace is the persistent
486
- * S3-backed filesystem mounted into a sandbox; agents referencing the same
487
- * workspaceId share the same files. Holds no secrets, so it is stored in
488
- * plaintext (unlike sandbox config). Validation and the public projection live
489
- * here.
500
+ * Workspace-config validation for the Convex config plane. Ports core's
501
+ * former storage/workspace-config.ts normalizer so the public /v1/workspaces
502
+ * contract is unchanged. Workspace config holds no secrets (a roleArn is not
503
+ * a secret), so it is stored and returned in plaintext. Pure module — safe
504
+ * for the default Convex runtime. The public projection lives in
505
+ * ./responses.ts.
490
506
  */
491
507
  declare const WORKSPACE_STORAGE_PROVIDERS: readonly ["s3"];
492
508
  type WorkspaceStorageProvider = (typeof WORKSPACE_STORAGE_PROVIDERS)[number];
@@ -505,43 +521,72 @@ interface WorkspaceStorageConfig {
505
521
  prefix?: string;
506
522
  auth?: WorkspaceStorageAuth;
507
523
  }
508
- interface WorkspaceHarnessConfig {
509
- workspace?: {
510
- enabled?: boolean;
511
- };
512
- memory?: {
513
- enabled?: boolean;
514
- };
515
- }
516
524
  interface WorkspaceConfig {
517
525
  storage: WorkspaceStorageConfig;
518
526
  isolation?: boolean;
519
- harness?: WorkspaceHarnessConfig;
527
+ harness?: {
528
+ workspace?: {
529
+ enabled?: boolean;
530
+ };
531
+ memory?: {
532
+ enabled?: boolean;
533
+ };
534
+ };
520
535
  }
521
536
 
522
537
  /**
523
- * Agent policy contracts and validation.
524
- * Runtime decisions are made by OPA using the same document/input shape.
538
+ * Agent-policy validation for the Convex config plane. Ports core's public
539
+ * CRUD normalizer so policy documents keep the account-management API
540
+ * contract. The public projection lives in ./responses.ts.
541
+ */
542
+ declare const AGENT_POLICY_ACTIONS: readonly ["agent.invoke", "tool.call", "workspace.read", "workspace.write", "workspace.exec", "subagent.run", "skill.load"];
543
+ /**
544
+ * API action namespace for account roles: one read/write pair per config-plane
545
+ * resource route. Roles carry the same PolicyDocument shape as agent policies;
546
+ * each caller passes its action set to `normalizePolicyDocument`.
547
+ */
548
+ declare const API_POLICY_ACTIONS: readonly ["account:read", "account:write", "agents:read", "agents:write", "channels:read", "channels:write", "crons:read", "crons:write", "env:read", "env:write", "hooks:read", "hooks:write", "mcp:read", "mcp:write", "policies:read", "policies:write", "sandboxes:read", "sandboxes:write", "skills:read", "skills:write", "tools:read", "tools:write", "workspaces:read", "workspaces:write"];
549
+ type AgentPolicyAction = (typeof AGENT_POLICY_ACTIONS)[number];
550
+ type ApiPolicyAction = (typeof API_POLICY_ACTIONS)[number];
551
+ type PolicyAction = AgentPolicyAction | ApiPolicyAction;
552
+ /**
553
+ * One optional predicate on a policy rule.
525
554
  */
526
- declare const POLICY_ACTIONS: readonly ["agent.invoke", "tool.call", "workspace.read", "workspace.write", "workspace.exec", "subagent.run", "skill.load"];
527
- type PolicyAction = (typeof POLICY_ACTIONS)[number];
528
- type PolicyEffect = "allow" | "deny";
529
- type PolicyMode = "enforce" | "audit";
530
- type PolicyConditionOperator = "equals" | "notEquals" | "in" | "notIn" | "prefix" | "contains";
531
555
  interface PolicyCondition {
532
556
  attribute: string;
533
557
  operator: PolicyConditionOperator;
534
558
  value: string | number | boolean | string[] | number[] | boolean[];
535
559
  }
560
+ type PolicyConditionOperator = "equals" | "notEquals" | "in" | "notIn" | "prefix" | "contains";
561
+ /**
562
+ * Versioned policy document accepted by account-management CRUD.
563
+ */
564
+ interface PolicyDocument {
565
+ version: 1;
566
+ /** How hard this policy bites where it is attached. Omitted reads as `audit`. */
567
+ mode?: "enforce" | "audit";
568
+ rules: PolicyRule[];
569
+ }
570
+ type PolicyEffect = "allow" | "deny";
571
+ /**
572
+ * Resource selector fields supported by policy rules.
573
+ */
536
574
  interface PolicyResourceSelector {
537
575
  toolNames?: string[];
538
576
  toolIds?: string[];
577
+ /** MCP registration ids, for scoping tool.call rules per server (#331). */
578
+ mcpIds?: string[];
539
579
  workspaceIds?: string[];
540
580
  workspaceNames?: string[];
541
581
  filePaths?: string[];
542
582
  subagentIds?: string[];
543
583
  skillPaths?: string[];
584
+ /** Config-plane resource ids for API-action rules; "*" matches every id. */
585
+ resourceIds?: string[];
544
586
  }
587
+ /**
588
+ * One allow/deny rule inside a policy document.
589
+ */
545
590
  interface PolicyRule {
546
591
  id: string;
547
592
  effect: PolicyEffect;
@@ -549,26 +594,13 @@ interface PolicyRule {
549
594
  resources?: PolicyResourceSelector;
550
595
  conditions?: PolicyCondition[];
551
596
  }
552
- interface PolicyDocument {
553
- version: 1;
554
- /**
555
- * How hard this policy bites. `audit` records what it would have done and
556
- * blocks nothing; `enforce` lets its deny rules refuse, and switches the
557
- * places it is attached to over to default-deny. Omitted reads as `audit`,
558
- * so a freshly written policy can never break a running agent.
559
- */
560
- mode?: PolicyMode;
561
- rules: PolicyRule[];
562
- }
563
597
 
564
598
  /**
565
- * Channel records: an account-scoped row per real place a team talks — one Slack
566
- * channel, one Discord channel, one repository. It binds that place to an agent
567
- * and adds instructions, workspaces, policies and roles scoped to it.
568
- * Distinct from `config.channels`, which holds one adapter's credentials.
569
- * A record narrows and adds; it never grants capability the agent lacks.
599
+ * Channel record validation for the config plane — the single home of the
600
+ * normalizers core's `shared/domain/channel-record.ts` re-exports. Kept free
601
+ * of Convex imports so the rules stay unit-testable; the public projection
602
+ * lives in ./responses.ts.
570
603
  */
571
-
572
604
  /** Where a reply lands: its own thread, or wherever the message came from. */
573
605
  declare const CHANNEL_REPLY_TARGETS: readonly ["thread", "source"];
574
606
  type ChannelReplyIn = (typeof CHANNEL_REPLY_TARGETS)[number];
@@ -685,7 +717,7 @@ interface ZaloSource {
685
717
  * import it without pulling the Convex server module graph into its typecheck.
686
718
  */
687
719
  type CliManifestResource = {
688
- kind: "agent" | "workspace" | "sandbox" | "cron" | "skill" | "tool" | "hook" | "policy" | "channelRecord";
720
+ kind: "agent" | "workspace" | "sandbox" | "cron" | "skill" | "tool" | "hook" | "mcp" | "policy" | "channelRecord";
689
721
  name: string;
690
722
  description?: string;
691
723
  config: unknown;
@@ -698,6 +730,7 @@ type GeneratedIds = {
698
730
  skills: Record<string, string>;
699
731
  tools: Record<string, string>;
700
732
  hooks: Record<string, string>;
733
+ mcpServers: Record<string, string>;
701
734
  policies: Record<string, string>;
702
735
  channelRecords: Record<string, string>;
703
736
  };
@@ -726,7 +759,7 @@ type AgentConfigDoc = Doc<"agentConfigs">;
726
759
  type WorkspaceConfigDoc = Doc<"workspaceConfigs">;
727
760
  type SandboxConfigDoc = Doc<"sandboxConfigs">;
728
761
  type CronDoc = Doc<"crons">;
729
- type CliResourceKind = "agent" | "workspace" | "sandbox" | "cron" | "skill" | "tool" | "policy" | "channelRecord";
762
+ type CliResourceKind = "agent" | "workspace" | "sandbox" | "cron" | "skill" | "tool" | "mcp" | "policy" | "channelRecord";
730
763
 
731
764
  /**
732
765
  * Wire types for the public account-manage and harness APIs. These mirror
@@ -1205,8 +1238,10 @@ declare function normalizeHttpServiceUrl(value: string): string;
1205
1238
  * server runtimes, as well as Node and Bun.
1206
1239
  *
1207
1240
  * Auth: every call sends `Authorization: Bearer {accountSecret}` to
1208
- * `{baseUrl}/v1/...`. Secrets inside agent configs are encrypted at rest by
1209
- * the platform and come back redacted (`********`) on reads.
1241
+ * `{baseUrl}/v1/...` — or a short-lived `fp_sts_` role session token from
1242
+ * `assumeRole()`, limited to what the role's policy allows. Secrets inside
1243
+ * agent configs are encrypted at rest by the platform and come back redacted
1244
+ * (`********`) on reads.
1210
1245
  */
1211
1246
 
1212
1247
  interface BroodsAccountClientOptions {
@@ -1214,6 +1249,12 @@ interface BroodsAccountClientOptions {
1214
1249
  baseUrl?: string;
1215
1250
  /** Account secret used as the Bearer token. Falls back to `BROODS_ACCOUNT_SECRET`. */
1216
1251
  accountSecret?: string;
1252
+ /**
1253
+ * Short-lived `fp_sts_` role session token (from {@link BroodsAccountClient.assumeRole})
1254
+ * used as the Bearer instead of the account secret. The session can only do
1255
+ * what its role's policy allows. Falls back to `BROODS_SESSION_TOKEN`.
1256
+ */
1257
+ sessionToken?: string;
1217
1258
  fetch?: typeof fetch;
1218
1259
  }
1219
1260
  /** Public account record returned by `GET /v1/account`. */
@@ -1293,6 +1334,29 @@ interface AccountPolicy {
1293
1334
  createdAt: string;
1294
1335
  updatedAt: string;
1295
1336
  }
1337
+ /**
1338
+ * Public account-role record returned by the roles routes. The policy uses the
1339
+ * API action namespace (`"agents:read"`, `"crons:write"`, ...); `projectId` and
1340
+ * `stageId` bound which stage runtime keys may assume the role.
1341
+ */
1342
+ interface AccountRole {
1343
+ accountId: string;
1344
+ roleId: string;
1345
+ name: string;
1346
+ projectId?: string;
1347
+ stageId?: string;
1348
+ status: "active" | "disabled";
1349
+ policy: PolicyDocument;
1350
+ createdAt: string;
1351
+ updatedAt: string;
1352
+ }
1353
+ /** Short-lived role session minted by `POST /v1/account/assume-role`. */
1354
+ interface AssumeRoleResult {
1355
+ /** `fp_sts_` bearer token; pass it as `sessionToken` to a new client. */
1356
+ token: string;
1357
+ /** ISO timestamp when the session stops working. */
1358
+ expiresAt: string;
1359
+ }
1296
1360
  /**
1297
1361
  * One real place a team talks — a Slack channel, a Discord channel, a repo —
1298
1362
  * bound to an agent. The runtime reads it on the inbound webhook to decide who
@@ -1386,6 +1450,46 @@ interface UpdateToolInput {
1386
1450
  runtime?: "isolate" | "sandbox";
1387
1451
  defaultConfig?: unknown;
1388
1452
  }
1453
+ /** Public MCP server registration returned by the `/v1/mcp` routes (#331). */
1454
+ interface AccountMcpServer {
1455
+ accountId: string;
1456
+ serverId: string;
1457
+ projectId: string;
1458
+ stageId: string;
1459
+ name: string;
1460
+ description?: string;
1461
+ transport: "http" | "hosted";
1462
+ /** External servers only; a hosted row has no endpoint of its own. */
1463
+ url?: string;
1464
+ /** Hosted servers only: content hash of the uploaded bundle. */
1465
+ sha256?: string;
1466
+ headers?: Record<string, string>;
1467
+ allowedTools?: string[];
1468
+ disabled: boolean;
1469
+ status: string;
1470
+ createdAt: string;
1471
+ updatedAt: string;
1472
+ deletedAt?: string;
1473
+ }
1474
+ /** Fields accepted by `POST /v1/mcp`: `url` connects, `bundle` uploads. */
1475
+ interface CreateMcpServerInput {
1476
+ name: string;
1477
+ description?: string;
1478
+ url?: string;
1479
+ bundle?: string;
1480
+ headers?: Record<string, string>;
1481
+ allowedTools?: string[];
1482
+ }
1483
+ /** Fields accepted by `PATCH /v1/mcp/{serverId}`; every field is optional. */
1484
+ interface UpdateMcpServerInput {
1485
+ name?: string;
1486
+ description?: string;
1487
+ url?: string;
1488
+ bundle?: string;
1489
+ headers?: Record<string, string>;
1490
+ allowedTools?: string[];
1491
+ disabled?: boolean;
1492
+ }
1389
1493
  /**
1390
1494
  * Body of a skill upload (`POST /v1/skills`, `PUT /v1/skills/{skillName}`).
1391
1495
  * `json` needs `name`/`description`/`content`; `files` needs base64 `files`
@@ -1443,7 +1547,7 @@ declare class BroodsAccountApiError extends Error {
1443
1547
  */
1444
1548
  declare class BroodsAccountClient {
1445
1549
  private readonly baseUrl;
1446
- private readonly accountSecret;
1550
+ private readonly bearerToken;
1447
1551
  private readonly fetchImpl;
1448
1552
  constructor(options?: BroodsAccountClientOptions);
1449
1553
  /** The account this secret belongs to. Its `accountId` is the first segment of channel webhook URLs. */
@@ -1453,6 +1557,15 @@ declare class BroodsAccountClient {
1453
1557
  username?: string;
1454
1558
  description?: string | null;
1455
1559
  }): Promise<BroodsAccount | null>;
1560
+ /**
1561
+ * Exchange a role for a short-lived `fp_sts_` session token. Callable with
1562
+ * the account secret, a CLI login token, or a stage runtime key (the latter
1563
+ * only into roles scoped to the key's own project/stage). Construct a new
1564
+ * client with `{ sessionToken: result.token }` to act as the role.
1565
+ */
1566
+ assumeRole(roleId: string, options?: {
1567
+ ttlSeconds?: number;
1568
+ }): Promise<AssumeRoleResult>;
1456
1569
  /** Rotate the account secret. The returned `secret` is shown once and the current secret stops working immediately, so persist it before the process exits. */
1457
1570
  rotateSecret(): Promise<RotateSecretResult>;
1458
1571
  /** Delete this account and cascade-clean every account-scoped resource. `cleanup` reports per-resource deletion counts. */
@@ -1548,6 +1661,12 @@ declare class BroodsAccountClient {
1548
1661
  /** PATCH an uploaded tool. Omitting `bundle` keeps the stored bundle and runtime. Returns null when the tool is gone. */
1549
1662
  updateTool(toolId: string, patch: UpdateToolInput): Promise<AccountTool | null>;
1550
1663
  deleteTool(toolId: string): Promise<boolean>;
1664
+ /** MCP servers are stage-scoped like tools; both scope fields are required. */
1665
+ listMcpServers(scope: ToolScope): Promise<AccountMcpServer[]>;
1666
+ createMcpServer(scope: ToolScope, input: CreateMcpServerInput): Promise<AccountMcpServer>;
1667
+ getMcpServer(serverId: string): Promise<AccountMcpServer | null>;
1668
+ updateMcpServer(serverId: string, patch: UpdateMcpServerInput): Promise<AccountMcpServer | null>;
1669
+ deleteMcpServer(serverId: string): Promise<boolean>;
1551
1670
  listPolicies(): Promise<AccountPolicy[]>;
1552
1671
  createPolicy(input: {
1553
1672
  name: string;
@@ -1563,6 +1682,23 @@ declare class BroodsAccountClient {
1563
1682
  status?: string;
1564
1683
  }): Promise<AccountPolicy | null>;
1565
1684
  deletePolicy(policyId: string): Promise<boolean>;
1685
+ /** Roles are account-secret only: a session cannot list, mint, or edit roles. */
1686
+ listRoles(): Promise<AccountRole[]>;
1687
+ /** Create a role whose policy uses the API action namespace. `projectId`/`stageId` must be provided together. */
1688
+ createRole(input: {
1689
+ name: string;
1690
+ policy: PolicyDocument;
1691
+ projectId?: string;
1692
+ stageId?: string;
1693
+ }): Promise<AccountRole>;
1694
+ getRole(roleId: string): Promise<AccountRole | null>;
1695
+ /** PATCH a role. `status: "disabled"` kills every live session of the role. Returns null when the role is gone. */
1696
+ updateRole(roleId: string, patch: {
1697
+ name?: string;
1698
+ policy?: PolicyDocument;
1699
+ status?: "active" | "disabled";
1700
+ }): Promise<AccountRole | null>;
1701
+ deleteRole(roleId: string): Promise<boolean>;
1566
1702
  listChannels(): Promise<AccountChannel[]>;
1567
1703
  /** Bind one real chat channel to an agent. One active record per place. */
1568
1704
  createChannel(input: {
@@ -1722,7 +1858,7 @@ interface BroodsConfigDefinition {
1722
1858
  readonly [CONFIG_MARKER]: true;
1723
1859
  readonly config: BroodsProjectConfig;
1724
1860
  }
1725
- type ResourceKind = "agent" | "workspace" | "sandbox" | "cron" | "skill" | "tool" | "policy" | "channelRecord";
1861
+ type ResourceKind = "agent" | "workspace" | "sandbox" | "cron" | "skill" | "tool" | "mcp" | "policy" | "channelRecord";
1726
1862
  interface ResourceDefinition<Kind extends ResourceKind, Name extends string, Config> {
1727
1863
  readonly [RESOURCE_MARKER]: true;
1728
1864
  readonly kind: Kind;
@@ -1738,14 +1874,24 @@ type ResourceInput<Name extends string, Config> = {
1738
1874
  name: Name;
1739
1875
  description?: string;
1740
1876
  } & Config;
1877
+ /**
1878
+ * Provider-specific sandbox knobs. `reservationKey` names the reserved machine a
1879
+ * `persistent` sandbox reconnects to when no workspace is mounted; unset, each
1880
+ * agent gets its own, and pinning one string on two sandboxes shares a machine.
1881
+ * Keys are scoped to the account, so they cannot reach another account's machine.
1882
+ */
1883
+ type SandboxDefinitionOptions = Record<string, unknown> & {
1884
+ reservationKey?: string;
1885
+ };
1741
1886
  /**
1742
1887
  * Code-first sandbox config surface. Mirrors core's `SandboxConfig` but lets
1743
1888
  * `envVars` values be `env("NAME")` references (compiled to `${NAME}` placeholders
1744
1889
  * at sync time, exactly like provider `apiKey`). Add overrides here if more
1745
1890
  * sandbox fields should accept env refs.
1746
1891
  */
1747
- type SandboxDefinitionConfig = Omit<SandboxConfig, "envVars"> & {
1892
+ type SandboxDefinitionConfig = Omit<SandboxConfig, "envVars" | "options"> & {
1748
1893
  envVars?: Record<string, string | EnvRef | undefined>;
1894
+ options?: SandboxDefinitionOptions;
1749
1895
  };
1750
1896
  type HarnessType = NonNullable<AgentConfig["harness"]>["type"];
1751
1897
  type HarnessDefinition = Omit<NonNullable<AgentConfig["harness"]>, "type"> & {
@@ -1805,6 +1951,33 @@ interface ToolDefinitionConfig<Input = Record<string, unknown>> {
1805
1951
  type PolicyDefinitionConfig = Omit<PolicyDocument, "version"> & {
1806
1952
  version?: PolicyDocument["version"];
1807
1953
  };
1954
+ /**
1955
+ * MCP server registration (#331) — external (`url`) or hosted (`path`).
1956
+ * Either way the server's tools are offered as `<name>__<tool>`; an external
1957
+ * row is dialed over the stateless HTTP transport (spec 2026-07-28) at agent
1958
+ * registration time. The name namespaces those tools, so it must be 1-32
1959
+ * lowercase letters, digits, or hyphens, starting with a letter.
1960
+ */
1961
+ interface McpServerDefinitionConfig {
1962
+ /** External server's MCP endpoint; http(s), no embedded credentials. */
1963
+ url?: string;
1964
+ /**
1965
+ * Hosted alternative to `url`: a module (resolved from the `broods/`
1966
+ * directory) whose default export is a fetch-style MCP handler —
1967
+ * `export default createMcpHandler(...)` from @modelcontextprotocol/server.
1968
+ * The CLI bundles it and the tool-runner Lambda hosts it, one invoke per
1969
+ * request.
1970
+ */
1971
+ path?: string;
1972
+ /**
1973
+ * Extra request headers. Credential-bearing headers (Authorization,
1974
+ * X-Api-Key, ...) must reference an account env var — e.g.
1975
+ * `Bearer ${env("TOKEN")}` — never carry an inline secret.
1976
+ */
1977
+ headers?: Record<string, string>;
1978
+ /** Tool names agents may use from this server; omit to allow all. */
1979
+ allowedTools?: string[];
1980
+ }
1808
1981
  type ChannelType = "telegram" | "github" | "slack" | "discord" | "pancake" | "zalo";
1809
1982
  /**
1810
1983
  * A connection is one app install: the credentials an agent needs before a
@@ -2106,7 +2279,7 @@ interface ProviderSettingsInput {
2106
2279
  }
2107
2280
  /** Per-provider settings; provider names stay synced with core's `AgentConfig`. */
2108
2281
  type ProviderConfigInput = Partial<Record<keyof NonNullable<AgentConfig["provider"]>, ProviderSettingsInput>>;
2109
- type AgentDefinitionConfig = EnvRefString<Pick<AgentConfig, "agent" | "model" | "scheduler" | "session" | "tools">> & {
2282
+ type AgentDefinitionConfig = EnvRefString<Pick<AgentConfig, "agent" | "model" | "scheduler" | "session" | "tools" | "mcpServers">> & {
2110
2283
  provider?: ProviderConfigInput;
2111
2284
  } & {
2112
2285
  harness?: HarnessDefinition;
@@ -2145,10 +2318,11 @@ type WorkspaceResource<Name extends string = string> = ResourceDefinition<"works
2145
2318
  type SandboxResource<Name extends string = string> = ResourceDefinition<"sandbox", Name, SandboxDefinitionConfig>;
2146
2319
  type SkillResource<Name extends string = string> = ResourceDefinition<"skill", Name, SkillDefinitionConfig>;
2147
2320
  type ToolResource<Name extends string = string> = ResourceDefinition<"tool", Name, ToolDefinitionConfig>;
2321
+ type McpServerResource<Name extends string = string> = ResourceDefinition<"mcp", Name, McpServerDefinitionConfig>;
2148
2322
  type PolicyResource<Name extends string = string> = ResourceDefinition<"policy", Name, PolicyDefinitionConfig>;
2149
2323
  type CronResource<Name extends string = string> = ResourceDefinition<"cron", Name, CronDefinitionConfig>;
2150
2324
  type ChannelResource<Name extends string = string> = ResourceDefinition<"channelRecord", Name, ChannelDefinitionConfig>;
2151
- type AnyResource = AgentResource | WorkspaceResource | SandboxResource | CronResource | SkillResource | ToolResource | PolicyResource | ChannelResource;
2325
+ type AnyResource = AgentResource | WorkspaceResource | SandboxResource | CronResource | SkillResource | ToolResource | McpServerResource | PolicyResource | ChannelResource;
2152
2326
  /**
2153
2327
  * References an account/environment variable resolved on the SERVER at runtime —
2154
2328
  * set it with `broods env set <NAME>` or in the dashboard (the Convex-style
@@ -2188,11 +2362,12 @@ declare function defineSkill<const Name extends string>(input: ResourceInput<Nam
2188
2362
  declare function defineTool<const Name extends string, Input = Record<string, unknown>>(input: {
2189
2363
  name: Name;
2190
2364
  } & ToolDefinitionConfig<Input>): ToolResource<Name>;
2365
+ declare function defineMcp<const Name extends string>(input: ResourceInput<Name, McpServerDefinitionConfig>): McpServerResource<Name>;
2191
2366
  declare function definePolicy<const Name extends string>(input: ResourceInput<Name, PolicyDefinitionConfig>): PolicyResource<Name>;
2192
2367
  declare function defineCron<const Name extends string>(input: ResourceInput<Name, CronDefinitionConfig>): CronResource<Name>;
2193
2368
  declare function isResource(value: unknown): value is AnyResource;
2194
2369
  declare function isConnectionDefinition(value: unknown): value is AnyConnectionDefinition;
2195
2370
  declare function isBroodsConfig(value: unknown): value is BroodsConfigDefinition;
2196
2371
 
2197
- export { BroodsAccountApiError, BroodsAccountClient, BroodsClient, BroodsWebSocketClient, DEFAULT_CORE_BASE_URL, IngressAcceptedError, MAX_OBSERVABILITY_BACKFILL, BroodsWebSocketClient as WebSocketClient, BroodsWebSocketClient as WebsocketClient, defineAgent, defineBroods, defineCron, defineDiscordChannel, defineDiscordConnection, defineGitHubChannel, defineGitHubConnection, defineHarness, definePancakeChannel, definePancakeConnection, definePolicy, defineSandbox, defineSkill, defineSlackChannel, defineSlackConnection, defineTelegramChannel, defineTelegramConnection, defineTool, defineWorkspace, defineZaloChannel, defineZaloConnection, env, envPlaceholder, isBroodsConfig, isConnectionDefinition, isLogLevel, isObservabilityClientMessage, isResource, isRootSpanKind, normalizeHttpServiceUrl, readSseStream, resolveRunEvents, toWebSocketBaseUrl };
2198
- export type { Account, AccountAgent, AccountChannel, AccountEnvVar, AccountPolicy, AccountSandbox, AccountTool, AccountWorkspace, Agent, AgentChannelsConfig, AgentCodeHookConfig, AgentConfig, AgentConfigDoc, AgentDefinitionConfig, AgentDiscordChannelConfig, AgentGitHubChannelConfig, AgentHandle, AgentHookEventName, AgentHooks, AgentHooksConfig, AgentPancakeChannelConfig, AgentProviderSettings, AgentReference, AgentResource, AgentRunEventInput, AgentRunInput, AgentRunModelOverrides, AgentRunOverrides, AgentRunResult, AgentSkillsDefinitionConfig, AgentSlackChannelConfig, AgentStreamPart, AgentSubagentDefinitionConfig, AgentTelegramChannelConfig, AgentWebhookHookConfig, AgentWorkspaceInput, AgentWorkspaceRef, AgentWorkspaceRefInput, AgentZaloChannelConfig, AnyConnectionDefinition, AnyResource, AsyncAgentRun, AsyncPollOptions, AsyncRequestAccepted, AsyncStatus, BroodsAccount, BroodsAccountClientOptions, BroodsClientOptions, BroodsConfigDefinition, BroodsProjectConfig, BroodsWebSocketClientOptions, ChannelAgentInput, ChannelDefinitionConfig, ChannelMessageReceived, ChannelPartition, ChannelRecordConfig, ChannelReference, ChannelReplyIn, ChannelResource, ChannelType, CliManifest, CliManifestResource, CliResourceKind, ConnectionDefinition, CreateAgentResult, CreateClientCronInput, CreateCronInput, CreateToolInput, Cron, CronDefinitionConfig, CronDoc, CronLastStatus, CronResource, CronRun, CronStatus, CustomTool, DeleteAccountResult, DiscordChannelInput, DiscordConnectionDefinition, DiscordConnectionInput, DiscordMessageSource, DiscordSource, Doc, EnvAccessor, EnvRef, EnvRefString, GeneratedIds, GitHubChannelInput, GitHubConnectionDefinition, GitHubConnectionInput, GitHubMessageSource, GitHubSource, HarnessDefinition, HarnessType, HookContext, Id, IngressMode, IngressStatus, LogLevel, ObservabilityBackfillMessage, ObservabilityClientMessage, ObservabilityErrorMessage, ObservabilityLogEntry, ObservabilityLogMessage, ObservabilityReadyMessage, ObservabilityServerMessage, ObservabilitySpanMessage, ObservabilitySpanRow, ObservabilitySubscribeMessage, ObservabilityUnsubscribeMessage, PancakeChannelInput, PancakeConnectionDefinition, PancakeConnectionInput, PancakeMessageSource, PancakeSource, PolicyDefinitionConfig, PolicyDocument, PolicyResource, ProjectDoc, ProviderConfigInput, ProviderSettingsInput, ResourceApi, ResourceDefinition, ResourceInput, ResourceKind, RotateSecretResult, Sandbox, SandboxConfig, SandboxConfigDoc, SandboxDefinitionConfig, SandboxLifecycleResult, SandboxResource, SandboxSnapshotResult, SandboxTerminalTicket, Skill, SkillDefinitionConfig, SkillResource, SkillUploadInput, SlackChannelInput, SlackConnectionDefinition, SlackConnectionInput, SlackMessageSource, SlackSource, StageDoc, TelegramChannelInput, TelegramConnectionDefinition, TelegramConnectionInput, TelegramMessageSource, TelegramSource, ToolApprovalSummary, ToolDefinitionConfig, ToolExecuteContext, ToolExecuteOptions, ToolResource, ToolScope, UpdateAgentInput, UpdateCronInput, UpdateToolInput, WebSocketAttachInput, WebSocketClientAttachMessage, WebSocketClientCancelMessage, WebSocketClientControlMessage, WebSocketClientExecuteMessage, WebSocketClientMessage, WebSocketConstructorLike, WebSocketHandlers, WebSocketLike, WebSocketOutputMessage, WebSocketRunInput, WebSocketServerMessage, WebSocketStreamMessage, WebSocketSubscription, Workspace, WorkspaceConfig, WorkspaceConfigDoc, WorkspaceDefinitionConfig, WorkspaceFileEntry, WorkspaceResource, ZaloChannelInput, ZaloConnectionDefinition, ZaloConnectionInput, ZaloMessageSource, ZaloSource };
2372
+ export { BroodsAccountApiError, BroodsAccountClient, BroodsClient, BroodsWebSocketClient, DEFAULT_CORE_BASE_URL, IngressAcceptedError, MAX_OBSERVABILITY_BACKFILL, BroodsWebSocketClient as WebSocketClient, BroodsWebSocketClient as WebsocketClient, defineAgent, defineBroods, defineCron, defineDiscordChannel, defineDiscordConnection, defineGitHubChannel, defineGitHubConnection, defineHarness, defineMcp, definePancakeChannel, definePancakeConnection, definePolicy, defineSandbox, defineSkill, defineSlackChannel, defineSlackConnection, defineTelegramChannel, defineTelegramConnection, defineTool, defineWorkspace, defineZaloChannel, defineZaloConnection, env, envPlaceholder, isBroodsConfig, isConnectionDefinition, isLogLevel, isObservabilityClientMessage, isResource, isRootSpanKind, normalizeHttpServiceUrl, readSseStream, resolveRunEvents, toWebSocketBaseUrl };
2373
+ export type { Account, AccountAgent, AccountChannel, AccountEnvVar, AccountMcpServer, AccountPolicy, AccountRole, AccountSandbox, AccountTool, AccountWorkspace, Agent, AgentChannelsConfig, AgentCodeHookConfig, AgentConfig, AgentConfigDoc, AgentDefinitionConfig, AgentDiscordChannelConfig, AgentGitHubChannelConfig, AgentHandle, AgentHookEventName, AgentHooks, AgentHooksConfig, AgentPancakeChannelConfig, AgentProviderSettings, AgentReference, AgentResource, AgentRunEventInput, AgentRunInput, AgentRunModelOverrides, AgentRunOverrides, AgentRunResult, AgentSkillsDefinitionConfig, AgentSlackChannelConfig, AgentStreamPart, AgentSubagentDefinitionConfig, AgentTelegramChannelConfig, AgentWebhookHookConfig, AgentWorkspaceInput, AgentWorkspaceRef, AgentWorkspaceRefInput, AgentZaloChannelConfig, AnyConnectionDefinition, AnyResource, AssumeRoleResult, AsyncAgentRun, AsyncPollOptions, AsyncRequestAccepted, AsyncStatus, BroodsAccount, BroodsAccountClientOptions, BroodsClientOptions, BroodsConfigDefinition, BroodsProjectConfig, BroodsWebSocketClientOptions, ChannelAgentInput, ChannelDefinitionConfig, ChannelMessageReceived, ChannelPartition, ChannelRecordConfig, ChannelReference, ChannelReplyIn, ChannelResource, ChannelType, CliManifest, CliManifestResource, CliResourceKind, ConnectionDefinition, CreateAgentResult, CreateClientCronInput, CreateCronInput, CreateMcpServerInput, CreateToolInput, Cron, CronDefinitionConfig, CronDoc, CronLastStatus, CronResource, CronRun, CronStatus, CustomTool, DeleteAccountResult, DiscordChannelInput, DiscordConnectionDefinition, DiscordConnectionInput, DiscordMessageSource, DiscordSource, Doc, EnvAccessor, EnvRef, EnvRefString, GeneratedIds, GitHubChannelInput, GitHubConnectionDefinition, GitHubConnectionInput, GitHubMessageSource, GitHubSource, HarnessDefinition, HarnessType, HookContext, Id, IngressMode, IngressStatus, LogLevel, McpServerDefinitionConfig, McpServerResource, ObservabilityBackfillMessage, ObservabilityClientMessage, ObservabilityErrorMessage, ObservabilityLogEntry, ObservabilityLogMessage, ObservabilityReadyMessage, ObservabilityServerMessage, ObservabilitySpanMessage, ObservabilitySpanRow, ObservabilitySubscribeMessage, ObservabilityUnsubscribeMessage, PancakeChannelInput, PancakeConnectionDefinition, PancakeConnectionInput, PancakeMessageSource, PancakeSource, PolicyDefinitionConfig, PolicyDocument, PolicyResource, ProjectDoc, ProviderConfigInput, ProviderSettingsInput, ResourceApi, ResourceDefinition, ResourceInput, ResourceKind, RotateSecretResult, Sandbox, SandboxConfig, SandboxConfigDoc, SandboxDefinitionConfig, SandboxDefinitionOptions, SandboxLifecycleResult, SandboxResource, SandboxSnapshotResult, SandboxTerminalTicket, Skill, SkillDefinitionConfig, SkillResource, SkillUploadInput, SlackChannelInput, SlackConnectionDefinition, SlackConnectionInput, SlackMessageSource, SlackSource, StageDoc, TelegramChannelInput, TelegramConnectionDefinition, TelegramConnectionInput, TelegramMessageSource, TelegramSource, ToolApprovalSummary, ToolDefinitionConfig, ToolExecuteContext, ToolExecuteOptions, ToolResource, ToolScope, UpdateAgentInput, UpdateCronInput, UpdateMcpServerInput, UpdateToolInput, WebSocketAttachInput, WebSocketClientAttachMessage, WebSocketClientCancelMessage, WebSocketClientControlMessage, WebSocketClientExecuteMessage, WebSocketClientMessage, WebSocketConstructorLike, WebSocketHandlers, WebSocketLike, WebSocketOutputMessage, WebSocketRunInput, WebSocketServerMessage, WebSocketStreamMessage, WebSocketSubscription, Workspace, WorkspaceConfig, WorkspaceConfigDoc, WorkspaceDefinitionConfig, WorkspaceFileEntry, WorkspaceResource, ZaloChannelInput, ZaloConnectionDefinition, ZaloConnectionInput, ZaloMessageSource, ZaloSource };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{S,r,y}from"./chunk-vyvy543y.js";import{p,b,c,x,d,m,_,g,T,k,E,C,R,A,M,P,O,N,D,j,z,U,L,Z,F,B,W,q,K,V,t,i,v}from"./chunk-t6xktzr3.js";var u=500;function f(e){if(typeof e!=="object"||e===null)return!1;let n=e;if(n.type==="subscribe"){let s=n.stream;if(s!=="logs"&&s!=="traces")return!1;let o=n.backfill;if(o!==void 0&&(typeof o!=="number"||!Number.isSafeInteger(o)||o<0||o>500))return!1;if(n.liveOnly!==void 0&&typeof n.liveOnly!=="boolean")return!1;let a=n.minLevel;if(a!==void 0&&!l(a))return!1;return!0}if(n.type==="unsubscribe"){let s=n.stream;return s==="logs"||s==="traces"}return!1}function l(e){return e==="DEBUG"||e==="INFO"||e==="WARN"||e==="ERROR"}function I(e){return e==="task"||e==="cron"||e==="subtask"}export{r as BroodsAccountApiError,y as BroodsAccountClient,d as BroodsClient,_ as BroodsWebSocketClient,c as DEFAULT_CORE_BASE_URL,x as IngressAcceptedError,u as MAX_OBSERVABILITY_BACKFILL,_ as WebSocketClient,_ as WebsocketClient,L as defineAgent,U as defineBroods,V as defineCron,P as defineDiscordChannel,k as defineDiscordConnection,O as defineGitHubChannel,E as defineGitHubConnection,Z as defineHarness,N as definePancakeChannel,C as definePancakeConnection,K as definePolicy,B as defineSandbox,W as defineSkill,D as defineSlackChannel,R as defineSlackConnection,j as defineTelegramChannel,A as defineTelegramConnection,q as defineTool,F as defineWorkspace,z as defineZaloChannel,M as defineZaloConnection,T as env,S as envPlaceholder,v as isBroodsConfig,i as isConnectionDefinition,l as isLogLevel,f as isObservabilityClientMessage,t as isResource,I as isRootSpanKind,m as normalizeHttpServiceUrl,b as readSseStream,p as resolveRunEvents,g as toWebSocketBaseUrl};
1
+ import{a as O,b as R,c as L}from"./chunk-36yhe6qb.js";import{A as _,B as P,C as U,D as B,E as H,F as K,G as j,H as G,I as F,J as z,K as Z,L as V,M as X,N as Y,O as J,P as Q,Q as ee,R as te,S as re,T as ne,U as se,d as v,e as k,p as S,q as A,r as M,s as h,t as w,u as W,v as E,w as D,x as T,y as q,z as N}from"./chunk-rwpj4428.js";import"./chunk-4sdsq7gb.js";var a=500;function i(e){if(typeof e!=="object"||e===null)return!1;let t=e;if(t.type==="subscribe"){let r=t.stream;if(r!=="logs"&&r!=="traces")return!1;let n=t.backfill;if(n!==void 0&&(typeof n!=="number"||!Number.isSafeInteger(n)||n<0||n>500))return!1;if(t.liveOnly!==void 0&&typeof t.liveOnly!=="boolean")return!1;let s=t.minLevel;if(s!==void 0&&!o(s))return!1;return!0}if(t.type==="unsubscribe"){let r=t.stream;return r==="logs"||r==="traces"}return!1}function o(e){return e==="DEBUG"||e==="INFO"||e==="WARN"||e==="ERROR"}function p(e){return e==="task"||e==="cron"||e==="subtask"}export{R as BroodsAccountApiError,L as BroodsAccountClient,M as BroodsClient,w as BroodsWebSocketClient,S as DEFAULT_CORE_BASE_URL,A as IngressAcceptedError,a as MAX_OBSERVABILITY_BACKFILL,w as WebSocketClient,w as WebsocketClient,z as defineAgent,F as defineBroods,te as defineCron,U as defineDiscordChannel,D as defineDiscordConnection,B as defineGitHubChannel,T as defineGitHubConnection,Z as defineHarness,Q as defineMcp,H as definePancakeChannel,q as definePancakeConnection,ee as definePolicy,X as defineSandbox,Y as defineSkill,K as defineSlackChannel,N as defineSlackConnection,j as defineTelegramChannel,_ as defineTelegramConnection,J as defineTool,V as defineWorkspace,G as defineZaloChannel,P as defineZaloConnection,E as env,O as envPlaceholder,se as isBroodsConfig,ne as isConnectionDefinition,o as isLogLevel,i as isObservabilityClientMessage,re as isResource,p as isRootSpanKind,h as normalizeHttpServiceUrl,k as readSseStream,v as resolveRunEvents,W as toWebSocketBaseUrl};