broods 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1008 @@
1
+ import { SystemModelMessage, CallSettings, streamText, JSONSchema7, ModelMessage, TextStreamPart, ToolSet } from 'ai';
2
+
3
+ /**
4
+ * Shared channel streaming driver.
5
+ * Turns the agent's streamed output into incremental channel updates so a chat
6
+ * reply appears live instead of only after the whole turn. Three modes:
7
+ * - "edit": post one placeholder message, then edit it in place on a throttled
8
+ * cadence (needs the channel's beginMessage/editMessage primitives); when the
9
+ * reply outgrows the channel's message-length cap the current message is frozen
10
+ * and streaming continues in a fresh one (rotation).
11
+ * - "progress": one live preview for the whole turn (openclaw's progress draft).
12
+ * While the model works it shows a compact status (💭 reasoning + 🛠 tool lines);
13
+ * when the answer starts streaming the text takes over the same message; finish()
14
+ * finalizes that one message in place. One message per turn — never per-block.
15
+ * - "chunk": send a new message as each paragraph completes (uses sendText, so it
16
+ * works for every channel).
17
+ * Accumulation + throttling live here so each channel adapter stays thin; a channel
18
+ * that cannot edit a posted message falls back to "chunk" for edit/progress modes.
19
+ */
20
+
21
+ type ChannelStreamMode = "edit" | "chunk" | "progress";
22
+
23
+ /**
24
+ * Supported account model provider names.
25
+ * Keep provider identifiers here so config validation and model resolution share one source.
26
+ */
27
+ declare const ACCOUNT_MODEL_PROVIDERS: {
28
+ readonly google: true;
29
+ readonly openai: true;
30
+ readonly anthropic: true;
31
+ readonly bedrock: true;
32
+ readonly gateway: true;
33
+ readonly minimax: true;
34
+ };
35
+ type AccountModelProviderName = keyof typeof ACCOUNT_MODEL_PROVIDERS;
36
+
37
+ /**
38
+ * Agent configuration: types for the per-agent settings object, input
39
+ * normalization, encryption helpers, patch-merge, and redaction.
40
+ * Account types and auth live in `./accounts.ts` and `../auth.ts`.
41
+ */
42
+
43
+ interface AgentConfig {
44
+ agent?: AgentBehaviorConfig;
45
+ model?: AgentModelConfig;
46
+ provider?: AgentProviderConfig;
47
+ sandbox?: string;
48
+ workspaces?: AgentWorkspaceRef[];
49
+ session?: AgentSessionConfig;
50
+ hooks?: AgentHooksConfig;
51
+ channels?: AgentChannelsConfig;
52
+ tools?: AgentToolsConfig;
53
+ skills?: AgentSkillsConfig;
54
+ subagent?: AgentSubagentConfig;
55
+ publicAccess?: boolean;
56
+ [key: string]: unknown;
57
+ }
58
+ interface AgentBehaviorConfig {
59
+ maxTurn?: number;
60
+ system?: string | SystemModelMessage | SystemModelMessage[];
61
+ [key: string]: unknown;
62
+ }
63
+ type StreamTextOptions$1 = Parameters<typeof streamText>[0];
64
+ type AgentModelProviderOptions = StreamTextOptions$1["providerOptions"];
65
+ interface AgentSkillsConfig {
66
+ enabled?: boolean;
67
+ allowed?: string[];
68
+ [key: string]: unknown;
69
+ }
70
+ interface AgentSubagentConfig {
71
+ enabled?: boolean;
72
+ allowed?: string[];
73
+ context?: "new" | "inherited";
74
+ mode?: "ephemeral" | "persistent";
75
+ [key: string]: unknown;
76
+ }
77
+ interface AgentModelConfig extends Omit<CallSettings, "abortSignal" | "headers"> {
78
+ provider?: AccountModelProviderName;
79
+ modelId?: string;
80
+ providerOptions?: AgentModelProviderOptions;
81
+ output?: AgentModelOutputConfig;
82
+ }
83
+ type AgentModelOutputConfig = ({
84
+ type: "text";
85
+ } & AgentModelOutputMetadata) | ({
86
+ type: "object";
87
+ schema: JSONSchema7;
88
+ } & AgentModelOutputMetadata) | ({
89
+ type: "array";
90
+ element: JSONSchema7;
91
+ } & AgentModelOutputMetadata) | ({
92
+ type: "choice";
93
+ options: string[];
94
+ } & AgentModelOutputMetadata) | ({
95
+ type: "json";
96
+ } & AgentModelOutputMetadata);
97
+ type AgentModelOutputMetadata = {
98
+ name?: string;
99
+ description?: string;
100
+ [key: string]: unknown;
101
+ };
102
+ type AgentProviderConfig = Partial<Record<AccountModelProviderName, AgentProviderSettings>>;
103
+ interface AgentProviderSettings {
104
+ [key: string]: unknown;
105
+ }
106
+ interface AgentWorkspaceRef {
107
+ name: string;
108
+ workspaceId: string;
109
+ sandbox?: string | null;
110
+ }
111
+ interface AgentSessionConfig {
112
+ pruning?: AgentSessionPruningConfig;
113
+ compaction?: AgentSessionCompactionConfig;
114
+ [key: string]: unknown;
115
+ }
116
+ interface AgentSessionPruningConfig {
117
+ enabled?: boolean;
118
+ [key: string]: unknown;
119
+ }
120
+ interface AgentSessionCompactionConfig {
121
+ enabled?: boolean;
122
+ maxContextLength?: number;
123
+ [key: string]: unknown;
124
+ }
125
+ interface AgentHooksConfig {
126
+ /** Outbound event webhooks. An agent may register several independent endpoints. */
127
+ webhooks?: AgentWebhookHookConfig[];
128
+ [key: string]: unknown;
129
+ }
130
+ interface AgentWebhookHookConfig {
131
+ enabled?: boolean;
132
+ url?: string;
133
+ secret?: string;
134
+ events?: AgentLifecycleEventName[];
135
+ [key: string]: unknown;
136
+ }
137
+ type AgentLifecycleEventName = "agent.started" | "agent.step.finished" | "agent.finished" | "agent.failed" | "agent.approval.required" | "tool.call.started" | "tool.call.finished" | "tool.result" | "subagent.task.started" | "subagent.task.finished";
138
+ type AgentToolsConfig = Record<string, AgentToolConfig>;
139
+ interface AgentToolConfig {
140
+ enabled?: boolean;
141
+ needsApproval?: boolean;
142
+ async?: boolean;
143
+ config?: Record<string, unknown>;
144
+ [key: string]: unknown;
145
+ }
146
+ interface AgentChannelsConfig {
147
+ telegram?: AgentTelegramChannelConfig;
148
+ github?: AgentGitHubChannelConfig;
149
+ slack?: AgentSlackChannelConfig;
150
+ discord?: AgentDiscordChannelConfig;
151
+ pancake?: AgentPancakeChannelConfig;
152
+ zalo?: AgentZaloChannelConfig;
153
+ [key: string]: unknown;
154
+ }
155
+ type AgentChannelStreamingMode = ChannelStreamMode | "off";
156
+ interface AgentChannelStreamingConfig {
157
+ mode?: AgentChannelStreamingMode;
158
+ [key: string]: unknown;
159
+ }
160
+ interface AgentTelegramChannelConfig {
161
+ botToken?: string;
162
+ webhookSecret?: string;
163
+ allowedChatIds?: number[];
164
+ reactionEmoji?: string;
165
+ streaming?: AgentChannelStreamingConfig;
166
+ [key: string]: unknown;
167
+ }
168
+ interface AgentGitHubChannelConfig {
169
+ webhookSecret?: string;
170
+ appId?: string;
171
+ privateKey?: string;
172
+ allowedRepos?: string[];
173
+ [key: string]: unknown;
174
+ }
175
+ interface AgentSlackChannelConfig {
176
+ botToken?: string;
177
+ signingSecret?: string;
178
+ allowedChannelIds?: string[];
179
+ streaming?: AgentChannelStreamingConfig;
180
+ [key: string]: unknown;
181
+ }
182
+ interface AgentDiscordChannelConfig {
183
+ botToken?: string;
184
+ publicKey?: string;
185
+ allowedGuildIds?: string[];
186
+ streaming?: AgentChannelStreamingConfig;
187
+ [key: string]: unknown;
188
+ }
189
+ interface AgentPancakeChannelConfig {
190
+ pageId?: string;
191
+ pageAccessToken?: string;
192
+ webhookSecret?: string;
193
+ senderId?: string;
194
+ options?: Record<string, unknown>;
195
+ streaming?: AgentChannelStreamingConfig;
196
+ [key: string]: unknown;
197
+ }
198
+ interface AgentZaloChannelConfig {
199
+ botToken?: string;
200
+ webhookSecret?: string;
201
+ allowedUserIds?: string[];
202
+ streaming?: AgentChannelStreamingConfig;
203
+ [key: string]: unknown;
204
+ }
205
+
206
+ /**
207
+ * Cron-job types, input normalization, and patch-merge helpers.
208
+ * Provider-agnostic — both the DynamoDB and Convex stores import the
209
+ * normalizer at their create/update entry points so behaviour is
210
+ * symmetric across modes.
211
+ */
212
+
213
+ type CronStatus = "active" | "paused";
214
+ type CronLastStatus = "started" | "completed" | "failed";
215
+ /**
216
+ * One-of run payload mirroring the agent direct API's AgentRunInput: provide a
217
+ * single `input` string (wrapped into one user message) or a full `events` list.
218
+ */
219
+ type CronRunInput = {
220
+ input: string;
221
+ events?: never;
222
+ } | {
223
+ events: ModelMessage[];
224
+ input?: never;
225
+ };
226
+ type CreateCronInput = {
227
+ name: string;
228
+ description?: string;
229
+ agentId: string;
230
+ conversationKey?: string;
231
+ scheduleExpression: string;
232
+ timezone?: string;
233
+ status?: CronStatus;
234
+ } & CronRunInput;
235
+ type UpdateCronInput = {
236
+ name?: string;
237
+ description?: string | null;
238
+ agentId?: string;
239
+ conversationKey?: string | null;
240
+ scheduleExpression?: string;
241
+ timezone?: string | null;
242
+ status?: CronStatus;
243
+ } & ({
244
+ input?: string;
245
+ events?: never;
246
+ } | {
247
+ events?: ModelMessage[];
248
+ input?: never;
249
+ });
250
+
251
+ /**
252
+ * Sandbox config: account-scoped, reusable sandbox definitions referenced by
253
+ * agents via `config.sandbox`. A sandbox is a collection of Claude-Code-style
254
+ * tools (bash/read/write/edit/glob/grep) backed by a provider. Validation +
255
+ * the public projection live here; the
256
+ * DynamoDB / Convex stores call these at their create/update entry points.
257
+ * Stored encrypted at rest because `envVars`/`options` may hold secrets.
258
+ */
259
+ type SandboxProvider = "lambda" | "e2b" | "daytona" | "kubernetes" | "vercel";
260
+ type SandboxRuntimeName = "bash" | "python" | "node";
261
+ type SandboxPermissionMode = "edit" | "ask" | "bypass";
262
+ type SandboxNetworkMode = "allow-all" | "deny-all" | "restricted";
263
+ interface SandboxLifecycleConfig {
264
+ idleTimeoutSeconds?: number;
265
+ maxLifetimeSeconds?: number;
266
+ }
267
+ interface SandboxNetworkConfig {
268
+ mode: SandboxNetworkMode;
269
+ allowDomains?: string[];
270
+ allowCidrs?: string[];
271
+ }
272
+ interface SandboxConfig {
273
+ provider: SandboxProvider;
274
+ runtimes?: SandboxRuntimeName[];
275
+ network?: SandboxNetworkConfig;
276
+ permissionMode?: SandboxPermissionMode;
277
+ persistent?: boolean;
278
+ ephemeralHome?: boolean;
279
+ lifecycle?: SandboxLifecycleConfig;
280
+ onCreate?: string[];
281
+ onResume?: string[];
282
+ timeout?: number;
283
+ memoryLimit?: number;
284
+ outputLimitBytes?: number;
285
+ envVars?: Record<string, undefined | string>;
286
+ options?: Record<string, unknown>;
287
+ }
288
+
289
+ /**
290
+ * Workspace config: account-scoped, reusable workspace definitions referenced by
291
+ * agents via `config.workspaces[].workspaceId`. A workspace is the persistent
292
+ * S3-backed filesystem mounted into a sandbox; agents referencing the same
293
+ * workspaceId share the same files. Holds no secrets, so it is stored in
294
+ * plaintext (unlike sandbox config). Validation + the public projection live
295
+ * here; the DynamoDB / Convex stores call these at create/update.
296
+ */
297
+ declare const WORKSPACE_STORAGE_PROVIDERS: readonly ["s3"];
298
+ type WorkspaceStorageProvider = (typeof WORKSPACE_STORAGE_PROVIDERS)[number];
299
+ interface WorkspaceConfig {
300
+ storage: {
301
+ provider: WorkspaceStorageProvider;
302
+ };
303
+ harness?: {
304
+ enabled?: boolean;
305
+ };
306
+ }
307
+
308
+ /**
309
+ * Canonical CLI manifest wire types — the single source of truth shared by the
310
+ * backend (cliSync.ts, cliHttp.ts) and the SDK/CLI (packages/broods).
311
+ *
312
+ * This file is intentionally type-only with no runtime imports so the SDK can
313
+ * import it without pulling the Convex server module graph into its typecheck.
314
+ */
315
+ type CliManifestResource = {
316
+ kind: "agent" | "workspace" | "sandbox" | "cron" | "skill" | "tool";
317
+ name: string;
318
+ description?: string;
319
+ config: unknown;
320
+ };
321
+ type GeneratedIds = {
322
+ agents: Record<string, string>;
323
+ workspaces: Record<string, string>;
324
+ sandboxes: Record<string, string>;
325
+ crons: Record<string, string>;
326
+ skills: Record<string, string>;
327
+ tools: Record<string, string>;
328
+ };
329
+ type CliManifest = {
330
+ version: 1;
331
+ project: string;
332
+ environment: string;
333
+ resources: CliManifestResource[];
334
+ };
335
+
336
+ /**
337
+ * Type contracts inherited from Convex and core storage/runtime modules.
338
+ * Keep this file type-only so the public SDK does not bundle backend code.
339
+ */
340
+
341
+ type Id<TableName extends string = string> = string & {
342
+ readonly __tableName?: TableName;
343
+ };
344
+ type Doc<TableName extends string = string> = Record<string, unknown> & {
345
+ readonly _id: Id<TableName>;
346
+ };
347
+
348
+ type ProjectDoc = Doc<"projects">;
349
+ type EnvironmentDoc = Doc<"environments">;
350
+ type AgentConfigDoc = Doc<"agentConfigs">;
351
+ type WorkspaceConfigDoc = Doc<"workspaceConfigs">;
352
+ type SandboxConfigDoc = Doc<"sandboxConfigs">;
353
+ type CronDoc = Doc<"crons">;
354
+ type CliResourceKind = "agent" | "workspace" | "sandbox" | "cron";
355
+
356
+ /**
357
+ * Wire types for the public account-manage and harness APIs. These mirror
358
+ * the deployed API contract (docs/api-reference/openapi.yaml is the source
359
+ * of truth); they are intentionally independent of the Lambda internals so
360
+ * the SDK keeps working when the runtime is ported.
361
+ */
362
+
363
+ interface Account {
364
+ account: {
365
+ accountId: string;
366
+ username: string;
367
+ };
368
+ secret: string;
369
+ }
370
+ interface Agent {
371
+ accountId: string;
372
+ agentId: string;
373
+ name: string;
374
+ }
375
+ interface Sandbox {
376
+ sandboxId: string;
377
+ name: string;
378
+ }
379
+ interface Workspace {
380
+ workspaceId: string;
381
+ name: string;
382
+ }
383
+ /** A tool call held for user approval by an `ask`-mode sandbox. */
384
+ interface ToolApprovalSummary {
385
+ approvalId: string;
386
+ toolCallId: string;
387
+ toolName: string;
388
+ input: unknown;
389
+ }
390
+ interface AsyncStatus {
391
+ status: "processing" | "awaiting_approval" | "completed" | "failed" | "not_found";
392
+ response?: unknown;
393
+ error?: string;
394
+ approvals?: ToolApprovalSummary[];
395
+ }
396
+ interface AsyncRequestAccepted {
397
+ statusUrl: string;
398
+ statusId: string;
399
+ eventId: string;
400
+ agentId: string;
401
+ }
402
+ interface Cron {
403
+ accountId: string;
404
+ cronId: string;
405
+ name: string;
406
+ description?: string;
407
+ agentId: string;
408
+ events: ModelMessage[];
409
+ conversationKey?: string;
410
+ scheduleExpression: string;
411
+ timezone?: string;
412
+ status: CronStatus;
413
+ createdAt: string;
414
+ updatedAt: string;
415
+ lastInvokedAt?: string;
416
+ lastStatus?: CronLastStatus;
417
+ lastError?: string;
418
+ }
419
+ interface CronRun {
420
+ accountId: string;
421
+ cronId: string;
422
+ runId: string;
423
+ eventId: string;
424
+ conversationKey: string;
425
+ status: CronLastStatus;
426
+ result?: unknown;
427
+ error?: string;
428
+ startedAt: string;
429
+ completedAt?: string;
430
+ }
431
+ interface Skill {
432
+ path: string;
433
+ name: string;
434
+ description: string;
435
+ files?: Array<{
436
+ path: string;
437
+ size?: number;
438
+ }>;
439
+ }
440
+ interface CustomTool {
441
+ accountId: string;
442
+ toolId: string;
443
+ name: string;
444
+ description: string;
445
+ sha256: string;
446
+ }
447
+
448
+ type StreamTextOptions = Parameters<typeof streamText>[0];
449
+ type JsonCallSettings = Partial<Omit<CallSettings, "abortSignal" | "headers">>;
450
+ type AgentRunModelOverrides = JsonCallSettings & Pick<StreamTextOptions, "providerOptions">;
451
+ type AgentRunOverrides = {
452
+ system?: SystemModelMessage | SystemModelMessage[];
453
+ model?: AgentRunModelOverrides;
454
+ };
455
+ type AgentRunEventInput = {
456
+ /** Shorthand for a single user text message. */
457
+ input: string;
458
+ events?: never;
459
+ } | {
460
+ /** Full-fidelity event list for multimodal content or tool responses. */
461
+ events: [ModelMessage, ...ModelMessage[]];
462
+ input?: never;
463
+ };
464
+ /**
465
+ * Resolves a run's events from either the explicit `events` list or the `input`
466
+ * string shorthand, matching the core direct API's event contract.
467
+ */
468
+ declare function resolveRunEvents(input: AgentRunEventInput): ModelMessage[];
469
+
470
+ /**
471
+ * Shared direct-run stream contracts and SSE parsing helpers.
472
+ */
473
+
474
+ type AgentStreamPart = TextStreamPart<ToolSet> | {
475
+ type: "structured-output";
476
+ output: unknown;
477
+ };
478
+ /** Yield the payload of each `data:` line from an SSE response body. */
479
+ declare function readSseStream(body: ReadableStream<Uint8Array>): AsyncGenerator<string>;
480
+
481
+ /**
482
+ * Shared WebSocket wire message contracts used by the SDK client and gateway.
483
+ */
484
+
485
+ type WebSocketStreamMessage = AgentStreamPart | {
486
+ type: string;
487
+ [key: string]: unknown;
488
+ };
489
+ type WebSocketServerMessage = {
490
+ type: "meta";
491
+ sessionId: string;
492
+ taskId: string;
493
+ } | WebSocketStreamMessage;
494
+ type WebSocketClientExecuteMessage = {
495
+ type: "execute";
496
+ agentId: string;
497
+ sessionId?: string;
498
+ eventId?: string;
499
+ } & AgentRunEventInput & AgentRunOverrides;
500
+ type WebSocketClientCancelMessage = {
501
+ type: "cancel";
502
+ };
503
+ type WebSocketClientMessage = WebSocketClientExecuteMessage | WebSocketClientCancelMessage;
504
+
505
+ /**
506
+ * Shared WebSocket wire-protocol types for the observability gateway, used by
507
+ * the gateway, the SDK/CLI, and the dashboard. Pure types + tiny pure helpers,
508
+ * zero runtime deps. Kept separate from the agent-test websocket-contracts.
509
+ */
510
+ type LogLevel = "INFO" | "WARN" | "ERROR";
511
+ declare const MAX_OBSERVABILITY_BACKFILL = 500;
512
+ type ObservabilityLogEntry = {
513
+ ts: number;
514
+ level: LogLevel | "DEBUG";
515
+ eventType: string;
516
+ message: string;
517
+ traceId?: string;
518
+ accountId?: string;
519
+ endpointId?: string;
520
+ service?: string;
521
+ agentId?: string;
522
+ conversationKey?: string;
523
+ data?: unknown;
524
+ };
525
+ type ObservabilitySpanRow = {
526
+ traceId: string;
527
+ spanId: string;
528
+ parentSpanId?: string;
529
+ name: string;
530
+ kind: "task" | "subtask" | "model.step" | "tool.call" | "phase";
531
+ startTimeMs: number;
532
+ endTimeMs: number;
533
+ durationMs: number;
534
+ status: "running" | "ok" | "error";
535
+ endpointId?: string;
536
+ agentId?: string;
537
+ conversationKey?: string;
538
+ attributes?: Record<string, unknown>;
539
+ error?: string;
540
+ };
541
+ type ObservabilitySubscribeMessage = {
542
+ type: "subscribe";
543
+ stream: "logs" | "traces";
544
+ backfill?: number;
545
+ minLevel?: LogLevel;
546
+ };
547
+ type ObservabilityUnsubscribeMessage = {
548
+ type: "unsubscribe";
549
+ stream: "logs" | "traces";
550
+ };
551
+ type ObservabilityClientMessage = ObservabilitySubscribeMessage | ObservabilityUnsubscribeMessage;
552
+ type ObservabilityReadyMessage = {
553
+ type: "ready";
554
+ };
555
+ type ObservabilityBackfillMessage = {
556
+ type: "backfill";
557
+ stream: "logs" | "traces";
558
+ entries: ObservabilityLogEntry[] | ObservabilitySpanRow[];
559
+ };
560
+ type ObservabilityLogMessage = {
561
+ type: "log";
562
+ entry: ObservabilityLogEntry;
563
+ };
564
+ type ObservabilitySpanMessage = {
565
+ type: "span";
566
+ entry: ObservabilitySpanRow;
567
+ };
568
+ type ObservabilityErrorMessage = {
569
+ type: "error";
570
+ error: string;
571
+ };
572
+ type ObservabilityServerMessage = ObservabilityReadyMessage | ObservabilityBackfillMessage | ObservabilityLogMessage | ObservabilitySpanMessage | ObservabilityErrorMessage;
573
+ declare function isObservabilityClientMessage(v: unknown): v is ObservabilityClientMessage;
574
+
575
+ /**
576
+ * Configurable client for running deployed agents over direct core SSE.
577
+ * Stream chunks are the Vercel AI SDK's `TextStreamPart` parts that core emits.
578
+ */
579
+
580
+ declare const DEFAULT_CORE_BASE_URL = "https://gateway.broods.app";
581
+ /**
582
+ * Input for a single agent run. The core direct API is event-based (a list of
583
+ * Vercel AI SDK model messages), so `events` is the full-fidelity form — use it
584
+ * for multimodal content (images/files), ephemeral system messages, or
585
+ * tool-approval responses. `input` is a shorthand for a single user text message
586
+ * and is wrapped into one user event. Provide exactly one of the two.
587
+ */
588
+ type AgentRunInputBase = {
589
+ conversationKey?: string;
590
+ eventId?: string;
591
+ } & AgentRunOverrides;
592
+ type AgentRunInput = AgentRunInputBase & AgentRunEventInput;
593
+ interface AgentRunResult {
594
+ text: string;
595
+ events: TextStreamPart<ToolSet>[];
596
+ }
597
+ interface AsyncPollOptions {
598
+ intervalMs?: number;
599
+ timeoutMs?: number;
600
+ signal?: AbortSignal;
601
+ }
602
+ interface AsyncAgentRun extends AsyncRequestAccepted {
603
+ conversationKey: string;
604
+ poll(): Promise<AsyncStatus>;
605
+ wait(options?: AsyncPollOptions): Promise<AsyncStatus>;
606
+ }
607
+ interface AgentReference<Name extends string = string> {
608
+ readonly kind: "agent";
609
+ readonly name: Name;
610
+ readonly id: string;
611
+ readonly project: string;
612
+ readonly environment: string;
613
+ /**
614
+ * Authoritative scope of the environment's runtime key, embedded by codegen
615
+ * from the deploy response. When present the client posts to the scoped URL
616
+ * `/v1/{projectSlug}/agents/{environmentSlug}/{endpointId}` (matching the
617
+ * dashboard); when absent it falls back to the base URL.
618
+ */
619
+ readonly endpointId?: string;
620
+ readonly projectSlug?: string;
621
+ readonly environmentSlug?: string;
622
+ }
623
+ interface ChannelReference {
624
+ readonly kind: "channel";
625
+ readonly type: "telegram" | "github" | "slack" | "discord" | "pancake" | "zalo";
626
+ readonly agentName: string;
627
+ readonly agentId: string;
628
+ readonly accountId: string;
629
+ readonly webhookPath: string;
630
+ }
631
+ interface ResourceApi {
632
+ readonly agents: Record<string, AgentReference>;
633
+ readonly channels?: Record<string, ChannelReference>;
634
+ readonly workspaces?: Record<string, unknown>;
635
+ readonly sandboxes?: Record<string, unknown>;
636
+ readonly crons?: Record<string, unknown>;
637
+ readonly skills?: Record<string, unknown>;
638
+ readonly tools?: Record<string, unknown>;
639
+ }
640
+ interface BroodsClientOptions {
641
+ /**
642
+ * Base URL of the core service to call directly. Use `https://gateway.broods.app`
643
+ * for the hosted service. If you only have a domain, use `host` instead.
644
+ */
645
+ baseUrl?: string;
646
+ /** Hostname or URL of the core service. `gateway.broods.app` becomes `https://gateway.broods.app`. */
647
+ host?: string;
648
+ /** API key used as the Bearer token for direct runtime calls. */
649
+ apiKey?: string;
650
+ fetch?: typeof fetch;
651
+ }
652
+ type AgentHandle = {
653
+ id: string;
654
+ run: (input: AgentRunInput) => Promise<AgentRunResult>;
655
+ runAsync: (input: AgentRunInput) => Promise<AsyncAgentRun>;
656
+ stream: (input: AgentRunInput) => AsyncGenerator<TextStreamPart<ToolSet>>;
657
+ };
658
+ type CreateClientCronInput = CreateCronInput | (Omit<CreateCronInput, "agentId"> & {
659
+ agent: AgentReference | string;
660
+ });
661
+ declare class BroodsClient {
662
+ private readonly baseUrl;
663
+ private readonly apiKey?;
664
+ private readonly fetchImpl;
665
+ constructor(options?: BroodsClientOptions);
666
+ /** Return the public provider webhook URL for a generated channel reference. */
667
+ channelWebhookUrl(ref: ChannelReference): string;
668
+ agent<const Name extends string>(ref: AgentReference<Name>): AgentHandle;
669
+ agent(name: string, agentId: string): AgentHandle;
670
+ /** Run an agent and accumulate the streamed text and raw parts. */
671
+ run(ref: AgentReference, input: AgentRunInput): Promise<AgentRunResult>;
672
+ run(input: AgentRunInput & {
673
+ agentId: string;
674
+ agentName?: string;
675
+ }): Promise<AgentRunResult>;
676
+ /** Stream an agent run, yielding each AI SDK `TextStreamPart` as it arrives. */
677
+ stream(ref: AgentReference, input: AgentRunInput): AsyncGenerator<TextStreamPart<ToolSet>>;
678
+ stream(input: AgentRunInput & {
679
+ agentId: string;
680
+ agentName?: string;
681
+ }): AsyncGenerator<TextStreamPart<ToolSet>>;
682
+ /** Start an async agent run and return the status id/URL used for polling. */
683
+ runAsync(ref: AgentReference, input: AgentRunInput): Promise<AsyncAgentRun>;
684
+ runAsync(input: AgentRunInput & {
685
+ agentId: string;
686
+ agentName?: string;
687
+ }): Promise<AsyncAgentRun>;
688
+ /** Fetch one async status snapshot by status URL or status id + agent id. */
689
+ getAsyncStatus(status: AsyncRequestAccepted | string, options?: {
690
+ agentId?: string;
691
+ }): Promise<AsyncStatus>;
692
+ /** Poll async status until it reaches completed, failed, awaiting_approval, or timeout. */
693
+ waitForAsyncStatus(status: AsyncRequestAccepted | string, options?: AsyncPollOptions & {
694
+ agentId?: string;
695
+ }): Promise<AsyncStatus>;
696
+ createCron(input: CreateClientCronInput): Promise<Cron>;
697
+ listCrons(): Promise<Cron[]>;
698
+ getCron(cronId: string): Promise<Cron | null>;
699
+ listCronRuns(cronId: string, options?: {
700
+ limit?: number;
701
+ }): Promise<CronRun[]>;
702
+ updateCron(cronId: string, patch: UpdateCronInput): Promise<Cron>;
703
+ deleteCron(cronId: string): Promise<boolean>;
704
+ /**
705
+ * Scoped invoke URL for a deployed agent. When codegen embedded the runtime
706
+ * key's scope, this is `/v1/{projectSlug}/agents/{environmentSlug}/{endpointId}`
707
+ * (the same URL the dashboard shows, so core can validate the key against the
708
+ * path); otherwise it falls back to the base URL.
709
+ */
710
+ private scopedUrl;
711
+ private openStream;
712
+ private fetchCore;
713
+ private apiKeyHeaders;
714
+ private fetchJson;
715
+ private resolveStatusUrl;
716
+ }
717
+ declare function normalizeHttpServiceUrl(value: string): string;
718
+
719
+ /**
720
+ * WebSocket client for deployed-agent endpoints.
721
+ * Uses the gateway URL when configured, or derives one from the core service URL.
722
+ */
723
+
724
+ type WebSocketRunInput = {
725
+ agent?: AgentReference;
726
+ agentId?: string;
727
+ endpointId?: string;
728
+ sessionId?: string;
729
+ eventId?: string;
730
+ projectSlug?: string;
731
+ environmentSlug?: string;
732
+ signal?: AbortSignal;
733
+ } & AgentRunEventInput & AgentRunOverrides;
734
+ interface WebSocketHandlers {
735
+ onMessage?(message: WebSocketServerMessage): void;
736
+ onMeta?(meta: Extract<WebSocketServerMessage, {
737
+ type: "meta";
738
+ }>): void;
739
+ onDone?(): void;
740
+ onError?(error: Error): void;
741
+ }
742
+ interface WebSocketSubscription {
743
+ readonly url: string;
744
+ close(code?: number, reason?: string): void;
745
+ }
746
+ interface BroodsWebSocketClientOptions {
747
+ /** Base URL of the core service. Use `https://...`; the client converts it to `wss://...`. */
748
+ baseUrl?: string;
749
+ /** Hostname or URL of the core service. `gateway.broods.app` becomes `https://gateway.broods.app`. */
750
+ host?: string;
751
+ /** API key used as the WebSocket token. Defaults to BROODS_API_KEY from the environment or local .env files. */
752
+ apiKey?: string;
753
+ WebSocket?: WebSocketConstructorLike;
754
+ connectTimeoutMs?: number;
755
+ }
756
+ interface WebSocketConstructorLike {
757
+ new (url: string): WebSocketLike;
758
+ }
759
+ interface WebSocketLike {
760
+ readyState: number;
761
+ onopen: ((event: unknown) => void) | null;
762
+ onmessage: ((event: {
763
+ data: unknown;
764
+ }) => void) | null;
765
+ onerror: ((event: unknown) => void) | null;
766
+ onclose: ((event: {
767
+ code: number;
768
+ reason: string;
769
+ }) => void) | null;
770
+ send(data: string): void;
771
+ close(code?: number, reason?: string): void;
772
+ }
773
+ declare class BroodsWebSocketClient {
774
+ private readonly baseUrl;
775
+ private readonly apiKey;
776
+ private readonly WebSocketImpl?;
777
+ private readonly connectTimeoutMs;
778
+ constructor(options?: BroodsWebSocketClientOptions);
779
+ subscribe(input: WebSocketRunInput, handlers?: WebSocketHandlers): WebSocketSubscription;
780
+ stream(input: WebSocketRunInput): AsyncGenerator<WebSocketServerMessage>;
781
+ buildUrl(input: Pick<WebSocketRunInput, "agent" | "endpointId" | "projectSlug" | "environmentSlug">): string;
782
+ private resolveWebSocket;
783
+ }
784
+
785
+ declare function toWebSocketBaseUrl(url: string): string;
786
+
787
+ /**
788
+ * Resource definition helpers for the code-first `broods/` project folder.
789
+ *
790
+ * Layout: markers, then types (env refs, project config, resource primitives,
791
+ * per-kind config surfaces, per-kind resource aliases), then the env runtime
792
+ * value, the resource constructors, and the type guards. Every runtime function
793
+ * here is synchronous.
794
+ */
795
+
796
+ declare const RESOURCE_MARKER: unique symbol;
797
+ declare const CONFIG_MARKER: unique symbol;
798
+ declare const CHANNEL_MARKER: unique symbol;
799
+ interface EnvRef<Name extends string = string> {
800
+ readonly __beeblastEnv: true;
801
+ readonly name: Name;
802
+ }
803
+ /** Callable + property-access accessor for {@link env}. */
804
+ interface EnvAccessor {
805
+ <const Name extends string>(name: Name): EnvRef<Name>;
806
+ readonly [name: string]: EnvRef;
807
+ }
808
+ type EnvRefString<T> = T extends string ? T | EnvRef : T extends readonly (infer Item)[] ? readonly EnvRefString<Item>[] : T extends (infer Item)[] ? EnvRefString<Item>[] : T extends object ? {
809
+ [Key in keyof T]: EnvRefString<T[Key]>;
810
+ } : T;
811
+ interface BroodsProjectConfig {
812
+ project?: string;
813
+ environments?: {
814
+ dev?: string;
815
+ deploy?: string;
816
+ [name: string]: string | undefined;
817
+ };
818
+ dashboardUrl?: string;
819
+ }
820
+ interface BroodsConfigDefinition {
821
+ readonly [CONFIG_MARKER]: true;
822
+ readonly config: BroodsProjectConfig;
823
+ }
824
+ type ResourceKind = "agent" | "workspace" | "sandbox" | "cron" | "skill" | "tool";
825
+ interface ResourceDefinition<Kind extends ResourceKind, Name extends string, Config> {
826
+ readonly [RESOURCE_MARKER]: true;
827
+ readonly kind: Kind;
828
+ readonly name: Name;
829
+ readonly description?: string;
830
+ readonly config: Config;
831
+ }
832
+ interface ResourceDefinitionInput<Name extends string, Config> {
833
+ name: Name;
834
+ description?: string;
835
+ config: Config;
836
+ }
837
+ /**
838
+ * Code-first sandbox config surface. Mirrors core's `SandboxConfig` but lets
839
+ * `envVars` values be `env.NAME` references (compiled to `${NAME}` placeholders
840
+ * at sync time, exactly like provider `apiKey`). Add overrides here if more
841
+ * sandbox fields should accept env refs.
842
+ */
843
+ type SandboxDefinitionConfig = Omit<SandboxConfig, "envVars"> & {
844
+ envVars?: Record<string, string | EnvRef | undefined>;
845
+ };
846
+ interface SkillDefinitionConfig {
847
+ /**
848
+ * Folder containing SKILL.md plus optional scripts/assets. Relative paths are
849
+ * resolved from the `broods/` project directory.
850
+ */
851
+ path: string;
852
+ }
853
+ interface ToolDefinitionConfig {
854
+ /**
855
+ * JavaScript module file exporting the custom tool bundle. Relative paths are
856
+ * resolved from the `broods/` project directory.
857
+ */
858
+ path: string;
859
+ description: string;
860
+ inputSchema: Record<string, unknown>;
861
+ defaultConfig?: Record<string, unknown>;
862
+ }
863
+ type ChannelType = "telegram" | "github" | "slack" | "discord" | "pancake" | "zalo";
864
+ interface ChannelDefinition<Type extends ChannelType, Config> {
865
+ readonly [CHANNEL_MARKER]: true;
866
+ readonly kind: "channel";
867
+ readonly type: Type;
868
+ readonly config: Config;
869
+ }
870
+ type ChannelSecret = string | EnvRef | undefined;
871
+ interface TelegramChannelInput {
872
+ botToken: ChannelSecret;
873
+ webhookSecret: ChannelSecret;
874
+ allowedChatIds: readonly number[];
875
+ reactionEmoji?: string | EnvRef;
876
+ streaming?: EnvRefString<NonNullable<AgentTelegramChannelConfig["streaming"]>>;
877
+ }
878
+ interface GitHubChannelInput {
879
+ webhookSecret: ChannelSecret;
880
+ appId: ChannelSecret;
881
+ privateKey: ChannelSecret;
882
+ allowedRepos?: readonly (string | EnvRef)[];
883
+ }
884
+ interface SlackChannelInput {
885
+ botToken: ChannelSecret;
886
+ signingSecret: ChannelSecret;
887
+ allowedChannelIds?: readonly (string | EnvRef)[];
888
+ streaming?: EnvRefString<NonNullable<AgentSlackChannelConfig["streaming"]>>;
889
+ }
890
+ interface DiscordChannelInput {
891
+ botToken: ChannelSecret;
892
+ publicKey: ChannelSecret;
893
+ allowedGuildIds?: readonly (string | EnvRef)[];
894
+ streaming?: EnvRefString<NonNullable<AgentDiscordChannelConfig["streaming"]>>;
895
+ }
896
+ interface PancakeChannelInput {
897
+ pageId: ChannelSecret;
898
+ pageAccessToken: ChannelSecret;
899
+ webhookSecret: ChannelSecret;
900
+ senderId?: string | EnvRef;
901
+ ignoreTagIds?: readonly (string | EnvRef)[];
902
+ streaming?: EnvRefString<NonNullable<AgentPancakeChannelConfig["streaming"]>>;
903
+ }
904
+ type PancakeChannelDefinitionConfig = Omit<PancakeChannelInput, "ignoreTagIds"> & {
905
+ options?: {
906
+ ignoreTagIds?: readonly (string | EnvRef)[];
907
+ };
908
+ };
909
+ interface ZaloChannelInput {
910
+ botToken: ChannelSecret;
911
+ webhookSecret: ChannelSecret;
912
+ allowedUserIds: readonly (string | EnvRef)[];
913
+ streaming?: EnvRefString<NonNullable<AgentZaloChannelConfig["streaming"]>>;
914
+ }
915
+ type TelegramChannelDefinition = ChannelDefinition<"telegram", TelegramChannelInput>;
916
+ type GitHubChannelDefinition = ChannelDefinition<"github", GitHubChannelInput>;
917
+ type SlackChannelDefinition = ChannelDefinition<"slack", SlackChannelInput>;
918
+ type DiscordChannelDefinition = ChannelDefinition<"discord", DiscordChannelInput>;
919
+ type PancakeChannelDefinition = ChannelDefinition<"pancake", PancakeChannelDefinitionConfig>;
920
+ type ZaloChannelDefinition = ChannelDefinition<"zalo", ZaloChannelInput>;
921
+ type AnyChannelDefinition = TelegramChannelDefinition | GitHubChannelDefinition | SlackChannelDefinition | DiscordChannelDefinition | PancakeChannelDefinition | ZaloChannelDefinition;
922
+ /**
923
+ * Per-agent workspace mount with an optional sandbox override. A bare
924
+ * `defineWorkspace(...)` inherits the agent-level sandbox; the object form lets
925
+ * a single workspace pin its own sandbox, or set `sandbox: null` to force the
926
+ * workspace read-only (no compute attached).
927
+ */
928
+ interface AgentWorkspaceRefInput {
929
+ workspace: WorkspaceResource | string;
930
+ sandbox?: SandboxResource | string | null;
931
+ }
932
+ type AgentWorkspaceInput = WorkspaceResource | AgentWorkspaceRefInput;
933
+ /**
934
+ * `subagent` block where `allowed` may reference other `defineAgent(...)`
935
+ * resources directly; the compiler rewrites them to agent names and the backend
936
+ * resolves those to deploy-time agent ids.
937
+ */
938
+ type AgentSubagentDefinitionConfig = Omit<NonNullable<AgentConfig["subagent"]>, "allowed"> & {
939
+ allowed?: readonly (AgentResource | string)[];
940
+ };
941
+ type AgentSkillsDefinitionConfig = Omit<NonNullable<AgentConfig["skills"]>, "allowed"> & {
942
+ allowed?: readonly (SkillResource | string)[];
943
+ };
944
+ /**
945
+ * Code-first agent config surface. Built from an explicit `Pick` of `AgentConfig`
946
+ * (not `Omit`) so the SDK input type does NOT inherit `AgentConfig`'s
947
+ * `[key: string]: unknown` index signature — which would otherwise disable
948
+ * TypeScript's excess-property checks and silently accept typos like
949
+ * `workspace:` instead of `workspaces:`. Add a key here when core's `AgentConfig`
950
+ * gains a new top-level field that should be code-definable.
951
+ */
952
+ type AgentDefinitionConfig = EnvRefString<Pick<AgentConfig, "agent" | "model" | "provider" | "session" | "hooks" | "tools">> & {
953
+ channels?: readonly AnyChannelDefinition[];
954
+ sandbox?: SandboxResource | string;
955
+ workspaces?: readonly AgentWorkspaceInput[];
956
+ subagent?: AgentSubagentDefinitionConfig;
957
+ skills?: AgentSkillsDefinitionConfig;
958
+ /**
959
+ * Opt the agent into the public runtime endpoint (SSE/WebSocket via the
960
+ * environment runtime key). Off by default — secured: when unset the public
961
+ * endpoint refuses requests for this agent. Reach a private agent through an
962
+ * internal endpoint or a channel webhook. See issue #65.
963
+ */
964
+ publicAccess?: boolean;
965
+ };
966
+ type CronDefinitionConfig = Omit<CreateCronInput, "agentId" | "name"> & {
967
+ agent: AgentResource | string;
968
+ };
969
+ type AgentResource<Name extends string = string> = ResourceDefinition<"agent", Name, AgentDefinitionConfig>;
970
+ type WorkspaceResource<Name extends string = string> = ResourceDefinition<"workspace", Name, WorkspaceConfig>;
971
+ type SandboxResource<Name extends string = string> = ResourceDefinition<"sandbox", Name, SandboxDefinitionConfig>;
972
+ type SkillResource<Name extends string = string> = ResourceDefinition<"skill", Name, SkillDefinitionConfig>;
973
+ type ToolResource<Name extends string = string> = ResourceDefinition<"tool", Name, ToolDefinitionConfig>;
974
+ type CronResource<Name extends string = string> = ResourceDefinition<"cron", Name, CronDefinitionConfig>;
975
+ type AnyResource = AgentResource | WorkspaceResource | SandboxResource | CronResource | SkillResource | ToolResource;
976
+ /**
977
+ * References an account/environment variable resolved on the SERVER at runtime —
978
+ * set it with `broods env set <NAME>` or in the dashboard (the Convex-style
979
+ * `convex env set` model). It is a deferred reference, never read from your local
980
+ * environment and never baked into the deployed config. Use either form:
981
+ *
982
+ * apiKey: env.OPENAI_API_KEY // property access (reads like process.env)
983
+ * apiKey: env("OPENAI_API_KEY") // call form (equivalent)
984
+ *
985
+ * Both compile to a `${NAME}` placeholder the harness fills in at run time. This is
986
+ * NOT `process.env`: agent configs are compiled locally, so `process.env.NAME` would
987
+ * bake the literal local value into the deployed config instead of deferring it.
988
+ */
989
+ declare const env: EnvAccessor;
990
+ declare function defineTelegramChannel(config: TelegramChannelInput): TelegramChannelDefinition;
991
+ declare function defineGitHubChannel(config: GitHubChannelInput): GitHubChannelDefinition;
992
+ declare function defineSlackChannel(config: SlackChannelInput): SlackChannelDefinition;
993
+ declare function defineDiscordChannel(config: DiscordChannelInput): DiscordChannelDefinition;
994
+ declare function definePancakeChannel(config: PancakeChannelInput): PancakeChannelDefinition;
995
+ declare function defineZaloChannel(config: ZaloChannelInput): ZaloChannelDefinition;
996
+ declare function defineBroods(config: BroodsProjectConfig): BroodsConfigDefinition;
997
+ declare function defineAgent<const Name extends string>(input: ResourceDefinitionInput<Name, AgentDefinitionConfig>): AgentResource<Name>;
998
+ declare function defineWorkspace<const Name extends string>(input: ResourceDefinitionInput<Name, WorkspaceConfig>): WorkspaceResource<Name>;
999
+ declare function defineSandbox<const Name extends string>(input: ResourceDefinitionInput<Name, SandboxDefinitionConfig>): SandboxResource<Name>;
1000
+ declare function defineSkill<const Name extends string>(input: ResourceDefinitionInput<Name, SkillDefinitionConfig>): SkillResource<Name>;
1001
+ declare function defineTool<const Name extends string>(input: ResourceDefinitionInput<Name, ToolDefinitionConfig>): ToolResource<Name>;
1002
+ declare function defineCron<const Name extends string>(input: ResourceDefinitionInput<Name, CronDefinitionConfig>): CronResource<Name>;
1003
+ declare function isResource(value: unknown): value is AnyResource;
1004
+ declare function isChannelDefinition(value: unknown): value is AnyChannelDefinition;
1005
+ declare function isBroodsConfig(value: unknown): value is BroodsConfigDefinition;
1006
+
1007
+ export { BroodsClient, BroodsWebSocketClient, DEFAULT_CORE_BASE_URL, MAX_OBSERVABILITY_BACKFILL, BroodsWebSocketClient as WebSocketClient, BroodsWebSocketClient as WebsocketClient, defineAgent, defineBroods, defineCron, defineDiscordChannel, defineGitHubChannel, definePancakeChannel, defineSandbox, defineSkill, defineSlackChannel, defineTelegramChannel, defineTool, defineWorkspace, defineZaloChannel, env, isBroodsConfig, isChannelDefinition, isObservabilityClientMessage, isResource, normalizeHttpServiceUrl, readSseStream, resolveRunEvents, toWebSocketBaseUrl };
1008
+ export type { Account, Agent, AgentChannelsConfig, AgentConfig, AgentConfigDoc, AgentDefinitionConfig, AgentDiscordChannelConfig, AgentGitHubChannelConfig, AgentHandle, AgentPancakeChannelConfig, AgentReference, AgentResource, AgentRunEventInput, AgentRunInput, AgentRunModelOverrides, AgentRunOverrides, AgentRunResult, AgentSkillsDefinitionConfig, AgentSlackChannelConfig, AgentStreamPart, AgentSubagentDefinitionConfig, AgentTelegramChannelConfig, AgentWorkspaceInput, AgentWorkspaceRef, AgentWorkspaceRefInput, AgentZaloChannelConfig, AnyChannelDefinition, AnyResource, AsyncAgentRun, AsyncPollOptions, AsyncRequestAccepted, AsyncStatus, BroodsClientOptions, BroodsConfigDefinition, BroodsProjectConfig, BroodsWebSocketClientOptions, ChannelDefinition, ChannelReference, ChannelType, CliManifest, CliManifestResource, CliResourceKind, CreateClientCronInput, CreateCronInput, Cron, CronDefinitionConfig, CronDoc, CronLastStatus, CronResource, CronRun, CronStatus, CustomTool, DiscordChannelDefinition, DiscordChannelInput, Doc, EnvAccessor, EnvRef, EnvRefString, EnvironmentDoc, GeneratedIds, GitHubChannelDefinition, GitHubChannelInput, Id, LogLevel, ObservabilityBackfillMessage, ObservabilityClientMessage, ObservabilityErrorMessage, ObservabilityLogEntry, ObservabilityLogMessage, ObservabilityReadyMessage, ObservabilityServerMessage, ObservabilitySpanMessage, ObservabilitySpanRow, ObservabilitySubscribeMessage, ObservabilityUnsubscribeMessage, PancakeChannelDefinition, PancakeChannelInput, ProjectDoc, ResourceApi, ResourceDefinition, ResourceDefinitionInput, ResourceKind, Sandbox, SandboxConfig, SandboxConfigDoc, SandboxDefinitionConfig, SandboxResource, Skill, SkillDefinitionConfig, SkillResource, SlackChannelDefinition, SlackChannelInput, TelegramChannelDefinition, TelegramChannelInput, ToolApprovalSummary, ToolDefinitionConfig, ToolResource, UpdateCronInput, WebSocketClientCancelMessage, WebSocketClientExecuteMessage, WebSocketClientMessage, WebSocketConstructorLike, WebSocketHandlers, WebSocketLike, WebSocketRunInput, WebSocketServerMessage, WebSocketStreamMessage, WebSocketSubscription, Workspace, WorkspaceConfig, WorkspaceConfigDoc, WorkspaceResource, ZaloChannelDefinition, ZaloChannelInput };