@ai-accounts/vue-headless 0.3.0-alpha.2 → 0.3.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.
package/dist/index.js CHANGED
@@ -144,6 +144,7 @@ function useLoginSession() {
144
144
  const accountId = ref4(null);
145
145
  const urlPrompt = ref4(null);
146
146
  const textPrompt = ref4(null);
147
+ const menuPrompt = ref4(null);
147
148
  const stdoutLines = ref4([]);
148
149
  const errorCode = ref4(null);
149
150
  const errorMessage = ref4(null);
@@ -152,15 +153,33 @@ function useLoginSession() {
152
153
  status.value = "running";
153
154
  urlPrompt.value = null;
154
155
  textPrompt.value = null;
156
+ menuPrompt.value = null;
155
157
  stdoutLines.value = [];
156
158
  errorCode.value = null;
157
159
  errorMessage.value = null;
158
- const { session_id } = await client.beginLogin(id, flow, inputs);
159
- sessionId.value = session_id;
160
- emit({ type: "login.started", sessionId: session_id, backendKind: "", flow });
161
- for await (const event of client.streamLogin(id, session_id)) {
162
- dispatch(event);
163
- if (status.value !== "running") return;
160
+ try {
161
+ const { session_id } = await client.beginLogin(id, flow, inputs);
162
+ sessionId.value = session_id;
163
+ emit({ type: "login.started", sessionId: session_id, backendKind: "", flow });
164
+ for await (const event of client.streamLogin(id, session_id)) {
165
+ dispatch(event);
166
+ if (status.value !== "running") return;
167
+ }
168
+ if (status.value === "running") {
169
+ status.value = "failed";
170
+ errorCode.value = "stream_ended";
171
+ errorMessage.value = "Login stream ended unexpectedly";
172
+ }
173
+ } catch (err) {
174
+ status.value = "failed";
175
+ errorCode.value = "network_error";
176
+ errorMessage.value = err instanceof Error ? err.message : String(err);
177
+ emit({
178
+ type: "login.failed",
179
+ sessionId: sessionId.value ?? "",
180
+ code: "network_error",
181
+ message: errorMessage.value
182
+ });
164
183
  }
165
184
  }
166
185
  function dispatch(event) {
@@ -173,6 +192,10 @@ function useLoginSession() {
173
192
  textPrompt.value = event;
174
193
  emit({ type: "login.prompt", sessionId: sessionId.value, promptKind: "text" });
175
194
  break;
195
+ case "menu_prompt":
196
+ menuPrompt.value = event;
197
+ emit({ type: "login.prompt", sessionId: sessionId.value, promptKind: "menu" });
198
+ break;
176
199
  case "stdout":
177
200
  stdoutLines.value = [...stdoutLines.value, event.text];
178
201
  break;
@@ -201,9 +224,12 @@ function useLoginSession() {
201
224
  }
202
225
  }
203
226
  async function respond(answer) {
204
- if (!sessionId.value || !accountId.value || !textPrompt.value) return;
205
- const promptId = textPrompt.value.prompt_id;
227
+ if (!sessionId.value || !accountId.value) return;
228
+ const activePrompt = textPrompt.value ?? menuPrompt.value;
229
+ if (!activePrompt) return;
230
+ const promptId = activePrompt.prompt_id;
206
231
  textPrompt.value = null;
232
+ menuPrompt.value = null;
207
233
  await client.respondLogin(accountId.value, sessionId.value, promptId, answer);
208
234
  }
209
235
  async function cancel() {
@@ -217,6 +243,7 @@ function useLoginSession() {
217
243
  accountId,
218
244
  urlPrompt,
219
245
  textPrompt,
246
+ menuPrompt,
220
247
  stdoutLines,
221
248
  errorCode,
222
249
  errorMessage,
@@ -226,6 +253,595 @@ function useLoginSession() {
226
253
  };
227
254
  }
228
255
 
256
+ // src/composables/useConversation.ts
257
+ import { ref as ref5, shallowRef } from "vue";
258
+ function useConversation(client) {
259
+ const sessionId = ref5(null);
260
+ const messages = shallowRef([]);
261
+ const isStreaming = ref5(false);
262
+ const streamingText = ref5("");
263
+ const error = ref5(null);
264
+ async function create(backendId, model) {
265
+ error.value = null;
266
+ const session = await client.createConversation({ backend_id: backendId, model });
267
+ sessionId.value = session.id;
268
+ messages.value = [];
269
+ }
270
+ async function load(id) {
271
+ error.value = null;
272
+ const detail = await client.getConversation(id);
273
+ sessionId.value = detail.id;
274
+ messages.value = detail.messages;
275
+ }
276
+ async function send(content) {
277
+ if (!sessionId.value) {
278
+ error.value = "No active session";
279
+ return;
280
+ }
281
+ error.value = null;
282
+ isStreaming.value = true;
283
+ streamingText.value = "";
284
+ const userMsg = {
285
+ id: `pending-${Date.now()}`,
286
+ role: "user",
287
+ content,
288
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
289
+ model: null,
290
+ tokens_in: null,
291
+ tokens_out: null
292
+ };
293
+ messages.value = [...messages.value, userMsg];
294
+ try {
295
+ let accumulated = "";
296
+ for await (const delta of client.streamChat(sessionId.value, content)) {
297
+ if (delta.kind === "token" && delta.text) {
298
+ accumulated += delta.text;
299
+ streamingText.value = accumulated;
300
+ } else if (delta.kind === "error") {
301
+ error.value = delta.text ?? "Unknown error";
302
+ }
303
+ }
304
+ if (accumulated) {
305
+ const assistantMsg = {
306
+ id: `msg-${Date.now()}`,
307
+ role: "assistant",
308
+ content: accumulated,
309
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
310
+ model: null,
311
+ tokens_in: null,
312
+ tokens_out: null
313
+ };
314
+ messages.value = [...messages.value, assistantMsg];
315
+ }
316
+ } catch (e) {
317
+ error.value = e instanceof Error ? e.message : "Stream failed";
318
+ } finally {
319
+ isStreaming.value = false;
320
+ streamingText.value = "";
321
+ }
322
+ }
323
+ return { sessionId, messages, isStreaming, streamingText, error, create, send, load };
324
+ }
325
+
326
+ // src/composables/useSmartChat.ts
327
+ import { ref as ref7, shallowRef as shallowRef2 } from "vue";
328
+
329
+ // src/composables/useProcessGroups.ts
330
+ import { ref as ref6 } from "vue";
331
+ var AUTO_COLLAPSE_MS = {
332
+ tool_call: 4e3,
333
+ reasoning: 2e3,
334
+ code_execution: 2e3
335
+ };
336
+ function useProcessGroups() {
337
+ const groups = ref6(/* @__PURE__ */ new Map());
338
+ function _triggerReactivity() {
339
+ groups.value = new Map(groups.value);
340
+ }
341
+ function addGroup(group) {
342
+ groups.value.set(group.id, { ...group, isExpanded: true });
343
+ _triggerReactivity();
344
+ }
345
+ function removeGroup(id) {
346
+ groups.value.delete(id);
347
+ _triggerReactivity();
348
+ }
349
+ function toggleGroup(id) {
350
+ const g = groups.value.get(id);
351
+ if (g) {
352
+ g.isExpanded = !g.isExpanded;
353
+ _triggerReactivity();
354
+ }
355
+ }
356
+ function collapseGroup(id) {
357
+ const g = groups.value.get(id);
358
+ if (g) {
359
+ g.isExpanded = false;
360
+ _triggerReactivity();
361
+ }
362
+ }
363
+ function expandGroup(id) {
364
+ const g = groups.value.get(id);
365
+ if (g) {
366
+ g.isExpanded = true;
367
+ _triggerReactivity();
368
+ }
369
+ }
370
+ function updateGroupContent(id, content) {
371
+ const g = groups.value.get(id);
372
+ if (g) {
373
+ g.content += content;
374
+ _triggerReactivity();
375
+ }
376
+ }
377
+ function clearGroups() {
378
+ groups.value.clear();
379
+ _triggerReactivity();
380
+ }
381
+ function processToolCallDelta(delta) {
382
+ const existing = groups.value.get(delta.id);
383
+ if (existing) {
384
+ if (delta.arguments) {
385
+ existing.content += delta.arguments;
386
+ _triggerReactivity();
387
+ }
388
+ return;
389
+ }
390
+ const type = delta.group_type ?? "tool_call";
391
+ addGroup({
392
+ id: delta.id,
393
+ type,
394
+ label: delta.name ?? delta.id,
395
+ content: delta.arguments ?? "",
396
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
397
+ autoCollapseMs: AUTO_COLLAPSE_MS[type]
398
+ });
399
+ }
400
+ return {
401
+ groups,
402
+ addGroup,
403
+ removeGroup,
404
+ toggleGroup,
405
+ collapseGroup,
406
+ expandGroup,
407
+ updateGroupContent,
408
+ clearGroups,
409
+ processToolCallDelta
410
+ };
411
+ }
412
+
413
+ // src/composables/useSmartChat.ts
414
+ var HEARTBEAT_TIMEOUT_MS = 9e4;
415
+ function useSmartChat() {
416
+ const { client } = useAiAccounts();
417
+ const sessionId = ref7(null);
418
+ const messages = shallowRef2([]);
419
+ const isStreaming = ref7(false);
420
+ const streamingContent = ref7("");
421
+ const error = ref7(null);
422
+ const chatMode = ref7("single");
423
+ const backendResponses = ref7(/* @__PURE__ */ new Map());
424
+ const synthesisState = ref7(null);
425
+ const selectedBackend = ref7(null);
426
+ const selectedAccount = ref7(null);
427
+ const selectedModel = ref7(null);
428
+ const processGroups = useProcessGroups();
429
+ const canFinalize = ref7(false);
430
+ const isFinalizing = ref7(false);
431
+ const detectedConfig = ref7(null);
432
+ let configParser = null;
433
+ function setConfigParser(parser) {
434
+ configParser = parser;
435
+ }
436
+ async function finalize() {
437
+ if (!canFinalize.value) return null;
438
+ isFinalizing.value = true;
439
+ try {
440
+ return detectedConfig.value;
441
+ } finally {
442
+ isFinalizing.value = false;
443
+ }
444
+ }
445
+ let lastSeq = 0;
446
+ let heartbeatTimer = null;
447
+ let activeAbort = null;
448
+ function clearHeartbeat() {
449
+ if (heartbeatTimer) {
450
+ clearTimeout(heartbeatTimer);
451
+ heartbeatTimer = null;
452
+ }
453
+ }
454
+ function resetHeartbeat() {
455
+ clearHeartbeat();
456
+ heartbeatTimer = setTimeout(() => {
457
+ error.value = "Connection lost \u2014 no activity from server";
458
+ isStreaming.value = false;
459
+ heartbeatTimer = null;
460
+ if (activeAbort) {
461
+ activeAbort.abort(new DOMException("heartbeat-timeout", "AbortError"));
462
+ }
463
+ }, HEARTBEAT_TIMEOUT_MS);
464
+ }
465
+ async function createSession(backendId, model) {
466
+ error.value = null;
467
+ const session = await client.createChatSession(backendId, model);
468
+ sessionId.value = session.id;
469
+ messages.value = [];
470
+ }
471
+ async function loadSession(id) {
472
+ error.value = null;
473
+ const detail = await client.getConversation(id);
474
+ sessionId.value = detail.id;
475
+ messages.value = detail.messages;
476
+ }
477
+ async function send(content) {
478
+ if (!sessionId.value) {
479
+ error.value = "No active session";
480
+ return;
481
+ }
482
+ error.value = null;
483
+ isStreaming.value = true;
484
+ streamingContent.value = "";
485
+ backendResponses.value = /* @__PURE__ */ new Map();
486
+ synthesisState.value = null;
487
+ canFinalize.value = false;
488
+ detectedConfig.value = null;
489
+ processGroups.clearGroups();
490
+ lastSeq = 0;
491
+ activeAbort = new AbortController();
492
+ resetHeartbeat();
493
+ const userMsg = {
494
+ id: `pending-${Date.now()}`,
495
+ role: "user",
496
+ content,
497
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
498
+ model: null,
499
+ tokens_in: null,
500
+ tokens_out: null
501
+ };
502
+ messages.value = [...messages.value, userMsg];
503
+ try {
504
+ const req = { session_id: sessionId.value, content, mode: chatMode.value };
505
+ if (selectedBackend.value) req.backend_kind = selectedBackend.value;
506
+ if (selectedAccount.value) req.account_id = selectedAccount.value;
507
+ if (selectedModel.value) req.model = selectedModel.value;
508
+ for await (const event of client.sendChat(req, { signal: activeAbort.signal })) {
509
+ dispatch(event);
510
+ }
511
+ if (chatMode.value === "single" && streamingContent.value) {
512
+ const assistantMsg = {
513
+ id: `msg-${Date.now()}`,
514
+ role: "assistant",
515
+ content: streamingContent.value,
516
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
517
+ model: null,
518
+ tokens_in: null,
519
+ tokens_out: null
520
+ };
521
+ messages.value = [...messages.value, assistantMsg];
522
+ }
523
+ if (configParser) {
524
+ const lastMsg = messages.value[messages.value.length - 1];
525
+ if (lastMsg && lastMsg.role === "assistant") {
526
+ try {
527
+ const cfg = configParser(lastMsg.content);
528
+ if (cfg) {
529
+ detectedConfig.value = cfg;
530
+ canFinalize.value = true;
531
+ }
532
+ } catch (e) {
533
+ console.error("[useSmartChat] configParser threw \u2014 canFinalize stays false", e);
534
+ }
535
+ }
536
+ }
537
+ } catch (e) {
538
+ if (e instanceof DOMException && e.name === "AbortError") {
539
+ } else if (e instanceof Error) {
540
+ error.value = `${e.name}: ${e.message}`;
541
+ } else {
542
+ error.value = `Chat failed: ${String(e)}`;
543
+ }
544
+ } finally {
545
+ clearHeartbeat();
546
+ activeAbort = null;
547
+ isStreaming.value = false;
548
+ streamingContent.value = "";
549
+ }
550
+ }
551
+ function dispatch(event) {
552
+ if (typeof event._seq === "number") {
553
+ if (event._seq <= lastSeq) return;
554
+ if (lastSeq > 0 && event._seq > lastSeq + 1) {
555
+ console.warn(
556
+ "[useSmartChat] seq gap detected: lastSeq=%d incoming=%d (lost %d events)",
557
+ lastSeq,
558
+ event._seq,
559
+ event._seq - lastSeq - 1
560
+ );
561
+ }
562
+ lastSeq = event._seq;
563
+ }
564
+ resetHeartbeat();
565
+ if (event.kind === "done" || event.kind === "error" || event.kind === "synthesis_complete" || event.kind === "synthesis_error") {
566
+ clearHeartbeat();
567
+ }
568
+ switch (event.kind) {
569
+ // Single mode
570
+ case "token":
571
+ streamingContent.value += event.payload;
572
+ break;
573
+ case "done":
574
+ break;
575
+ case "error":
576
+ error.value = event.payload ?? "Unknown error";
577
+ break;
578
+ case "tool_call": {
579
+ const delta = { id: event.id };
580
+ if (event.name !== void 0) delta.name = event.name;
581
+ if (event.arguments !== void 0) delta.arguments = event.arguments;
582
+ if (event.group_type !== void 0) delta.group_type = event.group_type;
583
+ processGroups.processToolCallDelta(delta);
584
+ break;
585
+ }
586
+ // All/compound mode — backend events
587
+ case "backend_delta": {
588
+ const existing = backendResponses.value.get(event.backend);
589
+ const updated = new Map(backendResponses.value);
590
+ updated.set(event.backend, {
591
+ backend: event.backend,
592
+ content: (existing?.content ?? "") + (event.text ?? ""),
593
+ status: "streaming"
594
+ });
595
+ backendResponses.value = updated;
596
+ break;
597
+ }
598
+ case "backend_complete": {
599
+ const existing = backendResponses.value.get(event.backend);
600
+ if (existing) {
601
+ const updated = new Map(backendResponses.value);
602
+ updated.set(event.backend, { ...existing, status: "complete" });
603
+ backendResponses.value = updated;
604
+ }
605
+ break;
606
+ }
607
+ case "backend_error": {
608
+ const existing = backendResponses.value.get(event.backend);
609
+ const updated = new Map(backendResponses.value);
610
+ updated.set(event.backend, {
611
+ backend: event.backend,
612
+ content: existing?.content ?? "",
613
+ status: "error",
614
+ error: event.error
615
+ });
616
+ backendResponses.value = updated;
617
+ break;
618
+ }
619
+ case "backend_timeout": {
620
+ const existing = backendResponses.value.get(event.backend);
621
+ const updated = new Map(backendResponses.value);
622
+ updated.set(event.backend, {
623
+ backend: event.backend,
624
+ content: existing?.content ?? "",
625
+ status: "timeout"
626
+ });
627
+ backendResponses.value = updated;
628
+ break;
629
+ }
630
+ // Compound synthesis
631
+ case "synthesis_start": {
632
+ synthesisState.value = {
633
+ status: "streaming",
634
+ content: "",
635
+ primaryBackend: event.primary_backend,
636
+ backendsCollected: event.backends_collected ?? []
637
+ };
638
+ break;
639
+ }
640
+ case "synthesis_delta": {
641
+ if (synthesisState.value) {
642
+ synthesisState.value = {
643
+ ...synthesisState.value,
644
+ content: synthesisState.value.content + (event.text ?? "")
645
+ };
646
+ }
647
+ break;
648
+ }
649
+ case "synthesis_complete":
650
+ if (synthesisState.value) {
651
+ synthesisState.value = { ...synthesisState.value, status: "complete" };
652
+ }
653
+ break;
654
+ case "synthesis_error": {
655
+ if (synthesisState.value) {
656
+ synthesisState.value = { ...synthesisState.value, status: "error", error: event.error };
657
+ } else {
658
+ synthesisState.value = {
659
+ status: "error",
660
+ content: "",
661
+ primaryBackend: "",
662
+ backendsCollected: [],
663
+ error: event.error
664
+ };
665
+ }
666
+ break;
667
+ }
668
+ }
669
+ }
670
+ function setMode(mode) {
671
+ chatMode.value = mode;
672
+ }
673
+ function selectBackend(kind) {
674
+ selectedBackend.value = kind;
675
+ selectedAccount.value = null;
676
+ selectedModel.value = null;
677
+ }
678
+ return {
679
+ sessionId,
680
+ messages,
681
+ isStreaming,
682
+ streamingContent,
683
+ error,
684
+ chatMode,
685
+ backendResponses,
686
+ synthesisState,
687
+ selectedBackend,
688
+ selectedAccount,
689
+ selectedModel,
690
+ createSession,
691
+ loadSession,
692
+ send,
693
+ setMode,
694
+ selectBackend,
695
+ processGroups,
696
+ canFinalize,
697
+ isFinalizing,
698
+ detectedConfig,
699
+ finalize,
700
+ setConfigParser
701
+ };
702
+ }
703
+
704
+ // src/composables/useSmartScroll.ts
705
+ import { ref as ref8, onMounted, onUnmounted } from "vue";
706
+ var THRESHOLD = 32;
707
+ function useSmartScroll() {
708
+ const containerRef = ref8(null);
709
+ const isNearBottom = ref8(true);
710
+ const showScrollButton = ref8(false);
711
+ function check() {
712
+ const el = containerRef.value;
713
+ if (!el) return;
714
+ const near = el.scrollHeight - el.scrollTop - el.clientHeight < THRESHOLD;
715
+ isNearBottom.value = near;
716
+ showScrollButton.value = !near;
717
+ }
718
+ function scrollToBottom() {
719
+ containerRef.value?.scrollTo({ top: containerRef.value.scrollHeight, behavior: "smooth" });
720
+ }
721
+ let observer = null;
722
+ onMounted(() => {
723
+ const el = containerRef.value;
724
+ if (!el) return;
725
+ el.addEventListener("scroll", check, { passive: true });
726
+ observer = new MutationObserver(() => {
727
+ if (isNearBottom.value) scrollToBottom();
728
+ });
729
+ observer.observe(el, { childList: true, subtree: true });
730
+ });
731
+ onUnmounted(() => {
732
+ containerRef.value?.removeEventListener("scroll", check);
733
+ observer?.disconnect();
734
+ });
735
+ return { containerRef, isNearBottom, showScrollButton, scrollToBottom };
736
+ }
737
+
738
+ // src/composables/useStreamingParser.ts
739
+ var DEFAULT_MAX_PENDING = 1e6;
740
+ var smdResolutionWarned = false;
741
+ async function resolveSmd() {
742
+ const injected = globalThis.__smd;
743
+ if (injected) return injected;
744
+ try {
745
+ const mod = await import(
746
+ /* @vite-ignore */
747
+ "streaming-markdown"
748
+ );
749
+ return mod;
750
+ } catch (err) {
751
+ if (!smdResolutionWarned) {
752
+ smdResolutionWarned = true;
753
+ console.warn(
754
+ '[useStreamingParser] Could not load "streaming-markdown" peer dep; markdown rendering disabled. Install it or inject globalThis.__smd.',
755
+ err
756
+ );
757
+ }
758
+ return null;
759
+ }
760
+ }
761
+ function useStreamingParser(options = {}) {
762
+ const maxPending = options.maxPendingChars ?? DEFAULT_MAX_PENDING;
763
+ let smd = null;
764
+ let parser = null;
765
+ let pending = [];
766
+ let pendingChars = 0;
767
+ let rafId = null;
768
+ let initToken = 0;
769
+ function flush() {
770
+ rafId = null;
771
+ if (!smd || !parser || pending.length === 0) return;
772
+ const text = pending.join("");
773
+ pending = [];
774
+ pendingChars = 0;
775
+ try {
776
+ smd.parser_write(parser, text);
777
+ } catch (err) {
778
+ console.error("[useStreamingParser] parser_write threw; chunk discarded", err);
779
+ }
780
+ options.onFlush?.();
781
+ }
782
+ function init(container) {
783
+ destroy();
784
+ container.textContent = "";
785
+ const token = ++initToken;
786
+ resolveSmd().then((resolved) => {
787
+ if (token !== initToken) return;
788
+ if (!resolved) return;
789
+ smd = resolved;
790
+ const renderer = resolved.default_renderer(container);
791
+ parser = resolved.parser(renderer);
792
+ if (pending.length > 0) {
793
+ const text = pending.join("");
794
+ pending = [];
795
+ pendingChars = 0;
796
+ try {
797
+ resolved.parser_write(parser, text);
798
+ } catch (err) {
799
+ console.error("[useStreamingParser] initial parser_write threw; buffered chunk discarded", err);
800
+ }
801
+ }
802
+ }).catch((err) => {
803
+ console.error("[useStreamingParser] resolveSmd unexpectedly rejected", err);
804
+ });
805
+ }
806
+ function write(text) {
807
+ if (initToken === 0) return;
808
+ if (pendingChars + text.length > maxPending) {
809
+ console.warn(
810
+ "[useStreamingParser] dropping write \u2014 pending buffer exceeded maxPendingChars (%d). smd may never have resolved.",
811
+ maxPending
812
+ );
813
+ return;
814
+ }
815
+ pending.push(text);
816
+ pendingChars += text.length;
817
+ if (rafId === null && typeof requestAnimationFrame !== "undefined") {
818
+ rafId = requestAnimationFrame(flush);
819
+ } else if (rafId === null) {
820
+ queueMicrotask(flush);
821
+ }
822
+ }
823
+ function finalize() {
824
+ if (rafId !== null) {
825
+ if (typeof cancelAnimationFrame !== "undefined") cancelAnimationFrame(rafId);
826
+ rafId = null;
827
+ }
828
+ if (pending.length > 0) flush();
829
+ if (smd && parser) {
830
+ try {
831
+ smd.parser_end(parser);
832
+ } catch (err) {
833
+ console.error("[useStreamingParser] parser_end threw", err);
834
+ }
835
+ }
836
+ parser = null;
837
+ smd = null;
838
+ }
839
+ function destroy() {
840
+ finalize();
841
+ }
842
+ return { init, write, finalize, destroy };
843
+ }
844
+
229
845
  // src/index.ts
230
846
  var version = "0.3.0-alpha.1";
231
847
  export {
@@ -234,7 +850,12 @@ export {
234
850
  useAccountWizard,
235
851
  useAiAccounts,
236
852
  useBackendRegistry,
853
+ useConversation,
237
854
  useLoginSession,
238
855
  useOnboarding,
856
+ useProcessGroups,
857
+ useSmartChat,
858
+ useSmartScroll,
859
+ useStreamingParser,
239
860
  version
240
861
  };