@builder.io/ai-utils 0.0.72 → 0.0.74

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/src/events.ts ADDED
@@ -0,0 +1,539 @@
1
+ import type { BuilderContent, BuilderElement } from "@builder.io/sdk";
2
+ import type { AssistantMessage } from "./messages.js";
3
+ import type { AssistantSettings } from "./settings.js";
4
+
5
+ export type BuilderAssistantEventHandler = (ev: BuilderAssistantEvent) => void;
6
+
7
+ export type BuilderAssistantEvent =
8
+ | AssistantCompletionResultEvent
9
+ | AssistantErrorEvent
10
+ | AssistantStreamErrorEvent
11
+ | AppCloseEvent
12
+ | AppMessagesClickEvent
13
+ | AppMessagesGenerationEvent
14
+ | AppMessageEditCustomInstructionsEvent
15
+ | AppPromptAbortEvent
16
+ | AppPromptFocusEvent
17
+ | AppPromptTextEvent
18
+ | AppReadyEvent
19
+ | AppSettingsResetEvent
20
+ | AppSettingsSetEvent
21
+ | AppThreadNewEvent
22
+ | AssistantStatsEvent
23
+ | AssistantThemeEvent
24
+ | BuilderEditorAuthEvent
25
+ | BuilderEditorStateEvent
26
+ | ContentUpdateEvent
27
+ | ContentApplySnapshotEvent
28
+ | ModelCreateEvent
29
+ | ModelUpdateEvent
30
+ | ModelUndoEvent
31
+ | ModelRedoEvent
32
+ | ResultEvent
33
+ | ThreadCreatedEvent
34
+ | ThreadMessageCompletedEvent
35
+ | ThreadMessageCreatedEvent
36
+ | ThreadMessageDeltaEvent
37
+ | ThreadMessageFeedbackEvent
38
+ | ThreadRunRequiresActionEvent
39
+ | ThreadRunStepCreatedEvent
40
+ | ThreadRunStepDeltaEvent
41
+ | AppAcceptChangeEvent
42
+ | AppAcceptRejectEvent
43
+ | AssistantTrackEvent
44
+ | AssistantEditorAuthMessage
45
+ | AppAttachmentTemplateEvent
46
+ | ThreadMessageRetryEvent;
47
+
48
+ export interface AssistantCompletionResultEvent {
49
+ type: "assistant.result";
50
+ data: {
51
+ content?: BuilderContent;
52
+ stats?: AssistantStats;
53
+ };
54
+ resolveId?: string;
55
+ }
56
+
57
+ export interface AssistantError {
58
+ message: string;
59
+ status?: number;
60
+ }
61
+
62
+ export interface AssistantErrorEvent {
63
+ type: "assistant.error";
64
+ data: AssistantError;
65
+ }
66
+
67
+ export interface AssistantStreamErrorEvent {
68
+ type: "assistant.stream.error";
69
+ data: AssistantError;
70
+ }
71
+
72
+ export interface AssistantTrackEvent {
73
+ type: "assistant.track";
74
+ data: {
75
+ name: string;
76
+ properties: Record<string, any>;
77
+ };
78
+ }
79
+
80
+ export interface AssistantThemeEvent {
81
+ type: "assistant.app.theme.update";
82
+ data: {
83
+ theme: string;
84
+ };
85
+ }
86
+
87
+ export interface AppCloseEvent {
88
+ type: "assistant.app.close";
89
+ }
90
+
91
+ export interface AppMessagesClickEvent {
92
+ type: "assistant.app.messages.click";
93
+ }
94
+
95
+ export interface AppAcceptChangeEvent {
96
+ type: "assistant.app.change.accept";
97
+ }
98
+ export interface AppAcceptRejectEvent {
99
+ type: "assistant.app.change.reject";
100
+ }
101
+
102
+ export interface AppMessageEditCustomInstructionsEvent {
103
+ type: "assistant.app.messages.editCustomInstructions";
104
+ }
105
+
106
+ export interface AppAttachmentTemplateEvent {
107
+ type: "assistant.app.attachment.template";
108
+ data: {
109
+ id: number;
110
+ name: string;
111
+ };
112
+ }
113
+
114
+ export interface AppMessagesGenerationEvent {
115
+ type: "assistant.app.messages.generation";
116
+ data: {
117
+ state: GenerationState;
118
+ };
119
+ }
120
+
121
+ /**
122
+ * idle: no messages are being generated or queued to be generated
123
+ *
124
+ * queued: messages have been sent to the LLM, but no response has been received yet
125
+ *
126
+ * generating: messages are actively being generated and streaming back to the UI
127
+ */
128
+ export type GenerationState = "idle" | "queued" | "generating";
129
+
130
+ export interface AppPromptAbortEvent {
131
+ type: "assistant.app.prompt.abort";
132
+ }
133
+
134
+ export interface AppPromptFocusEvent {
135
+ type: "assistant.app.prompt.focus";
136
+ }
137
+
138
+ export interface AppPromptTextEvent {
139
+ type: "assistant.app.prompt.text";
140
+ data: {
141
+ text: string;
142
+ };
143
+ }
144
+
145
+ export interface AppReadyEvent {
146
+ type: "assistant.app.ready";
147
+ }
148
+
149
+ export interface AppSettingsResetEvent {
150
+ type: "assistant.app.settings.reset";
151
+ }
152
+
153
+ export interface AppSettingsSetEvent {
154
+ type: "assistant.app.settings.set";
155
+ data: Partial<AssistantSettings>;
156
+ }
157
+
158
+ export interface AppThreadNewEvent {
159
+ type: "assistant.app.thread.new";
160
+ }
161
+
162
+ export interface AssistantEditorAuthMessage {
163
+ type: "assistant.editor.auth.update";
164
+ }
165
+
166
+ export interface BuilderEditorAuthEvent extends AwaitResultEvent {
167
+ type: "assistant.editor.auth";
168
+ }
169
+
170
+ export interface BuilderEditorStateEvent extends AwaitResultEvent {
171
+ type: "assistant.editor.state";
172
+ }
173
+
174
+ export interface AwaitResultEvent {
175
+ resolveId?: string;
176
+ }
177
+
178
+ export interface ResultEvent {
179
+ type: "assistant.result";
180
+ resolveId: string;
181
+ data: any;
182
+ }
183
+
184
+ export interface ContentCreatePatch {
185
+ parentId: string;
186
+ insertBeforeId: string;
187
+ element: BuilderElement;
188
+ }
189
+
190
+ export interface ContentApplySnapshot {
191
+ /**
192
+ * The id of the BuilderContent to apply the snapshot to
193
+ */
194
+ id: string;
195
+ /**
196
+ * Each snapshot can be either a full BuilderContent or individual BuilderElements.
197
+ * Order matters, as the snapshots will be applied in the order they are listed.
198
+ * The builder app will handle the logic of applying the snapshots in the correct order
199
+ * and to the right content/elements.
200
+ */
201
+ snapshots: (BuilderElement | BuilderContent)[];
202
+ }
203
+
204
+ export interface ContentApplySnapshotEvent {
205
+ type: "assistant.content.applysnapshot";
206
+ data: ContentApplySnapshot;
207
+ }
208
+
209
+ export interface ContentUpdateEvent {
210
+ type: "assistant.content.update";
211
+ data: ContentUpdatePatch[];
212
+ }
213
+
214
+ export type ContentUpdatePatch =
215
+ | ContentTsCodePatch
216
+ | ContentInsertBeforePatch
217
+ | ContentInsertAfterPatch
218
+ | ContentPropsUpdatePatch
219
+ | ContentSetChildrenPatch
220
+ | ContentStyleUpdatePatch
221
+ | ContentDeletePatch
222
+ | ContentSetStorePatch
223
+ | ContentSetMountPatch
224
+ | ContentMovePatch
225
+ | ContentMoveAfterPatch
226
+ | ContentMoveBeforePatch
227
+ | ContentSetTagNamePatch
228
+ | ContentTsUpdateComponentPatch;
229
+
230
+ interface ContentPatchBase {
231
+ id: string;
232
+ nodeId?: string;
233
+ builderId?: string;
234
+ description?: string;
235
+ value: string;
236
+ displayValue?: string;
237
+ ts: number;
238
+ /**
239
+ * A change value is considered incomplete until we also parsed it's closing xml tag.
240
+ */
241
+ incomplete?: boolean;
242
+ /**
243
+ * If there was an error applying the patch, this will contain the error message.
244
+ */
245
+ error?: string;
246
+ }
247
+
248
+ export interface ContentTsUpdateComponentPatch extends ContentPatchBase {
249
+ type: "update_component";
250
+ }
251
+
252
+ export interface ContentTsCodePatch extends ContentPatchBase {
253
+ type: "ts_code";
254
+ }
255
+
256
+ export interface ContentSetTagNamePatch extends ContentPatchBase {
257
+ type: "set_tag_name";
258
+ }
259
+
260
+ export interface ContentInsertBeforePatch extends ContentPatchBase {
261
+ type: "insert_before";
262
+ snapshotBuilderId?: string;
263
+ }
264
+
265
+ export interface ContentInsertAfterPatch extends ContentPatchBase {
266
+ type: "insert_after";
267
+ snapshotBuilderId?: string;
268
+ }
269
+
270
+ export interface ContentPropsUpdatePatch extends ContentPatchBase {
271
+ type: "props";
272
+ }
273
+
274
+ export interface ContentStyleUpdatePatch extends ContentPatchBase {
275
+ type: "style";
276
+ }
277
+
278
+ export interface ContentSetChildrenPatch extends ContentPatchBase {
279
+ type: "children";
280
+ snapshotBuilderId?: string;
281
+ }
282
+
283
+ export interface ContentDeletePatch extends ContentPatchBase {
284
+ type: "delete";
285
+ }
286
+
287
+ export interface ContentSetStorePatch extends ContentPatchBase {
288
+ type: "store";
289
+ }
290
+
291
+ export interface ContentSetMountPatch extends ContentPatchBase {
292
+ type: "mount";
293
+ }
294
+
295
+ export interface ContentMovePatch extends ContentPatchBase {
296
+ type: "move";
297
+ }
298
+
299
+ export interface ContentMoveAfterPatch extends ContentPatchBase {
300
+ type: "move_after";
301
+ }
302
+
303
+ export interface ContentMoveBeforePatch extends ContentPatchBase {
304
+ type: "move_before";
305
+ }
306
+
307
+ export interface AssistantStatsEvent {
308
+ type: "assistant.stats";
309
+ data: AssistantStats;
310
+ }
311
+
312
+ export interface AssistantStats {
313
+ /**
314
+ * The unique id of the thread (not the openai threadId)
315
+ */
316
+ threadId: string;
317
+ /**
318
+ * The unique id of the completion, which is a combination of the user's prompt and assistant's response.
319
+ */
320
+ completionId: string;
321
+ /**
322
+ * The model id used to generate this completion.
323
+ */
324
+ modelId: string;
325
+ /**
326
+ * The assistant's response message.
327
+ */
328
+ assistantMessage: string;
329
+ /**
330
+ * The user's prompt message.
331
+ */
332
+ userMessage: string;
333
+ /**
334
+ * The index within the thread the assistant message is.
335
+ * For a first assistant message, the index will be 1 (the user message is index 0).
336
+ * For a second assistant message, the index will be 3 (the user message is index 2), and so on.
337
+ */
338
+ assistantMessageIndex: number;
339
+ /**
340
+ * The timestamp (Date.now()) of when the user first submitted their prompt.
341
+ */
342
+ userPromptMs: number;
343
+ /**
344
+ * The timestamp of the first assistant chunk in the response.
345
+ */
346
+ firstChunkMs: number;
347
+ /**
348
+ * The timestamp of the last assistant chunk in the response.
349
+ */
350
+ lastChunkMs: number;
351
+ /**
352
+ * The total number of chunks in the assistant's streamed response.
353
+ */
354
+ chunkCount: number;
355
+ /**
356
+ * The total number of characters in the generated prompt sent to the LLM.
357
+ */
358
+ promptLength: number;
359
+ /**
360
+ * The total number of characters in the assistant's response.
361
+ */
362
+ completionLength: number;
363
+ /**
364
+ * If the user provided custom instructions for the prompt.
365
+ */
366
+ hasCustomInstructions: boolean;
367
+ /**
368
+ * The deployed version.
369
+ */
370
+ version: string;
371
+ /**
372
+ * Error message if there was one.
373
+ */
374
+ errorMessage?: string;
375
+ /**
376
+ * Input tokens
377
+ */
378
+ inputTokens?: number;
379
+ /**
380
+ * Output tokens
381
+ */
382
+ outputTokens?: number;
383
+ /**
384
+ * Output tokens
385
+ */
386
+ completionCost?: number;
387
+ /**
388
+ * Number of streamed snapshots
389
+ */
390
+ streamedSnapshots?: number;
391
+ /**
392
+ * Number of cached input tokens
393
+ */
394
+ cacheInputTokens?: number;
395
+ /**
396
+ * Number of cached created tokens
397
+ */
398
+ cacheCreatedTokens?: number;
399
+ }
400
+
401
+ export interface ModelCreateEvent {
402
+ type: "assistant.model.create";
403
+ data: BuilderModel;
404
+ }
405
+
406
+ export interface ModelUpdateEvent {
407
+ type: "assistant.model.update";
408
+ data: ModelUpdate;
409
+ }
410
+
411
+ export interface ModelUndoEvent {
412
+ type: "assistant.model.undo";
413
+ }
414
+
415
+ export interface ModelRedoEvent {
416
+ type: "assistant.model.redo";
417
+ }
418
+
419
+ export interface ModelUpdate {
420
+ patches: ModelPatch[];
421
+ }
422
+
423
+ export interface BuilderModel {
424
+ name?: string;
425
+ friendlyName?: string;
426
+ description?: string;
427
+ type?: string;
428
+ fields?: BuilderModelField[];
429
+ }
430
+
431
+ export interface BuilderModelField {
432
+ name?: string;
433
+ type?: string;
434
+ description?: string;
435
+ }
436
+
437
+ export type ModelPatch = {
438
+ op: "add" | "remove" | "replace";
439
+ path: string;
440
+ value?: any;
441
+ };
442
+
443
+ export interface ThreadMessageFeedbackEvent {
444
+ type: "assistant.thread.message.feedback";
445
+ data: CompletionResponseFeedback;
446
+ }
447
+
448
+ export interface CompletionResponseFeedback {
449
+ userId: string;
450
+ builderUserId?: string;
451
+ builderEmail?: string;
452
+ responseId?: string;
453
+ frontendUrl: string | undefined;
454
+ frontendCommitId: string | undefined;
455
+ backendDomain?: string;
456
+ backendCommitId: string | undefined;
457
+ feedbackText: string;
458
+ sentiment?: "positive" | "negative";
459
+ }
460
+
461
+ export interface ThreadCreatedEvent {
462
+ type: "assistant.thread.created";
463
+ data: ThreadCreated;
464
+ }
465
+
466
+ export interface ThreadCreated {
467
+ platformId: string;
468
+ threadId: string;
469
+ vectorStoreId: string;
470
+ }
471
+
472
+ export interface ThreadMessageCreatedEvent {
473
+ type: "assistant.thread.message.created";
474
+ data: ThreadMessageCreated;
475
+ }
476
+
477
+ export interface ThreadMessageCreated {
478
+ id: string;
479
+ responseId: string;
480
+ threadId: string;
481
+ }
482
+
483
+ export interface ThreadMessageDeltaEvent {
484
+ type: "assistant.thread.message.delta";
485
+ data: ThreadMessageDelta;
486
+ }
487
+
488
+ export interface ThreadMessageDelta {
489
+ id: string;
490
+ text: string;
491
+ }
492
+
493
+ export interface ThreadMessageCompletedEvent {
494
+ type: "assistant.thread.message.completed";
495
+ data: ThreadMessageCompleted;
496
+ }
497
+
498
+ export interface ThreadMessageRetryEvent {
499
+ type: "assistant.thread.message.retry";
500
+ }
501
+
502
+ export interface ThreadMessageCompleted extends AssistantMessage {
503
+ platformId: string;
504
+ threadId: string;
505
+ commitId?: string;
506
+ }
507
+
508
+ export interface ThreadRunRequiresActionEvent {
509
+ type: "assistant.thread.run.requires_action";
510
+ data: ThreadRunRequiredAction;
511
+ }
512
+
513
+ export interface ThreadRunRequiredAction {
514
+ platformId: string;
515
+ threadId: string;
516
+ action: {
517
+ name: string;
518
+ arguments: string;
519
+ };
520
+ }
521
+
522
+ export interface ThreadRunStepDeltaEvent {
523
+ type: "assistant.thread.run.step.delta";
524
+ data: ThreadMessageStepDelta;
525
+ }
526
+
527
+ export interface ThreadMessageStepDelta {
528
+ delta: any;
529
+ }
530
+
531
+ export interface ThreadRunStepCreatedEvent {
532
+ type: "assistant.thread.run.step.created";
533
+ }
534
+
535
+ export type DeepPartial<T> = T extends object
536
+ ? {
537
+ [P in keyof T]?: DeepPartial<T[P]>;
538
+ }
539
+ : T;
package/src/fetch.ts ADDED
@@ -0,0 +1,95 @@
1
+ export async function fetchJsonl<T>(
2
+ input: string | URL,
3
+ init: RequestInit,
4
+ onData: (ev: T) => void,
5
+ ) {
6
+ return new Promise<Response>(async (resolve, reject) => {
7
+ try {
8
+ init = {
9
+ ...init,
10
+ headers: {
11
+ accept: "application/jsonl",
12
+ "content-type": "application/json",
13
+ ...init.headers,
14
+ },
15
+ };
16
+
17
+ const rsp = await (async () => {
18
+ try {
19
+ return await fetch(input, init);
20
+ } catch (err) {
21
+ reject(new NetworkError(`${input}, status: network failure`));
22
+ }
23
+ })();
24
+
25
+ if (!rsp) {
26
+ return;
27
+ }
28
+
29
+ if (!rsp.ok) {
30
+ reject(new APIError(`${input}, status: ${rsp.status}`));
31
+ return;
32
+ }
33
+
34
+ if (!rsp.body) {
35
+ reject(new APIError(`${input}, missing body`));
36
+ return;
37
+ }
38
+
39
+ const reader = rsp.body.getReader();
40
+ const decoder = new TextDecoder();
41
+ let data = "";
42
+
43
+ const processStream = async () => {
44
+ const { done, value } = await reader.read();
45
+ data += decoder.decode(value, { stream: !done });
46
+
47
+ if (!done) {
48
+ let lines = data.split("\n");
49
+ if (!done) {
50
+ data = lines.pop() || "";
51
+ }
52
+
53
+ for (let line of lines) {
54
+ if (line) {
55
+ try {
56
+ line = line.trim();
57
+ if (line.startsWith("{") && line.endsWith("}")) {
58
+ onData(JSON.parse(line));
59
+ } else {
60
+ reject(`Invalid JSONL line: ${line}`);
61
+ return;
62
+ }
63
+ } catch (e) {
64
+ console.error(`Failed to parse JSONL: ${line}`);
65
+ reject(e);
66
+ return;
67
+ }
68
+ }
69
+ }
70
+
71
+ await processStream();
72
+ }
73
+ };
74
+
75
+ await processStream();
76
+ resolve(rsp);
77
+ } catch (e) {
78
+ reject(e);
79
+ }
80
+ });
81
+ }
82
+
83
+ class NetworkError extends Error {
84
+ constructor(message: string) {
85
+ super(message);
86
+ this.name = "NetworkError";
87
+ }
88
+ }
89
+
90
+ class APIError extends Error {
91
+ constructor(message: string) {
92
+ super(message);
93
+ this.name = "APIError";
94
+ }
95
+ }
@@ -5,3 +5,6 @@ export * from "./fetch.js";
5
5
  export * from "./messages.js";
6
6
  export * from "./settings.js";
7
7
  export * from "./thread.js";
8
+ export * from "./mapping.js";
9
+ export * from "./codegen.js";
10
+ export * from "./vcp.js";
package/src/mapping.ts ADDED
@@ -0,0 +1,88 @@
1
+ import type { ESMImport } from "./codegen";
2
+
3
+ export interface UserContext {
4
+ client: string;
5
+ clientVersion: string;
6
+ nodeVersion: string;
7
+ systemPlatform: string;
8
+ frameworks: string[];
9
+ systemEOL: string;
10
+ systemArch: string;
11
+ systemShell?: string;
12
+ inGitRepo?: boolean;
13
+ [key: string]: string | string[] | boolean | undefined;
14
+ }
15
+
16
+ export type ExportType = "default" | "named";
17
+
18
+ /**
19
+ * Gets the latest component mappings for a space
20
+ */
21
+ export interface FigmaMappingsData {
22
+ id: string;
23
+ figmaBuilderLinks: FigmaBuilderLink[];
24
+ version?: number;
25
+ createdDate?: string; // ISO string timestamp or unix timestamp
26
+ local: boolean;
27
+ userEmail?: string;
28
+ remoteUrl?: string;
29
+ }
30
+
31
+ export interface FigmaBuilderLink {
32
+ builderName: string;
33
+ figmaName: string;
34
+ figmaKey: string;
35
+ figmaUrl?: string;
36
+ inputMapper?: string;
37
+ originalInputMapper?: string;
38
+ exportType?: ExportType;
39
+ importName?: string;
40
+ importPath?: string;
41
+ source: string;
42
+ loc?: string;
43
+ imports?: ESMImport[];
44
+ }
45
+
46
+ export interface FigmaMapperFile {
47
+ filePath: string;
48
+ content: string;
49
+ }
50
+
51
+ export interface PublishedMapping {
52
+ figmaBuilderLinks: FigmaBuilderLink[];
53
+ mapperFiles: FigmaMapperFile[];
54
+
55
+ // Meta data
56
+ remoteUrl?: string;
57
+ defaultBranch?: string;
58
+ currentBranch?: string;
59
+ commit?: string;
60
+ spaceKind?: string;
61
+
62
+ userContext?: UserContext;
63
+ }
64
+
65
+ export interface FigmaComponentInfo {
66
+ documentName: string;
67
+ key: string;
68
+ tree?: string;
69
+ jsx?: string;
70
+ type: string;
71
+ name: string;
72
+ exportJson?: any;
73
+ inputs: FigmaComponentInput[];
74
+ description: string;
75
+ documentationLinks: string[];
76
+ instanceId: string;
77
+ }
78
+
79
+ export interface FigmaComponentInput {
80
+ id: string;
81
+ name: string;
82
+ value?: any;
83
+ type: string;
84
+ baseType: "text" | "variant" | "boolean" | "slot";
85
+ variantOptions?: string[];
86
+ isDefault: boolean;
87
+ ref?: string;
88
+ }