@8wave/ai-elements 0.98.0-beta.5 → 0.99.0-beta.1

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 (76) hide show
  1. package/README.md +24 -5
  2. package/dist/_chunks/{PkToolShowForm-BNV4Ja6g.js → PkToolShowForm-dFuoqTPs.js} +84 -80
  3. package/dist/_chunks/PkToolShowForm-dFuoqTPs.js.map +1 -0
  4. package/dist/ai-elements.es.js +3153 -2982
  5. package/dist/ai-elements.es.js.map +1 -1
  6. package/dist-vue/PkChatbot.js +1 -1
  7. package/dist-vue/PkChatbotMessages.js +1 -1
  8. package/dist-vue/PkChatbotStepToolDetail.js +1 -1
  9. package/dist-vue/PkChatbotSteps.js +1 -1
  10. package/dist-vue/PkChatbotViewChat.js +1 -1
  11. package/dist-vue/PkChatbotViewConversations.js +1 -1
  12. package/dist-vue/PkChatbotViewFiles.js +1 -1
  13. package/dist-vue/PkChatbotViewProfile.js +1 -1
  14. package/dist-vue/_chunks/{PkChatbot-DHkhT0Jf.js → PkChatbot-BlG1WlAO.js} +7 -7
  15. package/dist-vue/_chunks/{PkChatbot-DHkhT0Jf.js.map → PkChatbot-BlG1WlAO.js.map} +1 -1
  16. package/dist-vue/_chunks/PkChatbotMessages-BrufA7o1.js +752 -0
  17. package/dist-vue/_chunks/PkChatbotMessages-BrufA7o1.js.map +1 -0
  18. package/dist-vue/_chunks/{PkChatbotStepToolDetail-ldThv0t5.js → PkChatbotStepToolDetail-BVI72gyx.js} +2 -2
  19. package/dist-vue/_chunks/{PkChatbotStepToolDetail-ldThv0t5.js.map → PkChatbotStepToolDetail-BVI72gyx.js.map} +1 -1
  20. package/dist-vue/_chunks/PkChatbotSteps-Dv9NkYER.js +172 -0
  21. package/dist-vue/_chunks/{PkChatbotSteps-BpqdFhsG.js.map → PkChatbotSteps-Dv9NkYER.js.map} +1 -1
  22. package/dist-vue/_chunks/{PkChatbotViewChat-C08TsXiL.js → PkChatbotViewChat-CAqvbbfN.js} +66 -66
  23. package/dist-vue/_chunks/PkChatbotViewChat-CAqvbbfN.js.map +1 -0
  24. package/dist-vue/_chunks/{PkChatbotViewConversations-BQZi5kSC.js → PkChatbotViewConversations-Cq41H-tc.js} +2 -2
  25. package/dist-vue/_chunks/{PkChatbotViewConversations-BQZi5kSC.js.map → PkChatbotViewConversations-Cq41H-tc.js.map} +1 -1
  26. package/dist-vue/_chunks/{PkChatbotViewFiles-TLKE_tRw.js → PkChatbotViewFiles-DNuzmBJc.js} +2 -2
  27. package/dist-vue/_chunks/{PkChatbotViewFiles-TLKE_tRw.js.map → PkChatbotViewFiles-DNuzmBJc.js.map} +1 -1
  28. package/dist-vue/_chunks/{PkChatbotViewProfile-B6ANZY96.js → PkChatbotViewProfile-C0BXIY2N.js} +2 -2
  29. package/dist-vue/_chunks/{PkChatbotViewProfile-B6ANZY96.js.map → PkChatbotViewProfile-C0BXIY2N.js.map} +1 -1
  30. package/dist-vue/_chunks/{PkToolShowForm-C-mWyeka.js → PkToolShowForm-CQuX08lk.js} +62 -58
  31. package/dist-vue/_chunks/PkToolShowForm-CQuX08lk.js.map +1 -0
  32. package/dist-vue/_chunks/{createChatbotApiClient-BOBdBxmf.js → createChatbotApiClient-BMZltBLh.js} +367 -363
  33. package/dist-vue/_chunks/createChatbotApiClient-BMZltBLh.js.map +1 -0
  34. package/dist-vue/_chunks/{useChatbotStore-BJ-EDmND.js → useChatbotStore-DZiorgLW.js} +113 -103
  35. package/dist-vue/_chunks/{useChatbotStore-BJ-EDmND.js.map → useChatbotStore-DZiorgLW.js.map} +1 -1
  36. package/dist-vue/_chunks/{utils-BMa8jwJS.js → utils-Cru8TJxe.js} +48 -30
  37. package/dist-vue/_chunks/utils-Cru8TJxe.js.map +1 -0
  38. package/dist-vue/api.js +1 -1
  39. package/dist-vue/composables.js +3 -3
  40. package/dist-vue/index.js +4351 -4041
  41. package/dist-vue/index.js.map +1 -1
  42. package/dist-vue/locales.js +16 -0
  43. package/dist-vue/packages/components/src/PkCheckboxField.d.ts +45 -0
  44. package/dist-vue/packages/components/src/PkEditorRepeater.d.ts +2 -2
  45. package/dist-vue/packages/components/src/PkPwaInstallPrompt.d.ts +4 -0
  46. package/dist-vue/packages/components/src/PkPwaOfflineNotice.d.ts +4 -0
  47. package/dist-vue/packages/components/src/chat/PkAgentSettingsPanel.d.ts +11 -2
  48. package/dist-vue/packages/components/src/chat/PkChatbotMessages.d.ts +24 -2
  49. package/dist-vue/packages/components/src/chat/PkToolApprovalBadge.d.ts +4 -0
  50. package/dist-vue/packages/components/src/chat/PkToolApprovalCard.d.ts +35 -0
  51. package/dist-vue/packages/components/src/chat/PkToolApprovalPreviewMessage.d.ts +11 -0
  52. package/dist-vue/packages/components/src/chat/index.d.ts +2 -1
  53. package/dist-vue/packages/components/src/chat/toolApprovalPreviews.d.ts +12 -0
  54. package/dist-vue/packages/components/src/chat/toolComponentMap.d.ts +5 -3
  55. package/dist-vue/packages/components/src/chat/useChatScroll.d.ts +6 -0
  56. package/dist-vue/packages/components/src/chat/utils.d.ts +13 -0
  57. package/dist-vue/packages/components/src/index.d.ts +4 -1
  58. package/dist-vue/packages/composable/src/chatbot/useChatbotStore.d.ts +34 -1
  59. package/dist-vue/packages/models/src/schema/Agent.d.ts +48 -0
  60. package/dist-vue/packages/models/src/schema/ReasoningChat.d.ts +6 -0
  61. package/dist-vue/packages/models/src/schema/SubAgent.d.ts +6 -0
  62. package/dist-vue/style.css +1 -1
  63. package/package.json +1 -1
  64. package/dist/_chunks/PkToolRequestConfirm-FQ9nDFXy.js +0 -48
  65. package/dist/_chunks/PkToolRequestConfirm-FQ9nDFXy.js.map +0 -1
  66. package/dist/_chunks/PkToolShowForm-BNV4Ja6g.js.map +0 -1
  67. package/dist-vue/_chunks/PkChatbotMessages-B4qfTNOJ.js +0 -630
  68. package/dist-vue/_chunks/PkChatbotMessages-B4qfTNOJ.js.map +0 -1
  69. package/dist-vue/_chunks/PkChatbotSteps-BpqdFhsG.js +0 -172
  70. package/dist-vue/_chunks/PkChatbotViewChat-C08TsXiL.js.map +0 -1
  71. package/dist-vue/_chunks/PkToolRequestConfirm-CQNa3seA.js +0 -48
  72. package/dist-vue/_chunks/PkToolRequestConfirm-CQNa3seA.js.map +0 -1
  73. package/dist-vue/_chunks/PkToolShowForm-C-mWyeka.js.map +0 -1
  74. package/dist-vue/_chunks/createChatbotApiClient-BOBdBxmf.js.map +0 -1
  75. package/dist-vue/_chunks/utils-BMa8jwJS.js.map +0 -1
  76. package/dist-vue/packages/components/src/chat/PkToolRequestConfirm.d.ts +0 -11
package/README.md CHANGED
@@ -122,7 +122,23 @@ widget.setAttribute('external-token', jwt) // Single session created
122
122
 
123
123
  > **Note:** The `external-token` value is validated server-side. On a 401 response the component silently re-authenticates with the active external token; if that fails it emits `external-auth-expired` and applies the fallback above. Listen for that event to hand the widget a fresh JWT via `signIn(token)`.
124
124
 
125
- > **Note:** In external token mode (`external-token` set, or `await-external-token` present) the host application owns the authentication lifecycle: the widget hides its own sign-out button and the profile management link in the profile panel. The GDPR "delete my conversations" action stays available.
125
+ > **Note:** In external token mode (`external-token` set, or `await-external-token` present) the host application owns the authentication lifecycle: the widget hides its own sign-out button, the profile management link in the profile panel, and the GDPR "delete my conversations" action. That action erases every conversation of the account platform-wide, well beyond the widget, so it belongs to the host application. Deleting a single conversation from the list stays available.
126
+
127
+ ### Host session (same-origin embeds)
128
+
129
+ When the page already holds an Eight Wave session cookie for the backend origin, add the `use-host-session` attribute: the widget reuses that session instead of creating one of its own. No anonymous sign-in happens, requests travel with the cookie (`credentials: 'include'`) rather than a widget Bearer, and the chat history belongs to the logged-in account instead of a per-browser anonymous user.
130
+
131
+ ```html
132
+ <floating-chat-widget
133
+ organization-slug="your-org-slug"
134
+ agent-id="your-agent-id"
135
+ use-host-session
136
+ ></floating-chat-widget>
137
+ ```
138
+
139
+ This only works where that cookie is actually sent, so it is meant for applications authenticating against the same Eight Wave backend (the Agent Studio copilot is the reference case) and not for third-party embeds. On a site with no such session the widget stays signed out: use `external-token` instead.
140
+
141
+ The attribute is reactive, so bind it to your login state and the widget re-reads the session when it flips. As with external token mode the host owns the auth lifecycle, so sign-out, profile management and the bulk GDPR erase are hidden, and `signOut()` is a no-op: revoking the session would log the user out of the host application too.
126
142
 
127
143
  ## Attributes
128
144
 
@@ -135,6 +151,7 @@ widget.setAttribute('external-token', jwt) // Single session created
135
151
  | `base-url` | `string` | ❌ | `https://ai-api.8wave.it` (build-time) | Base URL of the Eight Wave backend API. Override when self-hosting or pointing to a different environment. |
136
152
  | `external-token` | `string` | ❌ | — | Pre-existing auth token. **Reactive** — can be set or changed at any time. When set, the widget authenticates with this token instead of anonymous sign-in. |
137
153
  | `await-external-token` | `boolean` | ❌ | `false` | When present, the widget waits for `external-token` instead of signing in anonymously. Use when the token is fetched asynchronously after mount. |
154
+ | `use-host-session` | `boolean` | ❌ | `false` | Reuse the Eight Wave session cookie already present on the backend origin instead of creating a widget session. Same-origin embeds only, see Host session. |
138
155
  | `floating-button-position` | `'left' \| 'right'` | ❌ | `'right'` | Position of the floating toggle button on the screen. |
139
156
  | `system-theme` | `'light' \| 'dark'` | ❌ | OS `prefers-color-scheme` | Force the chat color scheme instead of following the OS preference. Reactive: update it when the host app's theme changes. |
140
157
  | `custom-css` | `string` | ❌ | — | Raw CSS string injected into the shadow root to override default styles. |
@@ -148,6 +165,7 @@ widget.setAttribute('external-token', jwt) // Single session created
148
165
  | `base-url` | `string` | ❌ | `https://ai-api.8wave.it` (build-time) | Base URL of the Eight Wave backend API. Override when self-hosting or pointing to a different environment. |
149
166
  | `external-token` | `string` | ❌ | — | Pre-existing auth token. **Reactive** — can be set or changed at any time. When set, the widget authenticates with this token instead of anonymous sign-in. |
150
167
  | `await-external-token` | `boolean` | ❌ | `false` | When present, the widget waits for `external-token` instead of signing in anonymously. Use when the token is fetched asynchronously after mount. |
168
+ | `use-host-session` | `boolean` | ❌ | `false` | Reuse the Eight Wave session cookie already present on the backend origin instead of creating a widget session. Same-origin embeds only, see Host session. |
151
169
  | `forwarded-slots` | `string` | ❌ | — | Comma-separated slot names to forward to `PkChatbot` (e.g. `"tool-showArtifact,subagent"`). |
152
170
  | `system-theme` | `'light' \| 'dark'` | ❌ | OS `prefers-color-scheme` | Force the chat color scheme instead of following the OS preference. Reactive: update it when the host app's theme changes. |
153
171
  | `custom-css` | `string` | ❌ | — | Raw CSS string injected into the shadow root to override default styles. |
@@ -243,7 +261,7 @@ widget.setContext({
243
261
 
244
262
  ## How it works
245
263
 
246
- 1. On mount the component automatically signs in as an anonymous user via the Eight Wave Auth service.
264
+ 1. On mount the component automatically signs in as an anonymous user via the Eight Wave Auth service, unless the host provides the identity (`external-token`) or lends its own session (`use-host-session`).
247
265
  2. Once authenticated it fetches the agent configuration (name, interface colors, etc.) from the public API.
248
266
  3. A circular floating button appears in the bottom-right corner, styled with the agent's `mainColor`.
249
267
  4. Clicking the button toggles the chat panel open/closed.
@@ -423,6 +441,7 @@ const { client, session, isAuthenticating, token, headers, onError, userId } = u
423
441
  | `basePath` | `string` | ❌ | Auth base path appended to `baseUrl`. Defaults to `auth`. |
424
442
  | `externalToken` | `MaybeRefOrGetter<string \| undefined>` | ❌ | Pre-existing auth token. Accepts a static string, a ref, or a getter. When the value is truthy, the composable authenticates with it instead of signing in anonymously. Reactive — authentication triggers automatically when the value changes. |
425
443
  | `awaitExternalToken` | `boolean` | ❌ | When `true`, the composable does not fall back to anonymous sign-in while `externalToken` is falsy. Authentication triggers automatically when the token value becomes available. |
444
+ | `useHostSession` | `MaybeRefOrGetter<boolean \| undefined>` | ❌ | When `true`, reuses the session cookie the host page already holds on the backend origin: no sign-in of any kind, requests carry the cookie instead of the widget Bearer, and the stored Bearer is never sent or overwritten. Reactive: the session is re-read when the value changes. Same-origin embeds only. |
426
445
  | `isActive` | `MaybeRefOrGetter<boolean>` | ❌ | Reactive signal that triggers authentication when it becomes `true`. Defaults to always active. |
427
446
  | `cookieName` | `string` | ❌ | Cookie name for session persistence. Defaults to `eight-wave-ai`. Use different names to isolate multiple sessions on the same page. |
428
447
  | `onSignedIn` | `(detail: { userId, isAnonymous }) => void` | ❌ | Called when a session is established or the user changes (any flow). |
@@ -436,13 +455,13 @@ const { client, session, isAuthenticating, token, headers, onError, userId } = u
436
455
  | `client` | `AuthClient` | The underlying Better Auth client instance. Exposes `signIn.anonymous()`, `signIn.externalToken({ token })`, and `useSession()`. |
437
456
  | `session` | `Ref<Session>` | Reactive session state from the auth client. |
438
457
  | `isAuthenticating`| `Ref<boolean>` | `true` while a sign-in request is in flight. |
439
- | `isExternalAuth` | `ComputedRef<boolean>` | `true` in external token mode (`externalToken` set or `awaitExternalToken` enabled). The host application owns the auth lifecycle: the profile panel hides sign-out and profile management. |
458
+ | `isExternalAuth` | `ComputedRef<boolean>` | `true` when the host application owns the session: external token mode (`externalToken` set or `awaitExternalToken` enabled) or `useHostSession`. The profile panel then hides sign-out, profile management and the bulk GDPR erase. |
440
459
  | `token` | `WritableComputedRef<string>` | Reactive Bearer token, synced to the first-party cookie. |
441
- | `headers` | `ComputedRef<Record<string, string> \| undefined>` | Reactive `Authorization` header derived from `token`. Pass directly to `useChatbotAgent` or `PkChatbot`. |
460
+ | `headers` | `ComputedRef<Record<string, string> \| undefined>` | Reactive `Authorization` header derived from `token`. Pass directly to `useChatbotAgent` or `PkChatbot`. `undefined` in host-session mode, where the cookie carries the identity. |
442
461
  | `onError` | `(error) => void` | Pass to `PkChatbot`'s `@error` event to trigger automatic re-auth on 401. |
443
462
  | `userId` | `ComputedRef<string \| undefined>` | Reactive user ID extracted from the session. Pass to `PkChatbot`'s `:user-id`. |
444
463
  | `signInWithExternalToken` | `(externalToken: string) => Promise<void>` | Authenticates with an external JWT (imperative equivalent of the `externalToken` option). |
445
- | `signOut` | `() => Promise<void>` | Signs out and withdraws the active external token, so no automatic re-login happens with it. |
464
+ | `signOut` | `() => Promise<void>` | Signs out and withdraws the active external token, so no automatic re-login happens with it. No-op in host-session mode: revoking the session would sign the user out of the host application too. |
446
465
 
447
466
  #### End-to-end example (Vue + external JWT)
448
467
 
@@ -118,22 +118,22 @@ var ue = {
118
118
  }, fe = {
119
119
  key: 1,
120
120
  class: "flex flex-col gap-4 p-sm"
121
- }, j = { class: "flex justify-between text-10 text-word-3" }, M = { class: "h-4 bg-surface-3 rounded-full overflow-hidden" }, N = { class: "px-sm py-16 flex flex-col gap-12" }, P = { class: "leading-normal text-12" }, F = { class: "font-semibold" }, I = { class: "text-12" }, L = { class: "font-semibold" }, R = {
121
+ }, pe = { class: "flex justify-between text-10 text-word-3" }, j = { class: "h-4 bg-surface-3 rounded-full overflow-hidden" }, M = { class: "px-sm py-16 flex flex-col gap-12" }, N = { class: "leading-normal text-12" }, P = { class: "font-semibold" }, F = { class: "text-12" }, I = { class: "font-semibold" }, L = {
122
122
  key: 0,
123
123
  class: "text-word-3"
124
- }, z = { class: "text-12" }, B = { class: "font-semibold" }, V = {
124
+ }, R = { class: "text-12" }, z = { class: "font-semibold" }, B = {
125
125
  key: 0,
126
126
  class: "text-word-3"
127
- }, pe = {
127
+ }, me = {
128
128
  key: 2,
129
129
  class: "flex flex-col gap-6 w-full"
130
- }, me = {
130
+ }, V = {
131
131
  key: 0,
132
132
  class: "px-sm pb-sm border-t border-surface-3"
133
- }, H = {
133
+ }, he = {
134
134
  key: 1,
135
135
  class: "px-sm py-10 bg-surface border-t border-surface-3 flex justify-between gap-12"
136
- }, he = { key: 1 }, ge = { class: "px-sm py-12 bg-surface space-y-10" }, _e = { class: "flex flex-col gap-8" }, ve = { class: "text-12 text-word-3" }, ye = { class: "text-12 text-word-2 font-semibold" }, be = { class: "px-sm py-12 bg-surface border-t border-surface-3 flex items-center gap-10" }, xe = { class: "w-20 h-20 rounded-full border border-success text-success flex items-center justify-center" }, Se = { class: "flex flex-col" }, Ce = { class: "font-semibold text-12 text-word-1 leading-tight" }, U = /* @__PURE__ */ l({
136
+ }, ge = { key: 1 }, _e = { class: "px-sm py-12 bg-surface space-y-10" }, ve = { class: "flex flex-col gap-8" }, ye = { class: "text-12 text-word-3" }, be = { class: "text-12 text-word-2 font-semibold" }, xe = { class: "px-sm py-12 bg-surface border-t border-surface-3 flex items-center gap-10" }, Se = { class: "w-20 h-20 rounded-full border border-success text-success flex items-center justify-center" }, Ce = { class: "flex flex-col" }, we = { class: "font-semibold text-12 text-word-1 leading-tight" }, H = /* @__PURE__ */ l({
137
137
  __name: "PkToolShowForm",
138
138
  props: {
139
139
  part: { type: null },
@@ -142,36 +142,36 @@ var ue = {
142
142
  emits: ["select"],
143
143
  setup(e, { emit: n }) {
144
144
  let i = e, a = n, { t: o, d: c } = re({ useScope: "global" }), l = g(() => JSON.parse(JSON.stringify(i.part))), f = g(() => l.value.toolName === "showMultipleChoice" || l.value.type === "tool-showMultipleChoice"), _ = g(() => l.value.state === "input-available"), v = g(() => {
145
- let e = A.value;
146
- return e ? O.value.length === 1 && !e.allowFreeformInput && !i.allowCustomAnswer : !1;
147
- }), D = g(() => f.value && O.value.length === 1 && !A.value?.multiSelect), O = g(() => {
145
+ let e = H.value;
146
+ return e ? k.value.length === 1 && !e.allowFreeformInput && !i.allowCustomAnswer : !1;
147
+ }), D = g(() => f.value && k.value.length === 1 && !H.value?.multiSelect), O = g(() => !!H.value?.options && !H.value?.multiSelect && (v.value || D.value)), k = g(() => {
148
148
  let e = l.value.input;
149
149
  return e?.steps?.length ? e.steps : e?.question && e?.options ? [{
150
150
  id: "legacy",
151
151
  question: e.question,
152
152
  options: e.options.map((e) => typeof e == "string" ? { label: e } : e)
153
153
  }] : [];
154
- }), k = y(0), A = g(() => O.value[k.value]), U = g(() => k.value > 0), W = g(() => k.value < O.value.length - 1), G = g(() => O.value.length > 1), K = g(() => G.value ? Math.round((k.value + 1) / O.value.length * 100) : null), q = ne({}), J = y(""), Y = g({
154
+ }), A = y(0), H = g(() => k.value[A.value]), U = g(() => A.value > 0), W = g(() => A.value < k.value.length - 1), Te = g(() => k.value.length > 1), G = g(() => Te.value ? Math.round((A.value + 1) / k.value.length * 100) : null), K = ne({}), q = y(""), J = g({
155
155
  get: () => {
156
- let e = A.value ? q[A.value.id] : void 0;
156
+ let e = H.value ? K[H.value.id] : void 0;
157
157
  if (!(e == null || Array.isArray(e))) return e;
158
158
  },
159
159
  set: (e) => {
160
- A.value && (q[A.value.id] = e ?? null);
160
+ H.value && (K[H.value.id] = e ?? null);
161
161
  }
162
- }), X = g({
162
+ }), Y = g({
163
163
  get: () => {
164
- let e = A.value ? q[A.value.id] : void 0;
164
+ let e = H.value ? K[H.value.id] : void 0;
165
165
  return Array.isArray(e) ? e : [];
166
166
  },
167
167
  set: (e) => {
168
- A.value && (q[A.value.id] = e ?? []);
168
+ H.value && (K[H.value.id] = e ?? []);
169
169
  }
170
170
  });
171
171
  s(() => l.value.output, (e) => {
172
172
  if (e) {
173
- if (typeof e == "string") O.value.length === 1 && (q[O.value[0].id] = e);
174
- else if (e.answers) for (let t of e.answers) q[t.id] = t.value;
173
+ if (typeof e == "string") k.value.length === 1 && (K[k.value[0].id] = e);
174
+ else if (e.answers) for (let t of e.answers) K[t.id] = t.value;
175
175
  }
176
176
  }, { immediate: !0 }), s(g(() => {
177
177
  let e = l.value.output;
@@ -183,101 +183,105 @@ var ue = {
183
183
  }
184
184
  }
185
185
  }), (e) => {
186
- !e || !A.value || (A.value.options ?? []).map((e) => e.label).includes(e) || (J.value = e);
186
+ !e || !H.value || (H.value.options ?? []).map((e) => e.label).includes(e) || (q.value = e);
187
187
  }, { immediate: !0 });
188
- let Z = g(() => A.value?.options ? A.value.options.map((e) => ({
188
+ let X = g(() => H.value?.options ? H.value.options.map((e) => ({
189
189
  label: e.label,
190
190
  value: e.label,
191
191
  description: e.description
192
192
  })) : []);
193
- function Q() {
194
- W.value ? k.value++ : $();
193
+ function Z() {
194
+ if (q.value.trim()) {
195
+ $();
196
+ return;
197
+ }
198
+ W.value ? A.value++ : Q();
195
199
  }
196
- function we() {
197
- U.value && k.value--;
200
+ function Ee() {
201
+ U.value && A.value--;
198
202
  }
199
- function $() {
203
+ function Q() {
200
204
  if (!_.value) return;
201
- let e = O.value.map((e) => ({
205
+ let e = k.value.map((e) => ({
202
206
  id: e.id,
203
- value: q[e.id] ?? null
207
+ value: K[e.id] ?? null
204
208
  }));
205
- if (D.value && !A.value?.allowFreeformInput) {
209
+ if (D.value && !H.value?.allowFreeformInput) {
206
210
  let t = e[0].value;
207
211
  a("select", Array.isArray(t) ? t[0] : t);
208
212
  } else a("select", { answers: e });
209
213
  }
210
- function Te() {
211
- let e = J.value.trim();
212
- e && (q[A.value.id] = e, O.value.length === 1 ? $() : Q(), J.value = "");
214
+ function $() {
215
+ let e = q.value.trim();
216
+ e && (K[H.value.id] = e, q.value = "", k.value.length === 1 ? Q() : Z());
213
217
  }
214
- function Ee() {
215
- _.value && (v.value || D.value) && $();
218
+ function De() {
219
+ _.value && (v.value || D.value) && Q();
216
220
  }
217
- function De(e) {
218
- let t = q[e.id];
221
+ function Oe(e) {
222
+ let t = K[e.id];
219
223
  return t == null ? "—" : Array.isArray(t) ? t.join(", ") : e.type === "date" ? c(new Date(t), "short") : t;
220
224
  }
221
225
  return (e, n) => {
222
226
  let i = ae, a = oe, s = ie;
223
- return O.value.length ? (E(), p("div", ue, [l.value.input?.title || _.value && O.value.length > 1 ? (E(), p("div", de, [l.value.input?.title ? (E(), p("div", {
227
+ return k.value.length ? (E(), p("div", ue, [l.value.input?.title || _.value && k.value.length > 1 ? (E(), p("div", de, [l.value.input?.title ? (E(), p("div", {
224
228
  key: 0,
225
- class: r(["px-sm py-10 font-bold", { "border-b border-surface-3": _.value && O.value.length > 1 }])
226
- }, x(l.value.input?.title), 3)) : T("", !0), _.value && O.value.length > 1 ? (E(), p("div", fe, [d("div", j, [d("span", null, x(w(o)("showForm.step", {
227
- current: k.value + 1,
228
- total: O.value.length
229
- })), 1), d("span", null, x(K.value) + "%", 1)]), d("div", M, [d("div", {
229
+ class: r(["px-sm py-10 font-bold", { "border-b border-surface-3": _.value && k.value.length > 1 }])
230
+ }, x(l.value.input?.title), 3)) : T("", !0), _.value && k.value.length > 1 ? (E(), p("div", fe, [d("div", pe, [d("span", null, x(w(o)("showForm.step", {
231
+ current: A.value + 1,
232
+ total: k.value.length
233
+ })), 1), d("span", null, x(G.value) + "%", 1)]), d("div", j, [d("div", {
230
234
  class: "h-full bg-word-4 transition-all duration-300",
231
- style: ee({ width: `${K.value}%` })
235
+ style: ee({ width: `${G.value}%` })
232
236
  }, null, 4)])])) : T("", !0)])) : T("", !0), _.value ? (E(), p(b, { key: 1 }, [
233
- d("div", N, [d("div", P, [d("strong", F, x(A.value.question), 1), A.value.message ? (E(), S(se, {
237
+ d("div", M, [d("div", N, [d("strong", P, x(H.value.question), 1), H.value.message ? (E(), S(se, {
234
238
  key: 0,
235
- markdown: A.value.message,
239
+ markdown: H.value.message,
236
240
  class: "text-word-2 mt-4"
237
- }, null, 8, ["markdown"])) : T("", !0)]), A.value.options && A.value.multiSelect ? (E(), S(le, {
241
+ }, null, 8, ["markdown"])) : T("", !0)]), H.value.options && H.value.multiSelect ? (E(), S(le, {
238
242
  key: 0,
239
- modelValue: X.value,
240
- "onUpdate:modelValue": n[0] ||= (e) => X.value = e,
241
- name: A.value.id,
242
- options: Z.value,
243
+ modelValue: Y.value,
244
+ "onUpdate:modelValue": n[0] ||= (e) => Y.value = e,
245
+ name: H.value.id,
246
+ options: X.value,
243
247
  readonly: !_.value,
244
248
  class: "mb-0",
245
249
  vertical: ""
246
- }, C({ _: 2 }, [u(Z.value, (e) => ({
250
+ }, C({ _: 2 }, [u(X.value, (e) => ({
247
251
  name: e.value,
248
- fn: m(() => [d("div", I, [d("div", L, x(e.label), 1), e.description ? (E(), p("div", R, x(e.description), 1)) : T("", !0)])])
252
+ fn: m(() => [d("div", F, [d("div", I, x(e.label), 1), e.description ? (E(), p("div", L, x(e.description), 1)) : T("", !0)])])
249
253
  }))]), 1032, [
250
254
  "modelValue",
251
255
  "name",
252
256
  "options",
253
257
  "readonly"
254
- ])) : A.value.options && !A.value.multiSelect ? (E(), S(ce, {
258
+ ])) : H.value.options && !H.value.multiSelect ? (E(), S(ce, {
255
259
  key: 1,
256
- modelValue: Y.value,
257
- "onUpdate:modelValue": [n[1] ||= (e) => Y.value = e, Ee],
258
- name: A.value.id,
259
- options: Z.value,
260
+ modelValue: J.value,
261
+ "onUpdate:modelValue": [n[1] ||= (e) => J.value = e, De],
262
+ name: H.value.id,
263
+ options: X.value,
260
264
  readonly: !_.value,
261
265
  vertical: "",
262
266
  class: "mb-0"
263
- }, C({ _: 2 }, [u(Z.value, (e) => ({
267
+ }, C({ _: 2 }, [u(X.value, (e) => ({
264
268
  name: e.value,
265
- fn: m(() => [d("div", z, [d("div", B, x(e.label), 1), e.description ? (E(), p("div", V, x(e.description), 1)) : T("", !0)])])
269
+ fn: m(() => [d("div", R, [d("div", z, x(e.label), 1), e.description ? (E(), p("div", B, x(e.description), 1)) : T("", !0)])])
266
270
  }))]), 1032, [
267
271
  "modelValue",
268
272
  "name",
269
273
  "options",
270
274
  "readonly"
271
- ])) : A.value.options ? T("", !0) : (E(), p("div", pe, [t(i, {
272
- modelValue: Y.value,
273
- "onUpdate:modelValue": n[2] ||= (e) => Y.value = e,
274
- placeholder: A.value.placeholder || w(o)("placeholder.insert"),
275
- type: A.value.type,
275
+ ])) : H.value.options ? T("", !0) : (E(), p("div", me, [t(i, {
276
+ modelValue: J.value,
277
+ "onUpdate:modelValue": n[2] ||= (e) => J.value = e,
278
+ placeholder: H.value.placeholder || w(o)("placeholder.insert"),
279
+ type: H.value.type,
276
280
  class: "w-full",
277
- name: A.value.id,
281
+ name: H.value.id,
278
282
  modifiers: "compact rounded",
279
283
  disabled: !_.value,
280
- onKeyup: te(Q, ["enter"])
284
+ onKeyup: te(Z, ["enter"])
281
285
  }, null, 8, [
282
286
  "modelValue",
283
287
  "placeholder",
@@ -285,51 +289,51 @@ var ue = {
285
289
  "name",
286
290
  "disabled"
287
291
  ])]))]),
288
- A.value.allowFreeformInput && A.value.options ? (E(), p("div", me, [d("form", {
292
+ H.value.allowFreeformInput && H.value.options ? (E(), p("div", V, [d("form", {
289
293
  class: "flex gap-xs pt-sm",
290
- onSubmit: h(Te, ["prevent"])
294
+ onSubmit: h($, ["prevent"])
291
295
  }, [t(i, {
292
- modelValue: J.value,
293
- "onUpdate:modelValue": n[3] ||= (e) => J.value = e,
296
+ modelValue: q.value,
297
+ "onUpdate:modelValue": n[3] ||= (e) => q.value = e,
294
298
  class: "flex-1",
295
- name: `${A.value.id}-custom`,
299
+ name: `${H.value.id}-custom`,
296
300
  modifiers: "compact rounded",
297
301
  disabled: !_.value,
298
- placeholder: A.value.placeholder || w(o)("showForm.otherPlaceholder")
302
+ placeholder: H.value.placeholder || w(o)("showForm.otherPlaceholder")
299
303
  }, null, 8, [
300
304
  "modelValue",
301
305
  "name",
302
306
  "disabled",
303
307
  "placeholder"
304
308
  ])], 32)])) : T("", !0),
305
- G.value || A.value.multiSelect || !A.value.options ? (E(), p("div", H, [U.value ? (E(), S(a, {
309
+ O.value ? T("", !0) : (E(), p("div", he, [U.value ? (E(), S(a, {
306
310
  key: 0,
307
311
  modifiers: "action-quiet",
308
312
  icon: "ri:arrow-left-s-line",
309
313
  label: w(o)("action.back"),
310
- onClick: h(we, ["stop"])
311
- }, null, 8, ["label"])) : (E(), p("div", he)), t(a, {
314
+ onClick: h(Ee, ["stop"])
315
+ }, null, 8, ["label"])) : (E(), p("div", ge)), t(a, {
312
316
  modifiers: W.value ? "action-quiet" : "action-primary",
313
317
  icon: W.value ? "ri:arrow-right-s-line" : "ri:send-plane-2-line",
314
318
  "icon-position": "right",
315
319
  label: W.value ? w(o)("action.next") : w(o)("action.submit"),
316
- onClick: h(Q, ["stop"])
320
+ onClick: h(Z, ["stop"])
317
321
  }, null, 8, [
318
322
  "modifiers",
319
323
  "icon",
320
324
  "label"
321
- ])])) : T("", !0)
322
- ], 64)) : (E(), p(b, { key: 2 }, [d("div", ge, [d("ul", _e, [(E(!0), p(b, null, u(O.value, (e) => (E(), p("li", {
325
+ ])]))
326
+ ], 64)) : (E(), p(b, { key: 2 }, [d("div", _e, [d("ul", ve, [(E(!0), p(b, null, u(k.value, (e) => (E(), p("li", {
323
327
  key: e.id,
324
328
  class: "leading-normal"
325
- }, [d("div", ve, x(e.question), 1), d("span", ye, x(De(e)), 1)]))), 128))])]), d("div", be, [d("div", xe, [t(s, {
329
+ }, [d("div", ye, x(e.question), 1), d("span", be, x(Oe(e)), 1)]))), 128))])]), d("div", xe, [d("div", Se, [t(s, {
326
330
  name: "ri:check-line",
327
331
  class: "text-12"
328
- })]), d("div", Se, [d("span", Ce, x(w(o)("showForm.completed")), 1)])])], 64))])) : T("", !0);
332
+ })]), d("div", Ce, [d("span", we, x(w(o)("showForm.completed")), 1)])])], 64))])) : T("", !0);
329
333
  };
330
334
  }
331
335
  });
332
336
  //#endregion
333
- export { U as default };
337
+ export { H as default };
334
338
 
335
- //# sourceMappingURL=PkToolShowForm-BNV4Ja6g.js.map
339
+ //# sourceMappingURL=PkToolShowForm-dFuoqTPs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PkToolShowForm-dFuoqTPs.js","names":[],"sources":["../../../../packages/components/src/PkEditorRadioButtons.vue","../../../../packages/components/src/PkEditorRadioButtons.vue","../../../../packages/components/src/PkEditorCheckboxButtons.vue","../../../../packages/components/src/PkEditorCheckboxButtons.vue","../../../../packages/components/src/chat/PkToolShowForm.vue","../../../../packages/components/src/chat/PkToolShowForm.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import type { Option } from '@volverjs/ui-vue'\n import { computed } from 'vue'\n\n const props = defineProps<{\n name: string\n required?: boolean\n options: Option[]\n readonly?: boolean\n disabled?: boolean\n modifiers?: string | string[]\n }>()\n\n const modelValue = defineModel<\n string | number | boolean | symbol | unknown[] | undefined\n >()\n\n const radioModifiers = computed(() => {\n const toReturn = props.modifiers\n ? Array.isArray(props.modifiers)\n ? props.modifiers\n : [props.modifiers]\n : []\n return [...toReturn, 'button']\n })\n</script>\n\n<template>\n <VvRadioGroup v-model=\"modelValue\" :name modifiers=\"buttons\">\n <VvRadio\n v-for=\"(option, key) in options\"\n :key\n :name\n :required\n :readonly\n :disabled\n :value=\"option.value\"\n :modifiers=\"radioModifiers\">\n <slot :name=\"option.value\" v-bind=\"{ option }\">\n {{ option.label }}\n </slot>\n </VvRadio>\n </VvRadioGroup>\n</template>\n","<script setup lang=\"ts\">\n import type { Option } from '@volverjs/ui-vue'\n import { computed } from 'vue'\n\n const props = defineProps<{\n name: string\n required?: boolean\n options: Option[]\n readonly?: boolean\n disabled?: boolean\n modifiers?: string | string[]\n }>()\n\n const modelValue = defineModel<\n string | number | boolean | symbol | unknown[] | undefined\n >()\n\n const radioModifiers = computed(() => {\n const toReturn = props.modifiers\n ? Array.isArray(props.modifiers)\n ? props.modifiers\n : [props.modifiers]\n : []\n return [...toReturn, 'button']\n })\n</script>\n\n<template>\n <VvRadioGroup v-model=\"modelValue\" :name modifiers=\"buttons\">\n <VvRadio\n v-for=\"(option, key) in options\"\n :key\n :name\n :required\n :readonly\n :disabled\n :value=\"option.value\"\n :modifiers=\"radioModifiers\">\n <slot :name=\"option.value\" v-bind=\"{ option }\">\n {{ option.label }}\n </slot>\n </VvRadio>\n </VvRadioGroup>\n</template>\n","<script setup lang=\"ts\">\n import type { Option } from '@volverjs/ui-vue'\n\n defineProps<{\n name: string\n required?: boolean\n options: Option[]\n readonly?: boolean\n disabled?: boolean\n }>()\n\n const modelValue = defineModel<unknown[] | undefined>()\n</script>\n\n<template>\n <VvCheckboxGroup v-model=\"modelValue\" :name modifiers=\"buttons\">\n <VvCheckbox\n v-for=\"(option, key) in options\"\n :key\n :name\n :required\n :readonly\n :disabled\n :value=\"option.value\"\n modifiers=\"button\">\n <slot :name=\"String(option.value)\" v-bind=\"{ option }\">\n {{ option.label }}\n </slot>\n </VvCheckbox>\n </VvCheckboxGroup>\n</template>\n","<script setup lang=\"ts\">\n import type { Option } from '@volverjs/ui-vue'\n\n defineProps<{\n name: string\n required?: boolean\n options: Option[]\n readonly?: boolean\n disabled?: boolean\n }>()\n\n const modelValue = defineModel<unknown[] | undefined>()\n</script>\n\n<template>\n <VvCheckboxGroup v-model=\"modelValue\" :name modifiers=\"buttons\">\n <VvCheckbox\n v-for=\"(option, key) in options\"\n :key\n :name\n :required\n :readonly\n :disabled\n :value=\"option.value\"\n modifiers=\"button\">\n <slot :name=\"String(option.value)\" v-bind=\"{ option }\">\n {{ option.label }}\n </slot>\n </VvCheckbox>\n </VvCheckboxGroup>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref, reactive, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import PkEditorRadioButtons from '../PkEditorRadioButtons.vue'\n import PkEditorCheckboxButtons from '../PkEditorCheckboxButtons.vue'\n\n // --- Types ---\n\n interface FormOption {\n label: string\n description?: string\n }\n\n interface FormStep {\n id: string\n question: string\n message?: string\n type?: 'text' | 'number' | 'date'\n options?: FormOption[]\n multiSelect?: boolean\n allowFreeformInput?: boolean\n placeholder?: string\n }\n\n interface FormAnswer {\n id: string\n value: string | string[] | number | null\n }\n\n interface ToolPartShape {\n state?: 'input-available' | 'output-available'\n toolCallId?: string\n // AI SDK v5 encodes the tool name in `type` (e.g. 'tool-showMultipleChoice').\n // `toolName` is kept for backward compatibility but is normally absent.\n type?: string\n toolName?: string\n input?: {\n title?: string\n steps?: FormStep[]\n // Legacy showMultipleChoice fields\n question?: string\n options?: (string | FormOption)[]\n }\n output?: string | { answers: FormAnswer[] }\n }\n\n type AnswerValue = string | string[] | number | null\n\n // --- Props & Emits ---\n\n const props = defineProps<{\n part: unknown\n allowCustomAnswer?: boolean\n }>()\n\n const emit = defineEmits<{\n select: [answer: string | { answers: FormAnswer[] }]\n }>()\n\n const { t: $t, d: $d } = useI18n({ useScope: 'global' })\n\n // --- Parsed tool part ---\n\n const toolPart = computed(\n () => JSON.parse(JSON.stringify(props.part)) as ToolPartShape,\n )\n\n const isLegacy = computed(\n () =>\n toolPart.value.toolName === 'showMultipleChoice' ||\n toolPart.value.type === 'tool-showMultipleChoice',\n )\n\n const isInteractive = computed(\n () => toolPart.value.state === 'input-available',\n )\n\n /** Single-step with no custom-answer and no freeform → auto-submit on option pick */\n const isAutoSubmitStep = computed(() => {\n const step = currentStep.value\n if (!step) return false\n return (\n steps.value.length === 1 &&\n !step.allowFreeformInput &&\n !props.allowCustomAnswer\n )\n })\n\n /** Legacy tool should auto-submit on option pick regardless of allowCustomAnswer */\n const isLegacyAutoSubmit = computed(\n () =>\n isLegacy.value &&\n steps.value.length === 1 &&\n !currentStep.value?.multiSelect,\n )\n\n /**\n * True only for the steps that send themselves as soon as an option is\n * picked: the single case where the footer button would be redundant.\n * Every other shape needs it, single-step forms included: with\n * `allowFreeformInput` (or `allowCustomAnswer`) the radio pick no longer\n * auto-submits, so without the footer the user was left with a chosen\n * option and no way to send it.\n */\n const isSelfSubmitting = computed(\n () =>\n Boolean(currentStep.value?.options) &&\n !currentStep.value?.multiSelect &&\n (isAutoSubmitStep.value || isLegacyAutoSubmit.value),\n )\n\n // --- Steps ---\n\n const steps = computed<FormStep[]>(() => {\n const input = toolPart.value.input\n if (input?.steps?.length) {\n return input.steps\n }\n // Legacy showMultipleChoice → normalize into a single step\n if (input?.question && input?.options) {\n return [\n {\n id: 'legacy',\n question: input.question,\n options: input.options.map((o) =>\n typeof o === 'string' ? { label: o } : o,\n ),\n },\n ]\n }\n return []\n })\n\n // --- Navigation state ---\n\n const currentStepIndex = ref(0)\n const currentStep = computed(() => steps.value[currentStepIndex.value])\n const canGoBack = computed(() => currentStepIndex.value > 0)\n const canGoNext = computed(\n () => currentStepIndex.value < steps.value.length - 1,\n )\n const isMultiStep = computed(() => steps.value.length > 1)\n\n const progress = computed(() => {\n if (!isMultiStep.value) return null\n return Math.round(\n ((currentStepIndex.value + 1) / steps.value.length) * 100,\n )\n })\n\n // --- Answers ---\n\n const answers = reactive<Record<string, AnswerValue>>({})\n const customAnswer = ref('')\n\n // Single scalar answer shared by radio buttons and freeform text/number/date inputs.\n const scalarValue = computed<string | number | undefined>({\n get: () => {\n const val = currentStep.value\n ? answers[currentStep.value.id]\n : undefined\n if (val == null || Array.isArray(val)) return undefined\n return val\n },\n set: (val) => {\n if (currentStep.value) {\n answers[currentStep.value.id] = val ?? null\n }\n },\n })\n\n const activeCheckboxValue = computed<unknown[] | undefined>({\n get: () => {\n const val = currentStep.value\n ? answers[currentStep.value.id]\n : undefined\n return Array.isArray(val) ? val : []\n },\n set: (val) => {\n if (currentStep.value) {\n answers[currentStep.value.id] = (val as string[]) ?? []\n }\n },\n })\n\n // --- Initialize answers from existing output ---\n\n watch(\n () => toolPart.value.output,\n (output) => {\n if (!output) return\n if (typeof output === 'string') {\n if (steps.value.length === 1) {\n answers[steps.value[0].id] = output\n }\n } else if (output.answers) {\n for (const a of output.answers) {\n answers[a.id] = a.value\n }\n }\n },\n { immediate: true },\n )\n\n // --- Restore custom answer from output when it doesn't match any option ---\n\n const normalizedOutput = computed(() => {\n const out = toolPart.value.output\n if (!out) return undefined\n if (typeof out === 'string') return out\n if (out.answers?.length === 1) {\n const val = out.answers[0].value\n return Array.isArray(val) ? val.join(', ') : String(val)\n }\n return undefined\n })\n\n watch(\n normalizedOutput,\n (value) => {\n if (!value || !currentStep.value) return\n const optionLabels = (currentStep.value.options ?? []).map(\n (o) => o.label,\n )\n if (!optionLabels.includes(value)) {\n customAnswer.value = value\n }\n },\n { immediate: true },\n )\n\n // --- Option mapping for radio/checkbox components ---\n\n const radioOptions = computed(() => {\n if (!currentStep.value?.options) return []\n return currentStep.value.options.map((option) => ({\n label: option.label,\n value: option.label,\n description: option.description,\n }))\n })\n\n // --- Navigation & Submission ---\n\n function goNext() {\n // A typed freeform answer wins over the picked option: it is the more\n // recent intent, and the footer button is now the visible way to send\n // it (the freeform field only submits on Enter).\n if (customAnswer.value.trim()) {\n submitCustomAnswer()\n return\n }\n if (canGoNext.value) {\n currentStepIndex.value++\n } else {\n submitForm()\n }\n }\n\n function goBack() {\n if (canGoBack.value) {\n currentStepIndex.value--\n }\n }\n\n function submitForm() {\n if (!isInteractive.value) return\n\n const finalAnswers: FormAnswer[] = steps.value.map((step) => ({\n id: step.id,\n value: answers[step.id] ?? null,\n }))\n\n // Legacy backward compatibility: single-step, single-select → return plain string\n if (\n isLegacyAutoSubmit.value &&\n !currentStep.value?.allowFreeformInput\n ) {\n const val = finalAnswers[0].value\n emit('select', Array.isArray(val) ? val[0] : (val as string))\n } else {\n emit('select', { answers: finalAnswers })\n }\n }\n\n function submitCustomAnswer() {\n const value = customAnswer.value.trim()\n if (!value) return\n\n answers[currentStep.value.id] = value\n // Cleared before navigating: `goNext()` reads it back to route a typed\n // answer here, so leaving it set would recurse.\n customAnswer.value = ''\n if (steps.value.length === 1) {\n submitForm()\n } else {\n goNext()\n }\n }\n\n function onRadioChange() {\n if (!isInteractive.value) return\n if (isAutoSubmitStep.value || isLegacyAutoSubmit.value) {\n submitForm()\n }\n }\n\n // --- Summary helpers ---\n\n function getSummaryValue(step: FormStep) {\n const val = answers[step.id]\n if (val == null) return '—'\n if (Array.isArray(val)) return val.join(', ')\n if (step.type === 'date') return $d(new Date(val), 'short')\n return val\n }\n</script>\n\n<template>\n <div\n v-if=\"steps.length\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden flex flex-col transition-all bg-surface\">\n <!-- Header -->\n <div\n v-if=\"toolPart.input?.title || (isInteractive && steps.length > 1)\"\n class=\"text-12 border-b border-surface-3 text-word-3 bg-surface-1\">\n <div\n v-if=\"toolPart.input?.title\"\n class=\"px-sm py-10 font-bold\"\n :class=\"{\n 'border-b border-surface-3':\n isInteractive && steps.length > 1,\n }\">\n {{ toolPart.input?.title }}\n </div>\n <!-- Progress for multi-step -->\n <div\n v-if=\"isInteractive && steps.length > 1\"\n class=\"flex flex-col gap-4 p-sm\">\n <div class=\"flex justify-between text-10 text-word-3\">\n <span>\n {{\n $t('showForm.step', {\n current: currentStepIndex + 1,\n total: steps.length,\n })\n }}\n </span>\n <span>{{ progress }}%</span>\n </div>\n <div class=\"h-4 bg-surface-3 rounded-full overflow-hidden\">\n <div\n class=\"h-full bg-word-4 transition-all duration-300\"\n :style=\"{ width: `${progress}%` }\"></div>\n </div>\n </div>\n </div>\n\n <!-- Input Available State -->\n <template v-if=\"isInteractive\">\n <!-- Current Step Content -->\n <div class=\"px-sm py-16 flex flex-col gap-12\">\n <div class=\"leading-normal text-12\">\n <strong class=\"font-semibold\">\n {{ currentStep.question }}\n </strong>\n <PkStreamingMarkdown\n v-if=\"currentStep.message\"\n :markdown=\"currentStep.message\"\n class=\"text-word-2 mt-4\" />\n </div>\n\n <!-- Checkbox list for multi-select -->\n <PkEditorCheckboxButtons\n v-if=\"currentStep.options && currentStep.multiSelect\"\n v-model=\"activeCheckboxValue\"\n :name=\"currentStep.id\"\n :options=\"radioOptions\"\n :readonly=\"!isInteractive\"\n class=\"mb-0\"\n vertical>\n <template\n v-for=\"option in radioOptions\"\n :key=\"option.value\"\n #[option.value]>\n <!-- Shared option layout: label + optional description -->\n <div class=\"text-12\">\n <div class=\"font-semibold\">{{ option.label }}</div>\n <div v-if=\"option.description\" class=\"text-word-3\">\n {{ option.description }}\n </div>\n </div>\n </template>\n </PkEditorCheckboxButtons>\n\n <!-- Radio buttons for single-select -->\n <PkEditorRadioButtons\n v-else-if=\"currentStep.options && !currentStep.multiSelect\"\n v-model=\"scalarValue\"\n :name=\"currentStep.id\"\n :options=\"radioOptions\"\n :readonly=\"!isInteractive\"\n vertical\n class=\"mb-0\"\n @update:model-value=\"onRadioChange\">\n <template\n v-for=\"option in radioOptions\"\n :key=\"option.value\"\n #[option.value]>\n <!-- Shared option layout: label + optional description -->\n <div class=\"text-12\">\n <div class=\"font-semibold\">{{ option.label }}</div>\n <div v-if=\"option.description\" class=\"text-word-3\">\n {{ option.description }}\n </div>\n </div>\n </template>\n </PkEditorRadioButtons>\n\n <!-- Pure Freeform Input (text, number, date) -->\n <div\n v-else-if=\"!currentStep.options\"\n class=\"flex flex-col gap-6 w-full\">\n <VvInputText\n v-model=\"scalarValue\"\n :placeholder=\"\n currentStep.placeholder || $t('placeholder.insert')\n \"\n :type=\"currentStep.type\"\n class=\"w-full\"\n :name=\"currentStep.id\"\n modifiers=\"compact rounded\"\n :disabled=\"!isInteractive\"\n @keyup.enter=\"goNext\" />\n </div>\n </div>\n\n <!-- Custom footer freeform input (shown alongside options when allowFreeformInput) -->\n <div\n v-if=\"currentStep.allowFreeformInput && currentStep.options\"\n class=\"px-sm pb-sm border-t border-surface-3\">\n <form\n class=\"flex gap-xs pt-sm\"\n @submit.prevent=\"submitCustomAnswer\">\n <VvInputText\n v-model=\"customAnswer\"\n class=\"flex-1\"\n :name=\"`${currentStep.id}-custom`\"\n modifiers=\"compact rounded\"\n :disabled=\"!isInteractive\"\n :placeholder=\"\n currentStep.placeholder ||\n $t('showForm.otherPlaceholder')\n \" />\n </form>\n </div>\n\n <!-- Footer navigation: shown for every step that does not submit\n itself on option pick (see `isSelfSubmitting`). -->\n <div\n v-if=\"!isSelfSubmitting\"\n class=\"px-sm py-10 bg-surface border-t border-surface-3 flex justify-between gap-12\">\n <VvButton\n v-if=\"canGoBack\"\n modifiers=\"action-quiet\"\n icon=\"ri:arrow-left-s-line\"\n :label=\"$t('action.back')\"\n @click.stop=\"goBack\" />\n <div v-else></div>\n\n <VvButton\n :modifiers=\"canGoNext ? 'action-quiet' : 'action-primary'\"\n :icon=\"\n canGoNext\n ? 'ri:arrow-right-s-line'\n : 'ri:send-plane-2-line'\n \"\n icon-position=\"right\"\n :label=\"canGoNext ? $t('action.next') : $t('action.submit')\"\n @click.stop=\"goNext\" />\n </div>\n </template>\n\n <!-- Output Available State (Multi-step Summary) -->\n <template v-else>\n <div class=\"px-sm py-12 bg-surface space-y-10\">\n <ul class=\"flex flex-col gap-8\">\n <li\n v-for=\"step in steps\"\n :key=\"step.id\"\n class=\"leading-normal\">\n <div class=\"text-12 text-word-3\">\n {{ step.question }}\n </div>\n <span class=\"text-12 text-word-2 font-semibold\">\n {{ getSummaryValue(step) }}\n </span>\n </li>\n </ul>\n </div>\n <div\n class=\"px-sm py-12 bg-surface border-t border-surface-3 flex items-center gap-10\">\n <div\n class=\"w-20 h-20 rounded-full border border-success text-success flex items-center justify-center\">\n <VvIcon name=\"ri:check-line\" class=\"text-12\" />\n </div>\n <div class=\"flex flex-col\">\n <span\n class=\"font-semibold text-12 text-word-1 leading-tight\">\n {{ $t('showForm.completed') }}\n </span>\n </div>\n </div>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref, reactive, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import PkEditorRadioButtons from '../PkEditorRadioButtons.vue'\n import PkEditorCheckboxButtons from '../PkEditorCheckboxButtons.vue'\n\n // --- Types ---\n\n interface FormOption {\n label: string\n description?: string\n }\n\n interface FormStep {\n id: string\n question: string\n message?: string\n type?: 'text' | 'number' | 'date'\n options?: FormOption[]\n multiSelect?: boolean\n allowFreeformInput?: boolean\n placeholder?: string\n }\n\n interface FormAnswer {\n id: string\n value: string | string[] | number | null\n }\n\n interface ToolPartShape {\n state?: 'input-available' | 'output-available'\n toolCallId?: string\n // AI SDK v5 encodes the tool name in `type` (e.g. 'tool-showMultipleChoice').\n // `toolName` is kept for backward compatibility but is normally absent.\n type?: string\n toolName?: string\n input?: {\n title?: string\n steps?: FormStep[]\n // Legacy showMultipleChoice fields\n question?: string\n options?: (string | FormOption)[]\n }\n output?: string | { answers: FormAnswer[] }\n }\n\n type AnswerValue = string | string[] | number | null\n\n // --- Props & Emits ---\n\n const props = defineProps<{\n part: unknown\n allowCustomAnswer?: boolean\n }>()\n\n const emit = defineEmits<{\n select: [answer: string | { answers: FormAnswer[] }]\n }>()\n\n const { t: $t, d: $d } = useI18n({ useScope: 'global' })\n\n // --- Parsed tool part ---\n\n const toolPart = computed(\n () => JSON.parse(JSON.stringify(props.part)) as ToolPartShape,\n )\n\n const isLegacy = computed(\n () =>\n toolPart.value.toolName === 'showMultipleChoice' ||\n toolPart.value.type === 'tool-showMultipleChoice',\n )\n\n const isInteractive = computed(\n () => toolPart.value.state === 'input-available',\n )\n\n /** Single-step with no custom-answer and no freeform → auto-submit on option pick */\n const isAutoSubmitStep = computed(() => {\n const step = currentStep.value\n if (!step) return false\n return (\n steps.value.length === 1 &&\n !step.allowFreeformInput &&\n !props.allowCustomAnswer\n )\n })\n\n /** Legacy tool should auto-submit on option pick regardless of allowCustomAnswer */\n const isLegacyAutoSubmit = computed(\n () =>\n isLegacy.value &&\n steps.value.length === 1 &&\n !currentStep.value?.multiSelect,\n )\n\n /**\n * True only for the steps that send themselves as soon as an option is\n * picked: the single case where the footer button would be redundant.\n * Every other shape needs it, single-step forms included: with\n * `allowFreeformInput` (or `allowCustomAnswer`) the radio pick no longer\n * auto-submits, so without the footer the user was left with a chosen\n * option and no way to send it.\n */\n const isSelfSubmitting = computed(\n () =>\n Boolean(currentStep.value?.options) &&\n !currentStep.value?.multiSelect &&\n (isAutoSubmitStep.value || isLegacyAutoSubmit.value),\n )\n\n // --- Steps ---\n\n const steps = computed<FormStep[]>(() => {\n const input = toolPart.value.input\n if (input?.steps?.length) {\n return input.steps\n }\n // Legacy showMultipleChoice → normalize into a single step\n if (input?.question && input?.options) {\n return [\n {\n id: 'legacy',\n question: input.question,\n options: input.options.map((o) =>\n typeof o === 'string' ? { label: o } : o,\n ),\n },\n ]\n }\n return []\n })\n\n // --- Navigation state ---\n\n const currentStepIndex = ref(0)\n const currentStep = computed(() => steps.value[currentStepIndex.value])\n const canGoBack = computed(() => currentStepIndex.value > 0)\n const canGoNext = computed(\n () => currentStepIndex.value < steps.value.length - 1,\n )\n const isMultiStep = computed(() => steps.value.length > 1)\n\n const progress = computed(() => {\n if (!isMultiStep.value) return null\n return Math.round(\n ((currentStepIndex.value + 1) / steps.value.length) * 100,\n )\n })\n\n // --- Answers ---\n\n const answers = reactive<Record<string, AnswerValue>>({})\n const customAnswer = ref('')\n\n // Single scalar answer shared by radio buttons and freeform text/number/date inputs.\n const scalarValue = computed<string | number | undefined>({\n get: () => {\n const val = currentStep.value\n ? answers[currentStep.value.id]\n : undefined\n if (val == null || Array.isArray(val)) return undefined\n return val\n },\n set: (val) => {\n if (currentStep.value) {\n answers[currentStep.value.id] = val ?? null\n }\n },\n })\n\n const activeCheckboxValue = computed<unknown[] | undefined>({\n get: () => {\n const val = currentStep.value\n ? answers[currentStep.value.id]\n : undefined\n return Array.isArray(val) ? val : []\n },\n set: (val) => {\n if (currentStep.value) {\n answers[currentStep.value.id] = (val as string[]) ?? []\n }\n },\n })\n\n // --- Initialize answers from existing output ---\n\n watch(\n () => toolPart.value.output,\n (output) => {\n if (!output) return\n if (typeof output === 'string') {\n if (steps.value.length === 1) {\n answers[steps.value[0].id] = output\n }\n } else if (output.answers) {\n for (const a of output.answers) {\n answers[a.id] = a.value\n }\n }\n },\n { immediate: true },\n )\n\n // --- Restore custom answer from output when it doesn't match any option ---\n\n const normalizedOutput = computed(() => {\n const out = toolPart.value.output\n if (!out) return undefined\n if (typeof out === 'string') return out\n if (out.answers?.length === 1) {\n const val = out.answers[0].value\n return Array.isArray(val) ? val.join(', ') : String(val)\n }\n return undefined\n })\n\n watch(\n normalizedOutput,\n (value) => {\n if (!value || !currentStep.value) return\n const optionLabels = (currentStep.value.options ?? []).map(\n (o) => o.label,\n )\n if (!optionLabels.includes(value)) {\n customAnswer.value = value\n }\n },\n { immediate: true },\n )\n\n // --- Option mapping for radio/checkbox components ---\n\n const radioOptions = computed(() => {\n if (!currentStep.value?.options) return []\n return currentStep.value.options.map((option) => ({\n label: option.label,\n value: option.label,\n description: option.description,\n }))\n })\n\n // --- Navigation & Submission ---\n\n function goNext() {\n // A typed freeform answer wins over the picked option: it is the more\n // recent intent, and the footer button is now the visible way to send\n // it (the freeform field only submits on Enter).\n if (customAnswer.value.trim()) {\n submitCustomAnswer()\n return\n }\n if (canGoNext.value) {\n currentStepIndex.value++\n } else {\n submitForm()\n }\n }\n\n function goBack() {\n if (canGoBack.value) {\n currentStepIndex.value--\n }\n }\n\n function submitForm() {\n if (!isInteractive.value) return\n\n const finalAnswers: FormAnswer[] = steps.value.map((step) => ({\n id: step.id,\n value: answers[step.id] ?? null,\n }))\n\n // Legacy backward compatibility: single-step, single-select → return plain string\n if (\n isLegacyAutoSubmit.value &&\n !currentStep.value?.allowFreeformInput\n ) {\n const val = finalAnswers[0].value\n emit('select', Array.isArray(val) ? val[0] : (val as string))\n } else {\n emit('select', { answers: finalAnswers })\n }\n }\n\n function submitCustomAnswer() {\n const value = customAnswer.value.trim()\n if (!value) return\n\n answers[currentStep.value.id] = value\n // Cleared before navigating: `goNext()` reads it back to route a typed\n // answer here, so leaving it set would recurse.\n customAnswer.value = ''\n if (steps.value.length === 1) {\n submitForm()\n } else {\n goNext()\n }\n }\n\n function onRadioChange() {\n if (!isInteractive.value) return\n if (isAutoSubmitStep.value || isLegacyAutoSubmit.value) {\n submitForm()\n }\n }\n\n // --- Summary helpers ---\n\n function getSummaryValue(step: FormStep) {\n const val = answers[step.id]\n if (val == null) return '—'\n if (Array.isArray(val)) return val.join(', ')\n if (step.type === 'date') return $d(new Date(val), 'short')\n return val\n }\n</script>\n\n<template>\n <div\n v-if=\"steps.length\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden flex flex-col transition-all bg-surface\">\n <!-- Header -->\n <div\n v-if=\"toolPart.input?.title || (isInteractive && steps.length > 1)\"\n class=\"text-12 border-b border-surface-3 text-word-3 bg-surface-1\">\n <div\n v-if=\"toolPart.input?.title\"\n class=\"px-sm py-10 font-bold\"\n :class=\"{\n 'border-b border-surface-3':\n isInteractive && steps.length > 1,\n }\">\n {{ toolPart.input?.title }}\n </div>\n <!-- Progress for multi-step -->\n <div\n v-if=\"isInteractive && steps.length > 1\"\n class=\"flex flex-col gap-4 p-sm\">\n <div class=\"flex justify-between text-10 text-word-3\">\n <span>\n {{\n $t('showForm.step', {\n current: currentStepIndex + 1,\n total: steps.length,\n })\n }}\n </span>\n <span>{{ progress }}%</span>\n </div>\n <div class=\"h-4 bg-surface-3 rounded-full overflow-hidden\">\n <div\n class=\"h-full bg-word-4 transition-all duration-300\"\n :style=\"{ width: `${progress}%` }\"></div>\n </div>\n </div>\n </div>\n\n <!-- Input Available State -->\n <template v-if=\"isInteractive\">\n <!-- Current Step Content -->\n <div class=\"px-sm py-16 flex flex-col gap-12\">\n <div class=\"leading-normal text-12\">\n <strong class=\"font-semibold\">\n {{ currentStep.question }}\n </strong>\n <PkStreamingMarkdown\n v-if=\"currentStep.message\"\n :markdown=\"currentStep.message\"\n class=\"text-word-2 mt-4\" />\n </div>\n\n <!-- Checkbox list for multi-select -->\n <PkEditorCheckboxButtons\n v-if=\"currentStep.options && currentStep.multiSelect\"\n v-model=\"activeCheckboxValue\"\n :name=\"currentStep.id\"\n :options=\"radioOptions\"\n :readonly=\"!isInteractive\"\n class=\"mb-0\"\n vertical>\n <template\n v-for=\"option in radioOptions\"\n :key=\"option.value\"\n #[option.value]>\n <!-- Shared option layout: label + optional description -->\n <div class=\"text-12\">\n <div class=\"font-semibold\">{{ option.label }}</div>\n <div v-if=\"option.description\" class=\"text-word-3\">\n {{ option.description }}\n </div>\n </div>\n </template>\n </PkEditorCheckboxButtons>\n\n <!-- Radio buttons for single-select -->\n <PkEditorRadioButtons\n v-else-if=\"currentStep.options && !currentStep.multiSelect\"\n v-model=\"scalarValue\"\n :name=\"currentStep.id\"\n :options=\"radioOptions\"\n :readonly=\"!isInteractive\"\n vertical\n class=\"mb-0\"\n @update:model-value=\"onRadioChange\">\n <template\n v-for=\"option in radioOptions\"\n :key=\"option.value\"\n #[option.value]>\n <!-- Shared option layout: label + optional description -->\n <div class=\"text-12\">\n <div class=\"font-semibold\">{{ option.label }}</div>\n <div v-if=\"option.description\" class=\"text-word-3\">\n {{ option.description }}\n </div>\n </div>\n </template>\n </PkEditorRadioButtons>\n\n <!-- Pure Freeform Input (text, number, date) -->\n <div\n v-else-if=\"!currentStep.options\"\n class=\"flex flex-col gap-6 w-full\">\n <VvInputText\n v-model=\"scalarValue\"\n :placeholder=\"\n currentStep.placeholder || $t('placeholder.insert')\n \"\n :type=\"currentStep.type\"\n class=\"w-full\"\n :name=\"currentStep.id\"\n modifiers=\"compact rounded\"\n :disabled=\"!isInteractive\"\n @keyup.enter=\"goNext\" />\n </div>\n </div>\n\n <!-- Custom footer freeform input (shown alongside options when allowFreeformInput) -->\n <div\n v-if=\"currentStep.allowFreeformInput && currentStep.options\"\n class=\"px-sm pb-sm border-t border-surface-3\">\n <form\n class=\"flex gap-xs pt-sm\"\n @submit.prevent=\"submitCustomAnswer\">\n <VvInputText\n v-model=\"customAnswer\"\n class=\"flex-1\"\n :name=\"`${currentStep.id}-custom`\"\n modifiers=\"compact rounded\"\n :disabled=\"!isInteractive\"\n :placeholder=\"\n currentStep.placeholder ||\n $t('showForm.otherPlaceholder')\n \" />\n </form>\n </div>\n\n <!-- Footer navigation: shown for every step that does not submit\n itself on option pick (see `isSelfSubmitting`). -->\n <div\n v-if=\"!isSelfSubmitting\"\n class=\"px-sm py-10 bg-surface border-t border-surface-3 flex justify-between gap-12\">\n <VvButton\n v-if=\"canGoBack\"\n modifiers=\"action-quiet\"\n icon=\"ri:arrow-left-s-line\"\n :label=\"$t('action.back')\"\n @click.stop=\"goBack\" />\n <div v-else></div>\n\n <VvButton\n :modifiers=\"canGoNext ? 'action-quiet' : 'action-primary'\"\n :icon=\"\n canGoNext\n ? 'ri:arrow-right-s-line'\n : 'ri:send-plane-2-line'\n \"\n icon-position=\"right\"\n :label=\"canGoNext ? $t('action.next') : $t('action.submit')\"\n @click.stop=\"goNext\" />\n </div>\n </template>\n\n <!-- Output Available State (Multi-step Summary) -->\n <template v-else>\n <div class=\"px-sm py-12 bg-surface space-y-10\">\n <ul class=\"flex flex-col gap-8\">\n <li\n v-for=\"step in steps\"\n :key=\"step.id\"\n class=\"leading-normal\">\n <div class=\"text-12 text-word-3\">\n {{ step.question }}\n </div>\n <span class=\"text-12 text-word-2 font-semibold\">\n {{ getSummaryValue(step) }}\n </span>\n </li>\n </ul>\n </div>\n <div\n class=\"px-sm py-12 bg-surface border-t border-surface-3 flex items-center gap-10\">\n <div\n class=\"w-20 h-20 rounded-full border border-success text-success flex items-center justify-center\">\n <VvIcon name=\"ri:check-line\" class=\"text-12\" />\n </div>\n <div class=\"flex flex-col\">\n <span\n class=\"font-semibold text-12 text-word-1 leading-tight\">\n {{ $t('showForm.completed') }}\n </span>\n </div>\n </div>\n </template>\n </div>\n</template>\n"],"mappings":"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"}