@pushwoosh/rpc-gateway-ai-assistant 0.1.124 → 0.1.126

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/data.js CHANGED
@@ -6,7 +6,17 @@ export const data = {
6
6
  "values": [
7
7
  "DOCUMENT_BLOCK_TYPE_UNSPECIFIED",
8
8
  "DOCUMENT_BLOCK_TYPE_CARD",
9
- "DOCUMENT_BLOCK_TYPE_COLUMNS"
9
+ "DOCUMENT_BLOCK_TYPE_COLUMNS",
10
+ "DOCUMENT_BLOCK_TYPE_CONTENT",
11
+ "DOCUMENT_BLOCK_TYPE_GROUP"
12
+ ]
13
+ },
14
+ "pushwoosh.aibuilder.v1.GroupDirection": {
15
+ "type": "E",
16
+ "values": [
17
+ "GROUP_DIRECTION_UNSPECIFIED",
18
+ "GROUP_DIRECTION_VERTICAL",
19
+ "GROUP_DIRECTION_HORIZONTAL"
10
20
  ]
11
21
  },
12
22
  "pushwoosh.aibuilder.v1.CardLayout": {
@@ -29,6 +39,15 @@ export const data = {
29
39
  "BUTTON_GROUP_ALIGN_RIGHT"
30
40
  ]
31
41
  },
42
+ "pushwoosh.aibuilder.v1.GroupAlign": {
43
+ "type": "E",
44
+ "values": [
45
+ "GROUP_ALIGN_UNSPECIFIED",
46
+ "GROUP_ALIGN_START",
47
+ "GROUP_ALIGN_CENTER",
48
+ "GROUP_ALIGN_END"
49
+ ]
50
+ },
32
51
  "pushwoosh.aibuilder.v1.CardImageFit": {
33
52
  "type": "E",
34
53
  "values": [
@@ -84,16 +103,20 @@ export const data = {
84
103
  "type": "I",
85
104
  "fields": {
86
105
  "backgroundColor": {
87
- "type": "string"
106
+ "type": "string",
107
+ "optional": true
88
108
  },
89
109
  "borderColor": {
90
- "type": "string"
110
+ "type": "string",
111
+ "optional": true
91
112
  },
92
113
  "borderWidth": {
93
- "type": "number"
114
+ "type": "number",
115
+ "optional": true
94
116
  },
95
117
  "borderRadius": {
96
- "type": "number"
118
+ "type": "number",
119
+ "optional": true
97
120
  }
98
121
  }
99
122
  },
@@ -415,6 +438,29 @@ export const data = {
415
438
  }
416
439
  }
417
440
  },
441
+ "pushwoosh.aibuilder.v1.AiBuilderGroup": {
442
+ "type": "I",
443
+ "fields": {
444
+ "direction": {
445
+ "type": "pushwoosh.aibuilder.v1.GroupDirection"
446
+ },
447
+ "margin": {
448
+ "type": "pushwoosh.aibuilder.v1.EdgeInsets",
449
+ "optional": true
450
+ },
451
+ "padding": {
452
+ "type": "pushwoosh.aibuilder.v1.EdgeInsets",
453
+ "optional": true
454
+ },
455
+ "gap": {
456
+ "type": "number",
457
+ "optional": true
458
+ },
459
+ "align": {
460
+ "type": "pushwoosh.aibuilder.v1.GroupAlign"
461
+ }
462
+ }
463
+ },
418
464
  "pushwoosh.aibuilder.v1.AiBuilderBlock": {
419
465
  "type": "I",
420
466
  "fields": {
@@ -427,16 +473,27 @@ export const data = {
427
473
  "columns": {
428
474
  "type": "pushwoosh.aibuilder.v1.AiBuilderColumns"
429
475
  },
476
+ "content": {
477
+ "type": "pushwoosh.aibuilder.v1.Content"
478
+ },
479
+ "group": {
480
+ "type": "pushwoosh.aibuilder.v1.AiBuilderGroup"
481
+ },
430
482
  "styles": {
431
483
  "type": "pushwoosh.aibuilder.v1.BlockStyles",
432
484
  "optional": true
485
+ },
486
+ "parentId": {
487
+ "type": "string"
433
488
  }
434
489
  },
435
490
  "oneofs": {
436
491
  "block": {
437
492
  "oneof": [
438
493
  "card",
439
- "columns"
494
+ "columns",
495
+ "content",
496
+ "group"
440
497
  ]
441
498
  }
442
499
  }
@@ -444,16 +501,75 @@ export const data = {
444
501
  "pushwoosh.aibuilder.v1.Meta": {
445
502
  "type": "I",
446
503
  "fields": {
447
- "emailSubject": {
504
+ "templateName": {
505
+ "type": "string"
506
+ }
507
+ }
508
+ },
509
+ "pushwoosh.aibuilder.v1.EmailSettings": {
510
+ "type": "I",
511
+ "fields": {
512
+ "subject": {
448
513
  "type": "string",
449
514
  "optional": true
450
515
  },
451
- "emailPreheader": {
516
+ "preheader": {
452
517
  "type": "string",
453
518
  "optional": true
519
+ }
520
+ }
521
+ },
522
+ "pushwoosh.aibuilder.v1.PopupAnimation": {
523
+ "type": "E",
524
+ "values": [
525
+ "POPUP_ANIMATION_UNSPECIFIED",
526
+ "POPUP_ANIMATION_NONE",
527
+ "POPUP_ANIMATION_FADE",
528
+ "POPUP_ANIMATION_SLIDE"
529
+ ]
530
+ },
531
+ "pushwoosh.aibuilder.v1.PopupOverlay": {
532
+ "type": "I",
533
+ "fields": {
534
+ "color": {
535
+ "type": "string"
454
536
  },
455
- "templateName": {
537
+ "opacity": {
538
+ "type": "number"
539
+ }
540
+ }
541
+ },
542
+ "pushwoosh.aibuilder.v1.PopupSettings": {
543
+ "type": "I",
544
+ "fields": {
545
+ "borderRadius": {
546
+ "type": "number"
547
+ },
548
+ "boxShadow": {
456
549
  "type": "string"
550
+ },
551
+ "overlay": {
552
+ "type": "pushwoosh.aibuilder.v1.PopupOverlay",
553
+ "optional": true
554
+ },
555
+ "animation": {
556
+ "type": "pushwoosh.aibuilder.v1.PopupAnimation"
557
+ },
558
+ "top": {
559
+ "type": "number",
560
+ "optional": true
561
+ },
562
+ "bottom": {
563
+ "type": "number",
564
+ "optional": true
565
+ },
566
+ "left": {
567
+ "type": "number",
568
+ "optional": true
569
+ },
570
+ "right": {
571
+ "type": "number",
572
+ "optional": true
457
573
  }
458
574
  }
459
575
  },
@@ -489,6 +605,14 @@ export const data = {
489
605
  },
490
606
  "meta": {
491
607
  "type": "pushwoosh.aibuilder.v1.Meta"
608
+ },
609
+ "emailSettings": {
610
+ "type": "pushwoosh.aibuilder.v1.EmailSettings",
611
+ "optional": true
612
+ },
613
+ "popupSettings": {
614
+ "type": "pushwoosh.aibuilder.v1.PopupSettings",
615
+ "optional": true
492
616
  }
493
617
  }
494
618
  },
@@ -510,7 +634,18 @@ export const data = {
510
634
  "values": [
511
635
  "AI_GEN_BLOCK_TYPE_HINT_UNSPECIFIED",
512
636
  "AI_GEN_BLOCK_TYPE_HINT_CARD",
513
- "AI_GEN_BLOCK_TYPE_HINT_COLUMNS"
637
+ "AI_GEN_BLOCK_TYPE_HINT_COLUMNS",
638
+ "AI_GEN_BLOCK_TYPE_HINT_CONTENT",
639
+ "AI_GEN_BLOCK_TYPE_HINT_GROUP"
640
+ ]
641
+ },
642
+ "pushwoosh.aigen.v1.AiGenMode": {
643
+ "type": "E",
644
+ "values": [
645
+ "AI_GEN_MODE_UNSPECIFIED",
646
+ "AI_GEN_MODE_EMAIL",
647
+ "AI_GEN_MODE_FULL",
648
+ "AI_GEN_MODE_WEB_POPUP"
514
649
  ]
515
650
  },
516
651
  "pushwoosh.aigen.v1.AiGenBlockPath": {
@@ -557,6 +692,9 @@ export const data = {
557
692
  "addBlock": {
558
693
  "type": "pushwoosh.aigen.v1.AiGenAddBlock",
559
694
  "optional": true
695
+ },
696
+ "mode": {
697
+ "type": "pushwoosh.aigen.v1.AiGenMode"
560
698
  }
561
699
  }
562
700
  },
@@ -573,6 +711,9 @@ export const data = {
573
711
  },
574
712
  "typeHint": {
575
713
  "type": "pushwoosh.aigen.v1.AiGenBlockTypeHint"
714
+ },
715
+ "parentId": {
716
+ "type": "string"
576
717
  }
577
718
  }
578
719
  },
@@ -588,6 +729,9 @@ export const data = {
588
729
  },
589
730
  "prompt": {
590
731
  "type": "string"
732
+ },
733
+ "parentId": {
734
+ "type": "string"
591
735
  }
592
736
  }
593
737
  },
@@ -616,6 +760,9 @@ export const data = {
616
760
  "afterPath": {
617
761
  "type": "string",
618
762
  "array": true
763
+ },
764
+ "parentId": {
765
+ "type": "string"
619
766
  }
620
767
  }
621
768
  },
@@ -631,6 +778,9 @@ export const data = {
631
778
  },
632
779
  "prompt": {
633
780
  "type": "string"
781
+ },
782
+ "parentId": {
783
+ "type": "string"
634
784
  }
635
785
  }
636
786
  },
@@ -663,14 +813,20 @@ export const data = {
663
813
  }
664
814
  }
665
815
  },
666
- "pushwoosh.aigen.v1.AiGenBlockColors": {
816
+ "pushwoosh.aigen.v1.AiGenBlockStyles": {
667
817
  "type": "I",
668
818
  "fields": {
669
819
  "backgroundColor": {
670
- "type": "string"
820
+ "type": "string",
821
+ "optional": true
671
822
  },
672
823
  "borderColor": {
673
- "type": "string"
824
+ "type": "string",
825
+ "optional": true
826
+ },
827
+ "borderRadius": {
828
+ "type": "number",
829
+ "optional": true
674
830
  }
675
831
  }
676
832
  },
@@ -731,6 +887,14 @@ export const data = {
731
887
  }
732
888
  }
733
889
  },
890
+ "pushwoosh.aigen.v1.AiGenGroup": {
891
+ "type": "I",
892
+ "fields": {
893
+ "direction": {
894
+ "type": "pushwoosh.aibuilder.v1.GroupDirection"
895
+ }
896
+ }
897
+ },
734
898
  "pushwoosh.aigen.v1.AiGenBlock": {
735
899
  "type": "I",
736
900
  "fields": {
@@ -740,8 +904,14 @@ export const data = {
740
904
  "columns": {
741
905
  "type": "pushwoosh.aigen.v1.AiGenColumns"
742
906
  },
907
+ "content": {
908
+ "type": "pushwoosh.aibuilder.v1.Content"
909
+ },
910
+ "group": {
911
+ "type": "pushwoosh.aigen.v1.AiGenGroup"
912
+ },
743
913
  "styles": {
744
- "type": "pushwoosh.aigen.v1.AiGenBlockColors",
914
+ "type": "pushwoosh.aigen.v1.AiGenBlockStyles",
745
915
  "optional": true
746
916
  }
747
917
  },
@@ -749,7 +919,9 @@ export const data = {
749
919
  "block": {
750
920
  "oneof": [
751
921
  "card",
752
- "columns"
922
+ "columns",
923
+ "content",
924
+ "group"
753
925
  ]
754
926
  }
755
927
  }
@@ -950,6 +1122,12 @@ export const data = {
950
1122
  },
951
1123
  "isOnboarding": {
952
1124
  "type": "boolean"
1125
+ },
1126
+ "onboardingCompletedAt": {
1127
+ "type": "Date"
1128
+ },
1129
+ "handoffChildChatId": {
1130
+ "type": "number"
953
1131
  }
954
1132
  }
955
1133
  },
@@ -1262,6 +1440,22 @@ export const data = {
1262
1440
  }
1263
1441
  }
1264
1442
  },
1443
+ "pushwoosh.accounts.assistant.v1.CompleteOnboardingHandoffRequest": {
1444
+ "type": "I",
1445
+ "fields": {
1446
+ "chatId": {
1447
+ "type": "number"
1448
+ }
1449
+ }
1450
+ },
1451
+ "pushwoosh.accounts.assistant.v1.CompleteOnboardingHandoffResponse": {
1452
+ "type": "I",
1453
+ "fields": {
1454
+ "chat": {
1455
+ "type": "pushwoosh.accounts.assistant.v1.Chat"
1456
+ }
1457
+ }
1458
+ },
1265
1459
  "pushwoosh.accounts.assistant.v1.AssistantService": {
1266
1460
  "type": "S",
1267
1461
  "key": "assistant",
@@ -1360,6 +1554,12 @@ export const data = {
1360
1554
  "method": "post",
1361
1555
  "path": "/api/v1/chats/{chat_id}/onboarding/intro",
1362
1556
  "serverStreaming": true
1557
+ },
1558
+ "CompleteOnboardingHandoff": {
1559
+ "request": "pushwoosh.accounts.assistant.v1.CompleteOnboardingHandoffRequest",
1560
+ "response": "pushwoosh.accounts.assistant.v1.CompleteOnboardingHandoffResponse",
1561
+ "method": "post",
1562
+ "path": "/api/v1/chats/{chat_id}/onboarding/handoff"
1363
1563
  }
1364
1564
  }
1365
1565
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushwoosh/rpc-gateway-ai-assistant",
3
- "version": "0.1.124",
3
+ "version": "0.1.126",
4
4
  "description": "AI Assistant api gateway HTTP API Types and Data",
5
5
  "main": "index.js",
6
6
  "module": "index.js",
@@ -41,9 +41,26 @@ export type Chat = {
41
41
  /**
42
42
  * is_onboarding flags this chat as the account's onboarding chat.
43
43
  * Frontend uses it to decide whether to call StreamOnboardingIntro on the
44
- * first turn and may render the chat with onboarding-specific UI.
44
+ * first turn and may render the chat with onboarding-specific UI. Inference
45
+ * for onboarding chats is routed exclusively to StreamInferenceLLM — other
46
+ * StreamInference* endpoints are not used while is_onboarding=true.
45
47
  */
46
48
  isOnboarding: boolean;
49
+ /**
50
+ * onboarding_completed_at is set on the onboarding chat the moment the
51
+ * agent invokes the complete_onboarding tool. Frontend polls this field
52
+ * after each StreamInferenceLLM turn (and on chat reload) to detect that
53
+ * the agent has signalled completion and the handoff to a regular chat
54
+ * should be triggered via CompleteOnboardingHandoff.
55
+ */
56
+ onboardingCompletedAt: Date;
57
+ /**
58
+ * handoff_child_chat_id, on the onboarding chat, stores the id of the
59
+ * regular chat created by CompleteOnboardingHandoff. Non-zero means
60
+ * the handoff has already been performed — repeated calls are idempotent
61
+ * and return that chat. Zero means no handoff yet.
62
+ */
63
+ handoffChildChatId: number;
47
64
  };
48
65
  /** CreateChatRequest for creating a new chat */
49
66
  export type CreateChatRequest = {
@@ -195,6 +212,24 @@ export type CheckUsageAllowedResponse = {
195
212
  export type OnboardingIntroRequest = {
196
213
  chatId: number;
197
214
  };
215
+ /**
216
+ * CompleteOnboardingHandoffRequest performs the transition from a completed
217
+ * onboarding chat to a fresh regular chat. The referenced chat must be the
218
+ * account's onboarding chat with onboarding_completed_at already set by the
219
+ * agent's complete_onboarding tool call. Idempotent: subsequent calls return
220
+ * the same regular chat that the first call created.
221
+ */
222
+ export type CompleteOnboardingHandoffRequest = {
223
+ chatId: number;
224
+ };
225
+ /**
226
+ * CompleteOnboardingHandoffResponse returns the regular chat that should
227
+ * host the rest of the conversation. The chat carries the handoff summary
228
+ * in its system context — frontend can navigate to it directly.
229
+ */
230
+ export type CompleteOnboardingHandoffResponse = {
231
+ chat: Chat;
232
+ };
198
233
  export type AssistantService_CreateChat = RpcMethod<CreateChatRequest, CreateChatResponse>;
199
234
  export type AssistantService_GetChat = RpcMethod<GetChatRequest, GetChatResponse>;
200
235
  export type AssistantService_GetAllChats = RpcMethod<GetAllChatsRequest, GetAllChatsResponse>;
@@ -205,6 +240,7 @@ export type AssistantService_GetConsent = RpcMethod<GetConsentRequest, GetConsen
205
240
  export type AssistantService_GiveConsent = RpcMethod<GiveConsentRequest, GiveConsentResponse>;
206
241
  export type AssistantService_CompactifyContext = RpcMethod<CompactifyContextRequest, CompactifyContextResponse>;
207
242
  export type AssistantService_CheckUsageAllowed = RpcMethod<CheckUsageAllowedRequest, CheckUsageAllowedResponse>;
243
+ export type AssistantService_CompleteOnboardingHandoff = RpcMethod<CompleteOnboardingHandoffRequest, CompleteOnboardingHandoffResponse>;
208
244
  export interface AssistantService {
209
245
  /** Create a new chat */
210
246
  CreateChat: AssistantService_CreateChat;
@@ -228,6 +264,11 @@ export interface AssistantService {
228
264
  StreamInferenceChatGPT(request: InferenceRequest, options?: {
229
265
  signal?: AbortSignal;
230
266
  }): Promise<AsyncIterable<InferenceResponse>>;
267
+ /**
268
+ * StreamInferenceLLM is the self-hosted LLM (Qwen) inference endpoint.
269
+ * Frontend routes onboarding chats (is_onboarding=true) here exclusively;
270
+ * other StreamInference* endpoints are reserved for regular chats.
271
+ */
231
272
  StreamInferenceLLM(request: InferenceRequest, options?: {
232
273
  signal?: AbortSignal;
233
274
  }): Promise<AsyncIterable<InferenceResponse>>;
@@ -245,4 +286,13 @@ export interface AssistantService {
245
286
  StreamOnboardingIntro(request: OnboardingIntroRequest, options?: {
246
287
  signal?: AbortSignal;
247
288
  }): Promise<AsyncIterable<InferenceResponse>>;
289
+ /**
290
+ * CompleteOnboardingHandoff atomically creates the regular chat that
291
+ * succeeds a completed onboarding chat and copies the agent's handoff
292
+ * summary into it. Idempotent: a second call returns the same regular
293
+ * chat. Frontend calls this after detecting onboarding_completed_at on
294
+ * the onboarding chat (either right after a StreamInferenceLLM turn or
295
+ * on chat reload).
296
+ */
297
+ CompleteOnboardingHandoff: AssistantService_CompleteOnboardingHandoff;
248
298
  }
@@ -1,6 +1,37 @@
1
- export type DocumentBlockType = 'DOCUMENT_BLOCK_TYPE_UNSPECIFIED' | 'DOCUMENT_BLOCK_TYPE_CARD' | 'DOCUMENT_BLOCK_TYPE_COLUMNS';
1
+ export type DocumentBlockType = 'DOCUMENT_BLOCK_TYPE_UNSPECIFIED' | 'DOCUMENT_BLOCK_TYPE_CARD' | 'DOCUMENT_BLOCK_TYPE_COLUMNS'
2
+ /**
3
+ * Top-level free-form Content block (text + buttons), no card
4
+ * framing or image slot. Allowed in WEB_POPUP only.
5
+ */
6
+ | 'DOCUMENT_BLOCK_TYPE_CONTENT'
7
+ /**
8
+ * Structural stack container — a "group" block in the kind registry.
9
+ * Wire-shape is AiBuilderBlock.group. Allowed in EMAIL and WEB_POPUP.
10
+ */
11
+ | 'DOCUMENT_BLOCK_TYPE_GROUP';
12
+ /**
13
+ * GroupDirection picks which axis an AiBuilderGroup lays its children
14
+ * along. The planner emits UNSPECIFIED (proto zero) on freshly
15
+ * generated groups — clients should treat UNSPECIFIED and VERTICAL
16
+ * identically as a vertical stack. HORIZONTAL is only ever set by the
17
+ * client (post-generation) when it wants a side-by-side layout; the
18
+ * backend preserves the client's choice across edits. The enum lives
19
+ * at file scope so the same shape is shared between the document
20
+ * model and the AiGen wire types.
21
+ */
22
+ export type GroupDirection = 'GROUP_DIRECTION_UNSPECIFIED' | 'GROUP_DIRECTION_VERTICAL' | 'GROUP_DIRECTION_HORIZONTAL';
2
23
  export type CardLayout = 'CARD_LAYOUT_UNSPECIFIED' | 'CARD_LAYOUT_RIGHT' | 'CARD_LAYOUT_LEFT' | 'CARD_LAYOUT_TOP' | 'CARD_LAYOUT_NO' | 'CARD_LAYOUT_BACKGROUND';
3
24
  export type ButtonGroupAlign = 'BUTTON_GROUP_ALIGN_UNSPECIFIED' | 'BUTTON_GROUP_ALIGN_LEFT' | 'BUTTON_GROUP_ALIGN_CENTER' | 'BUTTON_GROUP_ALIGN_RIGHT';
25
+ /**
26
+ * GroupAlign controls alignment of an AiBuilderGroup's children along
27
+ * the perpendicular axis (for direction=VERTICAL → horizontal
28
+ * alignment of children; for direction=HORIZONTAL → vertical
29
+ * alignment). UNSPECIFIED is the proto zero value and clients should
30
+ * render it as START — same client-managed pattern as GroupDirection.
31
+ * Named in start/center/end terms (not left/right) because the
32
+ * concrete axis depends on direction.
33
+ */
34
+ export type GroupAlign = 'GROUP_ALIGN_UNSPECIFIED' | 'GROUP_ALIGN_START' | 'GROUP_ALIGN_CENTER' | 'GROUP_ALIGN_END';
4
35
  /**
5
36
  * CardImageFit controls how the card's image fills its image slot.
6
37
  * Why it exists: card slots have fixed proportions while images arrive
@@ -34,11 +65,50 @@ export type EdgeInsets = {
34
65
  bottom: number;
35
66
  left: number;
36
67
  };
68
+ /**
69
+ * BlockStyles is the universal per-block visual override applied at
70
+ * the AiBuilderBlock level — independent of the concrete block kind.
71
+ * Every block kind (card, columns, group, and any future kind we add)
72
+ * carries it through AiBuilderBlock.styles; the client renders the
73
+ * frame, the LLM emits the colour overrides, and the user adjusts the
74
+ * rest in the editor. Per-kind layout knobs (CardStyles padding,
75
+ * ColumnsStyles gap, …) live on their own messages and stay
76
+ * independent of this one.
77
+ *
78
+ * All fields are optional. An unset field means "inherit / no
79
+ * override" — the client falls back to DocumentSettings.default_styles
80
+ * and then to its renderer default.
81
+ *
82
+ * Tri-state semantics differ between string and numeric fields:
83
+ * - String fields (background_color, border_color): empty string ""
84
+ * is equivalent to unset — clients collapse both to "inherit".
85
+ * Backend should emit unset rather than ""; do not rely on "" as
86
+ * an "explicit reset" state for colours.
87
+ * - Numeric fields (border_width, border_radius): explicit 0 is
88
+ * distinct from unset (means "no border" / "sharp corners") and
89
+ * is preserved across edits.
90
+ *
91
+ * LLM-managed: background_color, border_color, border_radius — the
92
+ * block generator may emit these via AiGenBlockStyles and the
93
+ * pipeline lifts them into BlockStyles.
94
+ * Client-managed: border_width — the LLM never sees it, the backend
95
+ * preserves it verbatim across edits.
96
+ */
37
97
  export type BlockStyles = {
38
- backgroundColor: string;
39
- borderColor: string;
40
- borderWidth: number;
41
- borderRadius: number;
98
+ /**
99
+ * Empty string "" is treated as unset by clients. Prefer emitting
100
+ * unset.
101
+ */
102
+ backgroundColor?: string;
103
+ /**
104
+ * Empty string "" is treated as unset by clients. Prefer emitting
105
+ * unset.
106
+ */
107
+ borderColor?: string;
108
+ /** Explicit 0 is distinct from unset and preserved. */
109
+ borderWidth?: number;
110
+ /** Explicit 0 is distinct from unset and preserved. */
111
+ borderRadius?: number;
42
112
  };
43
113
  export type ColumnsStyles = {
44
114
  /** Padding applied to each column in the columns block. */
@@ -185,6 +255,37 @@ export type AiBuilderColumn = {
185
255
  content: Content;
186
256
  width?: string;
187
257
  };
258
+ /**
259
+ * AiBuilderGroup is a structural stack container. Children live as
260
+ * siblings in the same AiBuilderPage with their parent_id pointing at
261
+ * this block's id; the group itself has no copy and no image slot.
262
+ * Allowed in EMAIL and WEB_POPUP.
263
+ *
264
+ * direction / align / margin / padding / gap are client-managed: the
265
+ * LLM never sees them, the backend preserves them across edits. On
266
+ * freshly generated groups the backend emits proto-zero values
267
+ * (direction = UNSPECIFIED, align = UNSPECIFIED, optional fields
268
+ * unset); clients are expected to render UNSPECIFIED direction as a
269
+ * vertical stack, UNSPECIFIED align as START, and set non-default
270
+ * values themselves when needed.
271
+ */
272
+ export type AiBuilderGroup = {
273
+ direction: GroupDirection;
274
+ /** Outer spacing around the group block. */
275
+ margin?: EdgeInsets;
276
+ /** Inner spacing between the group's frame and its children. */
277
+ padding?: EdgeInsets;
278
+ /**
279
+ * Spacing between adjacent children. UNSPECIFIED (0) lets the
280
+ * client fall back to its default. Use a non-zero value to override.
281
+ */
282
+ gap?: number;
283
+ /**
284
+ * Alignment of children along the axis perpendicular to direction.
285
+ * UNSPECIFIED → render as START.
286
+ */
287
+ align: GroupAlign;
288
+ };
188
289
  export type AiBuilderBlock_block_card = {
189
290
  type: 'card';
190
291
  data: AiBuilderCard;
@@ -193,17 +294,106 @@ export type AiBuilderBlock_block_columns = {
193
294
  type: 'columns';
194
295
  data: AiBuilderColumns;
195
296
  };
196
- export type AiBuilderBlock_block = AiBuilderBlock_block_card | AiBuilderBlock_block_columns;
297
+ export type AiBuilderBlock_block_content = {
298
+ type: 'content';
299
+ data: Content;
300
+ };
301
+ export type AiBuilderBlock_block_group = {
302
+ type: 'group';
303
+ data: AiBuilderGroup;
304
+ };
305
+ export type AiBuilderBlock_block = AiBuilderBlock_block_card | AiBuilderBlock_block_columns | AiBuilderBlock_block_content | AiBuilderBlock_block_group;
197
306
  export type AiBuilderBlock = {
198
307
  id: string;
199
308
  styles?: BlockStyles;
309
+ /**
310
+ * Id of the block-of-this-page that contains this one. Empty string
311
+ * marks a top-level block. The parent (if set) must be a container
312
+ * kind in the same AiBuilderPage. Containers may nest to arbitrary
313
+ * depth; the server rejects trees deeper than 16 levels with
314
+ * InvalidArgument (a sanity cap, not a product limit). Per-mode
315
+ * soft hints in the planner prompt steer the model toward shallower
316
+ * structures appropriate for each channel.
317
+ */
318
+ parentId: string;
200
319
  block: AiBuilderBlock_block;
201
320
  };
321
+ /**
322
+ * Meta carries channel-agnostic document-level metadata generated by
323
+ * the meta generator. Channel-specific fields (email subject /
324
+ * preheader, future popup-only / inapp-only fields) live in their own
325
+ * optional sub-messages on AiBuilderDocument (EmailSettings,
326
+ * PopupSettings, ...) so this message stays small and uniform across
327
+ * all modes.
328
+ */
202
329
  export type Meta = {
203
- emailSubject?: string;
204
- emailPreheader?: string;
205
330
  templateName: string;
206
331
  };
332
+ /**
333
+ * EmailSettings holds the email-only document-level fields produced by
334
+ * the meta generator under mode=EMAIL. Populated only when the
335
+ * document was generated for the email channel; absent otherwise.
336
+ */
337
+ export type EmailSettings = {
338
+ subject?: string;
339
+ preheader?: string;
340
+ };
341
+ /**
342
+ * PopupAnimation chooses how a web-popup enters / exits the
343
+ * viewport. UNSPECIFIED leaves the choice to the client default
344
+ * (typically NONE or FADE). Client-managed: the LLM never selects an
345
+ * animation.
346
+ */
347
+ export type PopupAnimation = 'POPUP_ANIMATION_UNSPECIFIED' | 'POPUP_ANIMATION_NONE' | 'POPUP_ANIMATION_FADE' | 'POPUP_ANIMATION_SLIDE';
348
+ /**
349
+ * PopupOverlay describes the backdrop drawn behind the popup. Both
350
+ * fields are client-managed; the LLM does not see them.
351
+ */
352
+ export type PopupOverlay = {
353
+ /** Hex color, e.g. "#000000". Empty string = no overlay. */
354
+ color: string;
355
+ /** 0.0 (fully transparent) to 1.0 (opaque). */
356
+ opacity: number;
357
+ };
358
+ /**
359
+ * PopupSettings holds the web-popup channel's client-managed UI
360
+ * configuration on AiBuilderDocument. Populated by the client (the
361
+ * editor) and preserved across edits by the server through the same
362
+ * flow as AiBuilderGroup's client-managed fields: the LLM never sees
363
+ * these values, server-side conversion never writes to them, the
364
+ * client owns them end-to-end.
365
+ */
366
+ export type PopupSettings = {
367
+ /** Corner radius of the popup container, in px. 0 = sharp corners. */
368
+ borderRadius: number;
369
+ /**
370
+ * CSS box-shadow string, e.g. "0 4px 24px rgba(0,0,0,0.2)". Empty
371
+ * string = no shadow.
372
+ */
373
+ boxShadow: string;
374
+ /** Backdrop overlay. Absent = no overlay. */
375
+ overlay?: PopupOverlay;
376
+ /** Enter / exit animation. UNSPECIFIED = client default. */
377
+ animation: PopupAnimation;
378
+ /**
379
+ * Edge offsets in px (CSS-style positioning). Any subset of
380
+ * top / bottom / left / right may be set. When none are set the
381
+ * popup is centered in the viewport. Typical combinations:
382
+ * - centered: leave all unset
383
+ * - bottom-left: set bottom + left (with the desired gutter)
384
+ * - top-right: set top + right
385
+ * - full-bleed
386
+ * overlay band: set both top + bottom (and/or left + right);
387
+ * the client decides how to fill the gap.
388
+ * Conflicting pairs (top + bottom, left + right) are permitted on
389
+ * the wire — the client decides whether to stretch the popup
390
+ * between the two edges or to honour one of them.
391
+ */
392
+ top?: number;
393
+ bottom?: number;
394
+ left?: number;
395
+ right?: number;
396
+ };
207
397
  /**
208
398
  * AiBuilderPage groups a list of blocks under a single logical page. For
209
399
  * now every document has exactly one page; the structure is in place so
@@ -221,4 +411,14 @@ export type AiBuilderDocument = {
221
411
  textVariants: Record<string, TextVariantStyle>;
222
412
  colorScheme: Record<string, ColorSchemeItem>;
223
413
  meta: Meta;
414
+ /**
415
+ * Email channel-specific fields. Populated only when the document
416
+ * was generated for mode=EMAIL.
417
+ */
418
+ emailSettings?: EmailSettings;
419
+ /**
420
+ * Web popup channel-specific fields. Populated only when the
421
+ * document was generated for mode=WEB_POPUP.
422
+ */
423
+ popupSettings?: PopupSettings;
224
424
  };
@@ -6,6 +6,7 @@ import { CardLayout as pushwoosh_aibuilder_v1_CardLayout } from './pushwoosh_aib
6
6
  import { Image as pushwoosh_aibuilder_v1_Image } from './pushwoosh_aibuilder_v1';
7
7
  import { Content as pushwoosh_aibuilder_v1_Content } from './pushwoosh_aibuilder_v1';
8
8
  import { CardImageFit as pushwoosh_aibuilder_v1_CardImageFit } from './pushwoosh_aibuilder_v1';
9
+ import { GroupDirection as pushwoosh_aibuilder_v1_GroupDirection } from './pushwoosh_aibuilder_v1';
9
10
  /**
10
11
  * AiGenService unifies document create / edit / per-block regeneration and
11
12
  * targeted block insertion into a single streaming RPC. Dispatch rules:
@@ -31,7 +32,37 @@ export interface AiGenService {
31
32
  signal?: AbortSignal;
32
33
  }): Promise<AsyncIterable<AiGenEvent>>;
33
34
  }
34
- export type AiGenBlockTypeHint = 'AI_GEN_BLOCK_TYPE_HINT_UNSPECIFIED' | 'AI_GEN_BLOCK_TYPE_HINT_CARD' | 'AI_GEN_BLOCK_TYPE_HINT_COLUMNS';
35
+ export type AiGenBlockTypeHint = 'AI_GEN_BLOCK_TYPE_HINT_UNSPECIFIED' | 'AI_GEN_BLOCK_TYPE_HINT_CARD' | 'AI_GEN_BLOCK_TYPE_HINT_COLUMNS'
36
+ /** Top-level free-form Content block. Allowed in WEB_POPUP only. */
37
+ | 'AI_GEN_BLOCK_TYPE_HINT_CONTENT'
38
+ /**
39
+ * Structural stack container ("group"). The block generator is
40
+ * skipped — groups carry no copy, just children referenced via
41
+ * parent_id. Allowed in EMAIL and WEB_POPUP.
42
+ */
43
+ | 'AI_GEN_BLOCK_TYPE_HINT_GROUP';
44
+ /**
45
+ * AiGenMode selects the document-domain profile the generation pipeline
46
+ * runs under: which block kinds are allowed, which Meta fields are
47
+ * produced, how the system prompts phrase the document type.
48
+ *
49
+ * Clients must send a concrete mode on every AiGenRequest. EMAIL is
50
+ * the email-builder behaviour with a restricted block set and the
51
+ * email-only meta fields. WEB_POPUP targets web overlay popups: full
52
+ * block toolkit, popup-tuned prompts, popup-aware image generation.
53
+ * FULL was a transitional placeholder; it is now deprecated — the
54
+ * server rejects requests with mode=FULL and clients must move to
55
+ * WEB_POPUP (or a future concrete channel like INAPP_MOBILE).
56
+ * UNSPECIFIED is the proto3 zero value and is rejected by the server
57
+ * with InvalidArgument.
58
+ */
59
+ export type AiGenMode = 'AI_GEN_MODE_UNSPECIFIED' | 'AI_GEN_MODE_EMAIL'
60
+ /**
61
+ * Deprecated: kept for wire-compat. The server rejects requests
62
+ * with this mode (InvalidArgument). Use AI_GEN_MODE_WEB_POPUP for
63
+ * popups or a future concrete channel for other surfaces.
64
+ */
65
+ | 'AI_GEN_MODE_FULL' | 'AI_GEN_MODE_WEB_POPUP';
35
66
  /**
36
67
  * AiGenBlockPath wraps a block-addressing path so it can appear inside
37
68
  * repeated fields — proto3 disallows `repeated repeated`. Path is
@@ -63,6 +94,11 @@ export type AiGenRequest = {
63
94
  * with `block_path`. Requires `document`.
64
95
  */
65
96
  addBlock?: AiGenAddBlock;
97
+ /**
98
+ * Document-domain profile for this generation. Required — the server
99
+ * rejects UNSPECIFIED with InvalidArgument.
100
+ */
101
+ mode: AiGenMode;
66
102
  };
67
103
  /**
68
104
  * AiGenAddBlock triggers add-block mode on Generate. The server emits a
@@ -89,6 +125,13 @@ export type AiGenAddBlock = {
89
125
  * based on the prompt and surrounding blocks.
90
126
  */
91
127
  typeHint: AiGenBlockTypeHint;
128
+ /**
129
+ * Id of the parent container block in the same page. Empty string =
130
+ * top-level. The new block becomes a child of that container. The
131
+ * server rejects parent_id that does not resolve to an existing
132
+ * container block in `document`.
133
+ */
134
+ parentId: string;
92
135
  };
93
136
  export type AiGenStructureBlock = {
94
137
  /** [page_id, block_id] */
@@ -96,6 +139,12 @@ export type AiGenStructureBlock = {
96
139
  typeHint: AiGenBlockTypeHint;
97
140
  /** per-block prompt for the block generator */
98
141
  prompt: string;
142
+ /**
143
+ * Id of the parent container block (within the same page). Empty
144
+ * string marks a top-level block. Set on container kinds' children
145
+ * so the client can rebuild the tree from the stream.
146
+ */
147
+ parentId: string;
99
148
  };
100
149
  /** Emitted once for create, before any block_delta. */
101
150
  export type AiGenStructure = {
@@ -113,12 +162,25 @@ export type AiGenStructureAdd = {
113
162
  * same diff (must share `page_id`).
114
163
  */
115
164
  afterPath: string[];
165
+ /**
166
+ * Id of the parent container block. Empty string = top-level. May
167
+ * reference an existing container or another add from the same diff.
168
+ * The new block becomes a child of that container (still a sibling in
169
+ * page.blocks; the tree is rebuilt by group-by-parent on the client).
170
+ */
171
+ parentId: string;
116
172
  };
117
173
  export type AiGenStructureReplace = {
118
174
  /** existing block path, preserved */
119
175
  blockPath: string[];
120
176
  typeHint: AiGenBlockTypeHint;
121
177
  prompt: string;
178
+ /**
179
+ * Existing parent_id of the replaced block, echoed for completeness
180
+ * so the client doesn't need a side-table lookup. Replace never moves
181
+ * a block across containers — for that, the planner emits remove+add.
182
+ */
183
+ parentId: string;
122
184
  };
123
185
  /**
124
186
  * Emitted once for edit (when the planner ran), before any block_delta.
@@ -132,9 +194,39 @@ export type AiGenStructureDiff = {
132
194
  updateTextVariants: Record<string, pushwoosh_aibuilder_v1_TextVariantStyle>;
133
195
  updateColorScheme: Record<string, pushwoosh_aibuilder_v1_ColorSchemeItem>;
134
196
  };
135
- export type AiGenBlockColors = {
136
- backgroundColor: string;
137
- borderColor: string;
197
+ /**
198
+ * AiGenBlockStyles is the wire-format subset of BlockStyles the block
199
+ * generator can emit. Mirrors the LLM-managed fields of BlockStyles
200
+ * (background_color, border_color, border_radius). Client-managed
201
+ * fields like border_width are intentionally absent — they belong to
202
+ * the editor, not the model, and travel with the document, not with
203
+ * the AiGen stream.
204
+ *
205
+ * All fields are optional and follow BlockStyles presence semantics:
206
+ * - String fields (background_color, border_color): "" ≡ unset
207
+ * (inherit). The pipeline already normalises empty LLM output to
208
+ * unset; this documents that clients also collapse the two states.
209
+ * - Numeric fields (border_radius): explicit 0 is distinct from
210
+ * unset and preserved.
211
+ */
212
+ export type AiGenBlockStyles = {
213
+ /**
214
+ * Empty string "" is treated as unset by clients. The pipeline
215
+ * emits unset for empty LLM output.
216
+ */
217
+ backgroundColor?: string;
218
+ /**
219
+ * Empty string "" is treated as unset by clients. The pipeline
220
+ * emits unset for empty LLM output.
221
+ */
222
+ borderColor?: string;
223
+ /**
224
+ * Corner radius in px. Explicit 0 means "sharp corners" and is
225
+ * distinct from unset (which means "inherit"). Carried through the
226
+ * stream so the client picks up rounded-corner styling — common
227
+ * on web popups — without waiting for the next document fetch.
228
+ */
229
+ borderRadius?: number;
138
230
  };
139
231
  export type AiGenCard = {
140
232
  layout: pushwoosh_aibuilder_v1_CardLayout;
@@ -154,6 +246,17 @@ export type AiGenColumns = {
154
246
  contentBefore?: pushwoosh_aibuilder_v1_Content;
155
247
  contentAfter?: pushwoosh_aibuilder_v1_Content;
156
248
  };
249
+ /**
250
+ * AiGenGroup is the wire payload for a "group" container block. The
251
+ * block generator is skipped for groups; the planner emits the
252
+ * container's structure and the children come as separate block_delta
253
+ * events. The direction field on the underlying AiBuilderGroup is
254
+ * client-managed and not emitted by the planner — AiGenGroup carries
255
+ * it for symmetry with the document model only.
256
+ */
257
+ export type AiGenGroup = {
258
+ direction: pushwoosh_aibuilder_v1_GroupDirection;
259
+ };
157
260
  export type AiGenBlock_block_card = {
158
261
  type: 'card';
159
262
  data: AiGenCard;
@@ -162,13 +265,21 @@ export type AiGenBlock_block_columns = {
162
265
  type: 'columns';
163
266
  data: AiGenColumns;
164
267
  };
165
- export type AiGenBlock_block = AiGenBlock_block_card | AiGenBlock_block_columns;
268
+ export type AiGenBlock_block_content = {
269
+ type: 'content';
270
+ data: pushwoosh_aibuilder_v1_Content;
271
+ };
272
+ export type AiGenBlock_block_group = {
273
+ type: 'group';
274
+ data: AiGenGroup;
275
+ };
276
+ export type AiGenBlock_block = AiGenBlock_block_card | AiGenBlock_block_columns | AiGenBlock_block_content | AiGenBlock_block_group;
166
277
  /**
167
278
  * AiGenBlock is the payload carried by block_delta. The block's own id
168
279
  * lives in the enclosing event's `block_path`; the payload is id-less.
169
280
  */
170
281
  export type AiGenBlock = {
171
- styles?: AiGenBlockColors;
282
+ styles?: AiGenBlockStyles;
172
283
  block: AiGenBlock_block;
173
284
  };
174
285
  /**