@builder.io/ai-utils 0.49.0 → 0.50.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.49.0",
3
+ "version": "0.50.1",
4
4
  "description": "Builder.io AI utils",
5
5
  "files": [
6
6
  "src"
package/src/codegen.d.ts CHANGED
@@ -68,6 +68,13 @@ export interface CustomAgentDefinition {
68
68
  queueMode?: QueueMode;
69
69
  softContextWindow?: number;
70
70
  filePath?: string;
71
+ /** Maximum wall time (in milliseconds) before the agent watchdog aborts. */
72
+ maxTimeoutMs?: number;
73
+ /**
74
+ * Default max LLM completion turns when this agent is spawned via the Agent tool.
75
+ * Overrides generic sub-agent defaults in dev-tools when set.
76
+ */
77
+ maxCompletions?: number;
71
78
  /** Default reasoning effort level for this agent type. Overrides the session default. */
72
79
  reasoning?: ReasoningEffort;
73
80
  }
@@ -332,6 +339,7 @@ export interface TimelineRecording {
332
339
  startEventId: number;
333
340
  endEventId: number;
334
341
  testCaseIds?: string[];
342
+ replayId?: string;
335
343
  }>;
336
344
  }
337
345
  export interface TimelineSubmissionMetadata {
@@ -642,6 +650,7 @@ export interface ArchiveBranchToolInput {
642
650
  builder_user_id: string;
643
651
  reason?: string;
644
652
  }
653
+ export type ReviewSeverity = "high" | "medium" | "low";
645
654
  /** Comment for PR review - used by SubmitPRReview */
646
655
  export interface PRReviewComment {
647
656
  file_path: string;
@@ -649,15 +658,17 @@ export interface PRReviewComment {
649
658
  start_line?: number;
650
659
  title: string;
651
660
  body: string;
652
- severity: "high" | "medium" | "low";
661
+ severity: ReviewSeverity;
653
662
  debugInfo?: string;
654
663
  gif_id?: string;
655
664
  }
665
+ export type ReviewVerdict = "looks_good" | "has_findings" | "blocking";
656
666
  /** SubmitPRReview - Fast code review without recording */
657
667
  export interface SubmitPRReviewToolInput {
658
668
  summary: string;
659
669
  comments?: PRReviewComment[];
660
- risk_level?: "high" | "medium" | "low";
670
+ risk_level?: ReviewSeverity;
671
+ verdict?: ReviewVerdict;
661
672
  }
662
673
  export interface ResolveQACommentsToolInput {
663
674
  thread_node_ids: string[];
@@ -672,7 +683,7 @@ export interface ReportIssueToolInput {
672
683
  line: number;
673
684
  start_line?: number;
674
685
  title: string;
675
- severity: "high" | "medium" | "low";
686
+ severity: ReviewSeverity;
676
687
  body: string;
677
688
  }
678
689
  export interface CodeGenToolMap {
@@ -0,0 +1,21 @@
1
+ import type { CheckResult, Source, TestId } from "../types.js";
2
+ export interface WebSocketCheckOptions {
3
+ target: string;
4
+ source: Source;
5
+ testId: TestId;
6
+ timeout?: number;
7
+ }
8
+ /**
9
+ * Tests WebSocket connectivity by attempting to open a WSS connection.
10
+ *
11
+ * Protocol notes:
12
+ * - Uses wss:// (WebSocket Secure) — ws:// is blocked by browsers on HTTPS pages
13
+ * due to mixed-content restrictions, and wss:// uses port 443 which is typically
14
+ * allowed by firewalls that permit HTTPS traffic.
15
+ * - Considers the check passed as soon as the WebSocket `open` event fires,
16
+ * meaning the TCP+TLS+HTTP-upgrade handshake completed successfully.
17
+ * - A firewall or proxy that blocks WebSocket upgrades (even on the same host/port
18
+ * that allows normal HTTPS) will cause the `error` event instead, and the check fails.
19
+ * - The timeout guards against silent connection drops that never emit an event.
20
+ */
21
+ export declare function websocketCheck(options: WebSocketCheckOptions): Promise<CheckResult>;
@@ -0,0 +1,90 @@
1
+ const DEFAULT_TIMEOUT_MS = 10000;
2
+ /**
3
+ * Tests WebSocket connectivity by attempting to open a WSS connection.
4
+ *
5
+ * Protocol notes:
6
+ * - Uses wss:// (WebSocket Secure) — ws:// is blocked by browsers on HTTPS pages
7
+ * due to mixed-content restrictions, and wss:// uses port 443 which is typically
8
+ * allowed by firewalls that permit HTTPS traffic.
9
+ * - Considers the check passed as soon as the WebSocket `open` event fires,
10
+ * meaning the TCP+TLS+HTTP-upgrade handshake completed successfully.
11
+ * - A firewall or proxy that blocks WebSocket upgrades (even on the same host/port
12
+ * that allows normal HTTPS) will cause the `error` event instead, and the check fails.
13
+ * - The timeout guards against silent connection drops that never emit an event.
14
+ */
15
+ export async function websocketCheck(options) {
16
+ const { target, source, testId, timeout = DEFAULT_TIMEOUT_MS } = options;
17
+ const startTime = Date.now();
18
+ return new Promise((resolve) => {
19
+ let settled = false;
20
+ let ws = null;
21
+ const timeoutId = setTimeout(() => {
22
+ if (settled)
23
+ return;
24
+ settled = true;
25
+ ws === null || ws === void 0 ? void 0 : ws.close();
26
+ resolve({
27
+ source,
28
+ testId,
29
+ target,
30
+ passed: false,
31
+ errorCode: "tcp_connection_timeout",
32
+ durationMs: Date.now() - startTime,
33
+ metadata: {
34
+ error: "WebSocket connection timed out",
35
+ timeoutMs: timeout,
36
+ },
37
+ });
38
+ }, timeout);
39
+ try {
40
+ ws = new WebSocket(target);
41
+ }
42
+ catch (err) {
43
+ clearTimeout(timeoutId);
44
+ settled = true;
45
+ resolve({
46
+ source,
47
+ testId,
48
+ target,
49
+ passed: false,
50
+ errorCode: "unknown_error",
51
+ durationMs: Date.now() - startTime,
52
+ metadata: {
53
+ error: err instanceof Error ? err.message : "Failed to create WebSocket",
54
+ },
55
+ });
56
+ return;
57
+ }
58
+ ws.onopen = () => {
59
+ if (settled)
60
+ return;
61
+ settled = true;
62
+ clearTimeout(timeoutId);
63
+ const durationMs = Date.now() - startTime;
64
+ ws === null || ws === void 0 ? void 0 : ws.close(1000);
65
+ resolve({
66
+ source,
67
+ testId,
68
+ target,
69
+ passed: true,
70
+ durationMs,
71
+ metadata: { protocol: (ws === null || ws === void 0 ? void 0 : ws.protocol) || undefined },
72
+ });
73
+ };
74
+ ws.onerror = () => {
75
+ if (settled)
76
+ return;
77
+ settled = true;
78
+ clearTimeout(timeoutId);
79
+ resolve({
80
+ source,
81
+ testId,
82
+ target,
83
+ passed: false,
84
+ errorCode: "tcp_connection_refused",
85
+ durationMs: Date.now() - startTime,
86
+ metadata: { error: "WebSocket connection failed" },
87
+ });
88
+ };
89
+ });
90
+ }
@@ -7,13 +7,17 @@ export function isNode() {
7
7
  process.versions.node != null);
8
8
  }
9
9
  export function getCheckTypeForTestId(testId) {
10
+ if (testId === "health.builderio.xyz:ws" ||
11
+ testId === "health.builderio.dev:ws") {
12
+ return "websocket";
13
+ }
10
14
  if (testId.startsWith("git-host:")) {
11
15
  return testId.replace("git-host:", "");
12
16
  }
13
17
  return "http";
14
18
  }
15
19
  export function isCheckAvailable(checkType) {
16
- if (checkType === "http") {
20
+ if (checkType === "http" || checkType === "websocket") {
17
21
  return true;
18
22
  }
19
23
  // DNS, TCP, TLS, and SSH checks require Node.js modules
@@ -21,7 +25,7 @@ export function isCheckAvailable(checkType) {
21
25
  }
22
26
  export function getUnavailabilityReason(checkType) {
23
27
  if (isBrowser()) {
24
- return `${checkType.toUpperCase()} checks are not available in browser environments. Only HTTP checks can be performed from the browser.`;
28
+ return `${checkType.toUpperCase()} checks are not available in browser environments. Only HTTP and WebSocket checks can be performed from the browser.`;
25
29
  }
26
30
  return `${checkType.toUpperCase()} checks are not available in this environment.`;
27
31
  }
@@ -1,6 +1,7 @@
1
1
  import { resolveTarget } from "./targets.js";
2
2
  import { getCheckTypeForTestId, isCheckAvailable, getUnavailabilityReason, } from "./environment.js";
3
3
  import { httpCheck } from "./checks/http-check.js";
4
+ import { websocketCheck } from "./checks/websocket-check.js";
4
5
  export async function runChecks(input) {
5
6
  const { tests, gitHost, onProgress } = input;
6
7
  const results = [];
@@ -77,6 +78,8 @@ async function runSingleCheck(test, gitHost) {
77
78
  switch (checkType) {
78
79
  case "http":
79
80
  return httpCheck({ target, source, testId });
81
+ case "websocket":
82
+ return websocketCheck({ target, source, testId });
80
83
  default:
81
84
  return {
82
85
  source,
@@ -1,6 +1,7 @@
1
1
  import { resolveTarget, extractHostname, extractPort, extractExplicitPort, } from "./targets.js";
2
2
  import { getCheckTypeForTestId, isCheckAvailable, getUnavailabilityReason, } from "./environment.js";
3
3
  import { httpCheck } from "./checks/http-check.js";
4
+ import { websocketCheck } from "./checks/websocket-check.js";
4
5
  import { dnsCheck } from "./checks/dns-check.js";
5
6
  import { tcpCheck } from "./checks/tcp-check.js";
6
7
  import { tlsCheck } from "./checks/tls-check.js";
@@ -81,6 +82,8 @@ async function runSingleCheck(test, gitHost, fetchFn, dispatcher, connectFn) {
81
82
  switch (checkType) {
82
83
  case "http":
83
84
  return httpCheck({ target, source, testId, fetchFn, dispatcher });
85
+ case "websocket":
86
+ return websocketCheck({ target, source, testId });
84
87
  case "dns":
85
88
  return dnsCheck({
86
89
  hostname: extractHostname(target),
@@ -4,6 +4,9 @@ export const BUILDER_TARGETS = {
4
4
  "api.builder.io": "https://api.builder.io/codegen/health",
5
5
  "cdn.builder.io": "https://cdn.builder.io/api/v1/image/assets/TEMP/75a212ab82b6175c9862b125e0e23db8d369a58a?width=100",
6
6
  "health.builderio.xyz": "https://health.builderio.xyz/health",
7
+ "health.builderio.xyz:ws": "wss://health.builderio.xyz/ws",
8
+ "health.builderio.dev": "https://health.builderio.dev/health",
9
+ "health.builderio.dev:ws": "wss://health.builderio.dev/ws",
7
10
  "fly.dev": "https://fly.dev",
8
11
  };
9
12
  export const DEFAULT_PORTS = {
@@ -1,5 +1,5 @@
1
1
  export type Source = "local" | "cloud" | "static-ip";
2
- export type TestId = "builder.io" | "builder.codes" | "api.builder.io" | "cdn.builder.io" | "health.builderio.xyz" | "fly.dev" | "git-host:http" | "git-host:dns" | "git-host:tcp" | "git-host:tls" | "git-host:ssh";
2
+ export type TestId = "builder.io" | "builder.codes" | "api.builder.io" | "cdn.builder.io" | "health.builderio.xyz" | "health.builderio.xyz:ws" | "health.builderio.dev" | "health.builderio.dev:ws" | "fly.dev" | "git-host:http" | "git-host:dns" | "git-host:tcp" | "git-host:tls" | "git-host:ssh";
3
3
  export interface Test {
4
4
  source: Source;
5
5
  testId: TestId;
@@ -61,7 +61,7 @@ export interface CheckReport {
61
61
  results: CheckResult[];
62
62
  }
63
63
  export type ConnectivityErrorCode = "dns_resolution_failed" | "dns_timeout" | "dns_wrong_ip" | "tcp_connection_refused" | "tcp_connection_timeout" | "tcp_connection_reset" | "tcp_host_unreachable" | "tcp_network_unreachable" | "tls_self_signed_cert" | "tls_cert_expired" | "tls_cert_not_yet_valid" | "tls_cert_invalid" | "tls_cert_hostname_mismatch" | "tls_handshake_failed" | "tls_protocol_error" | "proxy_auth_required" | "proxy_connection_failed" | "proxy_tunnel_failed" | "http_unauthorized" | "http_forbidden" | "http_not_found" | "http_server_error" | "http_service_unavailable" | "latency_high" | "check_unavailable" | "unknown_error";
64
- export type CheckType = "http" | "dns" | "tcp" | "tls" | "ssh";
64
+ export type CheckType = "http" | "websocket" | "dns" | "tcp" | "tls" | "ssh";
65
65
  export type Recommendation = "ready_for_cloud_dev" | "enable_static_ip_proxy" | "whitelist_static_ip" | "fix_local_dns" | "fix_local_tls_certs" | "fix_local_firewall" | "use_local_development";
66
66
  export type LikelyCause = "ip_whitelisting_required" | "vpn_blocking" | "corporate_proxy_required" | "self_signed_certificate" | "dns_misconfiguration" | "firewall_blocking" | "server_unavailable";
67
67
  export type ConnectivityStatus = "pass" | "fail" | "unknown";
package/src/events.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { BuilderContent, BuilderElement } from "@builder.io/sdk";
2
2
  import type { AssistantMessage, AssistantMessageAction } from "./messages.js";
3
3
  import type { AssistantSettings } from "./settings.js";
4
- import type { ExitState, UserSource, CodeGenPosition } from "./codegen.js";
4
+ import type { ExitState, UserSource, CodeGenPosition, ReviewSeverity, ReviewVerdict } from "./codegen.js";
5
5
  import type { FileUpload } from "./messages.js";
6
6
  export type BuilderAssistantEventHandler = (ev: BuilderAssistantEvent) => void;
7
7
  export type BuilderAssistantEvent = AssistantCompletionResultEvent | AssistantErrorEvent | AssistantStreamErrorEvent | AppCloseEvent | AppMessagesClickEvent | AppMessagesGenerationEvent | AppMessageEditCustomInstructionsEvent | AppPromptAbortEvent | AppPromptFocusEvent | AppPromptSubmitEvent | AppReadyEvent | AppSettingsSetEvent | AppThreadNewEvent | AssistantStatsEvent | AssistantThemeEvent | BuilderEditorAuthEvent | BuilderEditorStateEvent | ContentUpdateEvent | ContentApplySnapshotEvent | ModelUndoEvent | ModelRedoEvent | ResultEvent | ThreadCreatedEvent | ThreadMessageCompletedEvent | ThreadMessageCreatedEvent | ThreadMessageDeltaEvent | ThreadMessageFeedbackEvent | ThreadRunStepCreatedEvent | ThreadRunStepDeltaEvent | AppAcceptChangeEvent | AppAcceptRejectEvent | AssistantTrackEvent | AssistantEditorAuthMessage | AppAttachmentTemplateEvent | AppPasteSmartExportEvent | ThreadMessageRetryEvent | AppFigmaImportEvent | AppWebImportEvent | AppMcpServersEvent | AssistantContentInitialEvent | ThreadMessageSummaryEvent | ThreadMessageSummaryCodegenDeltaEvent | ThreadMessageThinkingDeltaEvent | AssistantHeartbeatEvent | ShowUpgradeDialogEvent | AssistantFusionSuggestionEvent | AppNavigateToFusionEvent | ModelPermissionRequiredEvent | ModelPermissionResponseEvent;
@@ -514,7 +514,10 @@ export type ReviewSubmittedV1 = FusionEventVariant<"review.submitted", {
514
514
  start_line?: number | null;
515
515
  body: string;
516
516
  }>;
517
- riskLevel: "high" | "medium" | "low";
517
+ riskLevel: ReviewSeverity;
518
+ verdict?: ReviewVerdict;
519
+ verdictOverridden?: boolean;
520
+ modelVerdict?: ReviewVerdict;
518
521
  totalIssuesSubmitted: number;
519
522
  issuesPosted: number;
520
523
  issuesHigh: number;
package/src/projects.d.ts CHANGED
@@ -144,6 +144,8 @@ export interface ReadyMessage extends BaseMessage {
144
144
  state: "ready";
145
145
  message: string;
146
146
  url: string;
147
+ /** Public kube hostnames (no scheme), e.g. `*.builderio.xyz` and `*.builderio.dev` when both are routed. */
148
+ hostnames?: string[];
147
149
  status?: LaunchServerStatus;
148
150
  }
149
151
  export type MachineState = "unknown" | "created" | "starting" | "started" | "stopping" | "stopped" | "suspending" | "suspended" | "replacing" | "destroying" | "destroyed" | "not-found" | "running" | "failed";
@@ -480,6 +482,8 @@ export interface BranchSharedData {
480
482
  kubeNamespace?: string | null;
481
483
  kubePvcName?: string | null;
482
484
  kubeHostname?: string | null;
485
+ /** Public kube hostnames for this branch (no scheme), when more than one domain is available. */
486
+ kubeHostnames?: string[] | null;
483
487
  checkoutBranch?: string | null;
484
488
  /** Whether this branch is for a fork PR - affects git operations (read-only, can't push) */
485
489
  isFork?: boolean | null;
@@ -828,6 +832,18 @@ export interface CreateBranchOptions {
828
832
  gitAiBranch?: string | null;
829
833
  /** Contextual information (e.g., a git diff) used by the backend to generate a friendly branch name via LLM */
830
834
  branchContext?: string;
835
+ /**
836
+ * Lifecycle hook awaited by createBranch after the container is ready and
837
+ * before the initial message is dispatched to devtools/codegen. Use this to
838
+ * register webhook hooks so they're guaranteed to be in place before the
839
+ * first events stream out. Errors are caught + reported and do not block
840
+ * message dispatch.
841
+ */
842
+ onContainerReady?: (info: {
843
+ projectId: string;
844
+ branchName: string;
845
+ url: string;
846
+ }) => Promise<void> | void;
831
847
  }
832
848
  interface BaseCreateBranchMessage {
833
849
  }