@case-framework/survey-assistant 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -4
- package/dist/{authoring-references-CW38pYzK.mjs → authoring-references-BJQ_1nMX.mjs} +2 -2
- package/dist/authoring-references-BJQ_1nMX.mjs.map +1 -0
- package/dist/capabilities-1KNnNO1_.mjs +73 -0
- package/dist/capabilities-1KNnNO1_.mjs.map +1 -0
- package/dist/capabilities-default.d.mts +1 -1
- package/dist/capabilities-default.d.mts.map +1 -1
- package/dist/capabilities-default.mjs +22 -25
- package/dist/capabilities-default.mjs.map +1 -1
- package/dist/{constants-BMGTgfjv.d.mts → constants-Be91Gay9.d.mts} +3 -3
- package/dist/{constants-BMGTgfjv.d.mts.map → constants-Be91Gay9.d.mts.map} +1 -1
- package/dist/{controller-proxy-DMTqer6T.mjs → controller-proxy-BH05e-C2.mjs} +21 -8
- package/dist/controller-proxy-BH05e-C2.mjs.map +1 -0
- package/dist/{controller-proxy-mRvez2qw.d.mts → controller-proxy-Bd0ZHBPF.d.mts} +11 -11
- package/dist/controller-proxy-Bd0ZHBPF.d.mts.map +1 -0
- package/dist/{engine-CQwOAcwK.mjs → engine-Bo85Oyj0.mjs} +2985 -2347
- package/dist/engine-Bo85Oyj0.mjs.map +1 -0
- package/dist/engine.d.mts +2 -2
- package/dist/engine.mjs +3 -3
- package/dist/{index-D6nqkz0O.d.mts → index-Tnqv-yKW.d.mts} +56 -71
- package/dist/index-Tnqv-yKW.d.mts.map +1 -0
- package/dist/index-l_EK4yK7.d.mts +404 -0
- package/dist/index-l_EK4yK7.d.mts.map +1 -0
- package/dist/{index-DvTqML-0.d.mts → index-nhrgbgO5.d.mts} +19 -5
- package/dist/index-nhrgbgO5.d.mts.map +1 -0
- package/dist/{index-B0lxsAzx.d.mts → index-x0qprHgK.d.mts} +19 -7
- package/dist/index-x0qprHgK.d.mts.map +1 -0
- package/dist/{lifecycle-BmGAIUlv.d.mts → lifecycle-Bx0aq_4S.d.mts} +7 -1
- package/dist/{lifecycle-BmGAIUlv.d.mts.map → lifecycle-Bx0aq_4S.d.mts.map} +1 -1
- package/dist/{memory-thread-repository-CjFGVNZh.mjs → memory-thread-repository-KWHQWFEW.mjs} +43 -12
- package/dist/memory-thread-repository-KWHQWFEW.mjs.map +1 -0
- package/dist/{protocol-DJUP4gc0.mjs → protocol-BhzQbx81.mjs} +66 -16
- package/dist/protocol-BhzQbx81.mjs.map +1 -0
- package/dist/protocol.d.mts +3 -3
- package/dist/protocol.mjs +2 -2
- package/dist/react-B3ybjJ-X.mjs +1620 -0
- package/dist/react-B3ybjJ-X.mjs.map +1 -0
- package/dist/react-integration.d.mts +1 -1
- package/dist/react-integration.mjs +1 -1
- package/dist/react.d.mts +3 -3
- package/dist/react.mjs +3 -3
- package/dist/references/assistant-operations.md +45 -39
- package/dist/references/expressions.md +28 -0
- package/dist/references/item-types.md +1 -1
- package/dist/references/localization.md +5 -4
- package/dist/references/rich-text-content.md +60 -27
- package/dist/references/source-material-surveys.md +9 -2
- package/dist/references/survey-data-model.md +9 -1
- package/dist/{request-context-BjTHNcDd.mjs → request-context-CG4SWijt.mjs} +3 -3
- package/dist/{request-context-BjTHNcDd.mjs.map → request-context-CG4SWijt.mjs.map} +1 -1
- package/dist/server-agent.d.mts +19 -8
- package/dist/server-agent.d.mts.map +1 -1
- package/dist/server-agent.mjs +7 -11
- package/dist/server-agent.mjs.map +1 -1
- package/dist/server-runtime.d.mts +19 -13
- package/dist/server-runtime.d.mts.map +1 -1
- package/dist/server-runtime.mjs +7 -2
- package/dist/server-runtime.mjs.map +1 -1
- package/dist/server-tasks.d.mts +1 -1
- package/dist/server-tasks.mjs +2 -2
- package/dist/server-tools.d.mts +1 -1
- package/dist/server-tools.mjs +1 -1
- package/dist/server.d.mts +5 -5
- package/dist/server.mjs +3 -3
- package/dist/{tasks-DxzD25Zc.d.mts → tasks-CYqrcaRO.d.mts} +4 -4
- package/dist/{tasks-DxzD25Zc.d.mts.map → tasks-CYqrcaRO.d.mts.map} +1 -1
- package/dist/{thread-handlers-AbQbt4sX.d.mts → thread-handlers-DBAaU7BA.d.mts} +6 -4
- package/dist/thread-handlers-DBAaU7BA.d.mts.map +1 -0
- package/dist/{tools-CFh35R4d.mjs → tools-BvSovehT.mjs} +431 -495
- package/dist/tools-BvSovehT.mjs.map +1 -0
- package/dist/ui.css +1 -1
- package/dist/ui.d.mts +5 -4
- package/dist/ui.d.mts.map +1 -1
- package/dist/ui.mjs +619 -66
- package/dist/ui.mjs.map +1 -1
- package/docs/integration.md +40 -0
- package/package.json +21 -19
- package/dist/authoring-references-CW38pYzK.mjs.map +0 -1
- package/dist/controller-proxy-DMTqer6T.mjs.map +0 -1
- package/dist/controller-proxy-mRvez2qw.d.mts.map +0 -1
- package/dist/engine-CQwOAcwK.mjs.map +0 -1
- package/dist/form-authoring-kQDgC5oz.mjs +0 -155
- package/dist/form-authoring-kQDgC5oz.mjs.map +0 -1
- package/dist/index-B0lxsAzx.d.mts.map +0 -1
- package/dist/index-BS-Xjk1h.d.mts +0 -224
- package/dist/index-BS-Xjk1h.d.mts.map +0 -1
- package/dist/index-D6nqkz0O.d.mts.map +0 -1
- package/dist/index-DvTqML-0.d.mts.map +0 -1
- package/dist/memory-thread-repository-CjFGVNZh.mjs.map +0 -1
- package/dist/protocol-DJUP4gc0.mjs.map +0 -1
- package/dist/react-Dqlmasrs.mjs +0 -768
- package/dist/react-Dqlmasrs.mjs.map +0 -1
- package/dist/thread-handlers-AbQbt4sX.d.mts.map +0 -1
- package/dist/tools-CFh35R4d.mjs.map +0 -1
package/dist/ui.mjs
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { Lt as getSurveyAssistantEmbeddedBinaryMarker, Mt as parseSurveyAssistantError, jt as isSurveyAssistantErrorRetryable, l as surveyAssistantTurnFinalSchema, n as SURVEY_ASSISTANT_TURN_FINAL_PART_TYPE } from "./protocol-BhzQbx81.mjs";
|
|
3
3
|
import { n as isSurveyAssistantAttachmentMediaType, t as SURVEY_ASSISTANT_ATTACHMENT_MEDIA_TYPES } from "./attachments-B0hg3vpT.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { o as connectSurveyAssistantThreadLauncher } from "./controller-proxy-
|
|
4
|
+
import { E as isSurveyAssistantTurnActive, S as parseSurveyChangeSet, T as unwrapSurveyAssistantToolOutput, _ as createSurveyAssistantThreadClient, a as createSurveyAssistantSupportDetails, c as estimateSurveyAssistantSupportBundleBytes, d as prepareSurveyAssistantSupportBundle, i as SURVEY_ASSISTANT_DEFAULT_SUPPORT_BUNDLE_SELECTION, l as generateSurveyAssistantSupportBundle, m as createSurveyAssistantDiagnosticStore, o as createSurveyAssistantSupportMailto, r as useSurveyAssistantModelCatalog, s as downloadSurveyAssistantSupportBundle, t as useSurveyAssistantSession, u as isSurveyAssistantSupportBundleEnabled } from "./react-B3ybjJ-X.mjs";
|
|
5
|
+
import { o as connectSurveyAssistantThreadLauncher } from "./controller-proxy-BH05e-C2.mjs";
|
|
6
6
|
import { getToolName, isFileUIPart, isReasoningUIPart, isToolUIPart } from "ai";
|
|
7
7
|
import { createContext, createElement, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
8
|
-
import { Collapsible, Select, Slot, Tooltip } from "radix-ui";
|
|
8
|
+
import { Checkbox, Collapsible, Dialog, Select, Slot, Tooltip } from "radix-ui";
|
|
9
9
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
10
|
import { clsx } from "clsx";
|
|
11
11
|
import { twMerge } from "tailwind-merge";
|
|
12
12
|
import { useControllableState } from "@radix-ui/react-use-controllable-state";
|
|
13
|
-
import { ArrowDownIcon, ArrowUpIcon, BotIcon, BrainIcon, CheckCircleIcon, CheckIcon, ChevronDownIcon, ChevronRightIcon, ChevronUpIcon, ClockIcon, DotIcon, FileIcon, HistoryIcon, ListChecksIcon, LoaderCircleIcon, MessageSquarePlusIcon, PaperclipIcon, PencilIcon, PlusIcon, SearchIcon, SparklesIcon, SquareIcon, Trash2Icon, WandSparklesIcon, WrenchIcon, XCircleIcon, XIcon } from "lucide-react";
|
|
13
|
+
import { ArrowDownIcon, ArrowUpIcon, BotIcon, BrainIcon, CheckCircleIcon, CheckIcon, ChevronDownIcon, ChevronRightIcon, ChevronUpIcon, ClockIcon, CopyIcon, DotIcon, DownloadIcon, FileIcon, HistoryIcon, ListChecksIcon, LoaderCircleIcon, MailIcon, MessageSquarePlusIcon, PackageOpenIcon, PaperclipIcon, PencilIcon, PlusIcon, SearchIcon, SparklesIcon, SquareIcon, Trash2Icon, WandSparklesIcon, WrenchIcon, XCircleIcon, XIcon } from "lucide-react";
|
|
14
14
|
import { motion } from "motion/react";
|
|
15
15
|
import { createLocalizationTranslator, mergeLocalizationCatalogs } from "@case-framework/ui-localization";
|
|
16
16
|
import { cva } from "class-variance-authority";
|
|
@@ -247,6 +247,11 @@ const surveyAssistantEnMessages = {
|
|
|
247
247
|
dismiss: "Dismiss",
|
|
248
248
|
dismissAssistant: "Dismiss assistant error",
|
|
249
249
|
retry: "Try again",
|
|
250
|
+
exportDetails: "Export details",
|
|
251
|
+
showProviderDetails: "Show full provider message",
|
|
252
|
+
hideProviderDetails: "Hide provider message",
|
|
253
|
+
upstreamStatus: "Provider status {status}",
|
|
254
|
+
providerRequestId: "Request {requestId}",
|
|
250
255
|
fallbackDetail: "The assistant hit an error on the previous turn.",
|
|
251
256
|
model_unavailable: {
|
|
252
257
|
title: "Model unavailable",
|
|
@@ -272,6 +277,7 @@ const surveyAssistantEnMessages = {
|
|
|
272
277
|
threads: {
|
|
273
278
|
newChat: "New chat",
|
|
274
279
|
history: "Chat history",
|
|
280
|
+
exportSupportBundle: "Export support bundle",
|
|
275
281
|
recent: "Recent chats",
|
|
276
282
|
search: "Search chats",
|
|
277
283
|
searching: "Searching older chats…",
|
|
@@ -285,6 +291,48 @@ const surveyAssistantEnMessages = {
|
|
|
285
291
|
delete: "Delete {title}",
|
|
286
292
|
deleteTitle: "Delete chat",
|
|
287
293
|
deleteConfirm: "Delete \"{title}\" and its attachments?"
|
|
294
|
+
},
|
|
295
|
+
supportBundle: {
|
|
296
|
+
title: "Export support bundle",
|
|
297
|
+
description: "Choose which broad data categories to include. The ZIP is created and downloaded in this browser.",
|
|
298
|
+
close: "Close export dialog",
|
|
299
|
+
preparing: "Preparing diagnostic data…",
|
|
300
|
+
preparationFailed: "The support bundle could not be prepared",
|
|
301
|
+
generationFailed: "The support bundle could not be generated.",
|
|
302
|
+
chooseData: "Data to include",
|
|
303
|
+
core: {
|
|
304
|
+
title: "Core technical diagnostics (always included)",
|
|
305
|
+
description: "Request and turn identifiers, timing, status and error details, counters, and availability information."
|
|
306
|
+
},
|
|
307
|
+
categories: {
|
|
308
|
+
conversation: {
|
|
309
|
+
title: "Conversation and agent activity",
|
|
310
|
+
description: "Messages, visible reasoning, tool activity, and apply results."
|
|
311
|
+
},
|
|
312
|
+
survey: {
|
|
313
|
+
title: "Survey data",
|
|
314
|
+
description: "The submitted survey and a snapshot captured when this dialog opened."
|
|
315
|
+
},
|
|
316
|
+
attachments: {
|
|
317
|
+
title: "Attachments",
|
|
318
|
+
description: "Available source PDFs and images from this browser session."
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
sensitiveNote: "Conversation, reasoning, surveys, and attachments can contain sensitive research or authoring data. Deselect a category if you do not want to share it.",
|
|
322
|
+
estimatedSize: "Estimated ZIP size",
|
|
323
|
+
emailWarning: "This may be too large for some email providers.",
|
|
324
|
+
tooLarge: "The selection is too large. Deselect a category before downloading.",
|
|
325
|
+
unavailable: "{count} diagnostic component is unavailable or was truncated.",
|
|
326
|
+
unavailablePlural: "{count} diagnostic components are unavailable or were truncated.",
|
|
327
|
+
localOnly: "Nothing is sent automatically. You decide whether and how to share the downloaded ZIP.",
|
|
328
|
+
download: "Download support bundle",
|
|
329
|
+
downloadAgain: "Download again",
|
|
330
|
+
downloaded: "Downloaded {filename}. Attach it manually when contacting support.",
|
|
331
|
+
openEmail: "Open email draft",
|
|
332
|
+
supportDetails: "Support details to include with your request",
|
|
333
|
+
copyDetails: "Copy support details",
|
|
334
|
+
detailsCopied: "Support details copied",
|
|
335
|
+
copyDetailsFailed: "The support details could not be copied. Select and copy them manually."
|
|
288
336
|
}
|
|
289
337
|
};
|
|
290
338
|
//#endregion
|
|
@@ -464,6 +512,11 @@ const surveyAssistantNlMessages = {
|
|
|
464
512
|
dismiss: "Sluiten",
|
|
465
513
|
dismissAssistant: "Assistentfout sluiten",
|
|
466
514
|
retry: "Opnieuw proberen",
|
|
515
|
+
exportDetails: "Details exporteren",
|
|
516
|
+
showProviderDetails: "Volledig providerbericht tonen",
|
|
517
|
+
hideProviderDetails: "Providerbericht verbergen",
|
|
518
|
+
upstreamStatus: "Providerstatus {status}",
|
|
519
|
+
providerRequestId: "Verzoek {requestId}",
|
|
467
520
|
fallbackDetail: "Er is tijdens de vorige beurt een fout opgetreden.",
|
|
468
521
|
model_unavailable: {
|
|
469
522
|
title: "Model niet beschikbaar",
|
|
@@ -489,6 +542,7 @@ const surveyAssistantNlMessages = {
|
|
|
489
542
|
threads: {
|
|
490
543
|
newChat: "Nieuwe chat",
|
|
491
544
|
history: "Chatgeschiedenis",
|
|
545
|
+
exportSupportBundle: "Supportbundel exporteren",
|
|
492
546
|
recent: "Recente chats",
|
|
493
547
|
search: "Chats zoeken",
|
|
494
548
|
searching: "Oudere chats zoeken…",
|
|
@@ -502,6 +556,48 @@ const surveyAssistantNlMessages = {
|
|
|
502
556
|
delete: "{title} verwijderen",
|
|
503
557
|
deleteTitle: "Chat verwijderen",
|
|
504
558
|
deleteConfirm: "\"{title}\" en de bijlagen verwijderen?"
|
|
559
|
+
},
|
|
560
|
+
supportBundle: {
|
|
561
|
+
title: "Supportbundel exporteren",
|
|
562
|
+
description: "Kies welke brede gegevenscategorieën worden opgenomen. Het ZIP-bestand wordt in deze browser gemaakt en gedownload.",
|
|
563
|
+
close: "Exportvenster sluiten",
|
|
564
|
+
preparing: "Diagnostische gegevens voorbereiden…",
|
|
565
|
+
preparationFailed: "De supportbundel kon niet worden voorbereid",
|
|
566
|
+
generationFailed: "De supportbundel kon niet worden gemaakt.",
|
|
567
|
+
chooseData: "Op te nemen gegevens",
|
|
568
|
+
core: {
|
|
569
|
+
title: "Technische basisgegevens (altijd opgenomen)",
|
|
570
|
+
description: "Verzoek- en beurt-ID's, timing, status- en foutdetails, aantallen en beschikbaarheid."
|
|
571
|
+
},
|
|
572
|
+
categories: {
|
|
573
|
+
conversation: {
|
|
574
|
+
title: "Gesprek en agentactiviteit",
|
|
575
|
+
description: "Berichten, zichtbare redenering, hulpmiddelactiviteit en toepassingsresultaten."
|
|
576
|
+
},
|
|
577
|
+
survey: {
|
|
578
|
+
title: "Surveygegevens",
|
|
579
|
+
description: "De verzonden survey en een momentopname van toen dit venster werd geopend."
|
|
580
|
+
},
|
|
581
|
+
attachments: {
|
|
582
|
+
title: "Bijlagen",
|
|
583
|
+
description: "Beschikbare bron-pdf's en afbeeldingen uit deze browsersessie."
|
|
584
|
+
}
|
|
585
|
+
},
|
|
586
|
+
sensitiveNote: "Gesprek, redenering, surveys en bijlagen kunnen gevoelige onderzoeks- of auteursgegevens bevatten. Schakel een categorie uit als je die niet wilt delen.",
|
|
587
|
+
estimatedSize: "Geschatte ZIP-grootte",
|
|
588
|
+
emailWarning: "Dit bestand kan te groot zijn voor sommige e-mailproviders.",
|
|
589
|
+
tooLarge: "De selectie is te groot. Schakel een categorie uit voordat je downloadt.",
|
|
590
|
+
unavailable: "{count} diagnostisch onderdeel is niet beschikbaar of is ingekort.",
|
|
591
|
+
unavailablePlural: "{count} diagnostische onderdelen zijn niet beschikbaar of zijn ingekort.",
|
|
592
|
+
localOnly: "Er wordt niets automatisch verzonden. Je bepaalt zelf of en hoe je het gedownloade ZIP-bestand deelt.",
|
|
593
|
+
download: "Supportbundel downloaden",
|
|
594
|
+
downloadAgain: "Opnieuw downloaden",
|
|
595
|
+
downloaded: "{filename} is gedownload. Voeg het handmatig toe wanneer je contact opneemt met support.",
|
|
596
|
+
openEmail: "E-mailconcept openen",
|
|
597
|
+
supportDetails: "Supportgegevens voor je verzoek",
|
|
598
|
+
copyDetails: "Supportgegevens kopiëren",
|
|
599
|
+
detailsCopied: "Supportgegevens gekopieerd",
|
|
600
|
+
copyDetailsFailed: "De supportgegevens konden niet worden gekopieerd. Selecteer en kopieer ze handmatig."
|
|
505
601
|
}
|
|
506
602
|
};
|
|
507
603
|
//#endregion
|
|
@@ -1220,9 +1316,9 @@ const SurveyAssistantPromptInput = ({ attachmentsDisabled = false, attachmentBut
|
|
|
1220
1316
|
//#region src/ui/internal/tool-technical-details.ts
|
|
1221
1317
|
const formatOmittedLength = (length) => length.toLocaleString("en-US");
|
|
1222
1318
|
const stringifyToolTechnicalDetails = (value) => JSON.stringify(value, function redactEmbeddedBinary(key, currentValue) {
|
|
1223
|
-
const
|
|
1224
|
-
if (
|
|
1225
|
-
if (
|
|
1319
|
+
const marker = getSurveyAssistantEmbeddedBinaryMarker(currentValue, this && typeof this === "object" ? this : void 0, key);
|
|
1320
|
+
if (marker?.redacted === "base64") return `[embedded base64 omitted: ${formatOmittedLength(marker.characters)} characters]`;
|
|
1321
|
+
if (marker?.redacted === "data-url") return `[base64 data URL omitted: ${formatOmittedLength(marker.characters)} characters]`;
|
|
1226
1322
|
return currentValue;
|
|
1227
1323
|
}, 2);
|
|
1228
1324
|
//#endregion
|
|
@@ -1475,6 +1571,332 @@ const getSurveyAssistantInitialThreadLoadState = ({ error, hasSelectedThread, lo
|
|
|
1475
1571
|
return null;
|
|
1476
1572
|
};
|
|
1477
1573
|
//#endregion
|
|
1574
|
+
//#region src/ui/assistant-error-presentation.ts
|
|
1575
|
+
const getAssistantErrorPresentation = ({ authorizationError, error, t }) => {
|
|
1576
|
+
const parsed = parseSurveyAssistantError(authorizationError ? {
|
|
1577
|
+
code: "request_failed",
|
|
1578
|
+
detail: authorizationError,
|
|
1579
|
+
retryable: false
|
|
1580
|
+
} : error);
|
|
1581
|
+
return {
|
|
1582
|
+
title: t(`errors.${parsed.code}.title`),
|
|
1583
|
+
description: parsed.detail ?? t("errors.fallbackDetail"),
|
|
1584
|
+
hint: t(`errors.${parsed.code}.hint`),
|
|
1585
|
+
providerMessage: parsed.providerMessage,
|
|
1586
|
+
providerRequestId: parsed.providerRequestId,
|
|
1587
|
+
retryable: isSurveyAssistantErrorRetryable(parsed),
|
|
1588
|
+
tone: parsed.code === "model_unavailable" || parsed.code === "rate_limited" ? "warning" : "error",
|
|
1589
|
+
upstreamStatus: parsed.upstreamStatus
|
|
1590
|
+
};
|
|
1591
|
+
};
|
|
1592
|
+
//#endregion
|
|
1593
|
+
//#region src/ui/internal/checkbox.tsx
|
|
1594
|
+
const Checkbox$1 = ({ className, ...props }) => /* @__PURE__ */ jsx(Checkbox.Root, {
|
|
1595
|
+
className: cn("relative flex size-4 shrink-0 items-center justify-center rounded border border-input outline-none transition-colors focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40 disabled:cursor-not-allowed disabled:opacity-50 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground", className),
|
|
1596
|
+
...props,
|
|
1597
|
+
children: /* @__PURE__ */ jsx(Checkbox.Indicator, {
|
|
1598
|
+
className: "grid place-content-center text-current",
|
|
1599
|
+
children: /* @__PURE__ */ jsx(CheckIcon, { className: "size-3.5" })
|
|
1600
|
+
})
|
|
1601
|
+
});
|
|
1602
|
+
//#endregion
|
|
1603
|
+
//#region src/ui/internal/dialog.tsx
|
|
1604
|
+
const Dialog$1 = Dialog.Root;
|
|
1605
|
+
const DialogTitle = Dialog.Title;
|
|
1606
|
+
const DialogDescription = Dialog.Description;
|
|
1607
|
+
const DialogContent = ({ children, className, closeLabel, ...props }) => /* @__PURE__ */ jsx(Dialog.Portal, { children: /* @__PURE__ */ jsxs("div", {
|
|
1608
|
+
className: "case-survey-assistant case-survey-assistant-portal",
|
|
1609
|
+
children: [/* @__PURE__ */ jsx(Dialog.Overlay, { className: "fixed inset-0 z-50 bg-black/20 backdrop-blur-[1px] data-[state=closed]:animate-out data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0" }), /* @__PURE__ */ jsxs(Dialog.Content, {
|
|
1610
|
+
className: cn("fixed top-1/2 left-1/2 z-50 grid max-h-[min(42rem,calc(100vh-2rem))] w-[min(30rem,calc(100vw-2rem))] -translate-x-1/2 -translate-y-1/2 gap-4 overflow-y-auto rounded-xl border border-border bg-background p-4 text-foreground shadow-xl outline-none data-[state=closed]:animate-out data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95", className),
|
|
1611
|
+
...props,
|
|
1612
|
+
children: [children, /* @__PURE__ */ jsx(Dialog.Close, {
|
|
1613
|
+
"aria-label": closeLabel,
|
|
1614
|
+
className: "absolute top-2.5 right-2.5 flex size-7 items-center justify-center rounded-md text-muted-foreground hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
1615
|
+
type: "button",
|
|
1616
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "size-4" })
|
|
1617
|
+
})]
|
|
1618
|
+
})]
|
|
1619
|
+
}) });
|
|
1620
|
+
//#endregion
|
|
1621
|
+
//#region src/ui/support-bundle-dialog.tsx
|
|
1622
|
+
const CATEGORIES = [
|
|
1623
|
+
"conversation",
|
|
1624
|
+
"survey",
|
|
1625
|
+
"attachments"
|
|
1626
|
+
];
|
|
1627
|
+
const formatBytes = (bytes) => {
|
|
1628
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
1629
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KiB`;
|
|
1630
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MiB`;
|
|
1631
|
+
};
|
|
1632
|
+
const SurveyAssistantSupportBundleDialog = ({ config, error, fallbackFocusReturnRef, focusReturnRef, loading, onOpenChange, open, prepared }) => {
|
|
1633
|
+
const t = useSurveyAssistantTranslation();
|
|
1634
|
+
const [selection, setSelection] = useState({ ...SURVEY_ASSISTANT_DEFAULT_SUPPORT_BUNDLE_SELECTION });
|
|
1635
|
+
const [generated, setGenerated] = useState();
|
|
1636
|
+
const [generationError, setGenerationError] = useState();
|
|
1637
|
+
const [generating, setGenerating] = useState(false);
|
|
1638
|
+
const [supportDetailsCopied, setSupportDetailsCopied] = useState(false);
|
|
1639
|
+
const [supportDetailsCopyError, setSupportDetailsCopyError] = useState();
|
|
1640
|
+
const generationSequenceRef = useRef(0);
|
|
1641
|
+
const supportDetailsRef = useRef(null);
|
|
1642
|
+
useEffect(() => {
|
|
1643
|
+
generationSequenceRef.current += 1;
|
|
1644
|
+
if (open) setSelection({ ...SURVEY_ASSISTANT_DEFAULT_SUPPORT_BUNDLE_SELECTION });
|
|
1645
|
+
setGenerated(void 0);
|
|
1646
|
+
setGenerationError(void 0);
|
|
1647
|
+
setGenerating(false);
|
|
1648
|
+
setSupportDetailsCopied(false);
|
|
1649
|
+
setSupportDetailsCopyError(void 0);
|
|
1650
|
+
}, [open, prepared?.threadId]);
|
|
1651
|
+
const selectedBytes = useMemo(() => prepared ? estimateSurveyAssistantSupportBundleBytes(prepared, selection, config) : 0, [
|
|
1652
|
+
config,
|
|
1653
|
+
prepared,
|
|
1654
|
+
selection
|
|
1655
|
+
]);
|
|
1656
|
+
const blocked = Boolean(prepared && selectedBytes > prepared.limits.bundleBytes);
|
|
1657
|
+
const warning = Boolean(prepared && selectedBytes > prepared.limits.emailWarningBytes);
|
|
1658
|
+
const generate = async () => {
|
|
1659
|
+
if (!prepared || blocked) return;
|
|
1660
|
+
const generationSequence = generationSequenceRef.current + 1;
|
|
1661
|
+
generationSequenceRef.current = generationSequence;
|
|
1662
|
+
setGenerating(true);
|
|
1663
|
+
setSupportDetailsCopied(false);
|
|
1664
|
+
setSupportDetailsCopyError(void 0);
|
|
1665
|
+
try {
|
|
1666
|
+
const bundle = await generateSurveyAssistantSupportBundle(prepared, selection, config);
|
|
1667
|
+
if (generationSequenceRef.current !== generationSequence) return;
|
|
1668
|
+
downloadSurveyAssistantSupportBundle(bundle);
|
|
1669
|
+
setGenerated(bundle);
|
|
1670
|
+
setGenerationError(void 0);
|
|
1671
|
+
setSupportDetailsCopied(false);
|
|
1672
|
+
setSupportDetailsCopyError(void 0);
|
|
1673
|
+
} catch {
|
|
1674
|
+
if (generationSequenceRef.current === generationSequence) setGenerationError(t("supportBundle.generationFailed"));
|
|
1675
|
+
} finally {
|
|
1676
|
+
if (generationSequenceRef.current === generationSequence) setGenerating(false);
|
|
1677
|
+
}
|
|
1678
|
+
};
|
|
1679
|
+
const updateSelection = (category, checked) => {
|
|
1680
|
+
generationSequenceRef.current += 1;
|
|
1681
|
+
setSelection((current) => ({
|
|
1682
|
+
...current,
|
|
1683
|
+
[category]: checked
|
|
1684
|
+
}));
|
|
1685
|
+
setGenerated(void 0);
|
|
1686
|
+
setGenerationError(void 0);
|
|
1687
|
+
setGenerating(false);
|
|
1688
|
+
setSupportDetailsCopied(false);
|
|
1689
|
+
setSupportDetailsCopyError(void 0);
|
|
1690
|
+
};
|
|
1691
|
+
const mailto = generated && prepared && config ? createSurveyAssistantSupportMailto({
|
|
1692
|
+
bundle: generated,
|
|
1693
|
+
config,
|
|
1694
|
+
prepared
|
|
1695
|
+
}) : void 0;
|
|
1696
|
+
const supportDetails = generated && prepared ? createSurveyAssistantSupportDetails({
|
|
1697
|
+
bundle: generated,
|
|
1698
|
+
prepared
|
|
1699
|
+
}) : "";
|
|
1700
|
+
const copySupportDetails = async () => {
|
|
1701
|
+
if (!supportDetails) return;
|
|
1702
|
+
const copySequence = generationSequenceRef.current + 1;
|
|
1703
|
+
generationSequenceRef.current = copySequence;
|
|
1704
|
+
setSupportDetailsCopied(false);
|
|
1705
|
+
setSupportDetailsCopyError(void 0);
|
|
1706
|
+
try {
|
|
1707
|
+
if (navigator.clipboard?.writeText) await navigator.clipboard.writeText(supportDetails);
|
|
1708
|
+
else {
|
|
1709
|
+
if (!supportDetailsRef.current) throw new Error("Support details are not available.");
|
|
1710
|
+
supportDetailsRef.current.select();
|
|
1711
|
+
if (!document.execCommand("copy")) throw new Error("Copy was not available.");
|
|
1712
|
+
}
|
|
1713
|
+
if (generationSequenceRef.current !== copySequence) return;
|
|
1714
|
+
setSupportDetailsCopied(true);
|
|
1715
|
+
setSupportDetailsCopyError(void 0);
|
|
1716
|
+
} catch {
|
|
1717
|
+
if (generationSequenceRef.current !== copySequence) return;
|
|
1718
|
+
setSupportDetailsCopied(false);
|
|
1719
|
+
setSupportDetailsCopyError(t("supportBundle.copyDetailsFailed"));
|
|
1720
|
+
}
|
|
1721
|
+
};
|
|
1722
|
+
return /* @__PURE__ */ jsx(Dialog$1, {
|
|
1723
|
+
onOpenChange,
|
|
1724
|
+
open,
|
|
1725
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
1726
|
+
"aria-describedby": "survey-assistant-support-bundle-description",
|
|
1727
|
+
closeLabel: t("supportBundle.close"),
|
|
1728
|
+
onCloseAutoFocus: (event) => {
|
|
1729
|
+
const target = focusReturnRef?.current?.isConnected ? focusReturnRef.current : fallbackFocusReturnRef?.current?.isConnected ? fallbackFocusReturnRef.current : null;
|
|
1730
|
+
if (!target) return;
|
|
1731
|
+
event.preventDefault();
|
|
1732
|
+
target.focus();
|
|
1733
|
+
},
|
|
1734
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1735
|
+
className: "pr-8",
|
|
1736
|
+
children: [/* @__PURE__ */ jsx(DialogTitle, {
|
|
1737
|
+
className: "font-semibold text-base",
|
|
1738
|
+
children: t("supportBundle.title")
|
|
1739
|
+
}), /* @__PURE__ */ jsx(DialogDescription, {
|
|
1740
|
+
className: "mt-1 text-muted-foreground text-sm",
|
|
1741
|
+
id: "survey-assistant-support-bundle-description",
|
|
1742
|
+
children: t("supportBundle.description")
|
|
1743
|
+
})]
|
|
1744
|
+
}), loading ? /* @__PURE__ */ jsxs("div", {
|
|
1745
|
+
"aria-live": "polite",
|
|
1746
|
+
className: "flex min-h-28 items-center justify-center text-muted-foreground text-sm",
|
|
1747
|
+
role: "status",
|
|
1748
|
+
children: [/* @__PURE__ */ jsx(LoaderCircleIcon, { className: "mr-2 size-4 animate-spin" }), t("supportBundle.preparing")]
|
|
1749
|
+
}) : error ? /* @__PURE__ */ jsxs("div", {
|
|
1750
|
+
className: "rounded-md border border-destructive/20 bg-destructive/5 p-3 text-sm",
|
|
1751
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1752
|
+
className: "font-medium",
|
|
1753
|
+
children: t("supportBundle.preparationFailed")
|
|
1754
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
1755
|
+
className: "mt-1 text-muted-foreground",
|
|
1756
|
+
children: error
|
|
1757
|
+
})]
|
|
1758
|
+
}) : prepared ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1759
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1760
|
+
className: "rounded-md border border-border bg-muted/30 p-3 text-xs",
|
|
1761
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1762
|
+
className: "font-medium",
|
|
1763
|
+
children: t("supportBundle.core.title")
|
|
1764
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
1765
|
+
className: "mt-1 text-muted-foreground",
|
|
1766
|
+
children: t("supportBundle.core.description")
|
|
1767
|
+
})]
|
|
1768
|
+
}),
|
|
1769
|
+
/* @__PURE__ */ jsxs("fieldset", {
|
|
1770
|
+
className: "grid gap-2",
|
|
1771
|
+
"aria-describedby": "support-bundle-sensitive-note",
|
|
1772
|
+
children: [/* @__PURE__ */ jsx("legend", {
|
|
1773
|
+
className: "mb-1 font-medium text-sm",
|
|
1774
|
+
children: t("supportBundle.chooseData")
|
|
1775
|
+
}), CATEGORIES.map((category) => {
|
|
1776
|
+
const id = `support-bundle-${category}`;
|
|
1777
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
1778
|
+
className: "flex cursor-pointer items-start gap-3 rounded-md border border-border p-3 hover:bg-muted/30",
|
|
1779
|
+
htmlFor: id,
|
|
1780
|
+
children: [/* @__PURE__ */ jsx(Checkbox$1, {
|
|
1781
|
+
checked: selection[category],
|
|
1782
|
+
id,
|
|
1783
|
+
onCheckedChange: (checked) => updateSelection(category, checked === true)
|
|
1784
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
1785
|
+
className: "min-w-0 flex-1",
|
|
1786
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
1787
|
+
className: "flex items-center justify-between gap-2 font-medium text-sm",
|
|
1788
|
+
children: [/* @__PURE__ */ jsx("span", { children: t(`supportBundle.categories.${category}.title`) }), /* @__PURE__ */ jsx("span", {
|
|
1789
|
+
className: "shrink-0 text-muted-foreground text-xs",
|
|
1790
|
+
children: formatBytes(prepared.categoryBytes[category])
|
|
1791
|
+
})]
|
|
1792
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1793
|
+
className: "mt-0.5 block text-muted-foreground text-xs",
|
|
1794
|
+
children: t(`supportBundle.categories.${category}.description`)
|
|
1795
|
+
})]
|
|
1796
|
+
})]
|
|
1797
|
+
}, category);
|
|
1798
|
+
})]
|
|
1799
|
+
}),
|
|
1800
|
+
/* @__PURE__ */ jsx("p", {
|
|
1801
|
+
className: "text-muted-foreground text-xs",
|
|
1802
|
+
id: "support-bundle-sensitive-note",
|
|
1803
|
+
children: t("supportBundle.sensitiveNote")
|
|
1804
|
+
}),
|
|
1805
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1806
|
+
"aria-live": "polite",
|
|
1807
|
+
className: "rounded-md bg-muted/40 px-3 py-2 text-xs",
|
|
1808
|
+
role: "status",
|
|
1809
|
+
children: [
|
|
1810
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1811
|
+
className: "flex justify-between gap-3",
|
|
1812
|
+
children: [/* @__PURE__ */ jsx("span", { children: t("supportBundle.estimatedSize") }), /* @__PURE__ */ jsx("span", {
|
|
1813
|
+
className: "font-medium",
|
|
1814
|
+
children: formatBytes(selectedBytes)
|
|
1815
|
+
})]
|
|
1816
|
+
}),
|
|
1817
|
+
warning && !blocked && /* @__PURE__ */ jsx("div", {
|
|
1818
|
+
className: "mt-1 text-amber-700",
|
|
1819
|
+
children: t("supportBundle.emailWarning")
|
|
1820
|
+
}),
|
|
1821
|
+
blocked && /* @__PURE__ */ jsx("div", {
|
|
1822
|
+
className: "mt-1 text-destructive",
|
|
1823
|
+
children: t("supportBundle.tooLarge")
|
|
1824
|
+
}),
|
|
1825
|
+
prepared.unavailable.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
1826
|
+
className: "mt-1 text-muted-foreground",
|
|
1827
|
+
children: t(prepared.unavailable.length === 1 ? "supportBundle.unavailable" : "supportBundle.unavailablePlural", { count: prepared.unavailable.length })
|
|
1828
|
+
}),
|
|
1829
|
+
(generationError ?? error) && /* @__PURE__ */ jsx("div", {
|
|
1830
|
+
className: "mt-1 text-destructive",
|
|
1831
|
+
children: generationError ?? error
|
|
1832
|
+
})
|
|
1833
|
+
]
|
|
1834
|
+
}),
|
|
1835
|
+
generated ? /* @__PURE__ */ jsxs(Fragment, { children: [!mailto && /* @__PURE__ */ jsxs("div", {
|
|
1836
|
+
className: "grid gap-2 rounded-md border border-border p-3",
|
|
1837
|
+
children: [
|
|
1838
|
+
/* @__PURE__ */ jsx("label", {
|
|
1839
|
+
className: "font-medium text-xs",
|
|
1840
|
+
htmlFor: "support-bundle-details",
|
|
1841
|
+
children: t("supportBundle.supportDetails")
|
|
1842
|
+
}),
|
|
1843
|
+
/* @__PURE__ */ jsx("textarea", {
|
|
1844
|
+
className: "min-h-24 resize-y rounded-md border border-input bg-background p-2 font-mono text-xs",
|
|
1845
|
+
id: "support-bundle-details",
|
|
1846
|
+
readOnly: true,
|
|
1847
|
+
ref: supportDetailsRef,
|
|
1848
|
+
value: supportDetails
|
|
1849
|
+
}),
|
|
1850
|
+
/* @__PURE__ */ jsx("div", {
|
|
1851
|
+
className: "flex justify-end",
|
|
1852
|
+
children: /* @__PURE__ */ jsxs(Button, {
|
|
1853
|
+
disabled: generating,
|
|
1854
|
+
onClick: () => void copySupportDetails(),
|
|
1855
|
+
type: "button",
|
|
1856
|
+
variant: "secondary",
|
|
1857
|
+
children: [supportDetailsCopied ? /* @__PURE__ */ jsx(CheckIcon, {}) : /* @__PURE__ */ jsx(CopyIcon, {}), t(supportDetailsCopied ? "supportBundle.detailsCopied" : "supportBundle.copyDetails")]
|
|
1858
|
+
})
|
|
1859
|
+
}),
|
|
1860
|
+
supportDetailsCopyError && /* @__PURE__ */ jsx("div", {
|
|
1861
|
+
"aria-live": "polite",
|
|
1862
|
+
className: "text-destructive text-xs",
|
|
1863
|
+
role: "status",
|
|
1864
|
+
children: supportDetailsCopyError
|
|
1865
|
+
})
|
|
1866
|
+
]
|
|
1867
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1868
|
+
className: "flex flex-wrap justify-end gap-2",
|
|
1869
|
+
children: [mailto && /* @__PURE__ */ jsx(Button, {
|
|
1870
|
+
asChild: true,
|
|
1871
|
+
variant: "secondary",
|
|
1872
|
+
children: /* @__PURE__ */ jsxs("a", {
|
|
1873
|
+
href: mailto,
|
|
1874
|
+
children: [/* @__PURE__ */ jsx(MailIcon, {}), t("supportBundle.openEmail")]
|
|
1875
|
+
})
|
|
1876
|
+
}), /* @__PURE__ */ jsxs(Button, {
|
|
1877
|
+
disabled: generating,
|
|
1878
|
+
onClick: () => void generate(),
|
|
1879
|
+
type: "button",
|
|
1880
|
+
children: [generating ? /* @__PURE__ */ jsx(LoaderCircleIcon, { className: "animate-spin" }) : /* @__PURE__ */ jsx(DownloadIcon, {}), t("supportBundle.downloadAgain")]
|
|
1881
|
+
})]
|
|
1882
|
+
})] }) : /* @__PURE__ */ jsx("div", {
|
|
1883
|
+
className: "flex justify-end",
|
|
1884
|
+
children: /* @__PURE__ */ jsxs(Button, {
|
|
1885
|
+
disabled: blocked || generating,
|
|
1886
|
+
onClick: () => void generate(),
|
|
1887
|
+
type: "button",
|
|
1888
|
+
children: [generating ? /* @__PURE__ */ jsx(LoaderCircleIcon, { className: "animate-spin" }) : /* @__PURE__ */ jsx(DownloadIcon, {}), t("supportBundle.download")]
|
|
1889
|
+
})
|
|
1890
|
+
}),
|
|
1891
|
+
/* @__PURE__ */ jsx("p", {
|
|
1892
|
+
className: "text-muted-foreground text-xs",
|
|
1893
|
+
children: generated ? t("supportBundle.downloaded", { filename: generated.filename }) : t("supportBundle.localOnly")
|
|
1894
|
+
})
|
|
1895
|
+
] }) : null]
|
|
1896
|
+
})
|
|
1897
|
+
});
|
|
1898
|
+
};
|
|
1899
|
+
//#endregion
|
|
1478
1900
|
//#region src/ui/survey-assistant-panel.tsx
|
|
1479
1901
|
const isRootSurveyItem = (item) => typeof item.config === "object" && item.config !== null && item.config.isRoot === true;
|
|
1480
1902
|
const getAssistantEmptyStateContext = (controller) => {
|
|
@@ -1553,16 +1975,6 @@ const localizedToolNames = new Set([
|
|
|
1553
1975
|
const getToolDisplayName = (t, toolName, phase = "complete") => localizedToolNames.has(toolName) ? t(`activity.tools.${toolName}.${phase}`) : t(phase === "active" ? "activity.genericActive" : "activity.genericComplete");
|
|
1554
1976
|
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1555
1977
|
const unwrapOutput = unwrapSurveyAssistantToolOutput;
|
|
1556
|
-
const getAssistantErrorPresentation = (error, t) => {
|
|
1557
|
-
const parsed = parseSurveyAssistantError(error);
|
|
1558
|
-
return {
|
|
1559
|
-
title: t(`errors.${parsed.code}.title`),
|
|
1560
|
-
description: parsed.detail ?? t("errors.fallbackDetail"),
|
|
1561
|
-
hint: t(`errors.${parsed.code}.hint`),
|
|
1562
|
-
retryable: parsed.retryable ?? (parsed.code === "rate_limited" || parsed.code === "request_failed"),
|
|
1563
|
-
tone: parsed.code === "model_unavailable" || parsed.code === "rate_limited" ? "warning" : "error"
|
|
1564
|
-
};
|
|
1565
|
-
};
|
|
1566
1978
|
const getChangeSet = parseSurveyChangeSet;
|
|
1567
1979
|
const isChangeSet = (output) => {
|
|
1568
1980
|
return getChangeSet(output) !== null;
|
|
@@ -1969,7 +2381,7 @@ const SurveyAssistantHeaderIdentity = ({ indicatorClassName, status, title }) =>
|
|
|
1969
2381
|
})]
|
|
1970
2382
|
})]
|
|
1971
2383
|
});
|
|
1972
|
-
const SurveyAssistantChatPanel = ({ api, applyPolicy, controller, embedded = false, focusPromptOnMount = false, hasEarlierMessages, initialLaunch, initialMessages, modelId, models, onInitialLaunchHandled, onModelChange, onFirstSubmit, onLoadEarlierMessages, onTurnSettled, onApplyReceipts, onSettleApply, onReviewChangeSets, onTurnActiveChange, resourceId, surveyId, threadControls, threadId, threadTitle }) => {
|
|
2384
|
+
const SurveyAssistantChatPanel = ({ api, applyPolicy, controller, diagnosticStore, embedded = false, focusPromptOnMount = false, hasEarlierMessages, initialLaunch, initialMessages, modelId, models, onInitialLaunchHandled, onModelChange, onFirstSubmit, onExportDetails, onLoadEarlierMessages, onTurnSettled, onApplyReceipts, onSettleApply, onReviewChangeSets, onTurnActiveChange, resourceId, surveyId, threadControls, threadId, threadTitle }) => {
|
|
1973
2385
|
const t = useSurveyAssistantTranslation();
|
|
1974
2386
|
const emptyStateContext = getAssistantEmptyStateContext(controller);
|
|
1975
2387
|
const assistantQuickPrompts = getAssistantQuickPrompts(t, emptyStateContext);
|
|
@@ -1977,6 +2389,7 @@ const SurveyAssistantChatPanel = ({ api, applyPolicy, controller, embedded = fal
|
|
|
1977
2389
|
api,
|
|
1978
2390
|
applyPolicy,
|
|
1979
2391
|
controller,
|
|
2392
|
+
diagnosticStore,
|
|
1980
2393
|
initialMessages,
|
|
1981
2394
|
modelId,
|
|
1982
2395
|
onApplyReceipts,
|
|
@@ -1989,16 +2402,22 @@ const SurveyAssistantChatPanel = ({ api, applyPolicy, controller, embedded = fal
|
|
|
1989
2402
|
});
|
|
1990
2403
|
const hasSubmittedMessageRef = useRef((initialMessages?.length ?? 0) > 0);
|
|
1991
2404
|
const showAssistantError = Boolean(authorizationError) || Boolean(error);
|
|
1992
|
-
const assistantErrorPresentation = getAssistantErrorPresentation(
|
|
2405
|
+
const assistantErrorPresentation = getAssistantErrorPresentation({
|
|
2406
|
+
authorizationError,
|
|
2407
|
+
error,
|
|
2408
|
+
t
|
|
2409
|
+
});
|
|
1993
2410
|
const lastMessage = messages.at(-1);
|
|
1994
2411
|
const isAssistantTurnActive = isSurveyAssistantTurnActive({
|
|
1995
2412
|
isStreaming,
|
|
1996
2413
|
state
|
|
1997
2414
|
});
|
|
1998
2415
|
const promptTextareaRef = useRef(null);
|
|
2416
|
+
const exportDetailsButtonRef = useRef(null);
|
|
1999
2417
|
const shouldRestorePromptFocusRef = useRef(false);
|
|
2000
2418
|
const turnWasActiveRef = useRef(false);
|
|
2001
2419
|
const [loadingEarlierMessages, setLoadingEarlierMessages] = useState(false);
|
|
2420
|
+
const [providerMessageExpanded, setProviderMessageExpanded] = useState(false);
|
|
2002
2421
|
const loadEarlierMessages = useCallback(async () => {
|
|
2003
2422
|
if (loadingEarlierMessages) return;
|
|
2004
2423
|
setLoadingEarlierMessages(true);
|
|
@@ -2219,15 +2638,40 @@ const SurveyAssistantChatPanel = ({ api, applyPolicy, controller, embedded = fal
|
|
|
2219
2638
|
className: "mt-0.5 wrap-break-word text-muted-foreground",
|
|
2220
2639
|
children: assistantErrorPresentation.description
|
|
2221
2640
|
}),
|
|
2641
|
+
assistantErrorPresentation.providerMessage && /* @__PURE__ */ jsxs("div", {
|
|
2642
|
+
className: "mt-1",
|
|
2643
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
2644
|
+
className: cn("wrap-break-word text-muted-foreground text-xs", !providerMessageExpanded && "line-clamp-3"),
|
|
2645
|
+
children: assistantErrorPresentation.providerMessage
|
|
2646
|
+
}), assistantErrorPresentation.providerMessage.length > 180 && /* @__PURE__ */ jsx("button", {
|
|
2647
|
+
className: "mt-0.5 font-medium text-foreground text-xs hover:underline",
|
|
2648
|
+
onClick: () => setProviderMessageExpanded((current) => !current),
|
|
2649
|
+
type: "button",
|
|
2650
|
+
children: t(providerMessageExpanded ? "errors.hideProviderDetails" : "errors.showProviderDetails")
|
|
2651
|
+
})]
|
|
2652
|
+
}),
|
|
2653
|
+
(assistantErrorPresentation.upstreamStatus || assistantErrorPresentation.providerRequestId) && /* @__PURE__ */ jsx("p", {
|
|
2654
|
+
className: "mt-1 text-[11px] text-muted-foreground/80",
|
|
2655
|
+
children: [assistantErrorPresentation.upstreamStatus ? t("errors.upstreamStatus", { status: assistantErrorPresentation.upstreamStatus }) : null, assistantErrorPresentation.providerRequestId ? t("errors.providerRequestId", { requestId: assistantErrorPresentation.providerRequestId }) : null].filter(Boolean).join(" · ")
|
|
2656
|
+
}),
|
|
2222
2657
|
/* @__PURE__ */ jsx("p", {
|
|
2223
2658
|
className: "mt-1 text-muted-foreground/80",
|
|
2224
2659
|
children: assistantErrorPresentation.hint
|
|
2225
2660
|
}),
|
|
2226
|
-
assistantErrorPresentation.retryable && /* @__PURE__ */
|
|
2227
|
-
className: "mt-1.5
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2661
|
+
(assistantErrorPresentation.retryable || onExportDetails) && /* @__PURE__ */ jsxs("div", {
|
|
2662
|
+
className: "mt-1.5 flex flex-wrap gap-x-3 gap-y-1",
|
|
2663
|
+
children: [assistantErrorPresentation.retryable && /* @__PURE__ */ jsx("button", {
|
|
2664
|
+
className: "font-medium text-foreground text-xs hover:underline",
|
|
2665
|
+
onClick: retry,
|
|
2666
|
+
type: "button",
|
|
2667
|
+
children: t("errors.retry")
|
|
2668
|
+
}), onExportDetails && /* @__PURE__ */ jsx("button", {
|
|
2669
|
+
className: "font-medium text-foreground text-xs hover:underline",
|
|
2670
|
+
onClick: () => onExportDetails(exportDetailsButtonRef.current),
|
|
2671
|
+
ref: exportDetailsButtonRef,
|
|
2672
|
+
type: "button",
|
|
2673
|
+
children: t("errors.exportDetails")
|
|
2674
|
+
})]
|
|
2231
2675
|
})
|
|
2232
2676
|
]
|
|
2233
2677
|
})]
|
|
@@ -2282,8 +2726,9 @@ const listThreadPage = async (client, cursor) => {
|
|
|
2282
2726
|
if (client.listPage) return client.listPage(cursor ? { cursor } : void 0);
|
|
2283
2727
|
return cursor ? { threads: [] } : { threads: await client.list() };
|
|
2284
2728
|
};
|
|
2285
|
-
const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], onConfirmDeleteThread, onModelChange = () => {}, onTurnActiveChange: onAssistantTurnActiveChange, resourceId, selectedThreadStorageKey, surveyId, threadApi, threadClient: providedThreadClient, threadLauncher, ...sessionProps }) => {
|
|
2729
|
+
const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], onConfirmDeleteThread, onModelChange = () => {}, onTurnActiveChange: onAssistantTurnActiveChange, resourceId, selectedThreadStorageKey, supportBundle, surveyId, threadApi, threadClient: providedThreadClient, threadLauncher, ...sessionProps }) => {
|
|
2286
2730
|
const t = useSurveyAssistantTranslation();
|
|
2731
|
+
const supportBundleEnabled = isSurveyAssistantSupportBundleEnabled(supportBundle);
|
|
2287
2732
|
const threadClient = useMemo(() => providedThreadClient ?? createSurveyAssistantThreadClient(threadApi), [providedThreadClient, threadApi]);
|
|
2288
2733
|
const storageKey = selectedThreadStorageKey === false ? null : selectedThreadStorageKey ?? `${SELECTED_THREAD_STORAGE_KEY}:${encodeURIComponent(resourceId)}${surveyId ? `:${encodeURIComponent(surveyId)}` : ""}`;
|
|
2289
2734
|
const [threads, setThreads] = useState([]);
|
|
@@ -2302,8 +2747,23 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2302
2747
|
const [assistantTurnActive, setAssistantTurnActive] = useState(false);
|
|
2303
2748
|
const [initialLaunch, setInitialLaunch] = useState();
|
|
2304
2749
|
const [promptFocusThreadId, setPromptFocusThreadId] = useState();
|
|
2750
|
+
const [diagnosticStore] = useState(() => {
|
|
2751
|
+
try {
|
|
2752
|
+
return createSurveyAssistantDiagnosticStore(supportBundle?.limits);
|
|
2753
|
+
} catch {
|
|
2754
|
+
return createSurveyAssistantDiagnosticStore();
|
|
2755
|
+
}
|
|
2756
|
+
});
|
|
2757
|
+
const [supportBundleOpen, setSupportBundleOpen] = useState(false);
|
|
2758
|
+
const [supportBundleLoading, setSupportBundleLoading] = useState(false);
|
|
2759
|
+
const [supportBundleError, setSupportBundleError] = useState();
|
|
2760
|
+
const [preparedSupportBundle, setPreparedSupportBundle] = useState();
|
|
2305
2761
|
const historyControlsRef = useRef(null);
|
|
2762
|
+
const historyButtonRef = useRef(null);
|
|
2306
2763
|
const loadingAllThreadsRef = useRef(false);
|
|
2764
|
+
const supportBundleAbortRef = useRef(null);
|
|
2765
|
+
const supportBundleFocusReturnRef = useRef(null);
|
|
2766
|
+
const supportBundleThreadIdRef = useRef(void 0);
|
|
2307
2767
|
const selectModel = useCallback((modelId) => {
|
|
2308
2768
|
if (!models.some((model) => model.id === modelId)) return;
|
|
2309
2769
|
onModelChange(modelId);
|
|
@@ -2529,10 +2989,67 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2529
2989
|
renameThread,
|
|
2530
2990
|
threads
|
|
2531
2991
|
]);
|
|
2992
|
+
const closeSupportBundle = useCallback(() => {
|
|
2993
|
+
supportBundleAbortRef.current?.abort();
|
|
2994
|
+
supportBundleAbortRef.current = null;
|
|
2995
|
+
setSupportBundleOpen(false);
|
|
2996
|
+
setSupportBundleLoading(false);
|
|
2997
|
+
setPreparedSupportBundle(void 0);
|
|
2998
|
+
}, []);
|
|
2999
|
+
const openSupportBundle = useCallback(async (focusReturnElement) => {
|
|
3000
|
+
if (!supportBundleEnabled || !selectedThread || assistantTurnActive) return;
|
|
3001
|
+
supportBundleFocusReturnRef.current = focusReturnElement ?? historyButtonRef.current;
|
|
3002
|
+
await commitEditingThread();
|
|
3003
|
+
setHistoryOpen(false);
|
|
3004
|
+
supportBundleAbortRef.current?.abort();
|
|
3005
|
+
const abortController = new AbortController();
|
|
3006
|
+
supportBundleAbortRef.current = abortController;
|
|
3007
|
+
setSupportBundleOpen(true);
|
|
3008
|
+
supportBundleThreadIdRef.current = selectedThread.id;
|
|
3009
|
+
setSupportBundleLoading(true);
|
|
3010
|
+
setSupportBundleError(void 0);
|
|
3011
|
+
setPreparedSupportBundle(void 0);
|
|
3012
|
+
try {
|
|
3013
|
+
const prepared = await prepareSurveyAssistantSupportBundle({
|
|
3014
|
+
config: supportBundle,
|
|
3015
|
+
controller: sessionProps.controller,
|
|
3016
|
+
diagnosticStore,
|
|
3017
|
+
resourceId,
|
|
3018
|
+
signal: abortController.signal,
|
|
3019
|
+
threadClient,
|
|
3020
|
+
threadId: selectedThread.id
|
|
3021
|
+
});
|
|
3022
|
+
if (abortController.signal.aborted || selectedThread.id !== prepared.threadId) return;
|
|
3023
|
+
setPreparedSupportBundle(prepared);
|
|
3024
|
+
} catch (error) {
|
|
3025
|
+
if (abortController.signal.aborted) return;
|
|
3026
|
+
setSupportBundleError(parseSurveyAssistantError(error).detail ?? t("supportBundle.preparationFailed"));
|
|
3027
|
+
} finally {
|
|
3028
|
+
if (supportBundleAbortRef.current === abortController) {
|
|
3029
|
+
supportBundleAbortRef.current = null;
|
|
3030
|
+
setSupportBundleLoading(false);
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
}, [
|
|
3034
|
+
assistantTurnActive,
|
|
3035
|
+
commitEditingThread,
|
|
3036
|
+
diagnosticStore,
|
|
3037
|
+
resourceId,
|
|
3038
|
+
selectedThread,
|
|
3039
|
+
sessionProps.controller,
|
|
3040
|
+
supportBundle,
|
|
3041
|
+
supportBundleEnabled,
|
|
3042
|
+
t,
|
|
3043
|
+
threadClient
|
|
3044
|
+
]);
|
|
3045
|
+
useEffect(() => () => {
|
|
3046
|
+
supportBundleAbortRef.current?.abort();
|
|
3047
|
+
}, []);
|
|
2532
3048
|
const deleteThread = useCallback(async (thread) => {
|
|
2533
3049
|
if (!(onConfirmDeleteThread ? await onConfirmDeleteThread(thread) : window.confirm(t("threads.deleteConfirm", { title: thread.title })))) return;
|
|
2534
3050
|
try {
|
|
2535
3051
|
await threadClient.delete(thread.id);
|
|
3052
|
+
diagnosticStore.deleteThread(thread.id);
|
|
2536
3053
|
const remaining = threads.filter((item) => item.id !== thread.id);
|
|
2537
3054
|
setThreads(remaining);
|
|
2538
3055
|
if (selectedThread?.id === thread.id) if (remaining[0]) await selectThread(remaining[0]);
|
|
@@ -2542,6 +3059,7 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2542
3059
|
}
|
|
2543
3060
|
}, [
|
|
2544
3061
|
createThread,
|
|
3062
|
+
diagnosticStore,
|
|
2545
3063
|
onConfirmDeleteThread,
|
|
2546
3064
|
selectThread,
|
|
2547
3065
|
selectedThread,
|
|
@@ -2628,6 +3146,14 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2628
3146
|
promptFocusThreadId,
|
|
2629
3147
|
selectedThread?.id
|
|
2630
3148
|
]);
|
|
3149
|
+
useEffect(() => {
|
|
3150
|
+
if (!supportBundleOpen || supportBundleThreadIdRef.current === selectedThread?.id) return;
|
|
3151
|
+
closeSupportBundle();
|
|
3152
|
+
}, [
|
|
3153
|
+
closeSupportBundle,
|
|
3154
|
+
selectedThread?.id,
|
|
3155
|
+
supportBundleOpen
|
|
3156
|
+
]);
|
|
2631
3157
|
useEffect(() => {
|
|
2632
3158
|
const handleFocus = () => {
|
|
2633
3159
|
refreshThreadList(false);
|
|
@@ -2699,6 +3225,7 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2699
3225
|
className: "flex size-8 items-center justify-center rounded-lg text-muted-foreground hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-50",
|
|
2700
3226
|
disabled: assistantTurnActive,
|
|
2701
3227
|
onClick: toggleHistory,
|
|
3228
|
+
ref: historyButtonRef,
|
|
2702
3229
|
title: t("threads.history"),
|
|
2703
3230
|
type: "button",
|
|
2704
3231
|
children: /* @__PURE__ */ jsx(HistoryIcon, { className: "size-4" })
|
|
@@ -2789,6 +3316,15 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2789
3316
|
children: loadingOlderThreads ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(LoaderCircleIcon, { className: "mr-1.5 size-3.5 animate-spin" }), normalizedThreadSearch ? t("threads.searching") : t("threads.loadingOlder")] }) : t("threads.loadOlder")
|
|
2790
3317
|
})
|
|
2791
3318
|
]
|
|
3319
|
+
}),
|
|
3320
|
+
supportBundleEnabled && /* @__PURE__ */ jsx("div", {
|
|
3321
|
+
className: "border-t border-border p-1",
|
|
3322
|
+
children: /* @__PURE__ */ jsxs("button", {
|
|
3323
|
+
className: "flex h-9 w-full items-center gap-2 rounded-md px-2 text-left text-muted-foreground text-xs hover:bg-muted hover:text-foreground",
|
|
3324
|
+
onClick: () => void openSupportBundle(historyButtonRef.current),
|
|
3325
|
+
type: "button",
|
|
3326
|
+
children: [/* @__PURE__ */ jsx(PackageOpenIcon, { className: "size-3.5" }), t("threads.exportSupportBundle")]
|
|
3327
|
+
})
|
|
2792
3328
|
})
|
|
2793
3329
|
]
|
|
2794
3330
|
})
|
|
@@ -2796,46 +3332,63 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2796
3332
|
});
|
|
2797
3333
|
return /* @__PURE__ */ jsxs("div", {
|
|
2798
3334
|
className: "relative h-full min-h-0",
|
|
2799
|
-
children: [
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
3335
|
+
children: [
|
|
3336
|
+
/* @__PURE__ */ createElement(SurveyAssistantChatPanel, {
|
|
3337
|
+
...sessionProps,
|
|
3338
|
+
embedded,
|
|
3339
|
+
focusPromptOnMount: selectedThread.id === promptFocusThreadId,
|
|
3340
|
+
hasEarlierMessages: Boolean(nextMessageCursor),
|
|
3341
|
+
initialLaunch: initialLaunch?.input,
|
|
3342
|
+
initialMessages,
|
|
3343
|
+
key: selectedThread.id,
|
|
3344
|
+
modelId,
|
|
3345
|
+
models,
|
|
3346
|
+
diagnosticStore,
|
|
3347
|
+
onExportDetails: supportBundleEnabled ? (trigger) => void openSupportBundle(trigger) : void 0,
|
|
3348
|
+
onInitialLaunchHandled: handleInitialLaunchHandled,
|
|
3349
|
+
onModelChange: selectModel,
|
|
3350
|
+
onFirstSubmit: handleFirstSubmit,
|
|
3351
|
+
onLoadEarlierMessages: loadEarlierMessages,
|
|
3352
|
+
onTurnSettled: handleTurnSettled,
|
|
3353
|
+
onTurnActiveChange: handleTurnActiveChange,
|
|
3354
|
+
resourceId,
|
|
3355
|
+
surveyId,
|
|
3356
|
+
threadControls,
|
|
3357
|
+
threadId: selectedThread.id,
|
|
3358
|
+
threadTitle: selectedThread.title
|
|
3359
|
+
}),
|
|
3360
|
+
supportBundleEnabled && /* @__PURE__ */ jsx(SurveyAssistantSupportBundleDialog, {
|
|
3361
|
+
config: supportBundle,
|
|
3362
|
+
error: supportBundleError,
|
|
3363
|
+
fallbackFocusReturnRef: historyButtonRef,
|
|
3364
|
+
focusReturnRef: supportBundleFocusReturnRef,
|
|
3365
|
+
loading: supportBundleLoading,
|
|
3366
|
+
onOpenChange: (open) => {
|
|
3367
|
+
if (!open) closeSupportBundle();
|
|
3368
|
+
},
|
|
3369
|
+
open: supportBundleOpen,
|
|
3370
|
+
prepared: preparedSupportBundle
|
|
3371
|
+
}),
|
|
3372
|
+
threadError && /* @__PURE__ */ jsxs("div", {
|
|
3373
|
+
className: "absolute right-3 bottom-3 left-3 z-40 rounded-lg border border-destructive/20 bg-popover px-3 py-2 text-xs shadow-lg",
|
|
3374
|
+
children: [
|
|
3375
|
+
/* @__PURE__ */ jsx("div", {
|
|
3376
|
+
className: "font-medium",
|
|
3377
|
+
children: t("panel.controlsUnavailable")
|
|
3378
|
+
}),
|
|
3379
|
+
/* @__PURE__ */ jsx("div", {
|
|
3380
|
+
className: "mt-0.5 text-muted-foreground",
|
|
3381
|
+
children: threadError
|
|
3382
|
+
}),
|
|
3383
|
+
/* @__PURE__ */ jsx("button", {
|
|
3384
|
+
className: "mt-1 font-medium hover:underline",
|
|
3385
|
+
onClick: () => setThreadError(null),
|
|
3386
|
+
type: "button",
|
|
3387
|
+
children: t("errors.dismiss")
|
|
3388
|
+
})
|
|
3389
|
+
]
|
|
3390
|
+
})
|
|
3391
|
+
]
|
|
2839
3392
|
});
|
|
2840
3393
|
};
|
|
2841
3394
|
const SurveyAssistantPanel = ({ language, localizations, ...props }) => /* @__PURE__ */ jsx("div", {
|