broods 0.45.0 → 0.47.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
@@ -45,7 +45,7 @@ declare const MODEL_PROVIDERS: {
45
45
  readonly modelPlaceholder: "gpt-5.5";
46
46
  };
47
47
  readonly cloudflare: {
48
- readonly label: "Cloudflare Workers AI";
48
+ readonly label: "Cloudflare";
49
49
  readonly modelPlaceholder: "@cf/meta/llama-3.3-70b-instruct-fp8-fast";
50
50
  };
51
51
  readonly cohere: {
@@ -155,8 +155,9 @@ declare const AGENT_LIFECYCLE_EVENT_NAMES: readonly ["agent.started", "agent.ste
155
155
  * Shared validation for MCP server registrations (#331). One normalizer
156
156
  * serves every write path (CLI sync, direct API, dashboard). A `url` makes an "http" row
157
157
  * core connects to over the stateless 2026-07-28 transport; a `bundle` makes
158
- * a "hosted" row served by the mcp-runner Lambda, hashed here so sha256
159
- * always travels with the bundle. Auth header values may carry ${NAME}
158
+ * a "hosted" row, hashed here so sha256 always travels with the bundle; the
159
+ * S3 bundle writer (aws/bundles.ts) marks whether Cloudflare Dynamic Workers
160
+ * can run it. Auth header values may carry ${NAME}
160
161
  * account env refs; they resolve into the encrypted agent config at sync
161
162
  * time, never on this row, and credential-bearing headers must use one
162
163
  * instead of an inline secret. `oauth` follows the same rule: clientSecret
@@ -208,6 +209,10 @@ interface AgentConfig {
208
209
  skills?: AgentSkillsConfig;
209
210
  subagent?: AgentSubagentConfig;
210
211
  scheduler?: AgentSchedulerConfig;
212
+ /** Registers the `browse` tool, which runs Obscura on the first sandbox. */
213
+ browser?: {
214
+ enabled?: boolean;
215
+ };
211
216
  /** Policies that gate this agent. Each one carries its own enforcement mode. */
212
217
  policies?: string[];
213
218
  publicAccess?: boolean;
@@ -322,6 +327,8 @@ interface AgentProviderSettings {
322
327
  base_url?: string;
323
328
  /** OpenAI-compatible endpoint (`custom`). AI-SDK form; the dashboard writes both. */
324
329
  baseURL?: string;
330
+ /** Cloudflare AI Gateway id (`cloudflare`). Set, requests go through the gateway. */
331
+ gatewayId?: string;
325
332
  headers?: Record<string, string>;
326
333
  /** Endpoint label; becomes the provider id and the pi harness env prefix. */
327
334
  name?: string;
@@ -345,8 +352,9 @@ interface AgentSessionPruningConfig {
345
352
  }
346
353
  /**
347
354
  * Compaction after a finished turn, on unless `enabled: false`. It runs once
348
- * the turn's last model call read `maxContextLength` input tokens or more
349
- * (default 500000). `/compact` works whatever this says.
355
+ * the turn's last model call reaches the lower of `maxContextLength` (default
356
+ * 500000) and 80% of the model's context window. `/compact` works whatever
357
+ * this says.
350
358
  */
351
359
  interface AgentSessionAutoCompactionConfig {
352
360
  enabled?: boolean;
@@ -739,7 +747,7 @@ type UpdateCronInput = {
739
747
  * rules, core's executor registry and the SDK derive from. A leaf on purpose,
740
748
  * so `schema.ts` can read it without pulling the rules' import graph.
741
749
  */
742
- declare const SANDBOX_PROVIDERS: readonly ["sandbox", "lambda", "e2b", "daytona", "vercel", "machine", "custom"];
750
+ declare const SANDBOX_PROVIDERS: readonly ["sandbox", "lambda", "e2b", "daytona", "vercel", "cloudflare", "machine", "custom"];
743
751
  type SandboxProvider = (typeof SANDBOX_PROVIDERS)[number];
744
752
 
745
753
  /**
@@ -748,6 +756,7 @@ type SandboxProvider = (typeof SANDBOX_PROVIDERS)[number];
748
756
  * is unchanged. The public projection lives in ./responses.ts.
749
757
  */
750
758
 
759
+ declare const SANDBOX_IMAGES: readonly ["browser", "obscura"];
751
760
  declare const SANDBOX_RUNTIMES: readonly ["bash", "python", "node"];
752
761
  declare const SANDBOX_PERMISSION_MODES: readonly ["edit", "ask", "bypass"];
753
762
  declare const SANDBOX_NETWORK_MODES: readonly ["allow-all", "deny-all", "restricted"];
@@ -756,6 +765,7 @@ type RuntimeName = (typeof SANDBOX_RUNTIMES)[number];
756
765
  type PermissionMode = (typeof SANDBOX_PERMISSION_MODES)[number];
757
766
  type NetworkMode = (typeof SANDBOX_NETWORK_MODES)[number];
758
767
  type SandboxSize = (typeof SANDBOX_SIZE_NAMES)[number];
768
+ type SandboxImage = (typeof SANDBOX_IMAGES)[number];
759
769
  /**
760
770
  * Idle and maximum lifetime controls for a persistent sandbox.
761
771
  */
@@ -775,6 +785,7 @@ interface SandboxConfig {
775
785
  provider: SandboxProvider;
776
786
  fallbackProvider?: SandboxProvider;
777
787
  size?: SandboxSize;
788
+ image?: SandboxImage;
778
789
  snapshot?: string;
779
790
  runtimes?: RuntimeName[];
780
791
  network?: SandboxNetworkConfig;
@@ -859,7 +870,8 @@ type WorkspaceIsolation = (typeof WORKSPACE_ISOLATION_LEVELS)[number];
859
870
  * Workspace-config validation for the Convex config plane. Ports core's
860
871
  * former storage/workspace-config.ts normalizer so the public /v1/workspaces
861
872
  * contract is unchanged. Workspace config holds no secrets (a roleArn is not
862
- * a secret), so it is stored and returned in plaintext. Pure module, safe
873
+ * a secret, and R2 keys are `${NAME}` env refs), so it is stored and returned
874
+ * in plaintext. Pure module, safe
863
875
  * for the default Convex runtime. The public projection lives in
864
876
  * ./responses.ts. Core runs the storage access rule too, so it reads the env
865
877
  * names of both sides.
@@ -873,6 +885,12 @@ type WorkspaceStorageAuth = {
873
885
  type: "assumeRole";
874
886
  roleArn: string;
875
887
  externalId?: string;
888
+ } | {
889
+ type: "r2";
890
+ /** `${NAME}` ref to the parent R2 token's access key id. */
891
+ accessKeyId: string;
892
+ /** `${NAME}` ref to the parent R2 token's secret access key. */
893
+ secretAccessKey: string;
876
894
  };
877
895
  interface WorkspaceStorageConfig {
878
896
  provider: WorkspaceStorageProvider;
@@ -882,10 +900,6 @@ interface WorkspaceStorageConfig {
882
900
  prefix?: string;
883
901
  auth?: WorkspaceStorageAuth;
884
902
  }
885
- /** What the API accepts: the boolean spelling of isolation is stored as its level. */
886
- type WorkspaceConfigInput = Omit<WorkspaceConfig, "isolation"> & {
887
- isolation?: WorkspaceIsolation | boolean;
888
- };
889
903
  interface WorkspaceConfig {
890
904
  storage: WorkspaceStorageConfig;
891
905
  isolation?: WorkspaceIsolation;
@@ -2108,6 +2122,8 @@ interface McpOauthInput {
2108
2122
  refreshToken: string;
2109
2123
  tokenUrl?: string;
2110
2124
  }
2125
+ /** Where a hosted MCP server may run. */
2126
+ type McpRuntime = "auto" | "lambda";
2111
2127
  /** Public MCP server registration returned by the `/v1/mcp` routes (#331). */
2112
2128
  interface AccountMcp {
2113
2129
  accountId: string;
@@ -2119,10 +2135,14 @@ interface AccountMcp {
2119
2135
  transport: "http" | "hosted" | "machine";
2120
2136
  /** External servers only; a hosted row has no endpoint of its own. */
2121
2137
  url?: string;
2122
- /** Machine servers only: the machine sandbox (by name) whose daemon serves it. */
2138
+ /** Machine servers only: the sandbox (by name) that serves it. */
2123
2139
  sandbox?: string;
2140
+ /** Machine servers only: argv of the stdio server a lambda sandbox runs. */
2141
+ command?: string[];
2124
2142
  /** Hosted servers only: content hash of the uploaded bundle. */
2125
2143
  sha256?: string;
2144
+ /** Hosted servers only: "auto" or "lambda". */
2145
+ runtime?: McpRuntime;
2126
2146
  headers?: Record<string, string>;
2127
2147
  oauth?: McpOauthInput;
2128
2148
  allowedTools?: string[];
@@ -2135,19 +2155,26 @@ interface AccountMcp {
2135
2155
  /**
2136
2156
  * Fields accepted by `POST /v1/mcp`: `url` connects, `bundle` uploads inline
2137
2157
  * (≤10 MB); a larger bundle goes through `uploadMcpBundle` first; `sandbox`
2138
- * runs it on that machine sandbox's daemon.
2158
+ * runs it on that sandbox: a machine's daemon, or `command` on a lambda VM.
2139
2159
  */
2140
2160
  interface CreateMcpInput {
2141
2161
  name: string;
2142
2162
  description?: string;
2143
2163
  url?: string;
2144
2164
  sandbox?: string;
2165
+ command?: string[];
2145
2166
  bundle?: string;
2146
2167
  bundleStorageId?: string;
2147
2168
  sha256?: string;
2148
2169
  headers?: Record<string, string>;
2149
2170
  oauth?: McpOauthInput;
2150
2171
  allowedTools?: string[];
2172
+ /**
2173
+ * Hosted servers only. "auto" (the default) runs it on Cloudflare Workers
2174
+ * when its bundle can run there, on Lambda otherwise; "lambda" always runs
2175
+ * it on Lambda.
2176
+ */
2177
+ runtime?: McpRuntime;
2151
2178
  }
2152
2179
  /** Fields accepted by `PATCH /v1/mcp/{serverId}`; every field is optional. */
2153
2180
  interface UpdateMcpInput {
@@ -2155,12 +2182,19 @@ interface UpdateMcpInput {
2155
2182
  description?: string;
2156
2183
  url?: string;
2157
2184
  sandbox?: string;
2185
+ command?: string[];
2158
2186
  bundle?: string;
2159
2187
  bundleStorageId?: string;
2160
2188
  sha256?: string;
2161
2189
  headers?: Record<string, string>;
2162
2190
  oauth?: McpOauthInput;
2163
2191
  allowedTools?: string[];
2192
+ /**
2193
+ * Hosted servers only. "auto" (the default) runs it on Cloudflare Workers
2194
+ * when its bundle can run there, on Lambda otherwise; "lambda" always runs
2195
+ * it on Lambda.
2196
+ */
2197
+ runtime?: McpRuntime;
2164
2198
  disabled?: boolean;
2165
2199
  }
2166
2200
  /**
@@ -2301,13 +2335,13 @@ declare class BroodsAccountClient {
2301
2335
  createWorkspace(input: {
2302
2336
  name: string;
2303
2337
  description?: string;
2304
- config?: WorkspaceConfigInput;
2338
+ config?: WorkspaceConfig;
2305
2339
  }): Promise<AccountWorkspace>;
2306
2340
  getWorkspace(workspaceId: string): Promise<AccountWorkspace | null>;
2307
2341
  updateWorkspace(workspaceId: string, patch: {
2308
2342
  name?: string;
2309
2343
  description?: string | null;
2310
- config?: ConfigPatch<WorkspaceConfigInput>;
2344
+ config?: ConfigPatch<WorkspaceConfig>;
2311
2345
  }): Promise<AccountWorkspace | null>;
2312
2346
  deleteWorkspace(workspaceId: string): Promise<boolean>;
2313
2347
  /** Flat listing of every file in the workspace's S3-backed filesystem. Returns [] when the workspace is gone. */
@@ -2346,7 +2380,7 @@ declare class BroodsAccountClient {
2346
2380
  terminateSandbox(sandboxId: string, reservationKey: string): Promise<SandboxLifecycleResult>;
2347
2381
  /** Snapshot a persistent sandbox reservation into a reusable image (self-hosted `sandbox` provider). Throws on 404/403/409. */
2348
2382
  snapshotSandbox(sandboxId: string, reservationKey: string, name: string): Promise<SandboxSnapshotResult>;
2349
- /** Mint a short-lived sealed ticket for an interactive PTY session on a persistent sandbox (`sandbox`/`lambda` providers). Throws on 404/403/409. */
2383
+ /** Mint a short-lived sealed ticket for an interactive PTY session on a persistent sandbox (`sandbox`/`lambda`/`cloudflare` providers). Throws on 404/403/409. */
2350
2384
  openSandboxTerminal(sandboxId: string, reservationKey: string): Promise<SandboxTerminalTicket>;
2351
2385
  /** MCP servers live in one stage, so the collection routes need a scope. */
2352
2386
  listMcp(scope: StageScope): Promise<AccountMcp[]>;
@@ -2646,7 +2680,7 @@ type McpHandler = ((request: Request) => Response | Promise<Response>) | {
2646
2680
  };
2647
2681
  /**
2648
2682
  * MCP server registration (#331): external (`url`), hosted (`handler`), or on
2649
- * a user's computer (`sandbox`). Either way the server's tools are offered as
2683
+ * a sandbox (`sandbox`). Either way the server's tools are offered as
2650
2684
  * `<name>__<tool>`; an external row is dialed over the stateless HTTP
2651
2685
  * transport (spec 2026-07-28) at agent registration time. The name namespaces
2652
2686
  * those tools, so it must be 1-32 lowercase letters, digits, or hyphens,
@@ -2656,17 +2690,31 @@ interface McpDefinitionConfig {
2656
2690
  /** External server's MCP endpoint; http(s), no embedded credentials. */
2657
2691
  url?: string;
2658
2692
  /**
2659
- * Instead of `url` or `handler`: the machine sandbox whose daemon runs this
2660
- * server, from the entry with the same name in its `--mcp` file.
2693
+ * Instead of `url` or `handler`: the sandbox that runs this server. On a
2694
+ * machine sandbox its daemon runs the entry with the same name in its
2695
+ * `--mcp` file; on a lambda sandbox the VM runs `command`.
2661
2696
  */
2662
2697
  sandbox?: SandboxResource | string;
2698
+ /**
2699
+ * Argv of the stdio server, required when `sandbox` is a lambda sandbox,
2700
+ * e.g. `["obscura", "mcp"]`. A machine sandbox's daemon ignores it.
2701
+ */
2702
+ command?: string[];
2663
2703
  /**
2664
2704
  * Hosted alternative to `url`: declare the server inline as
2665
2705
  * `handler: createMcpHandler(...)` from @modelcontextprotocol/server,
2666
2706
  * right next to the `defineMcp` call. The CLI bundles the defining module
2667
- * and the mcp-runner Lambda hosts it, one invoke per batch of requests.
2707
+ * and the platform hosts it, one invocation per batch of requests: with
2708
+ * `runtime` "auto" on Cloudflare Workers when the bundle builds for them,
2709
+ * on Lambda otherwise.
2668
2710
  */
2669
2711
  handler?: McpHandler;
2712
+ /**
2713
+ * Hosted servers only. "auto" (the default) runs the handler on Cloudflare
2714
+ * Workers when it builds for them; "lambda" always ships the Node build to
2715
+ * Lambda, for a server that needs Node APIs Workers lack.
2716
+ */
2717
+ runtime?: McpRuntime;
2670
2718
  /**
2671
2719
  * Extra request headers. Credential-bearing headers (Authorization,
2672
2720
  * X-Api-Key, ...) must reference an account env var by name inside a plain
@@ -3086,12 +3134,14 @@ interface ProviderSettingsInput {
3086
3134
  apiKey?: string | EnvRef;
3087
3135
  base_url?: string | EnvRef;
3088
3136
  baseURL?: string | EnvRef;
3137
+ /** `cloudflare` only: the AI Gateway every request goes through. */
3138
+ gatewayId?: string;
3089
3139
  headers?: Record<string, string | EnvRef>;
3090
3140
  [key: string]: unknown;
3091
3141
  }
3092
3142
  /** Per-provider settings; provider names stay synced with core's `AgentConfig`. */
3093
3143
  type ProviderConfigInput = Partial<Record<keyof NonNullable<AgentConfig["provider"]>, ProviderSettingsInput>>;
3094
- type AgentDefinitionConfig = EnvRefString<Pick<AgentConfig, "agent" | "model" | "scheduler" | "session" | "tools" | "mcp">> & {
3144
+ type AgentDefinitionConfig = EnvRefString<Pick<AgentConfig, "agent" | "model" | "scheduler" | "browser" | "session" | "tools" | "mcp">> & {
3095
3145
  provider?: ProviderConfigInput;
3096
3146
  } & {
3097
3147
  harness?: HarnessDefinition;
@@ -3129,13 +3179,27 @@ type CronDefinitionConfig = Omit<CreateCronInput, "agentId" | "name"> & {
3129
3179
  type AgentResource<Name extends string = string> = ResourceDefinition<"agent", Name, AgentDefinitionConfig>;
3130
3180
  /**
3131
3181
  * Code-first workspace config. Says `partitioned` where storage says
3132
- * `isolation`. `true` or "conversation" permits a per-conversation split that
3133
- * a channel's `partition` performs; "agent" splits the workspace per attached
3134
- * agent on its own, with no partition needed.
3135
- */
3136
- type WorkspaceDefinitionConfig = Omit<WorkspaceConfig, "isolation"> & {
3137
- /** How to split this workspace: per conversation (`true`) or per agent. */
3138
- partitioned?: boolean | WorkspaceIsolation;
3182
+ * `isolation`. "conversation" permits a per-conversation split that a
3183
+ * channel's `partition` performs; "agent" splits the workspace per attached
3184
+ * agent on its own, with no partition needed. R2 keys take `env("NAME")`.
3185
+ */
3186
+ type WorkspaceDefinitionConfig = Omit<WorkspaceConfig, "isolation" | "storage"> & {
3187
+ storage?: WorkspaceStorageDefinition;
3188
+ /** How to split this workspace: per conversation or per agent. */
3189
+ partitioned?: WorkspaceIsolation;
3190
+ };
3191
+ type WorkspaceStorageAuthConfig = NonNullable<WorkspaceConfig["storage"]["auth"]>;
3192
+ type WorkspaceR2Auth = Extract<WorkspaceStorageAuthConfig, {
3193
+ type: "r2";
3194
+ }>;
3195
+ /** Workspace storage as authored: only the R2 keys take `env()`. */
3196
+ type WorkspaceStorageDefinition = Omit<WorkspaceConfig["storage"], "auth"> & {
3197
+ auth?: Exclude<WorkspaceStorageAuthConfig, {
3198
+ type: "r2";
3199
+ }> | (Omit<WorkspaceR2Auth, "accessKeyId" | "secretAccessKey"> & {
3200
+ accessKeyId: string | EnvRef;
3201
+ secretAccessKey: string | EnvRef;
3202
+ });
3139
3203
  };
3140
3204
  type WorkspaceResource<Name extends string = string> = ResourceDefinition<"workspace", Name, WorkspaceDefinitionConfig>;
3141
3205
  type SandboxResource<Name extends string = string> = ResourceDefinition<"sandbox", Name, SandboxDefinitionConfig>;
@@ -3211,4 +3275,4 @@ declare function isConnectionDefinition(value: unknown): value is AnyConnectionD
3211
3275
  declare function isResource(value: unknown): value is AnyResource;
3212
3276
 
3213
3277
  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, defineGoogleChatChannel, defineGoogleChatConnection, defineHarness, defineInstagramChannel, defineInstagramConnection, defineLinearChannel, defineLinearConnection, defineMatrixChannel, defineMatrixConnection, defineMcp, defineMessengerChannel, defineMessengerConnection, definePancakeChannel, definePancakeConnection, definePolicy, defineSandbox, defineSkill, defineSlackChannel, defineSlackConnection, defineTeamsChannel, defineTeamsConnection, defineTelegramChannel, defineTelegramConnection, defineTwilioChannel, defineTwilioConnection, defineWhatsAppChannel, defineWhatsAppConnection, defineWorkspace, defineZaloChannel, defineZaloConnection, env, envPlaceholder, isBroodsConfig, isConnectionDefinition, isLogLevel, isObservabilityClientMessage, isResource, isRootSpanKind, isSandboxLogId, isTraceId, normalizeHttpServiceUrl, readSseStream, resolveEnvCredential, resolveRunEvents, toWebSocketBaseUrl, webSocketSubprotocols };
3214
- export type { Account, AccountAgent, AccountChannel, AccountEnvVar, AccountMcp, AccountPolicy, AccountRole, AccountSandbox, AccountWorkspace, Agent, AgentChannelsConfig, AgentCodeHookConfig, AgentConfig, AgentConfigDoc, AgentContinueInput, AgentDefinitionConfig, AgentDiscordChannelConfig, AgentGitHubChannelConfig, AgentGoogleChatChannelConfig, AgentHandle, AgentHookEventName, AgentHooks, AgentHooksConfig, AgentInstagramChannelConfig, AgentLinearChannelConfig, AgentMatrixChannelConfig, AgentMessengerChannelConfig, AgentPancakeChannelConfig, AgentProviderSettings, AgentReference, AgentResource, AgentRunAnswerInput, AgentRunEventInput, AgentRunInput, AgentRunModelOverrides, AgentRunOverrides, AgentRunResult, AgentSkillsDefinitionConfig, AgentSlackChannelConfig, AgentStreamPart, AgentSubagentDefinitionConfig, AgentTeamsChannelConfig, AgentTelegramChannelConfig, AgentTwilioChannelConfig, AgentWebhookHookConfig, AgentWhatsAppChannelConfig, AgentWorkspaceInput, AgentWorkspaceRef, AgentWorkspaceRefInput, AgentZaloChannelConfig, AnyConnectionDefinition, AnyResource, AssumeRoleResult, AsyncAgentRun, AsyncPollOptions, AsyncRequestAccepted, AsyncStatus, AuditEvent, AuditPage, AuditPrincipalLink, AuditSink, AuditVerification, BroodsAccount, BroodsAccountClientOptions, BroodsClientOptions, BroodsConfigDefinition, BroodsProjectConfig, BroodsWebSocketClientOptions, ChannelAgentInput, ChannelDefinitionConfig, ChannelMessageReceived, ChannelPartition, ChannelRecordConfig, ChannelReference, ChannelReplyIn, ChannelResource, ChannelType, CliManifest, CliManifestResource, ConfigPatch, Connection, ConnectionCode, ConnectionDefinition, ConnectionStart, ConnectionStartResult, ConnectionType, CreateAgentResult, CreateCronInput, CreateMcpInput, Cron, CronDefinitionConfig, CronDoc, CronLastStatus, CronResource, CronRun, CronStatus, DeleteAccountResult, DiscordChannelInput, DiscordConnectionDefinition, DiscordConnectionInput, DiscordMessageSource, DiscordSource, Doc, EnvAccessor, EnvRef, EnvRefString, GeneratedIds, GitHubChannelInput, GitHubConnectionDefinition, GitHubConnectionInput, GitHubMessageSource, GitHubSource, GoogleChatChannelInput, GoogleChatConnectionDefinition, GoogleChatConnectionInput, GoogleChatMessageSource, GoogleChatSource, HarnessDefinition, HarnessType, HookAgentConfig, HookContext, Id, IngressMode, IngressStatus, InstagramChannelInput, InstagramConnectionDefinition, InstagramConnectionInput, InstagramMessageSource, InstagramSource, LinearChannelInput, LinearConnectionDefinition, LinearConnectionInput, LinearMessageSource, LinearSource, LogLevel, MatrixChannelInput, MatrixConnectionDefinition, MatrixConnectionInput, MatrixMessageSource, MatrixSource, McpDefinitionConfig, McpHandler, McpOauthInput, McpResource, MessengerChannelInput, MessengerConnectionDefinition, MessengerConnectionInput, MessengerMessageSource, MessengerSource, ObservabilityBackfillMessage, ObservabilityClientMessage, ObservabilityErrorMessage, ObservabilityFetchTraceMessage, ObservabilityLogEntry, ObservabilityLogMessage, ObservabilityReadyMessage, ObservabilityServerMessage, ObservabilitySpanMessage, ObservabilitySpanRow, ObservabilitySubscribeMessage, ObservabilityUnsubscribeMessage, PancakeChannelInput, PancakeConnectionDefinition, PancakeConnectionInput, PancakeMessageSource, PancakeSource, PendingQuestion, PolicyDefinitionConfig, PolicyDocument, PolicyResource, ProjectDoc, ProviderConfigInput, ProviderSettingsInput, QuestionAnswer, ResourceApi, ResourceDefinition, ResourceInput, ResourceKind, RotateSecretResult, Sandbox, SandboxConfig, SandboxConfigDoc, SandboxDefinitionConfig, SandboxDefinitionOptions, SandboxExecRequest, SandboxExecResponse, SandboxLifecycleResult, SandboxProvider, SandboxResource, SandboxSnapshotResult, SandboxTerminalTicket, Skill, SkillDefinitionConfig, SkillResource, SkillUploadInput, SlackChannelInput, SlackConnectionDefinition, SlackConnectionInput, SlackMessageSource, SlackSource, StageDoc, StageScope, TaskWaitingOn, TeamsChannelInput, TeamsConnectionDefinition, TeamsConnectionInput, TeamsMessageSource, TeamsSource, TelegramChannelInput, TelegramConnectionDefinition, TelegramConnectionInput, TelegramMessageSource, TelegramSource, ToolApprovalSummary, TwilioChannelInput, TwilioConnectionDefinition, TwilioConnectionInput, TwilioMessageSource, TwilioSource, UpdateAgentInput, UpdateCronInput, UpdateMcpInput, WebSocketAttachInput, WebSocketClientAttachMessage, WebSocketClientCancelMessage, WebSocketClientControlMessage, WebSocketClientExecuteMessage, WebSocketClientMessage, WebSocketConstructorLike, WebSocketHandlers, WebSocketLike, WebSocketOutputMessage, WebSocketRunInput, WebSocketServerMessage, WebSocketStreamMessage, WebSocketSubscription, WhatsAppChannelInput, WhatsAppConnectionDefinition, WhatsAppConnectionInput, WhatsAppMessageSource, WhatsAppSource, Workspace, WorkspaceConfig, WorkspaceConfigDoc, WorkspaceConfigInput, WorkspaceDefinitionConfig, WorkspaceFileEntry, WorkspaceIsolation, WorkspaceResource, ZaloChannelInput, ZaloConnectionDefinition, ZaloConnectionInput, ZaloMessageSource, ZaloSource };
3278
+ export type { Account, AccountAgent, AccountChannel, AccountEnvVar, AccountMcp, AccountPolicy, AccountRole, AccountSandbox, AccountWorkspace, Agent, AgentChannelsConfig, AgentCodeHookConfig, AgentConfig, AgentConfigDoc, AgentContinueInput, AgentDefinitionConfig, AgentDiscordChannelConfig, AgentGitHubChannelConfig, AgentGoogleChatChannelConfig, AgentHandle, AgentHookEventName, AgentHooks, AgentHooksConfig, AgentInstagramChannelConfig, AgentLinearChannelConfig, AgentMatrixChannelConfig, AgentMessengerChannelConfig, AgentPancakeChannelConfig, AgentProviderSettings, AgentReference, AgentResource, AgentRunAnswerInput, AgentRunEventInput, AgentRunInput, AgentRunModelOverrides, AgentRunOverrides, AgentRunResult, AgentSkillsDefinitionConfig, AgentSlackChannelConfig, AgentStreamPart, AgentSubagentDefinitionConfig, AgentTeamsChannelConfig, AgentTelegramChannelConfig, AgentTwilioChannelConfig, AgentWebhookHookConfig, AgentWhatsAppChannelConfig, AgentWorkspaceInput, AgentWorkspaceRef, AgentWorkspaceRefInput, AgentZaloChannelConfig, AnyConnectionDefinition, AnyResource, AssumeRoleResult, AsyncAgentRun, AsyncPollOptions, AsyncRequestAccepted, AsyncStatus, AuditEvent, AuditPage, AuditPrincipalLink, AuditSink, AuditVerification, BroodsAccount, BroodsAccountClientOptions, BroodsClientOptions, BroodsConfigDefinition, BroodsProjectConfig, BroodsWebSocketClientOptions, ChannelAgentInput, ChannelDefinitionConfig, ChannelMessageReceived, ChannelPartition, ChannelRecordConfig, ChannelReference, ChannelReplyIn, ChannelResource, ChannelType, CliManifest, CliManifestResource, ConfigPatch, Connection, ConnectionCode, ConnectionDefinition, ConnectionStart, ConnectionStartResult, ConnectionType, CreateAgentResult, CreateCronInput, CreateMcpInput, Cron, CronDefinitionConfig, CronDoc, CronLastStatus, CronResource, CronRun, CronStatus, DeleteAccountResult, DiscordChannelInput, DiscordConnectionDefinition, DiscordConnectionInput, DiscordMessageSource, DiscordSource, Doc, EnvAccessor, EnvRef, EnvRefString, GeneratedIds, GitHubChannelInput, GitHubConnectionDefinition, GitHubConnectionInput, GitHubMessageSource, GitHubSource, GoogleChatChannelInput, GoogleChatConnectionDefinition, GoogleChatConnectionInput, GoogleChatMessageSource, GoogleChatSource, HarnessDefinition, HarnessType, HookAgentConfig, HookContext, Id, IngressMode, IngressStatus, InstagramChannelInput, InstagramConnectionDefinition, InstagramConnectionInput, InstagramMessageSource, InstagramSource, LinearChannelInput, LinearConnectionDefinition, LinearConnectionInput, LinearMessageSource, LinearSource, LogLevel, MatrixChannelInput, MatrixConnectionDefinition, MatrixConnectionInput, MatrixMessageSource, MatrixSource, McpDefinitionConfig, McpHandler, McpOauthInput, McpResource, McpRuntime, MessengerChannelInput, MessengerConnectionDefinition, MessengerConnectionInput, MessengerMessageSource, MessengerSource, ObservabilityBackfillMessage, ObservabilityClientMessage, ObservabilityErrorMessage, ObservabilityFetchTraceMessage, ObservabilityLogEntry, ObservabilityLogMessage, ObservabilityReadyMessage, ObservabilityServerMessage, ObservabilitySpanMessage, ObservabilitySpanRow, ObservabilitySubscribeMessage, ObservabilityUnsubscribeMessage, PancakeChannelInput, PancakeConnectionDefinition, PancakeConnectionInput, PancakeMessageSource, PancakeSource, PendingQuestion, PolicyDefinitionConfig, PolicyDocument, PolicyResource, ProjectDoc, ProviderConfigInput, ProviderSettingsInput, QuestionAnswer, ResourceApi, ResourceDefinition, ResourceInput, ResourceKind, RotateSecretResult, Sandbox, SandboxConfig, SandboxConfigDoc, SandboxDefinitionConfig, SandboxDefinitionOptions, SandboxExecRequest, SandboxExecResponse, SandboxLifecycleResult, SandboxProvider, SandboxResource, SandboxSnapshotResult, SandboxTerminalTicket, Skill, SkillDefinitionConfig, SkillResource, SkillUploadInput, SlackChannelInput, SlackConnectionDefinition, SlackConnectionInput, SlackMessageSource, SlackSource, StageDoc, StageScope, TaskWaitingOn, TeamsChannelInput, TeamsConnectionDefinition, TeamsConnectionInput, TeamsMessageSource, TeamsSource, TelegramChannelInput, TelegramConnectionDefinition, TelegramConnectionInput, TelegramMessageSource, TelegramSource, ToolApprovalSummary, TwilioChannelInput, TwilioConnectionDefinition, TwilioConnectionInput, TwilioMessageSource, TwilioSource, UpdateAgentInput, UpdateCronInput, UpdateMcpInput, WebSocketAttachInput, WebSocketClientAttachMessage, WebSocketClientCancelMessage, WebSocketClientControlMessage, WebSocketClientExecuteMessage, WebSocketClientMessage, WebSocketConstructorLike, WebSocketHandlers, WebSocketLike, WebSocketOutputMessage, WebSocketRunInput, WebSocketServerMessage, WebSocketStreamMessage, WebSocketSubscription, WhatsAppChannelInput, WhatsAppConnectionDefinition, WhatsAppConnectionInput, WhatsAppMessageSource, WhatsAppSource, Workspace, WorkspaceConfig, WorkspaceConfigDoc, WorkspaceDefinitionConfig, WorkspaceFileEntry, WorkspaceIsolation, WorkspaceResource, WorkspaceStorageDefinition, ZaloChannelInput, ZaloConnectionDefinition, ZaloConnectionInput, ZaloMessageSource, ZaloSource };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{V,ge,Me,Pe,Ne,je,G,Ie,E,ye,F,J,xe,Y,z,qe,De,Le,Ue,Fe,Be,Ze,He,Ve,Ge,We,Ke,Je,Ye,Xe,Qe,et,tt,nt,rt,ot,st,it,at,ct,lt,ut,dt,pt,mt,ht,ft,gt,yt,St,bt,vt,_t,ie,w,g}from"./chunk-hdcy74kj.js";import{m,Ae,Z,R}from"./chunk-bb3jfhv3.js";export{m as BroodsAccountApiError,R as BroodsAccountClient,F as BroodsClient,xe as BroodsWebSocketClient,E as DEFAULT_CORE_BASE_URL,ye as IngressAcceptedError,Me as MAX_OBSERVABILITY_BACKFILL,xe as WebSocketClient,xe as WebsocketClient,De as defineAgent,Le as defineBroods,Ue as defineCron,ct as defineDiscordChannel,We as defineDiscordConnection,lt as defineGitHubChannel,Ke as defineGitHubConnection,ut as defineGoogleChatChannel,Je as defineGoogleChatConnection,Fe as defineHarness,dt as defineInstagramChannel,Ye as defineInstagramConnection,pt as defineLinearChannel,Xe as defineLinearConnection,mt as defineMatrixChannel,Qe as defineMatrixConnection,Be as defineMcp,ht as defineMessengerChannel,et as defineMessengerConnection,ft as definePancakeChannel,tt as definePancakeConnection,Ze as definePolicy,He as defineSandbox,Ve as defineSkill,gt as defineSlackChannel,nt as defineSlackConnection,yt as defineTeamsChannel,rt as defineTeamsConnection,St as defineTelegramChannel,ot as defineTelegramConnection,bt as defineTwilioChannel,st as defineTwilioConnection,vt as defineWhatsAppChannel,it as defineWhatsAppConnection,Ge as defineWorkspace,_t as defineZaloChannel,at as defineZaloConnection,qe as env,Ae as envPlaceholder,ie as isBroodsConfig,w as isConnectionDefinition,Pe as isLogLevel,Ne as isObservabilityClientMessage,g as isResource,je as isRootSpanKind,G as isSandboxLogId,Ie as isTraceId,J as normalizeHttpServiceUrl,ge as readSseStream,Z as resolveEnvCredential,V as resolveRunEvents,Y as toWebSocketBaseUrl,z as webSocketSubprotocols};
1
+ import{V,ge,Me,Pe,Ne,je,G,Ie,E,ye,F,J,xe,Y,z,qe,De,Le,Ue,Fe,Be,Ze,He,Ve,Ge,We,Ke,Je,Ye,Xe,Qe,et,tt,nt,rt,ot,st,it,at,ct,lt,ut,dt,pt,mt,ht,ft,gt,yt,St,bt,vt,_t,ie,w,g}from"./chunk-agza3wkj.js";import{m,Ae,Z,R}from"./chunk-bb3jfhv3.js";export{m as BroodsAccountApiError,R as BroodsAccountClient,F as BroodsClient,xe as BroodsWebSocketClient,E as DEFAULT_CORE_BASE_URL,ye as IngressAcceptedError,Me as MAX_OBSERVABILITY_BACKFILL,xe as WebSocketClient,xe as WebsocketClient,De as defineAgent,Le as defineBroods,Ue as defineCron,ct as defineDiscordChannel,We as defineDiscordConnection,lt as defineGitHubChannel,Ke as defineGitHubConnection,ut as defineGoogleChatChannel,Je as defineGoogleChatConnection,Fe as defineHarness,dt as defineInstagramChannel,Ye as defineInstagramConnection,pt as defineLinearChannel,Xe as defineLinearConnection,mt as defineMatrixChannel,Qe as defineMatrixConnection,Be as defineMcp,ht as defineMessengerChannel,et as defineMessengerConnection,ft as definePancakeChannel,tt as definePancakeConnection,Ze as definePolicy,He as defineSandbox,Ve as defineSkill,gt as defineSlackChannel,nt as defineSlackConnection,yt as defineTeamsChannel,rt as defineTeamsConnection,St as defineTelegramChannel,ot as defineTelegramConnection,bt as defineTwilioChannel,st as defineTwilioConnection,vt as defineWhatsAppChannel,it as defineWhatsAppConnection,Ge as defineWorkspace,_t as defineZaloChannel,at as defineZaloConnection,qe as env,Ae as envPlaceholder,ie as isBroodsConfig,w as isConnectionDefinition,Pe as isLogLevel,Ne as isObservabilityClientMessage,g as isResource,je as isRootSpanKind,G as isSandboxLogId,Ie as isTraceId,J as normalizeHttpServiceUrl,ge as readSseStream,Z as resolveEnvCredential,V as resolveRunEvents,Y as toWebSocketBaseUrl,z as webSocketSubprotocols};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "broods",
3
- "version": "0.45.0",
3
+ "version": "0.47.0",
4
4
  "description": "CLI + TypeScript SDK for the broods agent platform.",
5
5
  "keywords": [
6
6
  "agents",
@@ -1,5 +0,0 @@
1
- function V(e){if(e.events&&e.input!==void 0)throw Error("Run input accepts either `input` or `events`, not both");if(e.events&&e.events.length>0)return e.events;if(typeof e.input==="string")return[{role:"user",content:[{type:"text",text:e.input}]}];throw Error("Run input requires `input` (string) or a non-empty `events` array")}async function*ge(e){let n=e.getReader(),t=new TextDecoder,o="";try{while(!0){let{done:r,value:i}=await n.read();if(r)break;o+=t.decode(i,{stream:!0});let s=o.split(`
2
- `);o=s.pop()??"";for(let a of s)if(a.startsWith("data: "))yield a.slice(6)}}finally{n.releaseLock()}}var Me=500,Ce=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,he=/^(?!0{32}$)[0-9a-f]{32}$/;function Pe(e){return e==="DEBUG"||e==="INFO"||e==="WARN"||e==="ERROR"}function Ne(e){if(typeof e!=="object"||e===null)return!1;let n=e;if(n.type==="subscribe")return Se(n);if(n.type==="unsubscribe")return k(n.stream);if(n.type==="fetchTrace")return Ie(n.traceId);return!1}function je(e){return e==="task"||e==="cron"||e==="subtask"}function G(e){return typeof e==="string"&&Ce.test(e)}function Ie(e){return typeof e==="string"&&he.test(e)}function k(e){return e==="logs"||e==="traces"}function Se(e){let n=e.stream;if(!k(n))return!1;let t=e.backfill;if(t!==void 0&&(typeof t!=="number"||!Number.isSafeInteger(t)||t<0||t>500))return!1;if(e.liveOnly!==void 0&&typeof e.liveOnly!=="boolean")return!1;let o=e.minLevel;if(o!==void 0&&!Pe(o))return!1;let r=e.sandboxId;return r===void 0||n==="logs"&&G(r)}import{readFileSync as Re}from"node:fs";import{chmod as B,mkdir as be,writeFile as Ae}from"node:fs/promises";import{homedir as ke}from"node:os";import{dirname as D,join as ve}from"node:path";var y="broods",_="_generated",O=ve(ke(),".broods","config.json"),N="broods.app",P="dashboard",we="gateway";function T(e){let n=process.env.BROODS_TOKEN,t=e??process.env.BROODS_BASE_URL;if(n&&t)return{baseUrl:f(t),token:n,createdAt:new Date().toISOString()};let o=H();if(!o)return null;if(t)return o.logins[f(t)]??null;let r=process.env.BROODS_DASHBOARD_URL;if(r){let i=f(r);return Object.values(o.logins).find((s)=>s.dashboardUrl===i)??null}return o.logins[o.current]??null}async function W(e){let n=H()?.logins??{},t={current:e.baseUrl,logins:{...n,[e.baseUrl]:e}};await be(D(O),{recursive:!0,mode:448}),await B(D(O),448),await K(O,`${JSON.stringify(t,null,2)}
3
- `)}async function K(e,n){await Ae(e,n,{encoding:"utf8",mode:384}),await B(e,384)}function v(){return process.env.BROODS_STAGE}function f(e){let n=e.length;while(n>0&&e.charCodeAt(n-1)===47)n-=1;return e.slice(0,n)}function L(e){try{let n=new URL(e);if(!n.hostname.startsWith(`${P}.`))return;let t=n.hostname.slice(P.length+1);if(t!==N&&!t.endsWith(`.${N}`))return;return n.hostname=`${we}.${t}`,f(n.origin)}catch{return}}function H(){try{let e=JSON.parse(Re(O,"utf8"));if(typeof e.current!=="string"||!e.logins)return null;return{current:e.current,logins:e.logins}}catch{return null}}import{existsSync as q,readFileSync as Z,statSync as Ee}from"node:fs";import{join as X,resolve as Q}from"node:path";var A=new Map,Te=new Set(Object.keys(process.env)),j=new Set;function h(e=process.cwd()){Oe(e);let n=T();return{dashboardUrl:process.env.BROODS_DASHBOARD_URL??n?.dashboardUrl,baseUrl:process.env.BROODS_BASE_URL??n?.baseUrl,token:n?.token,project:process.env.BROODS_PROJECT,stage:v()}}function U(){let e={};for(let[n,t]of Object.entries(process.env))if(typeof t==="string"&&!n.startsWith("BROODS_"))e[n]=t;return e}function M(e,n=process.cwd()){let t=process.env[e];if(t===void 0)return!1;let o=Q(n);for(let r of[".env.local",".env"]){let i=X(o,r);if(!q(i))continue;let s=ee(Z(i,"utf8"));if(s[e]!==void 0)return s[e]!==t}return!0}function Oe(e){let n=Q(e),t=process.env.BROODS_RELOAD_ENV==="1";for(let o of[".env",".env.local"]){let r=X(n,o);if(!q(r)){A.delete(r);continue}let i=Ee(r).mtimeMs,s=A.get(r);if(s&&s.mtimeMs===i)continue;A.set(r,{mtimeMs:i});for(let[a,p]of Object.entries(ee(Z(r,"utf8"))))if(t||!Te.has(a)||j.has(a))process.env[a]=p,j.add(a)}}function ee(e){let n={};for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;let r=o.startsWith("export ")?o.slice(7).trim():o,i=r.indexOf("=");if(i<=0)continue;let s=r.slice(0,i).trim();if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(s))continue;n[s]=_e(r.slice(i+1).trim())}return n}function _e(e){if(e.startsWith('"')&&e.endsWith('"'))return e.slice(1,-1).replace(/\\n/g,`
4
- `).replace(/\\"/g,'"');if(e.startsWith("'")&&e.endsWith("'"))return e.slice(1,-1);let n=e.indexOf(" #");return n>=0?e.slice(0,n).trimEnd():e}var E="https://gateway.broods.app";class ye extends Error{accepted;constructor(e){super(`Ingress ${e.eventId} was accepted asynchronously with status ${e.status??"queued"}`);this.accepted=e;this.name="IngressAcceptedError"}}class F{baseUrl;apiKey;fetchImpl;constructor(e={}){h(),this.baseUrl=J(e.baseUrl||e.host||process.env.BROODS_BASE_URL||process.env.BROODS_HOST||E),this.apiKey=e.apiKey||process.env.BROODS_API_KEY||void 0,this.fetchImpl=e.fetch??fetch}channelWebhookUrl(e){return`${this.baseUrl}${e.webhookPath.startsWith("/")?"":"/"}${e.webhookPath}`}accountWebhookUrl(e,n){let t=[e,n].map(encodeURIComponent);return`${this.baseUrl}/v1/webhooks/${t.join("/")}`}stageWebhookUrl(e,n,t){let o=[e,"dev",n,t].map(encodeURIComponent);return`${this.baseUrl}/v1/webhooks/${o.join("/")}`}agent(e,n){if(typeof e==="string"){let o=e,r=n??"";if(!r)throw Error(`Agent ${o} is missing a generated id. Run broods dev --once or broods deploy to sync it first.`);return{id:r,run:(i)=>this.run({...i,agentName:o,agentId:r}),runAsync:(i)=>this.runAsync({...i,agentName:o,agentId:r}),continue:(i)=>this.continue({...i,agentId:r}),stream:(i)=>this.stream({...i,agentName:o,agentId:r})}}let t=e;if(!t.id)throw Error(`Agent ${t.name} is missing a generated id. Run broods dev --once or broods deploy to sync it first.`);return{id:t.id,run:(o)=>this.run(t,o),runAsync:(o)=>this.runAsync(t,o),continue:(o)=>this.continue(t,o),stream:(o)=>this.stream(t,o)}}async run(e,n){let t=[],o="",r=n?this.stream(e,n):this.stream(e);for await(let i of r)if(t.push(i),i.type==="text-delta")o+=i.text;return{text:o,events:t}}async*stream(e,n){let t=n?{...n,agentId:e.id,agentName:e.name}:e,o=ne(t,"cli"),r=n?this.scopedUrl(e):`${this.baseUrl}/v1/runs`,i=await this.openStream(o,r);if(!i.ok)throw Error(`Run failed: ${i.status} ${await i.text()}`);if(i.status===202)throw new ye(te(await i.json(),o));if(!i.body)throw Error("Run response has no body");for await(let s of ge(i.body)){let a;try{a=JSON.parse(s)}catch{continue}if(a.type==="error")throw Error(`Agent run failed: ${$e(a.error)}`);yield a}}async runAsync(e,n){let t=n?{...n,agentId:e.id,agentName:e.name}:e,o={...ne(t,"async"),background:!0},r=n?this.scopedUrl(e):`${this.baseUrl}/v1/runs`;return this.postAcceptedRun(r,o,"Async run")}async continue(e,n){let t=n?e:null,o=n??e,r={agentId:t?t.id:e.agentId,eventId:o.eventId??`continue-${crypto.randomUUID()}`,conversationKey:o.conversationKey,continue:!0},i=t?this.scopedUrl(t):`${this.baseUrl}/v1/runs`;return this.postAcceptedRun(i,r,"Continue")}async getAsyncStatus(e){let n=this.resolveStatusUrl(e),t=await this.fetchJson(n,{method:"GET",headers:this.apiKeyHeaders()});if(t.status===404)return{status:"not_found"};if(!t.ok)throw Error(`Status check failed: ${t.status} ${await t.text()}`);return await t.json()}async waitForAsyncStatus(e,n={}){let t=Date.now()+(n.timeoutMs??180000),o=n.intervalMs??2000;while(Date.now()<t){if(n.signal?.aborted)throw Error("Async status polling aborted.");let r=await this.getAsyncStatus(e);if(r.status==="awaiting_approval"||r.status==="awaiting_input"||r.status==="completed"||r.status==="failed"||r.status==="expired"||r.status==="not_found")return r;await en(o,n.signal)}throw Error("Polling timeout")}scopedUrl(e){if(e.projectSlug&&e.stageSlug&&e.endpointId)return`${this.baseUrl}/v1/projects/${encodeURIComponent(e.projectSlug)}/stages/${encodeURIComponent(e.stageSlug)}/agents/${encodeURIComponent(e.endpointId)}`;return`${this.baseUrl}/v1/runs`}asyncAgentRun(e,n){return{...e,conversationKey:n,poll:()=>this.getAsyncStatus(e),wait:(t)=>this.waitForAsyncStatus(e,t)}}async postAcceptedRun(e,n,t){let o=await this.fetchJson(e,{method:"POST",headers:this.apiKeyHeaders(),body:JSON.stringify(n)});if(o.status!==202)throw Error(`${t} failed: ${o.status} ${await ze(o,"202 JSON")}`);return this.asyncAgentRun(te(await o.json(),n),n.conversationKey)}async openStream(e,n){if(this.apiKey)return await this.fetchCore(e,n,{Authorization:`Bearer ${this.apiKey}`});throw Error(`BroodsClient streams directly from the core service at ${this.baseUrl}. Provide apiKey. For a self-hosted core service, set host/baseUrl or BROODS_HOST/BROODS_BASE_URL.`)}async fetchCore(e,n,t){try{return await this.fetchImpl(n,{method:"POST",headers:{"Content-Type":"application/json",Accept:"text/event-stream",...t},body:JSON.stringify(e)})}catch(o){throw Error(`Cannot access the broods core service at ${n}. The SDK uses ${E} by default; set host/baseUrl or BROODS_HOST/BROODS_BASE_URL to your own core service URL if your account uses a custom deployment. Cause: ${o instanceof Error?o.message:String(o)}`)}}apiKeyHeaders(){if(!this.apiKey)throw Error("BroodsClient requires apiKey or BROODS_API_KEY.");return{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`}}async fetchJson(e,n){try{return await this.fetchImpl(e,{...n,headers:{"Content-Type":"application/json",...n.headers}})}catch(t){throw Error(`Cannot access the broods core service at ${e}. Cause: ${t instanceof Error?t.message:String(t)}`)}}resolveStatusUrl(e){if(typeof e!=="string")return e.statusUrl;if(/^https?:\/\//.test(e))return e;return nn(this.baseUrl,e)}}function J(e){let n=e.trim(),t=/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(n)?n:`https://${n}`;return f(t)}function ne(e,n){let t=e.eventId??`${n}-${crypto.randomUUID()}`;return{agentId:e.agentId,eventId:t,conversationKey:e.conversationKey??t,events:V(e),...e.mode!==void 0?{mode:e.mode}:{},...e.idempotencyKey!==void 0?{idempotencyKey:e.idempotencyKey}:{},...e.system!==void 0?{system:e.system}:{},...e.model!==void 0?{model:e.model}:{}}}function $e(e){if(typeof e==="string")return e;if(!e||typeof e!=="object")return String(e);let n=e,t=n.data?.error?.message??n.message??n.responseBody??JSON.stringify(e),o=n.name?`${n.name}: `:"",r=n.statusCode?` (HTTP ${n.statusCode})`:"";return`${o}${t}${r}`}function te(e,n){if(!e||typeof e!=="object")throw Error("Async response must be an object");let t=e.statusUrl;if(typeof t!=="string"||t.length===0)throw Error("Async response missing statusUrl");let o=e.runId;if(typeof o!=="string"||o.length===0)throw Error("Async response missing runId");let r=typeof e.eventId==="string"?e.eventId:o,{status:i,requestedMode:s}=e;return{statusUrl:t,runId:o,eventId:r,agentId:n.agentId,...i==="accepted"||i==="queued"||i==="applied"||i==="processing"?{status:i}:{},...s==="reject"||s==="followup"||s==="collect"||s==="steer"?{requestedMode:s}:{}}}async function ze(e,n){if((e.headers.get("content-type")??"").toLowerCase().includes("text/event-stream"))return await e.body?.cancel().catch(()=>{}),`expected ${n}, but the server returned an SSE stream. This usually means the core deployment ignored the background flag and ran the request on the direct streaming runner.`;let o=await e.text();if(o.length<=2000)return o;return`${o.slice(0,2000)}... [truncated ${o.length-2000} chars]`}function en(e,n){return new Promise((t,o)=>{if(n?.aborted){o(Error("Async status polling aborted."));return}let r=setTimeout(t,e);n?.addEventListener("abort",()=>{clearTimeout(r),o(Error("Async status polling aborted."))},{once:!0})})}function nn(e,n){return`${J(e)}/v1/runs/${encodeURIComponent(n)}`}var tn=2000,oe=0,S=1;class xe{baseUrl;apiKey;WebSocketImpl;connectTimeoutMs;constructor(e={}){if(h(),this.baseUrl=ue(e.baseUrl||e.host||process.env.BROODS_BASE_URL||process.env.BROODS_HOST||E),this.apiKey=e.apiKey||process.env.BROODS_API_KEY||"",!this.apiKey)throw Error("BroodsWebSocketClient requires apiKey or BROODS_API_KEY.");this.WebSocketImpl=e.WebSocket,this.connectTimeoutMs=e.connectTimeoutMs??tn}subscribe(e,n={}){let t=this.resolveWebSocket(),o=this.buildUrl(e),r=on(e),i=ce(this.baseUrl),s=new t(o,z(this.apiKey)),a=!1,p=!1,d=setTimeout(()=>{if(!a)C(i)},this.connectTimeoutMs),x=(l=1000,b="client closed")=>{if(p)return;if(p=!0,clearTimeout(d),e.signal?.removeEventListener("abort",R),s.readyState===S||s.readyState===oe)s.close(l,b)},C=(l)=>{n.onError?.(l),x(1011,"websocket error")},me=()=>{n.onDone?.(),x(1000,"done")},R=()=>{if(s.readyState===S)s.send(JSON.stringify({type:"cancel"}));C(Error("WebSocket run aborted."))};return e.signal?.addEventListener("abort",R,{once:!0}),s.onopen=()=>{if(a=!0,clearTimeout(d),e.signal?.aborted){R();return}s.send(JSON.stringify({type:"execute",agentId:r,...e.answers?{answers:e.answers}:{events:V(e)},sessionId:e.sessionId,...e.eventId!==void 0?{eventId:e.eventId}:{},...e.mode!==void 0?{mode:e.mode}:{},...e.idempotencyKey!==void 0?{idempotencyKey:e.idempotencyKey}:{},...e.system!==void 0?{system:e.system}:{},...e.model!==void 0?{model:e.model}:{}}))},s.onmessage=(l)=>{if(typeof l.data!=="string")return;let b=se(l.data);if(!b)return;let I=ae(b,n);switch(n.onMessage?.(I),I.type){case"meta":n.onMeta?.(I);break;case"done":me();break;case"error":C(Error(re(I.error)));break}},s.onerror=()=>{C(i)},s.onclose=(l)=>{if(clearTimeout(d),e.signal?.removeEventListener("abort",R),p||l.code===1000)return;C(Error(l.reason||"WebSocket connection closed."))},{url:o,sendControl:function(l){if(s.readyState!==S)throw Error("WebSocket is not open");s.send(JSON.stringify({type:"control",...l}))},close:x}}attach(e,n={}){let t=this.resolveWebSocket(),o=this.buildUrl(e),r=new t(o,z(this.apiKey)),i=!1,s=(a=1000,p="client closed")=>{if(i)return;if(i=!0,r.readyState===S||r.readyState===oe)r.close(a,p)};return r.onopen=()=>r.send(JSON.stringify({type:"attach",...e,signal:void 0,agent:void 0})),r.onmessage=(a)=>{if(typeof a.data!=="string")return;let p=se(a.data);if(!p)return;let d=ae(p,n);if(n.onMessage?.(d),d.type==="done")n.onDone?.();if(d.type==="error")n.onError?.(Error(re(d.error)))},r.onerror=()=>n.onError?.(ce(this.baseUrl)),r.onclose=(a)=>{if(!i&&a.code!==1000)n.onError?.(Error(a.reason||"WebSocket connection closed."))},{url:o,sendControl:function(a){if(r.readyState!==S)throw Error("WebSocket is not open");r.send(JSON.stringify({type:"control",...a}))},close:s}}async*stream(e){let n=[],t=!1,o=null,r=null,i=()=>{r?.(),r=null},s=this.subscribe(e,{onMessage:function(a){n.push(a),i()},onDone:function(){t=!0,i()},onError:function(a){o=a,i()}});try{while(!0){if(n.length>0){yield n.shift();continue}if(o)throw o;if(t)return;await new Promise((a)=>{r=a})}}finally{s.close()}}buildUrl(e){let n=rn(e),t=e.projectSlug??e.agent?.projectSlug,o=e.stageSlug??e.agent?.stageSlug,r=t&&o?`/projects/${encodeURIComponent(t)}/stages/${encodeURIComponent(o)}`:"";return`${Y(this.baseUrl)}/v1${r}/agents/${encodeURIComponent(n)}/ws`}resolveWebSocket(){let e=this.WebSocketImpl??globalThis.WebSocket;if(!e)throw Error("WebSocket is not available. Pass a WebSocket implementation in BroodsWebSocketClient options.");return e}}function Y(e){let n=new URL(ue(e));if(n.protocol==="https:")n.protocol="wss:";if(n.protocol==="http:")n.protocol="ws:";return f(n.toString())}function z(e){return["broods.v1",`broods.token.${e}`]}function re(e){if(typeof e==="string")return e;if(e&&typeof e==="object"&&typeof e.message==="string")return e.message;return e===void 0?"WebSocket stream error.":JSON.stringify(e)}function ue(e){let n=e.trim();if(/^wss?:\/\//.test(n))return f(n);return J(n)}function se(e){try{let n=JSON.parse(e);return typeof n==="object"&&n!==null&&typeof n.type==="string"?n:null}catch{return null}}function on(e){let n=e.agentId??e.agent?.id??e.endpointId;if(!n)throw Error("WebSocket run requires agent, agentId, or endpointId.");return n}function rn(e){let n=e.endpointId??e.agent?.endpointId??e.agent?.id;if(!n)throw Error("WebSocket run requires agent or endpointId.");return n}function ae(e,n){if(e.type!=="output")return e;let t=e;return n.onOutput?.(t),t.data}function ce(e){return Error(`Cannot access the WebSocket service at ${e}.`)}var pe=Symbol.for("broods.resource"),de=Symbol.for("broods.config"),fe=Symbol.for("broods.connection"),le=/^[A-Z][A-Z0-9_]{0,63}$/,qe=new Proxy((e)=>{if(!le.test(e))throw Error("env name must match /^[A-Z][A-Z0-9_]*$/ and be at most 64 characters.");return{__beeblastEnv:!0,name:e}},{get:function(e,n,t){if(typeof n==="string"&&le.test(n))throw Error(`env.${n} is not supported; use env("${n}")`);return Reflect.get(e,n,t)}});function De(e){let{name:n,description:t,...o}=e;return m("agent",n,t,o)}function Le(e){return{[de]:!0,config:e}}function Ue(e){let{name:n,description:t,...o}=e;return m("cron",n,t,o)}function Fe(e){return e}function Be(e){let{name:n,description:t,...o}=e;return m("mcp",n,t,o)}function Ze(e){let{name:n,description:t,...o}=e;return m("policy",n,t,o)}function He(e){let{name:n,description:t,...o}=e;return m("sandbox",n,t,o)}function Ve(e){let{name:n,description:t,...o}=e;return m("skill",n,t,o)}function Ge(e){let{name:n,description:t,...o}=e;return m("workspace",n,t,o)}function We(e){return u("discord",e)}function Ke(e){return u("github",e)}function Je(e){return u("gchat",e)}function Ye(e){return u("instagram",e)}function Xe(e){return u("linear",e)}function Qe(e){return u("matrix",e)}function et(e){return u("messenger",e)}function tt(e){return u("pancake",e)}function nt(e){return u("slack",e)}function rt(e){return u("teams",e)}function ot(e){return u("telegram",e)}function st(e){return u("twilio",e)}function it(e){return u("whatsapp",e)}function at(e){return u("zalo",e)}function ct(e){let{name:n,description:t,channelId:o,guildId:r,...i}=e;return c(n,t,o,r,i)}function lt(e){let{name:n,description:t,repo:o,...r}=e,[i,...s]=o.split("/");if(!i||s.length!==1||!s[0])throw Error(`Channel "${n}" repo must be "owner/name", not "${o}"`);return c(n,t,o,i,r)}function ut(e){let{name:n,description:t,spaceName:o,...r}=e;return c(n,t,o,void 0,r)}function dt(e){let{name:n,description:t,igsid:o,...r}=e;return c(n,t,o,void 0,r)}function pt(e){let{name:n,description:t,team:o,...r}=e;return c(n,t,o,void 0,r)}function mt(e){let{name:n,description:t,channelId:o,...r}=e;return c(n,t,o,void 0,r)}function ht(e){let{name:n,description:t,psid:o,...r}=e;return c(n,t,o,void 0,r)}function ft(e){let{name:n,description:t,conversationId:o,...r}=e;return c(n,t,o,void 0,r)}function gt(e){let{name:n,description:t,channelId:o,teamId:r,...i}=e;return c(n,t,o,r,i)}function yt(e){let{name:n,description:t,channelId:o,teamId:r,...i}=e;return c(n,t,o,r,i)}function St(e){let{name:n,description:t,chatId:o,...r}=e;return c(n,t,o,void 0,r)}function bt(e){let{name:n,description:t,from:o,...r}=e;return c(n,t,o,void 0,r)}function vt(e){let{name:n,description:t,waId:o,...r}=e;return c(n,t,o,void 0,r)}function _t(e){let{name:n,description:t,chatId:o,...r}=e;return c(n,t,o,void 0,r)}function ie(e){return Boolean(e&&typeof e==="object"&&e[de])}function w(e){return Boolean(e&&typeof e==="object"&&e[fe])}function g(e){return Boolean(e&&typeof e==="object"&&e[pe])}function c(e,n,t,o,r){return m("channelRecord",e,n,{...r,externalId:t,...o?{workspaceRef:o}:{}})}function u(e,n){let{partition:t,...o}=n;return{[fe]:!0,kind:"connection",type:e,...t?{partition:t}:{},config:o}}function m(e,n,t,o){return{[pe]:!0,kind:e,name:n,...t?{description:t}:{},config:o}}
5
- export{V,ge,Me,Pe,Ne,je,G,Ie,y,_,O,T,W,K,v,f,L,h,U,M,E,ye,F,J,xe,Y,z,qe,De,Le,Ue,Fe,Be,Ze,He,Ve,Ge,We,Ke,Je,Ye,Xe,Qe,et,tt,nt,rt,ot,st,it,at,ct,lt,ut,dt,pt,mt,ht,ft,gt,yt,St,bt,vt,_t,ie,w,g};