broods 0.46.0 → 0.48.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;
@@ -346,7 +353,8 @@ interface AgentSessionPruningConfig {
346
353
  /**
347
354
  * Compaction after a finished turn, on unless `enabled: false`. It runs once
348
355
  * the turn's last model call read `maxContextLength` input tokens or more
349
- * (default 500000). `/compact` works whatever this says.
356
+ * (default 500000), or after the provider refused a turn for context length.
357
+ * `/compact` works whatever 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;
@@ -2104,6 +2122,8 @@ interface McpOauthInput {
2104
2122
  refreshToken: string;
2105
2123
  tokenUrl?: string;
2106
2124
  }
2125
+ /** Where a hosted MCP server may run. */
2126
+ type McpRuntime = "auto" | "lambda";
2107
2127
  /** Public MCP server registration returned by the `/v1/mcp` routes (#331). */
2108
2128
  interface AccountMcp {
2109
2129
  accountId: string;
@@ -2115,10 +2135,14 @@ interface AccountMcp {
2115
2135
  transport: "http" | "hosted" | "machine";
2116
2136
  /** External servers only; a hosted row has no endpoint of its own. */
2117
2137
  url?: string;
2118
- /** Machine servers only: the machine sandbox (by name) whose daemon serves it. */
2138
+ /** Machine servers only: the sandbox (by name) that serves it. */
2119
2139
  sandbox?: string;
2140
+ /** Machine servers only: argv of the stdio server a lambda sandbox runs. */
2141
+ command?: string[];
2120
2142
  /** Hosted servers only: content hash of the uploaded bundle. */
2121
2143
  sha256?: string;
2144
+ /** Hosted servers only: "auto" or "lambda". */
2145
+ runtime?: McpRuntime;
2122
2146
  headers?: Record<string, string>;
2123
2147
  oauth?: McpOauthInput;
2124
2148
  allowedTools?: string[];
@@ -2131,19 +2155,26 @@ interface AccountMcp {
2131
2155
  /**
2132
2156
  * Fields accepted by `POST /v1/mcp`: `url` connects, `bundle` uploads inline
2133
2157
  * (≤10 MB); a larger bundle goes through `uploadMcpBundle` first; `sandbox`
2134
- * runs it on that machine sandbox's daemon.
2158
+ * runs it on that sandbox: a machine's daemon, or `command` on a lambda VM.
2135
2159
  */
2136
2160
  interface CreateMcpInput {
2137
2161
  name: string;
2138
2162
  description?: string;
2139
2163
  url?: string;
2140
2164
  sandbox?: string;
2165
+ command?: string[];
2141
2166
  bundle?: string;
2142
2167
  bundleStorageId?: string;
2143
2168
  sha256?: string;
2144
2169
  headers?: Record<string, string>;
2145
2170
  oauth?: McpOauthInput;
2146
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;
2147
2178
  }
2148
2179
  /** Fields accepted by `PATCH /v1/mcp/{serverId}`; every field is optional. */
2149
2180
  interface UpdateMcpInput {
@@ -2151,12 +2182,19 @@ interface UpdateMcpInput {
2151
2182
  description?: string;
2152
2183
  url?: string;
2153
2184
  sandbox?: string;
2185
+ command?: string[];
2154
2186
  bundle?: string;
2155
2187
  bundleStorageId?: string;
2156
2188
  sha256?: string;
2157
2189
  headers?: Record<string, string>;
2158
2190
  oauth?: McpOauthInput;
2159
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;
2160
2198
  disabled?: boolean;
2161
2199
  }
2162
2200
  /**
@@ -2340,9 +2378,9 @@ declare class BroodsAccountClient {
2340
2378
  resumeSandbox(sandboxId: string, reservationKey: string): Promise<SandboxLifecycleResult>;
2341
2379
  /** Terminate a persistent sandbox reservation and drop its live-instance row. Throws on 404/403/409. */
2342
2380
  terminateSandbox(sandboxId: string, reservationKey: string): Promise<SandboxLifecycleResult>;
2343
- /** Snapshot a persistent sandbox reservation into a reusable image (self-hosted `sandbox` provider). Throws on 404/403/409. */
2381
+ /** Snapshot a persistent sandbox reservation into a reusable image (`sandbox`, or `lambda`, which answers `building` until its image build lands). Throws on 404/403/409. */
2344
2382
  snapshotSandbox(sandboxId: string, reservationKey: string, name: string): Promise<SandboxSnapshotResult>;
2345
- /** 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. */
2346
2384
  openSandboxTerminal(sandboxId: string, reservationKey: string): Promise<SandboxTerminalTicket>;
2347
2385
  /** MCP servers live in one stage, so the collection routes need a scope. */
2348
2386
  listMcp(scope: StageScope): Promise<AccountMcp[]>;
@@ -2642,7 +2680,7 @@ type McpHandler = ((request: Request) => Response | Promise<Response>) | {
2642
2680
  };
2643
2681
  /**
2644
2682
  * MCP server registration (#331): external (`url`), hosted (`handler`), or on
2645
- * 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
2646
2684
  * `<name>__<tool>`; an external row is dialed over the stateless HTTP
2647
2685
  * transport (spec 2026-07-28) at agent registration time. The name namespaces
2648
2686
  * those tools, so it must be 1-32 lowercase letters, digits, or hyphens,
@@ -2652,17 +2690,31 @@ interface McpDefinitionConfig {
2652
2690
  /** External server's MCP endpoint; http(s), no embedded credentials. */
2653
2691
  url?: string;
2654
2692
  /**
2655
- * Instead of `url` or `handler`: the machine sandbox whose daemon runs this
2656
- * 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`.
2657
2696
  */
2658
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[];
2659
2703
  /**
2660
2704
  * Hosted alternative to `url`: declare the server inline as
2661
2705
  * `handler: createMcpHandler(...)` from @modelcontextprotocol/server,
2662
2706
  * right next to the `defineMcp` call. The CLI bundles the defining module
2663
- * 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.
2664
2710
  */
2665
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;
2666
2718
  /**
2667
2719
  * Extra request headers. Credential-bearing headers (Authorization,
2668
2720
  * X-Api-Key, ...) must reference an account env var by name inside a plain
@@ -3082,12 +3134,14 @@ interface ProviderSettingsInput {
3082
3134
  apiKey?: string | EnvRef;
3083
3135
  base_url?: string | EnvRef;
3084
3136
  baseURL?: string | EnvRef;
3137
+ /** `cloudflare` only: the AI Gateway every request goes through. */
3138
+ gatewayId?: string;
3085
3139
  headers?: Record<string, string | EnvRef>;
3086
3140
  [key: string]: unknown;
3087
3141
  }
3088
3142
  /** Per-provider settings; provider names stay synced with core's `AgentConfig`. */
3089
3143
  type ProviderConfigInput = Partial<Record<keyof NonNullable<AgentConfig["provider"]>, ProviderSettingsInput>>;
3090
- type AgentDefinitionConfig = EnvRefString<Pick<AgentConfig, "agent" | "model" | "scheduler" | "session" | "tools" | "mcp">> & {
3144
+ type AgentDefinitionConfig = EnvRefString<Pick<AgentConfig, "agent" | "model" | "scheduler" | "browser" | "session" | "tools" | "mcp">> & {
3091
3145
  provider?: ProviderConfigInput;
3092
3146
  } & {
3093
3147
  harness?: HarnessDefinition;
@@ -3127,12 +3181,26 @@ type AgentResource<Name extends string = string> = ResourceDefinition<"agent", N
3127
3181
  * Code-first workspace config. Says `partitioned` where storage says
3128
3182
  * `isolation`. "conversation" permits a per-conversation split that a
3129
3183
  * channel's `partition` performs; "agent" splits the workspace per attached
3130
- * agent on its own, with no partition needed.
3184
+ * agent on its own, with no partition needed. R2 keys take `env("NAME")`.
3131
3185
  */
3132
- type WorkspaceDefinitionConfig = Omit<WorkspaceConfig, "isolation"> & {
3186
+ type WorkspaceDefinitionConfig = Omit<WorkspaceConfig, "isolation" | "storage"> & {
3187
+ storage?: WorkspaceStorageDefinition;
3133
3188
  /** How to split this workspace: per conversation or per agent. */
3134
3189
  partitioned?: WorkspaceIsolation;
3135
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
+ });
3203
+ };
3136
3204
  type WorkspaceResource<Name extends string = string> = ResourceDefinition<"workspace", Name, WorkspaceDefinitionConfig>;
3137
3205
  type SandboxResource<Name extends string = string> = ResourceDefinition<"sandbox", Name, SandboxDefinitionConfig>;
3138
3206
  type SkillResource<Name extends string = string> = ResourceDefinition<"skill", Name, SkillDefinitionConfig>;
@@ -3207,4 +3275,4 @@ declare function isConnectionDefinition(value: unknown): value is AnyConnectionD
3207
3275
  declare function isResource(value: unknown): value is AnyResource;
3208
3276
 
3209
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 };
3210
- 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, 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-hb3c3xt9.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.46.0",
3
+ "version": "0.48.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};