@cms.ai/brand_brain 0.0.1 → 0.1.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.
@@ -1,5 +1,9 @@
1
1
  //#region src/types.d.ts
2
- /** The `name` on `CUSTOM` guide events (skill payloads). */
2
+ /**
3
+ * The `name` on `CUSTOM` guide events (skill payloads). `SkillGate` and
4
+ * `SkillError` never surface as `skill` stream events — the SDK re-maps them to
5
+ * the dedicated `gate` / `error` {@link GuideStreamEvent} variants.
6
+ */
3
7
  declare const GuideEvent: {
4
8
  readonly SkillStart: "skill_start";
5
9
  readonly SkillContent: "skill_content";
@@ -20,9 +24,7 @@ declare const GuideEvent: {
20
24
  readonly SkillEnd: "skill_end";
21
25
  readonly SkillError: "skill_error";
22
26
  readonly SkillGate: "skill_gate";
23
- readonly InputSuggestions: "input_suggestions";
24
27
  };
25
- type GuideEventName = (typeof GuideEvent)[keyof typeof GuideEvent];
26
28
  /** The guide skill types. `answer` is always on; the rest are enabled per-guide. */
27
29
  declare const SkillResponseType: {
28
30
  readonly Answer: "answer";
@@ -74,9 +76,62 @@ interface GuideGraphSnapshot {
74
76
  }>;
75
77
  }
76
78
  /**
77
- * Resolved guide metadata returned by `guides.resolve`. `theme` / `skillIconStyle`
78
- * are left as `unknown` in v1 read them defensively or narrow as needed.
79
+ * The guide's brand theme shadcn-style design tokens as CSS color strings
80
+ * (hex or `oklch(...)`). Every property is optional: absent tokens mean "keep
81
+ * your default". Map them onto your CSS variables / Tailwind theme so the
82
+ * guide UI matches the brand:
83
+ *
84
+ * ```css
85
+ * :root {
86
+ * --primary: <theme.primary>;
87
+ * --background: <theme.background>;
88
+ * }
89
+ * ```
79
90
  */
91
+ interface BrandKitTheme {
92
+ /** Main brand color (buttons, focus rings) */
93
+ primary?: string;
94
+ /** Text on primary backgrounds */
95
+ primaryForeground?: string;
96
+ /** Secondary surface color */
97
+ secondary?: string;
98
+ /** Text on secondary surfaces */
99
+ secondaryForeground?: string;
100
+ /** Main page background */
101
+ background?: string;
102
+ /** Default body text */
103
+ foreground?: string;
104
+ /** Muted areas, borders, inputs */
105
+ muted?: string;
106
+ /** Muted/secondary text */
107
+ mutedForeground?: string;
108
+ /** Border color */
109
+ border?: string;
110
+ /** Input border color */
111
+ input?: string;
112
+ /** Focus ring color */
113
+ ring?: string;
114
+ }
115
+ /** How a brand kit colors the guide's skill icons. */
116
+ declare const SkillIconColorMode: {
117
+ /** Keep the built-in per-skill colors. */readonly Default: "default"; /** Apply a single brand color to every skill icon. */
118
+ readonly Mono: "mono"; /** Pick a color per skill; skills left unset fall back to the default. */
119
+ readonly PerSkill: "per_skill";
120
+ };
121
+ /**
122
+ * Per-brand-kit skill icon color customization, discriminated on `mode`.
123
+ * Colors are CSS color strings (same format as {@link BrandKitTheme}).
124
+ */
125
+ type SkillIconStyle = {
126
+ mode: typeof SkillIconColorMode.Default;
127
+ } | {
128
+ mode: typeof SkillIconColorMode.Mono; /** Single color applied to every skill icon. */
129
+ monoColor: string;
130
+ } | {
131
+ mode: typeof SkillIconColorMode.PerSkill; /** Color per skill; missing keys fall back to the default. */
132
+ colors: Partial<Record<SkillResponseTypeType, string>>;
133
+ };
134
+ /** Resolved guide metadata returned by `guides.resolve`. */
80
135
  interface ResolvedGuide {
81
136
  id: string;
82
137
  name: string;
@@ -89,8 +144,9 @@ interface ResolvedGuide {
89
144
  advancedSettings: {
90
145
  gatePdfDownload: boolean;
91
146
  };
92
- theme: unknown;
93
- skillIconStyle: unknown;
147
+ /** Brand design tokens — apply to your UI so the guide matches the brand. */
148
+ theme: BrandKitTheme | null;
149
+ skillIconStyle: SkillIconStyle | null;
94
150
  faviconUrl: string | null;
95
151
  logoUrl: string | null;
96
152
  heroImageUrl: string | null;
@@ -124,7 +180,12 @@ interface ConversationWithMessages {
124
180
  conversation: Conversation;
125
181
  messages: ConversationMessage[];
126
182
  }
127
- /** A persisted skill deliverable. `data` shape varies by `type`. */
183
+ /**
184
+ * A persisted skill deliverable. `data` shape varies by `type` — it is the
185
+ * skill's completed output (e.g. for `howto` a `{ title, steps: HowToStep[] }`
186
+ * record); the streamed payload interfaces in this file describe the same
187
+ * building blocks.
188
+ */
128
189
  interface SkillInstance {
129
190
  id: string;
130
191
  skillOutputId: string;
@@ -218,8 +279,10 @@ interface InitGuideConfig {
218
279
  /** Guide slug to resolve (e.g. "default"). */
219
280
  slug: string;
220
281
  /**
221
- * Host domain used for account resolution + attribution. Defaults to
222
- * `window.location.hostname`. Required when running without a browser window.
282
+ * Optional override for the host used in account resolution + attribution.
283
+ * Defaults to the `baseUrl` hostname (lowercased, `www.`/port stripped), which
284
+ * is the registered account domain. Only set this if resolution must key off a
285
+ * different registered domain than the one requests are sent to.
223
286
  */
224
287
  domain?: string;
225
288
  /**
@@ -250,10 +313,414 @@ interface AskOptions {
250
313
  /** Abort the in-flight stream. */
251
314
  signal?: AbortSignal;
252
315
  }
316
+ /** Kind of content a document/playlist item points at. */
317
+ declare const ContentType: {
318
+ readonly PDF: "pdf";
319
+ readonly DOCX: "docx";
320
+ readonly PPTX: "pptx";
321
+ readonly Image: "image";
322
+ readonly VideoNative: "video_native";
323
+ readonly VideoYouTube: "video_youtube";
324
+ readonly VideoWistia: "video_wistia";
325
+ readonly Document: "document";
326
+ readonly URL: "url";
327
+ readonly Text: "text";
328
+ readonly Markdown: "markdown";
329
+ };
330
+ type ContentTypeName = (typeof ContentType)[keyof typeof ContentType];
331
+ /**
332
+ * Document reference streamed with a reply — the sources behind the answer.
333
+ * Render as source cards/citations: title, optional link, optional thumbnail.
334
+ */
335
+ interface GuideDocument {
336
+ id: string;
337
+ title: string;
338
+ tag?: string;
339
+ /** Lucide icon name. */
340
+ icon?: string;
341
+ url?: string;
342
+ contentType?: ContentTypeName;
343
+ body?: string;
344
+ thumbnailUrl?: string;
345
+ /** 1-based citation number matching the [N] references in the reply text. Undefined if the document was not part of the reply context. */
346
+ citationIndex?: number;
347
+ }
348
+ /** Confidence level attached to a content recommendation. */
349
+ declare const Confidence: {
350
+ readonly High: "high";
351
+ readonly Medium: "medium";
352
+ readonly Low: "low";
353
+ };
354
+ type ConfidenceName = (typeof Confidence)[keyof typeof Confidence];
355
+ /**
356
+ * Follow-up recommendation to invoke a skill — render as a pill button that
357
+ * calls `ask(prompt, { forcedSkill: skill })`.
358
+ */
359
+ interface SkillRecommendation {
360
+ id: string;
361
+ skill: SkillResponseTypeType;
362
+ label: string;
363
+ prompt: string;
364
+ }
365
+ /**
366
+ * A content recommendation generated by the recommend skill — render as a card
367
+ * whose click calls `ask(prompt, { forcedSkill: targetSkill })`.
368
+ */
369
+ interface ContentRecommendation {
370
+ id: string;
371
+ targetSkill: Exclude<SkillResponseTypeType, "recommend">;
372
+ title: string;
373
+ rationale: string;
374
+ prompt: string;
375
+ confidence: ConfidenceName;
376
+ }
377
+ /** The render kind of a surfaced call-to-action. */
378
+ declare const SkillCtaKind: {
379
+ readonly Url: "url";
380
+ readonly Form: "form";
381
+ readonly Product: "product";
382
+ readonly Scheduler: "scheduler";
383
+ };
384
+ /** Where a surfaced CTA renders. One slot today: below the skill response. */
385
+ declare const CtaPlacement: {
386
+ readonly ResponseFooter: "response_footer";
387
+ };
388
+ type CtaPlacementName = (typeof CtaPlacement)[keyof typeof CtaPlacement];
389
+ /** Which scheduler embed a scheduler CTA loads. */
390
+ declare const SchedulerProvider: {
391
+ readonly HubSpot: "hubspot";
392
+ readonly Calendly: "calendly";
393
+ };
394
+ type SchedulerProviderName = (typeof SchedulerProvider)[keyof typeof SchedulerProvider];
395
+ /**
396
+ * A call-to-action surfaced for a turn, discriminated on `kind`:
397
+ * - `url`: external link — render a button that opens `href`.
398
+ * - `form`: in-guide form — render a button/banner for the form `formId`.
399
+ * - `product`: product recommendation — render a link/card to `href`.
400
+ * - `scheduler`: meeting embed — render a button that opens `url` in the
401
+ * provider's scheduling widget (or a new tab).
402
+ *
403
+ * Only render the first CTA in the list; the wire carries a list for forward
404
+ * compatibility. `ctaInstanceId` (when present) should be echoed on CTA
405
+ * analytics events so impressions and clicks join up.
406
+ */
407
+ type SkillCTA = {
408
+ kind: typeof SkillCtaKind.Url;
409
+ placement: CtaPlacementName;
410
+ ctaId: string | null;
411
+ label: string;
412
+ href: string; /** Custom banner heading; absent → use a default like "Recommended next step". */
413
+ bannerText?: string; /** Lucide icon name; absent → a default lightbulb. */
414
+ bannerIcon?: string;
415
+ ctaInstanceId?: string;
416
+ } | {
417
+ kind: typeof SkillCtaKind.Form;
418
+ placement: CtaPlacementName;
419
+ ctaId: string;
420
+ label: string;
421
+ formId: string;
422
+ bannerText?: string;
423
+ bannerIcon?: string;
424
+ ctaInstanceId?: string;
425
+ } | {
426
+ kind: typeof SkillCtaKind.Product;
427
+ placement: CtaPlacementName;
428
+ productId: string;
429
+ label: string;
430
+ href: string;
431
+ ctaInstanceId?: string;
432
+ } | {
433
+ kind: typeof SkillCtaKind.Scheduler;
434
+ placement: CtaPlacementName;
435
+ ctaId: string;
436
+ label: string;
437
+ provider: SchedulerProviderName; /** The meeting/scheduling link the embed loads. */
438
+ url: string;
439
+ bannerText?: string;
440
+ bannerIcon?: string;
441
+ ctaInstanceId?: string;
442
+ };
443
+ /** Diagnose skill mode. */
444
+ declare const DiagnoseSubtype: {
445
+ /** A scored self-assessment rendered with results at the end. */readonly Standalone: "standalone"; /** Questions gather context for a follow-up skill (see `followUpSkill`). */
446
+ readonly ContextGathering: "context_gathering";
447
+ };
448
+ type DiagnoseSubtypeName = (typeof DiagnoseSubtype)[keyof typeof DiagnoseSubtype];
449
+ /** Answer option labels for diagnose questions. */
450
+ declare const DiagnoseOptionLabel: {
451
+ readonly A: "A";
452
+ readonly B: "B";
453
+ readonly C: "C";
454
+ readonly D: "D";
455
+ };
456
+ type DiagnoseOptionLabelName = (typeof DiagnoseOptionLabel)[keyof typeof DiagnoseOptionLabel];
457
+ /** Header for a diagnostic assessment — render as the assessment intro. */
458
+ interface DiagnosticHeader {
459
+ targetTopic: string;
460
+ subtitle: string;
461
+ /** Total number of questions the assessment will stream. */
462
+ questionCount: number;
463
+ subtype?: DiagnoseSubtypeName;
464
+ /** For context_gathering mode — the skill to invoke after the user submits answers. */
465
+ followUpSkill?: string;
466
+ /** For context_gathering mode — the prompt to send to `followUpSkill` afterwards. */
467
+ followUpPrompt?: string;
468
+ }
469
+ /**
470
+ * A self-assessment question (no correct answer). Render the options as a
471
+ * single-choice list; `score` supports a results chart in standalone mode.
472
+ */
473
+ interface DiagnosticQuestion {
474
+ id: string;
475
+ /** Short category name, usable as a results-chart axis label. */
476
+ category: string;
477
+ questionText: string;
478
+ options: Array<{
479
+ label: DiagnoseOptionLabelName;
480
+ text: string;
481
+ score?: number;
482
+ }>;
483
+ prerequisiteConceptId: string | null;
484
+ prerequisiteConceptName: string | null;
485
+ }
486
+ /** A step title in a how-to outline (details stream later as {@link HowToStep}). */
487
+ interface HowToStepOutline {
488
+ id: string;
489
+ title: string;
490
+ }
491
+ /** How-to outline — render immediately as a skeleton; steps fill in after. */
492
+ interface HowToOutline {
493
+ title: string;
494
+ steps: HowToStepOutline[];
495
+ }
496
+ /** Content reference attached to a how-to step — render as a source card. */
497
+ interface HowToStepContent {
498
+ contentId: string;
499
+ title: string;
500
+ url: string | null;
501
+ contentType: ContentTypeName | null;
502
+ /** The matching excerpt that demonstrates relevance. */
503
+ excerpt: string;
504
+ thumbnailUrl?: string;
505
+ }
506
+ /** A fully detailed how-to step — replaces the outline entry with the same `id`. */
507
+ interface HowToStep {
508
+ id: string;
509
+ title: string;
510
+ description: string;
511
+ content: HowToStepContent | null;
512
+ /** Lucide icon name. */
513
+ icon?: string;
514
+ }
515
+ /** Header for a playlist — render as the playlist title/description. */
516
+ interface PlaylistHeader {
517
+ title: string;
518
+ description: string;
519
+ }
520
+ /** A single item in a curated playlist — render as a content card. */
521
+ interface PlaylistItem {
522
+ id: string;
523
+ title: string;
524
+ description: string | null;
525
+ body?: string | null;
526
+ contentType: ContentTypeName;
527
+ url: string | null;
528
+ thumbnailUrl?: string;
529
+ /** Why this item is included — streams in later via `skill_playlist_rationale`. */
530
+ rationale?: string;
531
+ }
532
+ /** Business case format sub-types. */
533
+ declare const BusinessCaseSubType: {
534
+ readonly RoiAnalysis: "roi-analysis";
535
+ readonly StakeholderBrief: "stakeholder-brief";
536
+ readonly VendorComparison: "vendor-comparison";
537
+ };
538
+ type BusinessCaseSubTypeName = (typeof BusinessCaseSubType)[keyof typeof BusinessCaseSubType];
539
+ /** Format option in the business case chooser — render as a selectable card. */
540
+ interface BusinessCaseFormatOption {
541
+ subType: BusinessCaseSubTypeName;
542
+ label: string;
543
+ description: string;
544
+ /** Lucide icon name. */
545
+ icon: string;
546
+ }
547
+ /** Reference to a pre-generated business case draft, keyed by sub-type. */
548
+ interface BusinessCaseDraftRef {
549
+ draftId: string;
550
+ skillInstanceId: string;
551
+ }
552
+ /** Node types in a solution design diagram. */
553
+ declare const SolutionDesignNodeType: {
554
+ readonly Process: "process";
555
+ readonly Decision: "decision";
556
+ readonly Datastore: "datastore";
557
+ readonly External: "external";
558
+ readonly Trigger: "trigger";
559
+ readonly Start: "start";
560
+ readonly End: "end";
561
+ };
562
+ type SolutionDesignNodeTypeName = (typeof SolutionDesignNodeType)[keyof typeof SolutionDesignNodeType];
563
+ /** A node in a solution design diagram — render as a flowchart node. */
564
+ interface SolutionDesignNode {
565
+ id: string;
566
+ label: string;
567
+ description: string;
568
+ nodeType: SolutionDesignNodeTypeName;
569
+ /** Lucide icon name. */
570
+ icon: string;
571
+ }
572
+ /** A directed edge between two solution design nodes (by node `id`). */
573
+ interface SolutionDesignEdge {
574
+ id: string;
575
+ source: string;
576
+ target: string;
577
+ label?: string;
578
+ }
579
+ /** Header for a solution design — render as the diagram title/summary. */
580
+ interface SolutionDesignHeader {
581
+ title: string;
582
+ summary: string;
583
+ }
584
+ /** Suggested retry attached to a recoverable skill error. */
585
+ interface SkillErrorRetryHint {
586
+ /** Re-ask with this prompt… */
587
+ prompt: string;
588
+ /** …optionally forcing this skill. */
589
+ forcedSkill?: SkillResponseTypeType;
590
+ }
253
591
  /**
254
- * A single event yielded by {@link GuideClient.ask}. The common case is `text`
255
- * (the streamed chat reply); `skill` carries every structured skill payload,
256
- * discriminated by its {@link GuideEventName} `name`.
592
+ * A structured skill event, discriminated on `name`. Every turn runs one skill
593
+ * (plain answers are the `answer` skill): `skill_start` announces which,
594
+ * payload events stream the deliverable, and `skill_end` closes it. Use
595
+ * {@link reduceSkillEvent} to fold these into renderable state instead of
596
+ * handling each variant by hand.
597
+ */
598
+ type GuideSkillEvent = {
599
+ type: "skill";
600
+ name: typeof GuideEvent.SkillStart; /** Which skill this turn runs, and the assistant message it belongs to. */
601
+ value: {
602
+ skill: SkillResponseTypeType;
603
+ messageId: string;
604
+ diagnoseSubtype?: DiagnoseSubtypeName;
605
+ followUpSkill?: string;
606
+ };
607
+ } | {
608
+ type: "skill";
609
+ name: typeof GuideEvent.SkillContent; /** Markdown token chunk of the skill's long-form body (business case drafts, etc.). */
610
+ value: {
611
+ delta: string;
612
+ };
613
+ } | {
614
+ type: "skill";
615
+ name: typeof GuideEvent.SkillDocuments; /** Source documents behind the reply — render as citation/source cards. */
616
+ value: {
617
+ documents: GuideDocument[];
618
+ };
619
+ } | {
620
+ type: "skill";
621
+ name: typeof GuideEvent.SkillRecommendations;
622
+ /**
623
+ * Either the recommend skill's content cards ({@link ContentRecommendation},
624
+ * has `targetSkill`) or post-answer follow-up pills ({@link SkillRecommendation},
625
+ * has `skill`). Discriminate by which of those keys is present.
626
+ */
627
+ value: {
628
+ recommendations: ContentRecommendation[] | SkillRecommendation[];
629
+ };
630
+ } | {
631
+ type: "skill";
632
+ name: typeof GuideEvent.SkillCTAs; /** Calls-to-action for this turn — render the first below the response. */
633
+ value: {
634
+ ctas: SkillCTA[];
635
+ };
636
+ } | {
637
+ type: "skill";
638
+ name: typeof GuideEvent.SkillDiagnoseHeader;
639
+ value: {
640
+ header: DiagnosticHeader;
641
+ };
642
+ } | {
643
+ type: "skill";
644
+ name: typeof GuideEvent.SkillDiagnoseQuestion;
645
+ value: {
646
+ question: DiagnosticQuestion;
647
+ };
648
+ } | {
649
+ type: "skill";
650
+ name: typeof GuideEvent.SkillPlaylistItems;
651
+ value: {
652
+ items: PlaylistItem[];
653
+ };
654
+ } | {
655
+ type: "skill";
656
+ name: typeof GuideEvent.SkillPlaylistHeader;
657
+ value: {
658
+ header: PlaylistHeader;
659
+ };
660
+ } | {
661
+ type: "skill";
662
+ name: typeof GuideEvent.SkillPlaylistRationale; /** Late-streamed rationale for the playlist item with this `itemId`. */
663
+ value: {
664
+ itemId: string;
665
+ rationale: string;
666
+ };
667
+ } | {
668
+ type: "skill";
669
+ name: typeof GuideEvent.SkillHowToOutline; /** Render the outline immediately; detailed steps stream in `skill_howto_steps`. */
670
+ value: {
671
+ outline: HowToOutline;
672
+ skillInstanceId?: string;
673
+ };
674
+ } | {
675
+ type: "skill";
676
+ name: typeof GuideEvent.SkillHowToSteps;
677
+ value: {
678
+ steps: HowToStep[];
679
+ };
680
+ } | {
681
+ type: "skill";
682
+ name: typeof GuideEvent.SkillBusinessCaseChooser; /** Format options to choose from; `drafts` maps subType → pre-generated draft. */
683
+ value: {
684
+ formats: BusinessCaseFormatOption[];
685
+ drafts: Record<string, BusinessCaseDraftRef>;
686
+ };
687
+ } | {
688
+ type: "skill";
689
+ name: typeof GuideEvent.SkillBusinessCaseDelta; /** Markdown chunk of the draft for one business case format. */
690
+ value: {
691
+ subType: BusinessCaseSubTypeName;
692
+ delta: string;
693
+ };
694
+ } | {
695
+ type: "skill";
696
+ name: typeof GuideEvent.SkillSolutionDesignHeader;
697
+ value: {
698
+ header: SolutionDesignHeader;
699
+ };
700
+ } | {
701
+ type: "skill";
702
+ name: typeof GuideEvent.SkillSolutionDesignDiagram; /** Flowchart nodes + edges — render with any diagram/graph component. */
703
+ value: {
704
+ nodes: SolutionDesignNode[];
705
+ edges: SolutionDesignEdge[];
706
+ };
707
+ } | {
708
+ type: "skill";
709
+ name: typeof GuideEvent.SkillEnd; /** `skillInstanceId` is the persisted deliverable's id (for `skills.get`/`update`). */
710
+ value: {
711
+ skillInstanceId?: string;
712
+ skillResponseId?: string;
713
+ };
714
+ };
715
+ /**
716
+ * A single event yielded by {@link GuideClient.ask}.
717
+ *
718
+ * - `text` streams the chat reply; `skill` carries the structured deliverable
719
+ * (see {@link GuideSkillEvent}).
720
+ * - `gate` means the guide wants an email before continuing — collect one,
721
+ * call `submitGate(email)`, then re-send the message.
722
+ * - `skill-unknown` is a forward-compatibility escape hatch: a structured
723
+ * event this SDK version doesn't know. Safe to ignore.
257
724
  */
258
725
  type GuideStreamEvent = {
259
726
  type: "run-started";
@@ -269,9 +736,9 @@ type GuideStreamEvent = {
269
736
  } | {
270
737
  type: "message-end";
271
738
  messageId: string;
272
- } | {
273
- type: "skill";
274
- name: GuideEventName;
739
+ } | GuideSkillEvent | {
740
+ type: "skill-unknown";
741
+ name: string;
275
742
  value: Record<string, unknown>;
276
743
  } | {
277
744
  type: "gate";
@@ -282,6 +749,8 @@ type GuideStreamEvent = {
282
749
  type: "error";
283
750
  message: string;
284
751
  code?: string;
752
+ retryable?: boolean;
753
+ retryHint?: SkillErrorRetryHint;
285
754
  } | {
286
755
  type: "run-finished";
287
756
  finishReason?: string;
@@ -305,6 +774,11 @@ interface SkillsApi {
305
774
  markShared(skillInstanceId: string): Promise<MarkSharedResult>;
306
775
  importShared(sourceSkillInstanceId: string): Promise<ImportSharedResult>;
307
776
  }
777
+ /**
778
+ * Normalize `baseUrl` to the bare host the server stores: lowercased, no port,
779
+ * no leading `www.` (the domain write-path strips it, so a `www.` host can
780
+ * never match). Accepts a bare host too, in case `baseUrl` omits the protocol.
781
+ */
308
782
  /**
309
783
  * The client returned by {@link initGuide}. Holds the resolved guide, the
310
784
  * credentialed live API client, and the in-memory conversation history. Every
@@ -357,7 +831,74 @@ declare class GuideClient {
357
831
  private applyInitialConsent;
358
832
  }
359
833
  //#endregion
834
+ //#region src/skill-state.d.ts
835
+ /**
836
+ * Renderable state for one skill turn, folded from the `skill` events of a
837
+ * single {@link GuideClient.ask} stream. Which fields fill in depends on
838
+ * `skill`; everything else stays at its empty default:
839
+ *
840
+ * - `answer`: `documents`, `followUpRecommendations`, `ctas`
841
+ * - `recommend`: `contentRecommendations`, `ctas`
842
+ * - `diagnose`: `diagnoseHeader`, `diagnoseQuestions`
843
+ * - `playlist`: `playlistHeader`, `playlistItems`
844
+ * - `howto`: `howToOutline` (render first), then `howToSteps`
845
+ * - `businesscase`: `businessCaseFormats`/`businessCaseDrafts` (chooser), then
846
+ * `businessCaseContent[subType]` markdown as a format streams
847
+ * - `solutiondesign`: `solutionDesignHeader`, `solutionDesignNodes`/`Edges`
848
+ */
849
+ interface GuideSkillTurn {
850
+ /** Which skill this turn ran. Null until `skill_start` arrives. */
851
+ skill: SkillResponseTypeType | null;
852
+ /** `streaming` until `skill_end`. */
853
+ status: "streaming" | "complete";
854
+ /** The assistant message this skill output belongs to. */
855
+ messageId: string | null;
856
+ /** Diagnose mode — `context_gathering` runs `followUpSkill` after answers are submitted. */
857
+ diagnoseSubtype: DiagnoseSubtypeName | null;
858
+ followUpSkill: string | null;
859
+ /** Accumulated long-form markdown body (`skill_content` deltas). */
860
+ content: string;
861
+ /** Source documents behind the reply — render as citation/source cards. */
862
+ documents: GuideDocument[];
863
+ /** The recommend skill's content cards. */
864
+ contentRecommendations: ContentRecommendation[];
865
+ /** Post-answer follow-up pills — `ask(prompt, { forcedSkill: skill })` on click. */
866
+ followUpRecommendations: SkillRecommendation[];
867
+ /** Calls-to-action — render the first below the response. */
868
+ ctas: SkillCTA[];
869
+ diagnoseHeader: DiagnosticHeader | null;
870
+ diagnoseQuestions: DiagnosticQuestion[];
871
+ playlistHeader: PlaylistHeader | null;
872
+ playlistItems: PlaylistItem[];
873
+ howToOutline: HowToOutline | null;
874
+ howToSteps: HowToStep[];
875
+ businessCaseFormats: BusinessCaseFormatOption[];
876
+ businessCaseDrafts: Record<string, BusinessCaseDraftRef>;
877
+ /** Accumulated draft markdown per business case subType. */
878
+ businessCaseContent: Record<string, string>;
879
+ solutionDesignHeader: SolutionDesignHeader | null;
880
+ solutionDesignNodes: SolutionDesignNode[];
881
+ solutionDesignEdges: SolutionDesignEdge[];
882
+ /** Persisted deliverable id (for `client.skills.get`/`update`), set on `skill_end`. */
883
+ skillInstanceId: string | null;
884
+ }
885
+ //#endregion
360
886
  //#region src/react/useGuide.d.ts
887
+ interface UseGuideConfig extends InitGuideConfig {
888
+ /**
889
+ * Called with every raw stream event, in order — the escape hatch for
890
+ * anything the hook's derived state doesn't cover.
891
+ */
892
+ onEvent?: (event: GuideStreamEvent) => void;
893
+ }
894
+ /** A pending email gate — the guide wants an email before finishing the turn. */
895
+ interface GateRequest {
896
+ /** The skill that was gated. */
897
+ skill: SkillResponseTypeType;
898
+ /** The visitor prompt that triggered the gate (re-sent after unlocking). */
899
+ prompt?: string;
900
+ skillInstanceId?: string;
901
+ }
361
902
  interface UseGuideResult {
362
903
  /** The client once bootstrapped, else `null`. */
363
904
  client: GuideClient | null;
@@ -365,23 +906,41 @@ interface UseGuideResult {
365
906
  guide: ResolvedGuide | null;
366
907
  /** Conversation history, kept in sync with the client. */
367
908
  messages: ChatMessage[];
909
+ /**
910
+ * Structured deliverable of the current / most recent turn (documents,
911
+ * recommendations, CTAs, how-to steps, …). `null` before the first ask.
912
+ */
913
+ skillTurn: GuideSkillTurn | null;
914
+ /**
915
+ * Set when the guide asks for an email mid-turn. Render an email form, call
916
+ * `submitGate(email)`, then `retryLastAsk()` to finish the interrupted turn.
917
+ */
918
+ gate: GateRequest | null;
368
919
  /** `true` once the client has finished initializing. */
369
920
  isReady: boolean;
370
921
  /** `true` while a reply is streaming. */
371
922
  isStreaming: boolean;
372
923
  /** Init or stream error, else `null`. */
373
924
  error: Error | null;
374
- /** Send a message and stream the reply into `messages`. */
925
+ /** Send a message and stream the reply into `messages` / `skillTurn`. */
375
926
  ask: (message: string, options?: AskOptions) => Promise<void>;
927
+ /**
928
+ * Submit the visitor's email — for the pending `gate` (its context is merged
929
+ * in automatically) or as general lead capture. Clears `gate` on success.
930
+ */
931
+ submitGate: (email: string, options?: SubmitGateOptions) => Promise<SubmitGateResult>;
932
+ /** Re-send the last user message, e.g. to finish a gated turn after `submitGate`. */
933
+ retryLastAsk: () => Promise<void>;
376
934
  /** Clear the in-memory conversation. */
377
935
  reset: () => void;
378
936
  }
379
937
  /**
380
938
  * React binding over {@link initGuide}. Bootstraps once per `baseUrl`+`slug`,
381
- * mirrors the streamed reply into state, and ends the session on unmount —
939
+ * mirrors the streamed reply into `messages`, folds structured skill events
940
+ * into `skillTurn`, surfaces email gates, and ends the session on unmount —
382
941
  * encapsulating the streaming/cleanup patterns so generated UIs stay correct.
383
942
  */
384
- declare function useGuide(config: InitGuideConfig): UseGuideResult;
943
+ declare function useGuide(config: UseGuideConfig): UseGuideResult;
385
944
  //#endregion
386
- export { type UseGuideResult, useGuide };
945
+ export { type GateRequest, type UseGuideConfig, type UseGuideResult, useGuide };
387
946
  //# sourceMappingURL=index.d.cts.map