@meistrari/chat-nuxt 4.13.0-rc.3 → 4.13.0-rc.5

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.
Files changed (23) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/conversations/components/chat-export-code-block.d.vue.ts +9 -0
  3. package/dist/runtime/conversations/components/chat-export-code-block.vue +12 -0
  4. package/dist/runtime/conversations/components/chat-export-code-block.vue.d.ts +9 -0
  5. package/dist/runtime/conversations/components/chat-export-openui.vue +3 -1
  6. package/dist/runtime/conversations/components/chat-export-steps.d.vue.ts +15 -0
  7. package/dist/runtime/conversations/components/chat-export-steps.vue +18 -0
  8. package/dist/runtime/conversations/components/chat-export-steps.vue.d.ts +15 -0
  9. package/dist/runtime/conversations/components/chat-new-conversation-modal.d.vue.ts +1 -1
  10. package/dist/runtime/conversations/components/chat-new-conversation-modal.vue.d.ts +1 -1
  11. package/dist/runtime/conversations/export.js +15 -2
  12. package/dist/runtime/embed/components/mobile/chat-mobile-header.d.vue.ts +6 -6
  13. package/dist/runtime/embed/components/mobile/chat-mobile-header.vue.d.ts +6 -6
  14. package/dist/runtime/embed/components/mobile/chat-mobile-shell.d.vue.ts +13 -13
  15. package/dist/runtime/embed/components/mobile/chat-mobile-shell.vue.d.ts +13 -13
  16. package/dist/runtime/messages/components/chat-debug-widget-gallery.d.vue.ts +7 -0
  17. package/dist/runtime/messages/components/chat-debug-widget-gallery.vue +218 -0
  18. package/dist/runtime/messages/components/chat-debug-widget-gallery.vue.d.ts +7 -0
  19. package/dist/runtime/rendering/debug/widget-gallery.d.ts +24 -0
  20. package/dist/runtime/rendering/debug/widget-gallery.js +25 -0
  21. package/dist/runtime/types/schemas/chat/v3.d.ts +2 -0
  22. package/dist/runtime/types/schemas/chat/v3.js +2 -0
  23. package/package.json +2 -2
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
3
  "configKey": "chatNuxt",
4
- "version": "4.13.0-rc.3",
4
+ "version": "4.13.0-rc.5",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
@@ -0,0 +1,9 @@
1
+ type __VLS_Props = {
2
+ props: {
3
+ code: string;
4
+ language?: string;
5
+ };
6
+ };
7
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
8
+ declare const _default: typeof __VLS_export;
9
+ export default _default;
@@ -0,0 +1,12 @@
1
+ <script setup>
2
+ defineProps({
3
+ props: { type: Object, required: true }
4
+ });
5
+ </script>
6
+
7
+ <template>
8
+ <div data-openui="code-block" border rounded-8px p-12px flex="~ col" gap-4px>
9
+ <span v-if="props.language" body-12-regular>{{ props.language }}</span>
10
+ <pre m-0 whitespace-pre-wrap font-mono text-13px><code>{{ props.code }}</code></pre>
11
+ </div>
12
+ </template>
@@ -0,0 +1,9 @@
1
+ type __VLS_Props = {
2
+ props: {
3
+ code: string;
4
+ language?: string;
5
+ };
6
+ };
7
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
8
+ declare const _default: typeof __VLS_export;
9
+ export default _default;
@@ -4,13 +4,15 @@ import OpenuiImage from "../../rendering/components/openui/image.vue";
4
4
  import OpenuiCitation from "../../rendering/components/openui/citation.vue";
5
5
  import ChatExportQuestions from "./chat-export-questions.vue";
6
6
  import ChatExportFile from "./chat-export-file.vue";
7
+ import ChatExportCodeBlock from "./chat-export-code-block.vue";
8
+ import ChatExportSteps from "./chat-export-steps.vue";
7
9
  const props = defineProps({
8
10
  node: { type: Object, required: true }
9
11
  });
10
12
  const code = computed(() => props.node.code ?? props.node.content ?? "");
11
13
  const host = {
12
14
  prose: OpenuiMarkdownProse,
13
- components: { Questions: ChatExportQuestions, FileCard: ChatExportFile, Image: OpenuiImage, Citation: OpenuiCitation }
15
+ components: { Questions: ChatExportQuestions, FileCard: ChatExportFile, Image: OpenuiImage, Citation: OpenuiCitation, CodeBlock: ChatExportCodeBlock, Steps: ChatExportSteps }
14
16
  };
15
17
  </script>
16
18
 
@@ -0,0 +1,15 @@
1
+ type Step = {
2
+ props?: {
3
+ title?: string;
4
+ description?: string;
5
+ status?: string;
6
+ };
7
+ };
8
+ type __VLS_Props = {
9
+ props: {
10
+ steps?: Step[];
11
+ };
12
+ };
13
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
+ declare const _default: typeof __VLS_export;
15
+ export default _default;
@@ -0,0 +1,18 @@
1
+ <script setup>
2
+ defineProps({
3
+ props: { type: Object, required: true }
4
+ });
5
+ const STATUS_LABELS = { done: "conclu\xEDda", current: "em andamento", pending: "pendente" };
6
+ function line(step) {
7
+ const status = STATUS_LABELS[step.props?.status ?? ""];
8
+ return `${step.props?.title ?? ""}${status ? ` (${status})` : ""}${step.props?.description ? ` \u2014 ${step.props.description}` : ""}`;
9
+ }
10
+ </script>
11
+
12
+ <template>
13
+ <ol data-openui="steps" pl-20px>
14
+ <li v-for="(step, index) in props.steps ?? []" :key="index" body-14-regular>
15
+ {{ line(step) }}
16
+ </li>
17
+ </ol>
18
+ </template>
@@ -0,0 +1,15 @@
1
+ type Step = {
2
+ props?: {
3
+ title?: string;
4
+ description?: string;
5
+ status?: string;
6
+ };
7
+ };
8
+ type __VLS_Props = {
9
+ props: {
10
+ steps?: Step[];
11
+ };
12
+ };
13
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
+ declare const _default: typeof __VLS_export;
15
+ export default _default;
@@ -6,8 +6,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
6
6
  } & {
7
7
  create: (canvasTools: CanvasTool[]) => any;
8
8
  }, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
9
- "onUpdate:modelValue"?: ((value: boolean | undefined) => any) | undefined;
10
9
  onCreate?: ((canvasTools: CanvasTool[]) => any) | undefined;
10
+ "onUpdate:modelValue"?: ((value: boolean | undefined) => any) | undefined;
11
11
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
12
12
  declare const _default: typeof __VLS_export;
13
13
  export default _default;
@@ -6,8 +6,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
6
6
  } & {
7
7
  create: (canvasTools: CanvasTool[]) => any;
8
8
  }, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
9
- "onUpdate:modelValue"?: ((value: boolean | undefined) => any) | undefined;
10
9
  onCreate?: ((canvasTools: CanvasTool[]) => any) | undefined;
10
+ "onUpdate:modelValue"?: ((value: boolean | undefined) => any) | undefined;
11
11
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
12
12
  declare const _default: typeof __VLS_export;
13
13
  export default _default;
@@ -38,13 +38,14 @@ export function conversationExportFilename(title, format) {
38
38
  return `${title.trim().replace(/[<>:"/\\|?*\p{Cc}]/gu, "_").slice(0, 150) || "Conversa"}.${format}`;
39
39
  }
40
40
  export function renderedConversationToText(html) {
41
- const blocks = /* @__PURE__ */ new Set(["h1", "h2", "h3", "h4", "h5", "h6", "p", "div", "section", "article", "header", "footer", "table", "ul", "ol", "pre", "blockquote", "figure"]);
41
+ const blocks = /* @__PURE__ */ new Set(["h1", "h2", "h3", "h4", "h5", "h6", "p", "div", "section", "article", "header", "footer", "table", "ul", "ol", "dl", "pre", "blockquote", "figure"]);
42
42
  const ignored = /* @__PURE__ */ new Set(["script", "style", "svg"]);
43
43
  const links = [];
44
44
  let text = "";
45
45
  let ignoredDepth = 0;
46
46
  const whitespace = [];
47
47
  let cells = 0;
48
+ let trimNextText = false;
48
49
  const parser = new Parser({
49
50
  onopentag(name, attributes) {
50
51
  if (ignoredDepth || ignored.has(name)) {
@@ -65,6 +66,14 @@ export function renderedConversationToText(html) {
65
66
  }
66
67
  if (name === "li")
67
68
  text += "\n- ";
69
+ if (name === "dt") {
70
+ text += "\n";
71
+ trimNextText = true;
72
+ }
73
+ if (name === "dd") {
74
+ text = `${text.replace(/[ \t]+$/, "")}: `;
75
+ trimNextText = true;
76
+ }
68
77
  if (name === "br" || name === "hr")
69
78
  text += "\n";
70
79
  if (name === "img" && attributes.alt)
@@ -75,7 +84,11 @@ export function renderedConversationToText(html) {
75
84
  ontext(value) {
76
85
  if (!ignoredDepth) {
77
86
  const mode = whitespace.at(-1);
78
- text += mode === "pre" || mode === "pre-wrap" || mode === "break-spaces" ? value : mode === "pre-line" ? value.replace(/[^\S\r\n]+/g, " ") : value.replace(/\s+/g, " ");
87
+ const written = mode === "pre" || mode === "pre-wrap" || mode === "break-spaces" ? value : mode === "pre-line" ? value.replace(/[^\S\r\n]+/g, " ") : value.replace(/\s+/g, " ");
88
+ const shown = trimNextText ? written.trimStart() : written;
89
+ if (shown)
90
+ trimNextText = false;
91
+ text += shown;
79
92
  }
80
93
  },
81
94
  onclosetag(name) {
@@ -15,23 +15,23 @@ type __VLS_Props = {
15
15
  };
16
16
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
17
17
  delete: () => any;
18
+ openDrawer: () => any;
19
+ copyLink: () => any;
20
+ openOutdatedSettings: () => any;
18
21
  rename: () => any;
19
22
  duplicate: () => any;
20
23
  export: () => any;
21
- copyLink: () => any;
22
24
  debug: () => any;
23
- openDrawer: () => any;
24
- openOutdatedSettings: () => any;
25
25
  tabChange: (tab: TopbarTab) => any;
26
26
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
27
27
  onDelete?: (() => any) | undefined;
28
+ onOpenDrawer?: (() => any) | undefined;
29
+ onCopyLink?: (() => any) | undefined;
30
+ onOpenOutdatedSettings?: (() => any) | undefined;
28
31
  onRename?: (() => any) | undefined;
29
32
  onDuplicate?: (() => any) | undefined;
30
33
  onExport?: (() => any) | undefined;
31
- onCopyLink?: (() => any) | undefined;
32
34
  onDebug?: (() => any) | undefined;
33
- onOpenDrawer?: (() => any) | undefined;
34
- onOpenOutdatedSettings?: (() => any) | undefined;
35
35
  onTabChange?: ((tab: TopbarTab) => any) | undefined;
36
36
  }>, {
37
37
  showDrawerButton: boolean;
@@ -15,23 +15,23 @@ type __VLS_Props = {
15
15
  };
16
16
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
17
17
  delete: () => any;
18
+ openDrawer: () => any;
19
+ copyLink: () => any;
20
+ openOutdatedSettings: () => any;
18
21
  rename: () => any;
19
22
  duplicate: () => any;
20
23
  export: () => any;
21
- copyLink: () => any;
22
24
  debug: () => any;
23
- openDrawer: () => any;
24
- openOutdatedSettings: () => any;
25
25
  tabChange: (tab: TopbarTab) => any;
26
26
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
27
27
  onDelete?: (() => any) | undefined;
28
+ onOpenDrawer?: (() => any) | undefined;
29
+ onCopyLink?: (() => any) | undefined;
30
+ onOpenOutdatedSettings?: (() => any) | undefined;
28
31
  onRename?: (() => any) | undefined;
29
32
  onDuplicate?: (() => any) | undefined;
30
33
  onExport?: (() => any) | undefined;
31
- onCopyLink?: (() => any) | undefined;
32
34
  onDebug?: (() => any) | undefined;
33
- onOpenDrawer?: (() => any) | undefined;
34
- onOpenOutdatedSettings?: (() => any) | undefined;
35
35
  onTabChange?: ((tab: TopbarTab) => any) | undefined;
36
36
  }>, {
37
37
  showDrawerButton: boolean;
@@ -66,46 +66,46 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
66
66
  } & {
67
67
  delete: () => any;
68
68
  cancel: () => any;
69
+ settings: () => any;
70
+ send: (content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any;
71
+ newConversation: (groupId?: string | null | undefined) => any;
72
+ selectExecutionProfile: (profile: ChatExecutionProfile) => any;
73
+ copyLink: () => any;
69
74
  rename: () => any;
70
75
  duplicate: () => any;
71
76
  export: () => any;
72
- copyLink: () => any;
73
77
  debug: () => any;
74
- selectConversation: (id: string) => any;
75
- send: (content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any;
76
- settings: () => any;
77
- newConversation: (groupId?: string | null | undefined) => any;
78
- selectExecutionProfile: (profile: ChatExecutionProfile) => any;
79
78
  tabChange: (tab: TopbarTab) => any;
80
79
  switchWorkspace: () => any;
81
80
  signout: () => any;
82
81
  cancelEditing: () => any;
83
82
  dismissOutdatedBanner: () => any;
84
83
  saveTitle: () => any;
84
+ selectConversation: (id: string) => any;
85
85
  "update:drawerOpen": (value: boolean) => any;
86
86
  "update:editTitle": (value: string) => any;
87
87
  "update:workspaceSheetOpen": (value: boolean) => any;
88
88
  }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
89
89
  onDelete?: (() => any) | undefined;
90
90
  onCancel?: (() => any) | undefined;
91
- onRename?: (() => any) | undefined;
92
- onDuplicate?: (() => any) | undefined;
93
- onExport?: (() => any) | undefined;
94
- onCopyLink?: (() => any) | undefined;
95
- onDebug?: (() => any) | undefined;
96
- onSelectConversation?: ((id: string) => any) | undefined;
97
- onSend?: ((content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any) | undefined;
98
91
  onSettings?: (() => any) | undefined;
92
+ onSend?: ((content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any) | undefined;
99
93
  onNewConversation?: ((groupId?: string | null | undefined) => any) | undefined;
100
94
  onSelectExecutionProfile?: ((profile: ChatExecutionProfile) => any) | undefined;
101
95
  "onUpdate:selectedModel"?: ((value: string | null) => any) | undefined;
102
96
  "onUpdate:selectedReasoningEffort"?: ((value: any) => any) | undefined;
97
+ onCopyLink?: (() => any) | undefined;
98
+ onRename?: (() => any) | undefined;
99
+ onDuplicate?: (() => any) | undefined;
100
+ onExport?: (() => any) | undefined;
101
+ onDebug?: (() => any) | undefined;
103
102
  onTabChange?: ((tab: TopbarTab) => any) | undefined;
104
103
  onSwitchWorkspace?: (() => any) | undefined;
105
104
  onSignout?: (() => any) | undefined;
106
105
  onCancelEditing?: (() => any) | undefined;
107
106
  onDismissOutdatedBanner?: (() => any) | undefined;
108
107
  onSaveTitle?: (() => any) | undefined;
108
+ onSelectConversation?: ((id: string) => any) | undefined;
109
109
  "onUpdate:drawerOpen"?: ((value: boolean) => any) | undefined;
110
110
  "onUpdate:editTitle"?: ((value: string) => any) | undefined;
111
111
  "onUpdate:workspaceSheetOpen"?: ((value: boolean) => any) | undefined;
@@ -66,46 +66,46 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
66
66
  } & {
67
67
  delete: () => any;
68
68
  cancel: () => any;
69
+ settings: () => any;
70
+ send: (content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any;
71
+ newConversation: (groupId?: string | null | undefined) => any;
72
+ selectExecutionProfile: (profile: ChatExecutionProfile) => any;
73
+ copyLink: () => any;
69
74
  rename: () => any;
70
75
  duplicate: () => any;
71
76
  export: () => any;
72
- copyLink: () => any;
73
77
  debug: () => any;
74
- selectConversation: (id: string) => any;
75
- send: (content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any;
76
- settings: () => any;
77
- newConversation: (groupId?: string | null | undefined) => any;
78
- selectExecutionProfile: (profile: ChatExecutionProfile) => any;
79
78
  tabChange: (tab: TopbarTab) => any;
80
79
  switchWorkspace: () => any;
81
80
  signout: () => any;
82
81
  cancelEditing: () => any;
83
82
  dismissOutdatedBanner: () => any;
84
83
  saveTitle: () => any;
84
+ selectConversation: (id: string) => any;
85
85
  "update:drawerOpen": (value: boolean) => any;
86
86
  "update:editTitle": (value: string) => any;
87
87
  "update:workspaceSheetOpen": (value: boolean) => any;
88
88
  }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
89
89
  onDelete?: (() => any) | undefined;
90
90
  onCancel?: (() => any) | undefined;
91
- onRename?: (() => any) | undefined;
92
- onDuplicate?: (() => any) | undefined;
93
- onExport?: (() => any) | undefined;
94
- onCopyLink?: (() => any) | undefined;
95
- onDebug?: (() => any) | undefined;
96
- onSelectConversation?: ((id: string) => any) | undefined;
97
- onSend?: ((content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any) | undefined;
98
91
  onSettings?: (() => any) | undefined;
92
+ onSend?: ((content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any) | undefined;
99
93
  onNewConversation?: ((groupId?: string | null | undefined) => any) | undefined;
100
94
  onSelectExecutionProfile?: ((profile: ChatExecutionProfile) => any) | undefined;
101
95
  "onUpdate:selectedModel"?: ((value: string | null) => any) | undefined;
102
96
  "onUpdate:selectedReasoningEffort"?: ((value: any) => any) | undefined;
97
+ onCopyLink?: (() => any) | undefined;
98
+ onRename?: (() => any) | undefined;
99
+ onDuplicate?: (() => any) | undefined;
100
+ onExport?: (() => any) | undefined;
101
+ onDebug?: (() => any) | undefined;
103
102
  onTabChange?: ((tab: TopbarTab) => any) | undefined;
104
103
  onSwitchWorkspace?: (() => any) | undefined;
105
104
  onSignout?: (() => any) | undefined;
106
105
  onCancelEditing?: (() => any) | undefined;
107
106
  onDismissOutdatedBanner?: (() => any) | undefined;
108
107
  onSaveTitle?: (() => any) | undefined;
108
+ onSelectConversation?: ((id: string) => any) | undefined;
109
109
  "onUpdate:drawerOpen"?: ((value: boolean) => any) | undefined;
110
110
  "onUpdate:editTitle"?: ((value: string) => any) | undefined;
111
111
  "onUpdate:workspaceSheetOpen"?: ((value: boolean) => any) | undefined;
@@ -0,0 +1,7 @@
1
+ import type { WidgetGalleryStory } from '../../rendering/debug/widget-gallery.js';
2
+ type __VLS_Props = {
3
+ stories: readonly WidgetGalleryStory[];
4
+ };
5
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
6
+ declare const _default: typeof __VLS_export;
7
+ export default _default;
@@ -0,0 +1,218 @@
1
+ <script setup>
2
+ import { provideEmbedConfig } from "../../embed/composables/embed-config";
3
+ import ChatVaultLink from "../../files/components/chat-vault-link.vue";
4
+ import OpenuiBlock from "../../rendering/components/openui-block.vue";
5
+ import { buildSlackPreview, groupWidgetStories } from "../../rendering/debug/widget-gallery";
6
+ import { OPENUI_ERROR_REPORTER_KEY, OPENUI_MARKDOWN_COMPONENTS_KEY } from "../../rendering/openui/context";
7
+ import { CHAT_MESSAGE_CONTEXT_KEY, CHAT_MESSAGE_SEND_KEY } from "../../types/messages";
8
+ import { createChatDebugCitationsConfig } from "../debug/chat-debug-citations";
9
+ const props = defineProps({
10
+ stories: { type: Array, required: true }
11
+ });
12
+ const STREAM_TICK_MS = 40;
13
+ const STREAM_CHARACTERS_PER_TICK = 6;
14
+ const groups = computed(() => groupWidgetStories(props.stories));
15
+ const selectedId = ref(props.stories[0]?.id ?? "");
16
+ const selectedStory = computed(() => props.stories.find((story) => story.id === selectedId.value) ?? props.stories[0]);
17
+ const code = ref(selectedStory.value?.code ?? "");
18
+ const viewportWidth = ref("default");
19
+ const viewportOptions = [
20
+ { id: "narrow", label: "Narrow" },
21
+ { id: "default", label: "Default" },
22
+ { id: "wide", label: "Wide" }
23
+ ];
24
+ const streamedCharacters = ref(null);
25
+ const streaming = computed(() => streamedCharacters.value !== null);
26
+ const visibleCode = computed(() => streamedCharacters.value === null ? code.value : code.value.slice(0, streamedCharacters.value));
27
+ let streamTimer = null;
28
+ const mountRevision = ref(0);
29
+ const sentMessages = ref([]);
30
+ const widgetErrors = ref([]);
31
+ const slack = computed(() => buildSlackPreview(code.value));
32
+ const slackJson = computed(() => JSON.stringify(slack.value.blocks, null, 2));
33
+ provideEmbedConfig({
34
+ workspaceId: "chat-debug-widget-gallery",
35
+ hideSidebar: true,
36
+ citations: createChatDebugCitationsConfig()
37
+ }, { syncGlobal: false });
38
+ provide(CHAT_MESSAGE_CONTEXT_KEY, {
39
+ messageId: "chat-debug-widget-gallery",
40
+ role: "assistant",
41
+ isLatestMessage: ref(true),
42
+ streaming
43
+ });
44
+ provide(CHAT_MESSAGE_SEND_KEY, async (content) => {
45
+ sentMessages.value = [...sentMessages.value, content];
46
+ return true;
47
+ });
48
+ provide(OPENUI_ERROR_REPORTER_KEY, (errors) => {
49
+ widgetErrors.value = errors.map((error) => `${error.code}: ${error.message}`);
50
+ });
51
+ provide(OPENUI_MARKDOWN_COMPONENTS_KEY, ref({ link: ChatVaultLink }));
52
+ function stopStream() {
53
+ if (streamTimer)
54
+ clearInterval(streamTimer);
55
+ streamTimer = null;
56
+ streamedCharacters.value = null;
57
+ }
58
+ function remount() {
59
+ stopStream();
60
+ sentMessages.value = [];
61
+ widgetErrors.value = [];
62
+ mountRevision.value += 1;
63
+ }
64
+ function selectStory(story) {
65
+ selectedId.value = story.id;
66
+ code.value = story.code;
67
+ remount();
68
+ }
69
+ function playStream() {
70
+ remount();
71
+ streamedCharacters.value = 0;
72
+ streamTimer = setInterval(() => {
73
+ const next = (streamedCharacters.value ?? 0) + STREAM_CHARACTERS_PER_TICK;
74
+ if (next >= code.value.length)
75
+ stopStream();
76
+ else
77
+ streamedCharacters.value = next;
78
+ }, STREAM_TICK_MS);
79
+ }
80
+ async function copySlackJson() {
81
+ await navigator.clipboard.writeText(slackJson.value);
82
+ }
83
+ watch(code, () => {
84
+ widgetErrors.value = [];
85
+ });
86
+ onBeforeUnmount(stopStream);
87
+ </script>
88
+
89
+ <template>
90
+ <section class="chat-debug-widget-gallery" w-full h-full bg text-primary>
91
+ <aside px-20px py-22px overflow-y-auto>
92
+ <div v-for="group in groups" :key="group.name" mb-20px>
93
+ <div body-caption-9-medium text-tertiary mb-10px>
94
+ {{ group.name }}
95
+ </div>
96
+ <div flex="~ col" gap-4px>
97
+ <button
98
+ v-for="story in group.stories"
99
+ :key="story.id"
100
+ type="button"
101
+ py-5px
102
+ text-left
103
+ group
104
+ :data-story="story.id"
105
+ @click="selectStory(story)"
106
+ >
107
+ <div flex items-center gap-7px>
108
+ <span
109
+ w-4px h-4px rounded-full shrink-0
110
+ :class="story.id === selectedId ? 'bg-gray-900' : 'bg-gray-300 group-hover:bg-gray-500'"
111
+ transition-colors
112
+ />
113
+ <span
114
+ body-12-medium
115
+ truncate
116
+ :class="story.id === selectedId ? 'text-primary' : 'text-secondary group-hover:text-primary'"
117
+ transition-colors
118
+ >
119
+ {{ story.title }}
120
+ </span>
121
+ </div>
122
+ </button>
123
+ </div>
124
+ </div>
125
+ </aside>
126
+
127
+ <main min-w-0 min-h-0 flex="~ col">
128
+ <div h-48px px-24px flex items-center justify-between shrink-0>
129
+ <div flex items-center gap-8px body-11-regular text-tertiary>
130
+ <span>{{ selectedStory?.title }}</span>
131
+ <TelaDotSeparator />
132
+ <span>{{ streaming ? "streaming" : "complete" }}</span>
133
+ </div>
134
+ <div flex items-center gap-12px>
135
+ <div flex items-center gap-10px>
136
+ <button
137
+ v-for="option in viewportOptions"
138
+ :key="option.id"
139
+ type="button"
140
+ body-11-regular
141
+ :class="viewportWidth === option.id ? 'text-primary' : 'text-tertiary hover:text-secondary'"
142
+ transition-colors
143
+ @click="viewportWidth = option.id"
144
+ >
145
+ {{ option.label }}
146
+ </button>
147
+ </div>
148
+ <button type="button" body-11-regular text-tertiary hover:text-secondary transition-colors data-action="stream" @click="playStream">
149
+ Stream
150
+ </button>
151
+ <button type="button" body-11-regular text-tertiary hover:text-secondary transition-colors data-action="reset" @click="remount">
152
+ Reset
153
+ </button>
154
+ </div>
155
+ </div>
156
+
157
+ <div min-h-0 grow overflow-y-auto px-24px pb-24px>
158
+ <div class="widget-under-test" :class="`widget-under-test--${viewportWidth}`" data-gallery="web">
159
+ <OpenuiBlock :key="mountRevision" :node="{ type: 'code_block', raw: visibleCode, code: visibleCode }" :loading="streaming" />
160
+ </div>
161
+
162
+ <div class="widget-under-test" :class="`widget-under-test--${viewportWidth}`" mt-24px>
163
+ <div body-caption-9-medium text-tertiary mb-8px>
164
+ Sent messages
165
+ </div>
166
+ <p v-if="!sentMessages.length" body-11-regular text-tertiary>
167
+ Buttons, forms and questions list here the user message they send.
168
+ </p>
169
+ <pre v-for="(message, index) in sentMessages" :key="index" class="gallery-code" body-12-regular mb-8px data-gallery="sent">{{ message }}</pre>
170
+
171
+ <template v-if="widgetErrors.length">
172
+ <div body-caption-9-medium text-tertiary mt-16px mb-8px>
173
+ Widget errors
174
+ </div>
175
+ <pre class="gallery-code" body-12-regular text-red-600 data-gallery="errors">{{ widgetErrors.join("\n") }}</pre>
176
+ </template>
177
+ </div>
178
+ </div>
179
+ </main>
180
+
181
+ <aside min-h-0 px-24px py-22px flex="~ col" gap-20px overflow-y-auto>
182
+ <div>
183
+ <div body-caption-9-medium text-tertiary mb-8px>
184
+ OpenUI Lang
185
+ </div>
186
+ <textarea
187
+ v-model="code"
188
+ class="gallery-code gallery-editor"
189
+ body-12-regular
190
+ spellcheck="false"
191
+ data-gallery="code"
192
+ />
193
+ </div>
194
+
195
+ <div min-h-0>
196
+ <div flex items-center justify-between mb-8px>
197
+ <span body-caption-9-medium text-tertiary>Slack Block Kit · {{ slack.blocks.length }} blocks</span>
198
+ <span flex items-center gap-10px body-11-regular>
199
+ <button type="button" text-tertiary hover:text-secondary transition-colors @click="copySlackJson">
200
+ Copy
201
+ </button>
202
+ <a :href="slack.builderUrl" target="_blank" rel="noopener" text-tertiary hover:text-secondary transition-colors data-gallery="builder-link">
203
+ Block Kit Builder
204
+ </a>
205
+ </span>
206
+ </div>
207
+ <p body-11-regular text-tertiary mb-8px data-gallery="slack-note">
208
+ Renderer output, before the connector applies its own limits: it sends a long answer as a file instead of blocks.
209
+ </p>
210
+ <pre class="gallery-code" body-12-regular data-gallery="slack">{{ slackJson }}</pre>
211
+ </div>
212
+ </aside>
213
+ </section>
214
+ </template>
215
+
216
+ <style scoped>
217
+ .chat-debug-widget-gallery{display:grid;grid-template-columns:220px minmax(420px,1fr) minmax(360px,480px);overflow:hidden}.widget-under-test{margin-inline:auto;width:100%}.widget-under-test--narrow{max-width:520px}.widget-under-test--default{max-width:760px}.widget-under-test--wide{max-width:1040px}.gallery-code{background:#f9fafb;border:1px solid #e5e7eb;border-radius:8px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;margin:0;overflow-x:auto;padding:12px;white-space:pre-wrap;word-break:break-word}.gallery-editor{display:block;min-height:220px;outline:none;resize:vertical;width:100%}
218
+ </style>
@@ -0,0 +1,7 @@
1
+ import type { WidgetGalleryStory } from '../../rendering/debug/widget-gallery.js';
2
+ type __VLS_Props = {
3
+ stories: readonly WidgetGalleryStory[];
4
+ };
5
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
6
+ declare const _default: typeof __VLS_export;
7
+ export default _default;
@@ -0,0 +1,24 @@
1
+ import type { SlackBlock } from '@meistrari/chat-ui-lang';
2
+ export type WidgetGalleryStory = {
3
+ id: string;
4
+ group: string;
5
+ title: string;
6
+ /** One OpenUI Lang program, without its fence. */
7
+ code: string;
8
+ };
9
+ export type WidgetGalleryGroup = {
10
+ name: string;
11
+ stories: WidgetGalleryStory[];
12
+ };
13
+ export declare function groupWidgetStories(stories: readonly WidgetGalleryStory[]): WidgetGalleryGroup[];
14
+ export type SlackPreview = {
15
+ blocks: SlackBlock[];
16
+ /** The answer written out, which Slack uses for notifications. */
17
+ text: string;
18
+ builderUrl: string;
19
+ };
20
+ /**
21
+ * What the Slack renderer produces for one program, published in a thread so send buttons stay clickable. The connector
22
+ * applies its own limits after it, such as sending a long answer as a file.
23
+ */
24
+ export declare function buildSlackPreview(code: string): SlackPreview;
@@ -0,0 +1,25 @@
1
+ import { renderSlackAnswer, UI_LANG_FENCE } from "@meistrari/chat-ui-lang";
2
+ export function groupWidgetStories(stories) {
3
+ const groups = /* @__PURE__ */ new Map();
4
+ for (const story of stories)
5
+ groups.set(story.group, [...groups.get(story.group) ?? [], story]);
6
+ return [...groups].map(([name, grouped]) => ({ name, stories: grouped }));
7
+ }
8
+ const BLOCK_KIT_BUILDER_URL = "https://app.slack.com/block-kit-builder/";
9
+ const PREVIEW_THREAD_TS = "1700000000.000100";
10
+ const PREVIEW_MAX_BLOCKS = 40;
11
+ export function buildSlackPreview(code) {
12
+ const answer = code.trim() ? renderSlackAnswer(`\`\`\`${UI_LANG_FENCE}
13
+ ${code}
14
+ \`\`\``, {
15
+ prose: (text) => [{ type: "markdown", text }],
16
+ threadTs: PREVIEW_THREAD_TS,
17
+ maxBlocks: PREVIEW_MAX_BLOCKS
18
+ }) : null;
19
+ const blocks = answer?.blocks ?? [];
20
+ return {
21
+ blocks,
22
+ text: answer?.text ?? "",
23
+ builderUrl: `${BLOCK_KIT_BUILDER_URL}#${encodeURIComponent(JSON.stringify({ blocks }))}`
24
+ };
25
+ }
@@ -313,6 +313,7 @@ export declare const chatV3MessageSchema: z.ZodObject<{
313
313
  textInVault: z.ZodBoolean;
314
314
  reply: z.ZodString;
315
315
  createdAt: z.ZodString;
316
+ completedAt: z.ZodNullable<z.ZodString>;
316
317
  fileCount: z.ZodNumber;
317
318
  question: z.ZodNullable<z.ZodObject<{
318
319
  eventId: z.ZodString;
@@ -370,6 +371,7 @@ export declare const chatV3MessageListSchema: z.ZodObject<{
370
371
  textInVault: z.ZodBoolean;
371
372
  reply: z.ZodString;
372
373
  createdAt: z.ZodString;
374
+ completedAt: z.ZodNullable<z.ZodString>;
373
375
  fileCount: z.ZodNumber;
374
376
  question: z.ZodNullable<z.ZodObject<{
375
377
  eventId: z.ZodString;
@@ -235,6 +235,8 @@ export const chatV3MessageSchema = z.object({
235
235
  textInVault: z.boolean(),
236
236
  reply: z.string(),
237
237
  createdAt: z.string(),
238
+ /** When its turn ended (completed, failed, cancelled or uncertain); `null` while it is queued or running. */
239
+ completedAt: z.string().nullable(),
238
240
  /** Files sent with the message. agent-api keeps no name for them, so only how many. */
239
241
  fileCount: z.number().int().nonnegative(),
240
242
  /** What the agent asked while answering, if it did: its turn ended waiting for the answer. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
- "version": "4.13.0-rc.3",
3
+ "version": "4.13.0-rc.5",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -52,7 +52,7 @@
52
52
  "@iconify-json/ph": "^1.2.2",
53
53
  "@iconify/vue": "^5.0.0",
54
54
  "@meistrari/auth-nuxt": "3.31.0",
55
- "@meistrari/chat-ui-lang": "0.7.0",
55
+ "@meistrari/chat-ui-lang": "0.8.0-rc.1",
56
56
  "@meistrari/logger": "^2.1.3",
57
57
  "@meistrari/tela-build": "^1.79.0",
58
58
  "@openuidev/lang-core": "1.0.0",