@builder.io/ai-utils 0.31.0 → 0.32.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@builder.io/ai-utils",
3
- "version": "0.31.0",
3
+ "version": "0.32.0",
4
4
  "description": "Builder.io AI utils",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/claw.d.ts CHANGED
@@ -41,5 +41,47 @@ export interface ParsedChannelId {
41
41
  * "slack/thread/T01234/C56789/1234567890.123456" → { platform: "slack", type: "thread", ids: ["T01234", "C56789", "1234567890.123456"] }
42
42
  * "jira/comment/cloud-id/PROJ-123" → { platform: "jira", type: "comment", ids: ["cloud-id", "PROJ-123"] }
43
43
  * "builder/branch/proj-id/my-branch" → { platform: "builder", type: "branch", ids: ["proj-id", "my-branch"] }
44
+ * "inbox/user/builder-user-id" → { platform: "inbox", type: "user", ids: ["builder-user-id"] }
44
45
  */
45
46
  export declare function parseChannelId(channelId: string): ParsedChannelId;
47
+ export interface WorkerReportOptions {
48
+ /** The original user's channel that triggered this work. */
49
+ originChannelId?: string;
50
+ /** The report content. */
51
+ content: string;
52
+ /** Project ID (for branch reports). */
53
+ projectId?: string;
54
+ /** Branch name (for branch reports). */
55
+ branchName?: string;
56
+ /** Agent/tool ID (for sub-agent reports). */
57
+ agentId?: string;
58
+ }
59
+ /**
60
+ * Formats a `<worker_report>` message for the org-agent.
61
+ *
62
+ * Used when a spawned branch or sub-agent reports its results back.
63
+ * The org-agent uses `<origin_channel_id>` to route the response to the
64
+ * correct user channel.
65
+ */
66
+ export declare function formatWorkerReport(opts: WorkerReportOptions): string;
67
+ export interface IncomingMessageOptions {
68
+ /** The source channel (e.g. slack/thread/TEAM/CHANNEL/TS). */
69
+ channelId: string;
70
+ /** DM channel ID, if the message was a direct message. */
71
+ dmId?: string;
72
+ /** Display name of the sender. */
73
+ sender?: string;
74
+ /** Pre-formatted timestamp string. */
75
+ timestamp: string;
76
+ /** The message body. */
77
+ content: string;
78
+ /** Optional context to prepend (e.g. Slack thread history). */
79
+ messageContext?: string;
80
+ }
81
+ /**
82
+ * Formats an `<incoming_message>` for the org-agent.
83
+ *
84
+ * Used when a real user message arrives from an integration.
85
+ * The org-agent uses `<channel_id>` to reply in the same medium.
86
+ */
87
+ export declare function formatIncomingMessage(opts: IncomingMessageOptions): string;
package/src/claw.js CHANGED
@@ -6,6 +6,7 @@
6
6
  * "slack/thread/T01234/C56789/1234567890.123456" → { platform: "slack", type: "thread", ids: ["T01234", "C56789", "1234567890.123456"] }
7
7
  * "jira/comment/cloud-id/PROJ-123" → { platform: "jira", type: "comment", ids: ["cloud-id", "PROJ-123"] }
8
8
  * "builder/branch/proj-id/my-branch" → { platform: "builder", type: "branch", ids: ["proj-id", "my-branch"] }
9
+ * "inbox/user/builder-user-id" → { platform: "inbox", type: "user", ids: ["builder-user-id"] }
9
10
  */
10
11
  export function parseChannelId(channelId) {
11
12
  const parts = channelId.split("/");
@@ -15,3 +16,63 @@ export function parseChannelId(channelId) {
15
16
  const [platform, type, ...ids] = parts;
16
17
  return { platform, type, ids };
17
18
  }
19
+ // ── Org-agent message formatting ──
20
+ //
21
+ // The org-agent receives two kinds of messages in its conversation:
22
+ // 1. <incoming_message> — from real users (Slack, Jira, GitHub, etc.)
23
+ // 2. <worker_report> — from spawned agents or branches reporting back
24
+ //
25
+ // These XML tags are consumed by the LLM (not parsed by code), so the
26
+ // format matters for prompt clarity and consistency.
27
+ const WORKER_REPORT_TRAILER = "This is a report from a background worker, NOT a user message. Review the results and take appropriate action (e.g., send findings to the user, update memory).";
28
+ /**
29
+ * Formats a `<worker_report>` message for the org-agent.
30
+ *
31
+ * Used when a spawned branch or sub-agent reports its results back.
32
+ * The org-agent uses `<origin_channel_id>` to route the response to the
33
+ * correct user channel.
34
+ */
35
+ export function formatWorkerReport(opts) {
36
+ let xml = `<worker_report>\n`;
37
+ if (opts.originChannelId) {
38
+ xml += `<origin_channel_id>${opts.originChannelId}</origin_channel_id>\n`;
39
+ }
40
+ if (opts.projectId) {
41
+ xml += `<project_id>${opts.projectId}</project_id>\n`;
42
+ }
43
+ if (opts.branchName && opts.projectId) {
44
+ xml += `<branch_name>${opts.branchName}</branch_name>\n`;
45
+ xml += `<channel_id>builder/branch/${opts.projectId}/${opts.branchName}</channel_id>\n`;
46
+ }
47
+ if (opts.agentId) {
48
+ xml += `<agent_id>${opts.agentId}</agent_id>\n`;
49
+ }
50
+ xml += `<content>${opts.content}</content>\n`;
51
+ xml += `</worker_report>\n`;
52
+ xml += WORKER_REPORT_TRAILER;
53
+ return xml;
54
+ }
55
+ /**
56
+ * Formats an `<incoming_message>` for the org-agent.
57
+ *
58
+ * Used when a real user message arrives from an integration.
59
+ * The org-agent uses `<channel_id>` to reply in the same medium.
60
+ */
61
+ export function formatIncomingMessage(opts) {
62
+ let result = "";
63
+ if (opts.messageContext) {
64
+ result += `${opts.messageContext}\n\n`;
65
+ }
66
+ result += `<incoming_message>\n`;
67
+ result += `<channel_id>${opts.channelId}</channel_id>\n`;
68
+ if (opts.dmId) {
69
+ result += `<dm_id>${opts.dmId}</dm_id>\n`;
70
+ }
71
+ if (opts.sender) {
72
+ result += `<sender>${opts.sender}</sender>\n`;
73
+ }
74
+ result += `<timestamp>${opts.timestamp}</timestamp>\n`;
75
+ result += `<content>${opts.content}</content>\n`;
76
+ result += `</incoming_message>\n`;
77
+ return result;
78
+ }
package/src/codegen.d.ts CHANGED
@@ -92,6 +92,8 @@ export interface DevServerControlInput {
92
92
  }
93
93
  export interface DevServerLogsInput {
94
94
  }
95
+ export interface DevServerRestartInput {
96
+ }
95
97
  export interface BashToolInput {
96
98
  command?: string | null;
97
99
  timeout?: number | null;
@@ -179,6 +181,8 @@ export interface AgentToolInput {
179
181
  prompt: string;
180
182
  subagent_type?: string;
181
183
  resume?: string;
184
+ origin_channel_id?: string;
185
+ attachmentUrls?: string[];
182
186
  }
183
187
  export interface ListDirToolInput {
184
188
  path: string;
@@ -450,8 +454,8 @@ export interface ProposeConfigParams {
450
454
  isMicrofrontend?: boolean;
451
455
  setupNeedsCredentials?: boolean;
452
456
  devServerNeedsCredentials?: boolean;
453
- projectDescription?: string;
454
457
  needsVPN?: boolean;
458
+ projectDescription?: string;
455
459
  }
456
460
  export interface VerifySetupCommandToolInput {
457
461
  command: string;
@@ -479,6 +483,11 @@ export interface VerifyRuntimeDependencyToolInput {
479
483
  version: string;
480
484
  source?: string;
481
485
  }
486
+ export interface ProposeEnvVariableToolInput {
487
+ key: string;
488
+ value: string;
489
+ secret?: boolean;
490
+ }
482
491
  export interface SetEnvVariableToolInput {
483
492
  key: string;
484
493
  value: string;
@@ -499,6 +508,9 @@ export interface SpawnBranchToolInput {
499
508
  hidden?: boolean;
500
509
  sourceChannelId?: string;
501
510
  sourceDmId?: string;
511
+ sessionMode?: "normal" | "planning" | "deep-research";
512
+ model?: "auto" | "opus" | "sonnet" | "haiku";
513
+ attachmentUrls?: string[];
502
514
  }
503
515
  export interface ReadBranchToolInput {
504
516
  projectId: string;
@@ -580,6 +592,7 @@ export interface CodeGenToolMap {
580
592
  Glob: GlobSearchToolInput;
581
593
  DevServerControl: DevServerControlInput;
582
594
  DevServerLogs: DevServerLogsInput;
595
+ DevServerRestart: DevServerRestartInput;
583
596
  Revert: RevertToolInput;
584
597
  TodoRead: TodoReadToolInput;
585
598
  TodoWrite: TodoWriteToolInput;
@@ -604,6 +617,7 @@ export interface CodeGenToolMap {
604
617
  VerifyDevServer: VerifyDevServerToolInput;
605
618
  VerifyValidateCommand: VerifyValidateCommandToolInput;
606
619
  VerifyRuntimeDependency: VerifyRuntimeDependencyToolInput;
620
+ ProposeEnvVariable: ProposeEnvVariableToolInput;
607
621
  SetEnvVariable: SetEnvVariableToolInput;
608
622
  SendMessage: SendMessageToolInput;
609
623
  SpawnBranch: SpawnBranchToolInput;
@@ -1733,6 +1747,8 @@ export interface FusionConfig {
1733
1747
  errorIgnorePatterns?: string[];
1734
1748
  /** When true, sync the git working tree to the latest remote state during init */
1735
1749
  syncBranch?: boolean;
1750
+ /** How the PVC was provisioned. Used by InitStateMachine to decide whether to restore from backup. */
1751
+ pvcCreationSource?: "fresh" | "snapshot" | "existing";
1736
1752
  /**
1737
1753
  * Maximum number of agent completions before pausing to ask the user to continue.
1738
1754
  * Read from project settings, with fallback to organization/space settings.
@@ -1772,7 +1788,7 @@ export interface LoadHistoryResult {
1772
1788
  updatedUnixTime: number;
1773
1789
  turns: CodegenTurn[];
1774
1790
  }
1775
- export type InitStateStep = "initial" | "init" | "validation" | "check-directories" | "create-directories" | "configure-git-repos" | "check-existing-git" | "update-remote-url" | "clone-repo" | "apply-partial-backup" | "configure-git-user" | "stash-changes" | "collect-repo-info" | "init-success" | "init-command" | "init-failed" | "snapshot-git-sync";
1791
+ export type InitStateStep = "initial" | "init" | "validation" | "check-directories" | "create-directories" | "configure-git-repos" | "check-existing-git" | "update-remote-url" | "clone-repo" | "apply-partial-backup" | "configure-git-user" | "stash-changes" | "collect-repo-info" | "init-success" | "init-command" | "init-failed" | "snapshot-git-sync" | "snapshot-backup-restore";
1776
1792
  export interface InitStatusLog {
1777
1793
  id: number;
1778
1794
  timestamp: string;
@@ -1,3 +1,4 @@
1
+ import net from "net";
1
2
  import type { CheckResult, Source, TestId } from "../types.js";
2
3
  export interface TcpCheckOptions {
3
4
  hostname: string;
@@ -5,5 +6,7 @@ export interface TcpCheckOptions {
5
6
  source: Source;
6
7
  testId: TestId;
7
8
  timeout?: number;
9
+ /** Provide a pre-connected socket (e.g. tunneled through a proxy via CONNECT). */
10
+ connectFn?: (hostname: string, port: number) => Promise<net.Socket>;
8
11
  }
9
12
  export declare function tcpCheck(options: TcpCheckOptions): Promise<CheckResult>;
@@ -4,11 +4,29 @@ const DEFAULT_TIMEOUT_MS = 5000;
4
4
  const DEFAULT_PORT = 443;
5
5
  export async function tcpCheck(options) {
6
6
  var _a, _b;
7
- const { hostname, port = DEFAULT_PORT, source, testId, timeout = DEFAULT_TIMEOUT_MS, } = options;
7
+ const { hostname, port = DEFAULT_PORT, source, testId, timeout = DEFAULT_TIMEOUT_MS, connectFn, } = options;
8
8
  const target = `${hostname}:${port}`;
9
9
  const startTime = Date.now();
10
10
  try {
11
11
  const result = await new Promise((resolve) => {
12
+ if (connectFn) {
13
+ const timer = setTimeout(() => {
14
+ const error = new Error("Connection timed out");
15
+ error.code = "ETIMEDOUT";
16
+ resolve({ success: false, error });
17
+ }, timeout);
18
+ connectFn(hostname, port)
19
+ .then((socket) => {
20
+ clearTimeout(timer);
21
+ socket.destroy();
22
+ resolve({ success: true });
23
+ })
24
+ .catch((err) => {
25
+ clearTimeout(timer);
26
+ resolve({ success: false, error: err });
27
+ });
28
+ return;
29
+ }
12
30
  const socket = new net.Socket();
13
31
  socket.setTimeout(timeout);
14
32
  socket.on("connect", () => {
@@ -1,3 +1,4 @@
1
+ import type net from "net";
1
2
  import type { CheckResult, Source, TestId } from "../types.js";
2
3
  export interface TlsCheckOptions {
3
4
  hostname: string;
@@ -5,5 +6,7 @@ export interface TlsCheckOptions {
5
6
  source: Source;
6
7
  testId: TestId;
7
8
  timeout?: number;
9
+ /** Provide a pre-connected socket (e.g. tunneled through a proxy via CONNECT). TLS upgrade happens on top. */
10
+ connectFn?: (hostname: string, port: number) => Promise<net.Socket>;
8
11
  }
9
12
  export declare function tlsCheck(options: TlsCheckOptions): Promise<CheckResult>;
@@ -4,10 +4,38 @@ const DEFAULT_TIMEOUT_MS = 10000;
4
4
  const DEFAULT_PORT = 443;
5
5
  export async function tlsCheck(options) {
6
6
  var _a, _b;
7
- const { hostname, port = DEFAULT_PORT, source, testId, timeout = DEFAULT_TIMEOUT_MS, } = options;
7
+ const { hostname, port = DEFAULT_PORT, source, testId, timeout = DEFAULT_TIMEOUT_MS, connectFn, } = options;
8
8
  const target = `${hostname}:${port}`;
9
9
  const startTime = Date.now();
10
10
  try {
11
+ let tunnelSocket;
12
+ if (connectFn) {
13
+ let timedOut = false;
14
+ const connectPromise = connectFn(hostname, port);
15
+ tunnelSocket = await new Promise((resolve, reject) => {
16
+ const timer = setTimeout(() => {
17
+ timedOut = true;
18
+ connectPromise.then((s) => s.destroy()).catch(() => { });
19
+ const error = new Error("Proxy CONNECT timed out");
20
+ error.code = "ETIMEDOUT";
21
+ reject(error);
22
+ }, timeout);
23
+ connectPromise
24
+ .then((socket) => {
25
+ clearTimeout(timer);
26
+ if (timedOut) {
27
+ socket.destroy();
28
+ }
29
+ else {
30
+ resolve(socket);
31
+ }
32
+ })
33
+ .catch((err) => {
34
+ clearTimeout(timer);
35
+ reject(err);
36
+ });
37
+ });
38
+ }
11
39
  const result = await new Promise((resolve) => {
12
40
  const socket = tls.connect({
13
41
  host: hostname,
@@ -15,6 +43,7 @@ export async function tlsCheck(options) {
15
43
  servername: hostname, // SNI required for virtual hosts
16
44
  rejectUnauthorized: true,
17
45
  timeout,
46
+ ...(tunnelSocket ? { socket: tunnelSocket } : {}),
18
47
  }, () => {
19
48
  const cert = socket.getPeerCertificate();
20
49
  let certInfo;
@@ -6,7 +6,7 @@ import { tcpCheck } from "./checks/tcp-check.js";
6
6
  import { tlsCheck } from "./checks/tls-check.js";
7
7
  import { sshCheck } from "./checks/ssh-check.js";
8
8
  export async function runChecks(input) {
9
- const { tests, gitHost, onProgress, fetchFn, dispatcher } = input;
9
+ const { tests, gitHost, onProgress, fetchFn, dispatcher, connectFn } = input;
10
10
  const results = [];
11
11
  const total = tests.length;
12
12
  for (let index = 0; index < tests.length; index++) {
@@ -17,7 +17,7 @@ export async function runChecks(input) {
17
17
  index,
18
18
  total,
19
19
  });
20
- const result = await runSingleCheck(test, gitHost, fetchFn, dispatcher);
20
+ const result = await runSingleCheck(test, gitHost, fetchFn, dispatcher, connectFn);
21
21
  results.push(result);
22
22
  emitProgress(onProgress, {
23
23
  type: "test:complete",
@@ -36,7 +36,7 @@ export async function runChecks(input) {
36
36
  results,
37
37
  };
38
38
  }
39
- async function runSingleCheck(test, gitHost, fetchFn, dispatcher) {
39
+ async function runSingleCheck(test, gitHost, fetchFn, dispatcher, connectFn) {
40
40
  const { source, testId } = test;
41
41
  const checkType = getCheckTypeForTestId(testId);
42
42
  if (!isCheckAvailable(checkType)) {
@@ -93,6 +93,7 @@ async function runSingleCheck(test, gitHost, fetchFn, dispatcher) {
93
93
  port: extractPort(target, 443),
94
94
  source,
95
95
  testId,
96
+ connectFn: connectFn,
96
97
  });
97
98
  case "tls":
98
99
  return tlsCheck({
@@ -100,6 +101,7 @@ async function runSingleCheck(test, gitHost, fetchFn, dispatcher) {
100
101
  port: extractPort(target, 443),
101
102
  source,
102
103
  testId,
104
+ connectFn: connectFn,
103
105
  });
104
106
  case "ssh":
105
107
  return sshCheck({
@@ -25,6 +25,12 @@ export interface RunChecksInput {
25
25
  * Typically only needed server-side for static IP routing.
26
26
  */
27
27
  dispatcher?: object;
28
+ /**
29
+ * Returns a connected socket tunneled through a proxy (via HTTP CONNECT).
30
+ * Used by TCP and TLS checks for static IP routing. The returned socket
31
+ * is already connected to hostname:port through the proxy.
32
+ */
33
+ connectFn?: (hostname: string, port: number) => Promise<unknown>;
28
34
  }
29
35
  export type ProgressEvent = {
30
36
  type: "test:start";
package/src/events.d.ts CHANGED
@@ -493,6 +493,14 @@ export declare const ClientDevtoolsSessionStartedEvent: {
493
493
  eventName: "client.devtools.session.started";
494
494
  version: "1";
495
495
  };
496
+ export type ClientDevtoolsSessionIdleEventV1 = FusionEventVariant<"client.devtools.session.idle", {
497
+ sessionId?: string;
498
+ lastMessage?: string;
499
+ }, {}, 1>;
500
+ export declare const ClientDevtoolsSessionIdleEventV1: {
501
+ eventName: "client.devtools.session.idle";
502
+ version: "1";
503
+ };
496
504
  export type FusionProjectCreatedV1 = FusionEventVariant<"fusion.project.created", {
497
505
  projectId: string;
498
506
  branchName?: string;
@@ -546,7 +554,7 @@ export interface SendMessageToOrgAgentInput {
546
554
  senderDisplayName?: string;
547
555
  messageContext?: string;
548
556
  }
549
- export type FusionEvent = AiTaskCompletedEvent | AiTaskFailedEvent | GitPrCreatedEvent | ClientDevtoolsSessionStartedEvent | FusionProjectCreatedV1 | SetupAgentCompletedV1 | ForceSetupAgentV1 | ClawMessageSentV1;
557
+ export type FusionEvent = AiTaskCompletedEvent | AiTaskFailedEvent | GitPrCreatedEvent | ClientDevtoolsSessionStartedEvent | ClientDevtoolsSessionIdleEventV1 | FusionProjectCreatedV1 | SetupAgentCompletedV1 | ForceSetupAgentV1 | ClawMessageSentV1;
550
558
  export interface ModelPermissionRequiredEvent {
551
559
  type: "assistant.model.permission.required";
552
560
  data: {
package/src/events.js CHANGED
@@ -14,6 +14,10 @@ export const ClientDevtoolsSessionStartedEvent = {
14
14
  eventName: "client.devtools.session.started",
15
15
  version: "1",
16
16
  };
17
+ export const ClientDevtoolsSessionIdleEventV1 = {
18
+ eventName: "client.devtools.session.idle",
19
+ version: "1",
20
+ };
17
21
  export const FusionProjectCreatedV1 = {
18
22
  eventName: "fusion.project.created",
19
23
  version: "1",
package/src/projects.d.ts CHANGED
@@ -775,6 +775,7 @@ export interface CreateBranchOptions {
775
775
  featureFlags?: Record<string, boolean>;
776
776
  checkoutBranch?: string | null;
777
777
  canHandleTools?: (keyof CodeGenToolMap)[];
778
+ skipPromptAnalysis?: boolean;
778
779
  useKube?: boolean;
779
780
  fireAndForget?: boolean;
780
781
  /** PR number for QA bot branches */
@@ -789,13 +790,6 @@ export interface CreateBranchOptions {
789
790
  }
790
791
  interface BaseCreateBranchMessage {
791
792
  }
792
- export interface ValidatingProjectMessage extends BaseCreateBranchMessage {
793
- type: "validating-project";
794
- message: string;
795
- projectId: string;
796
- projectName?: string;
797
- branchName: string;
798
- }
799
793
  export interface CreatingBranchMessage extends BaseCreateBranchMessage {
800
794
  type: "creating-branch";
801
795
  message: string;
@@ -811,6 +805,7 @@ export interface SettingUpContainerMessage extends BaseCreateBranchMessage {
811
805
  projectName: string;
812
806
  branchName: string;
813
807
  branchFriendlyName: string | undefined;
808
+ branchDescription: string | undefined;
814
809
  }
815
810
  export interface ContainerReadyMessage extends BaseCreateBranchMessage {
816
811
  type: "container-ready";
@@ -851,7 +846,7 @@ export interface AiMessage extends BaseCreateBranchMessage {
851
846
  type: "ai";
852
847
  event: GenerateCompletionStep;
853
848
  }
854
- export type CreateBranchChunkMessage = ValidatingProjectMessage | CreatingBranchMessage | SettingUpContainerMessage | SendingInitialMessageMessage | BranchCreatedMessage | CreateBranchErrorMessage | EnsureContainerMessage | ContainerReadyMessage | AiMessage;
849
+ export type CreateBranchChunkMessage = CreatingBranchMessage | SettingUpContainerMessage | SendingInitialMessageMessage | BranchCreatedMessage | CreateBranchErrorMessage | EnsureContainerMessage | ContainerReadyMessage | AiMessage;
855
850
  export interface CreateBranchResponse {
856
851
  success: boolean;
857
852
  branchName?: string;
@@ -938,12 +933,6 @@ export interface ValidatingBranchMessage extends BaseSendMessageMessage {
938
933
  projectId: string;
939
934
  branchName: string;
940
935
  }
941
- export interface SettingUpContainerMessage extends BaseSendMessageMessage {
942
- type: "setting-up-container";
943
- message: string;
944
- projectId: string;
945
- branchName: string;
946
- }
947
936
  export interface SendingMessageMessage extends BaseSendMessageMessage {
948
937
  type: "sending-message";
949
938
  message: string;