@builder.io/ai-utils 0.31.0 → 0.31.1

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.31.1",
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
@@ -179,6 +179,8 @@ export interface AgentToolInput {
179
179
  prompt: string;
180
180
  subagent_type?: string;
181
181
  resume?: string;
182
+ origin_channel_id?: string;
183
+ attachmentUrls?: string[];
182
184
  }
183
185
  export interface ListDirToolInput {
184
186
  path: string;
@@ -499,6 +501,9 @@ export interface SpawnBranchToolInput {
499
501
  hidden?: boolean;
500
502
  sourceChannelId?: string;
501
503
  sourceDmId?: string;
504
+ sessionMode?: "normal" | "planning" | "deep-research";
505
+ model?: "auto" | "opus" | "sonnet" | "haiku";
506
+ attachmentUrls?: string[];
502
507
  }
503
508
  export interface ReadBranchToolInput {
504
509
  projectId: string;
@@ -1733,6 +1738,8 @@ export interface FusionConfig {
1733
1738
  errorIgnorePatterns?: string[];
1734
1739
  /** When true, sync the git working tree to the latest remote state during init */
1735
1740
  syncBranch?: boolean;
1741
+ /** How the PVC was provisioned. Used by InitStateMachine to decide whether to restore from backup. */
1742
+ pvcCreationSource?: "fresh" | "snapshot" | "existing";
1736
1743
  /**
1737
1744
  * Maximum number of agent completions before pausing to ask the user to continue.
1738
1745
  * Read from project settings, with fallback to organization/space settings.
@@ -1772,7 +1779,7 @@ export interface LoadHistoryResult {
1772
1779
  updatedUnixTime: number;
1773
1780
  turns: CodegenTurn[];
1774
1781
  }
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";
1782
+ 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
1783
  export interface InitStatusLog {
1777
1784
  id: number;
1778
1785
  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/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;