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