@case-framework/survey-assistant 0.3.0 → 0.4.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 +12 -4
- package/dist/capabilities-default.d.mts +1 -1
- package/dist/capabilities-default.mjs +1 -1
- package/dist/{constants-DrGZXtQf.d.mts → constants-k1b_evIb.d.mts} +5 -2
- package/dist/constants-k1b_evIb.d.mts.map +1 -0
- package/dist/{controller-proxy-CpkQRezb.mjs → controller-proxy-jWIPOZAv.mjs} +17 -8
- package/dist/controller-proxy-jWIPOZAv.mjs.map +1 -0
- package/dist/{controller-proxy-DmBdzqKs.d.mts → controller-proxy-quQjtA7j.d.mts} +2 -2
- package/dist/{controller-proxy-DmBdzqKs.d.mts.map → controller-proxy-quQjtA7j.d.mts.map} +1 -1
- package/dist/{engine-CWTuN3o2.mjs → engine-BvfUx_Jx.mjs} +85 -12
- package/dist/engine-BvfUx_Jx.mjs.map +1 -0
- package/dist/engine.d.mts +2 -2
- package/dist/engine.mjs +3 -3
- package/dist/{form-authoring-DCd9XfXf.mjs → form-authoring-BQh40yDb.mjs} +2 -2
- package/dist/{form-authoring-DCd9XfXf.mjs.map → form-authoring-BQh40yDb.mjs.map} +1 -1
- package/dist/{index-D4OitUg4.d.mts → index-8x1Eqlnz.d.mts} +4 -1
- package/dist/index-8x1Eqlnz.d.mts.map +1 -0
- package/dist/{index-Dxgg0-D_.d.mts → index-BDp6S7r9.d.mts} +11 -5
- package/dist/index-BDp6S7r9.d.mts.map +1 -0
- package/dist/{index-DZk20e3k.d.mts → index-biZnRl-h.d.mts} +3 -3
- package/dist/{index-DZk20e3k.d.mts.map → index-biZnRl-h.d.mts.map} +1 -1
- package/dist/{index-Bo4dHAo8.d.mts → index-r8HVcn5b.d.mts} +8 -4
- package/dist/index-r8HVcn5b.d.mts.map +1 -0
- package/dist/{memory-thread-repository-acbz6HZJ.mjs → memory-thread-repository-xBZOog_q.mjs} +49 -21
- package/dist/memory-thread-repository-xBZOog_q.mjs.map +1 -0
- package/dist/{protocol-DATvkr1S.mjs → protocol-DJUP4gc0.mjs} +10 -4
- package/dist/protocol-DJUP4gc0.mjs.map +1 -0
- package/dist/protocol.d.mts +1 -1
- package/dist/protocol.mjs +1 -1
- package/dist/{react-Br5YE8H-.mjs → react-CY6N7lVi.mjs} +25 -5
- package/dist/react-CY6N7lVi.mjs.map +1 -0
- package/dist/react-integration.d.mts +1 -1
- package/dist/react-integration.mjs +1 -1
- package/dist/react.d.mts +2 -2
- package/dist/react.mjs +2 -2
- package/dist/{request-context-BEjnaaFr.mjs → request-context-DixY5DYu.mjs} +3 -3
- package/dist/request-context-DixY5DYu.mjs.map +1 -0
- package/dist/server-agent.d.mts +4 -4
- package/dist/server-agent.d.mts.map +1 -1
- package/dist/server-agent.mjs +4 -3
- package/dist/server-agent.mjs.map +1 -1
- package/dist/server-runtime.d.mts +340 -7
- package/dist/server-runtime.d.mts.map +1 -1
- package/dist/server-runtime.mjs +321 -23
- package/dist/server-runtime.mjs.map +1 -1
- package/dist/server-tasks.d.mts +1 -1
- package/dist/server-tasks.mjs +5 -4
- package/dist/server-tasks.mjs.map +1 -1
- package/dist/server-tools.d.mts +1 -1
- package/dist/server-tools.mjs +1 -1
- package/dist/server.d.mts +6 -6
- package/dist/server.d.mts.map +1 -1
- package/dist/server.mjs +2 -2
- package/dist/{tasks-DQgL449A.d.mts → tasks-BWmTMXoK.d.mts} +3 -3
- package/dist/{tasks-DQgL449A.d.mts.map → tasks-BWmTMXoK.d.mts.map} +1 -1
- package/dist/{thread-handlers-CeYl45xG.d.mts → thread-handlers-D8gkLfU6.d.mts} +13 -5
- package/dist/{thread-handlers-CeYl45xG.d.mts.map → thread-handlers-D8gkLfU6.d.mts.map} +1 -1
- package/dist/{tools-Dg9HZrYU.mjs → tools-TXI8bfzZ.mjs} +25 -6
- package/dist/{tools-Dg9HZrYU.mjs.map → tools-TXI8bfzZ.mjs.map} +1 -1
- package/dist/ui.css +1 -1
- package/dist/ui.d.mts +3 -3
- package/dist/ui.d.mts.map +1 -1
- package/dist/ui.mjs +370 -127
- package/dist/ui.mjs.map +1 -1
- package/docs/integration.md +83 -62
- package/package.json +3 -3
- package/dist/constants-DrGZXtQf.d.mts.map +0 -1
- package/dist/controller-proxy-CpkQRezb.mjs.map +0 -1
- package/dist/engine-CWTuN3o2.mjs.map +0 -1
- package/dist/index-Bo4dHAo8.d.mts.map +0 -1
- package/dist/index-D4OitUg4.d.mts.map +0 -1
- package/dist/index-Dxgg0-D_.d.mts.map +0 -1
- package/dist/memory-thread-repository-acbz6HZJ.mjs.map +0 -1
- package/dist/protocol-DATvkr1S.mjs.map +0 -1
- package/dist/react-Br5YE8H-.mjs.map +0 -1
- package/dist/request-context-BEjnaaFr.mjs.map +0 -1
package/dist/ui.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jt as parseSurveyAssistantError, l as surveyAssistantTurnFinalSchema, n as SURVEY_ASSISTANT_TURN_FINAL_PART_TYPE } from "./protocol-
|
|
3
|
-
import { f as unwrapSurveyAssistantToolOutput, i as createSurveyAssistantThreadClient, l as parseSurveyChangeSet, p as isSurveyAssistantTurnActive, r as useSurveyAssistantModelCatalog, t as useSurveyAssistantSession } from "./react-
|
|
4
|
-
import { o as connectSurveyAssistantThreadLauncher } from "./controller-proxy-
|
|
2
|
+
import { jt as parseSurveyAssistantError, l as surveyAssistantTurnFinalSchema, n as SURVEY_ASSISTANT_TURN_FINAL_PART_TYPE } from "./protocol-DJUP4gc0.mjs";
|
|
3
|
+
import { f as unwrapSurveyAssistantToolOutput, i as createSurveyAssistantThreadClient, l as parseSurveyChangeSet, p as isSurveyAssistantTurnActive, r as useSurveyAssistantModelCatalog, t as useSurveyAssistantSession } from "./react-CY6N7lVi.mjs";
|
|
4
|
+
import { o as connectSurveyAssistantThreadLauncher } from "./controller-proxy-jWIPOZAv.mjs";
|
|
5
5
|
import { getToolName, isFileUIPart, isReasoningUIPart, isToolUIPart } from "ai";
|
|
6
6
|
import { createContext, createElement, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
7
7
|
import { Collapsible, Select, Slot } from "radix-ui";
|
|
@@ -9,7 +9,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
9
9
|
import { clsx } from "clsx";
|
|
10
10
|
import { twMerge } from "tailwind-merge";
|
|
11
11
|
import { useControllableState } from "@radix-ui/react-use-controllable-state";
|
|
12
|
-
import { ArrowDownIcon, ArrowUpIcon, BotIcon, BrainIcon, CheckCircleIcon, CheckIcon, ChevronDownIcon, ChevronRightIcon, ChevronUpIcon, ClockIcon, DotIcon, FileIcon, HistoryIcon, ListChecksIcon, LoaderCircleIcon, MessageSquarePlusIcon, PaperclipIcon, PencilIcon, PlusIcon, SparklesIcon, SquareIcon, Trash2Icon, WandSparklesIcon, WrenchIcon, XCircleIcon, XIcon } from "lucide-react";
|
|
12
|
+
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
13
|
import { motion } from "motion/react";
|
|
14
14
|
import { createLocalizationTranslator, mergeLocalizationCatalogs } from "@case-framework/ui-localization";
|
|
15
15
|
import { cva } from "class-variance-authority";
|
|
@@ -80,13 +80,30 @@ const surveyAssistantEnMessages = {
|
|
|
80
80
|
},
|
|
81
81
|
empty: {
|
|
82
82
|
title: "What are you working on?",
|
|
83
|
-
description: "Draft, inspect, or refine your survey - just describe what you need, or start with one of these."
|
|
83
|
+
description: "Draft, inspect, or refine your survey - just describe what you need, or start with one of these.",
|
|
84
|
+
newSurveyTitle: "Create with the assistant",
|
|
85
|
+
newSurveyDescription: "Describe the survey you need, share a brief, or plan the right questions together."
|
|
84
86
|
},
|
|
85
87
|
quickActions: {
|
|
88
|
+
draftSurvey: {
|
|
89
|
+
label: "Draft a survey",
|
|
90
|
+
description: "Create a first draft from your goals",
|
|
91
|
+
prompt: "Help me create a first draft of a new survey. Ask me about its topic, audience, and goals before drafting it."
|
|
92
|
+
},
|
|
93
|
+
useBrief: {
|
|
94
|
+
label: "Use a brief or notes",
|
|
95
|
+
description: "Turn requirements into a survey",
|
|
96
|
+
prompt: "Help me turn a brief or set of notes into a survey. Ask me to paste the text or attach the document."
|
|
97
|
+
},
|
|
98
|
+
planSurvey: {
|
|
99
|
+
label: "Plan the questions",
|
|
100
|
+
description: "Outline the structure before drafting",
|
|
101
|
+
prompt: "Help me plan the questions and structure for a new survey before we draft it."
|
|
102
|
+
},
|
|
86
103
|
review: {
|
|
87
104
|
label: "Review survey",
|
|
88
105
|
description: "Spot issues and suggest improvements",
|
|
89
|
-
prompt: "
|
|
106
|
+
prompt: "Run a deterministic audit of the current survey, including expression-reference integrity, then review its quality and suggest improvements."
|
|
90
107
|
},
|
|
91
108
|
create: {
|
|
92
109
|
label: "New question",
|
|
@@ -97,6 +114,11 @@ const surveyAssistantEnMessages = {
|
|
|
97
114
|
label: "Refine wording",
|
|
98
115
|
description: "Polish respondent-facing text",
|
|
99
116
|
prompt: "Suggest improvements to the respondent-facing wording."
|
|
117
|
+
},
|
|
118
|
+
refineSelection: {
|
|
119
|
+
label: "Refine selected item",
|
|
120
|
+
description: "Polish the wording in context",
|
|
121
|
+
prompt: "Suggest improvements to the respondent-facing wording of the selected item."
|
|
100
122
|
}
|
|
101
123
|
},
|
|
102
124
|
input: {
|
|
@@ -111,6 +133,8 @@ const surveyAssistantEnMessages = {
|
|
|
111
133
|
defaultModel: "Default model"
|
|
112
134
|
},
|
|
113
135
|
conversation: {
|
|
136
|
+
loadEarlier: "Load earlier messages",
|
|
137
|
+
loadingEarlier: "Loading earlier messages…",
|
|
114
138
|
noMessages: "No messages yet",
|
|
115
139
|
startConversation: "Start a conversation to see messages here",
|
|
116
140
|
scrollToLatest: "Scroll to latest message",
|
|
@@ -246,6 +270,11 @@ const surveyAssistantEnMessages = {
|
|
|
246
270
|
newChat: "New chat",
|
|
247
271
|
history: "Chat history",
|
|
248
272
|
recent: "Recent chats",
|
|
273
|
+
search: "Search chats",
|
|
274
|
+
searching: "Searching older chats…",
|
|
275
|
+
noMatches: "No matching chats",
|
|
276
|
+
loadOlder: "Load older chats",
|
|
277
|
+
loadingOlder: "Loading older chats…",
|
|
249
278
|
automaticTitle: "Use automatic title",
|
|
250
279
|
automaticShort: "Auto",
|
|
251
280
|
rename: "Rename {title}",
|
|
@@ -266,13 +295,30 @@ const surveyAssistantNlMessages = {
|
|
|
266
295
|
},
|
|
267
296
|
empty: {
|
|
268
297
|
title: "Waar werk je aan?",
|
|
269
|
-
description: "Maak, controleer of verbeter je survey. Beschrijf wat je nodig hebt of kies een van deze opties."
|
|
298
|
+
description: "Maak, controleer of verbeter je survey. Beschrijf wat je nodig hebt of kies een van deze opties.",
|
|
299
|
+
newSurveyTitle: "Maak iets met de assistent",
|
|
300
|
+
newSurveyDescription: "Beschrijf de survey die je nodig hebt, deel een briefing of plan samen de juiste vragen."
|
|
270
301
|
},
|
|
271
302
|
quickActions: {
|
|
303
|
+
draftSurvey: {
|
|
304
|
+
label: "Een survey opstellen",
|
|
305
|
+
description: "Maak een eerste versie vanuit je doelen",
|
|
306
|
+
prompt: "Help me een eerste versie van een nieuwe survey te maken. Vraag me vóór het opstellen naar het onderwerp, de doelgroep en de doelen."
|
|
307
|
+
},
|
|
308
|
+
useBrief: {
|
|
309
|
+
label: "Gebruik een briefing of notities",
|
|
310
|
+
description: "Zet vereisten om in een survey",
|
|
311
|
+
prompt: "Help me een briefing of verzameling notities om te zetten in een survey. Vraag me de tekst te plakken of het document toe te voegen."
|
|
312
|
+
},
|
|
313
|
+
planSurvey: {
|
|
314
|
+
label: "Plan de vragen",
|
|
315
|
+
description: "Schets eerst de structuur",
|
|
316
|
+
prompt: "Help me de vragen en structuur voor een nieuwe survey te plannen voordat we die opstellen."
|
|
317
|
+
},
|
|
272
318
|
review: {
|
|
273
319
|
label: "Survey controleren",
|
|
274
320
|
description: "Problemen vinden en verbeteringen voorstellen",
|
|
275
|
-
prompt: "
|
|
321
|
+
prompt: "Voer een deterministische controle van de huidige survey uit, inclusief de geldigheid van expressieverwijzingen, beoordeel daarna de kwaliteit en stel verbeteringen voor."
|
|
276
322
|
},
|
|
277
323
|
create: {
|
|
278
324
|
label: "Nieuwe vraag",
|
|
@@ -283,6 +329,11 @@ const surveyAssistantNlMessages = {
|
|
|
283
329
|
label: "Formulering verbeteren",
|
|
284
330
|
description: "Tekst voor respondenten aanscherpen",
|
|
285
331
|
prompt: "Stel verbeteringen voor voor de tekst die respondenten zien."
|
|
332
|
+
},
|
|
333
|
+
refineSelection: {
|
|
334
|
+
label: "Geselecteerd item verbeteren",
|
|
335
|
+
description: "Scherp de formulering in context aan",
|
|
336
|
+
prompt: "Stel verbeteringen voor voor de respondentgerichte formulering van het geselecteerde item."
|
|
286
337
|
}
|
|
287
338
|
},
|
|
288
339
|
input: {
|
|
@@ -297,6 +348,8 @@ const surveyAssistantNlMessages = {
|
|
|
297
348
|
defaultModel: "Standaardmodel"
|
|
298
349
|
},
|
|
299
350
|
conversation: {
|
|
351
|
+
loadEarlier: "Eerdere berichten laden",
|
|
352
|
+
loadingEarlier: "Eerdere berichten laden…",
|
|
300
353
|
noMessages: "Nog geen berichten",
|
|
301
354
|
startConversation: "Start een gesprek om hier berichten te zien",
|
|
302
355
|
scrollToLatest: "Naar het nieuwste bericht scrollen",
|
|
@@ -432,6 +485,11 @@ const surveyAssistantNlMessages = {
|
|
|
432
485
|
newChat: "Nieuwe chat",
|
|
433
486
|
history: "Chatgeschiedenis",
|
|
434
487
|
recent: "Recente chats",
|
|
488
|
+
search: "Chats zoeken",
|
|
489
|
+
searching: "Oudere chats zoeken…",
|
|
490
|
+
noMatches: "Geen overeenkomende chats",
|
|
491
|
+
loadOlder: "Oudere chats laden",
|
|
492
|
+
loadingOlder: "Oudere chats laden…",
|
|
435
493
|
automaticTitle: "Automatische titel gebruiken",
|
|
436
494
|
automaticShort: "Automatisch",
|
|
437
495
|
rename: "{title} hernoemen",
|
|
@@ -1351,26 +1409,61 @@ const getPersistedMessageTurnStatus = (message) => {
|
|
|
1351
1409
|
};
|
|
1352
1410
|
//#endregion
|
|
1353
1411
|
//#region src/ui/survey-assistant-panel.tsx
|
|
1354
|
-
const
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
prompt: t("quickActions.create.prompt")
|
|
1366
|
-
},
|
|
1367
|
-
{
|
|
1368
|
-
label: t("quickActions.refine.label"),
|
|
1369
|
-
description: t("quickActions.refine.description"),
|
|
1370
|
-
icon: WandSparklesIcon,
|
|
1371
|
-
prompt: t("quickActions.refine.prompt")
|
|
1412
|
+
const isRootSurveyItem = (item) => typeof item.config === "object" && item.config !== null && item.config.isRoot === true;
|
|
1413
|
+
const getAssistantEmptyStateContext = (controller) => {
|
|
1414
|
+
try {
|
|
1415
|
+
const snapshot = controller?.getSnapshot();
|
|
1416
|
+
if (!snapshot) return "survey";
|
|
1417
|
+
const surveyItems = snapshot.survey.surveyItems.filter((item) => !isRootSurveyItem(item));
|
|
1418
|
+
if (surveyItems.length === 0) return "new-survey";
|
|
1419
|
+
if (surveyItems.some((item) => item.id === snapshot.ui.selectedItemId)) return "selected-item";
|
|
1420
|
+
return "survey";
|
|
1421
|
+
} catch {
|
|
1422
|
+
return "survey";
|
|
1372
1423
|
}
|
|
1373
|
-
|
|
1424
|
+
};
|
|
1425
|
+
const getAssistantQuickPrompts = (t, context) => {
|
|
1426
|
+
if (context === "new-survey") return [
|
|
1427
|
+
{
|
|
1428
|
+
label: t("quickActions.draftSurvey.label"),
|
|
1429
|
+
description: t("quickActions.draftSurvey.description"),
|
|
1430
|
+
icon: WandSparklesIcon,
|
|
1431
|
+
prompt: t("quickActions.draftSurvey.prompt")
|
|
1432
|
+
},
|
|
1433
|
+
{
|
|
1434
|
+
label: t("quickActions.useBrief.label"),
|
|
1435
|
+
description: t("quickActions.useBrief.description"),
|
|
1436
|
+
icon: FileIcon,
|
|
1437
|
+
prompt: t("quickActions.useBrief.prompt")
|
|
1438
|
+
},
|
|
1439
|
+
{
|
|
1440
|
+
label: t("quickActions.planSurvey.label"),
|
|
1441
|
+
description: t("quickActions.planSurvey.description"),
|
|
1442
|
+
icon: ListChecksIcon,
|
|
1443
|
+
prompt: t("quickActions.planSurvey.prompt")
|
|
1444
|
+
}
|
|
1445
|
+
];
|
|
1446
|
+
return [
|
|
1447
|
+
{
|
|
1448
|
+
label: t("quickActions.review.label"),
|
|
1449
|
+
description: t("quickActions.review.description"),
|
|
1450
|
+
icon: ListChecksIcon,
|
|
1451
|
+
prompt: t("quickActions.review.prompt")
|
|
1452
|
+
},
|
|
1453
|
+
{
|
|
1454
|
+
label: t("quickActions.create.label"),
|
|
1455
|
+
description: t("quickActions.create.description"),
|
|
1456
|
+
icon: MessageSquarePlusIcon,
|
|
1457
|
+
prompt: t("quickActions.create.prompt")
|
|
1458
|
+
},
|
|
1459
|
+
{
|
|
1460
|
+
label: t(context === "selected-item" ? "quickActions.refineSelection.label" : "quickActions.refine.label"),
|
|
1461
|
+
description: t(context === "selected-item" ? "quickActions.refineSelection.description" : "quickActions.refine.description"),
|
|
1462
|
+
icon: WandSparklesIcon,
|
|
1463
|
+
prompt: t(context === "selected-item" ? "quickActions.refineSelection.prompt" : "quickActions.refine.prompt")
|
|
1464
|
+
}
|
|
1465
|
+
];
|
|
1466
|
+
};
|
|
1374
1467
|
const isSurveyAssistantAttachmentReferencePart = (part) => {
|
|
1375
1468
|
if (part.type !== "data-survey-assistant-attachment" || typeof part.data !== "object" || part.data === null) return false;
|
|
1376
1469
|
const data = part.data;
|
|
@@ -1399,6 +1492,7 @@ const getAssistantErrorPresentation = (error, t) => {
|
|
|
1399
1492
|
title: t(`errors.${parsed.code}.title`),
|
|
1400
1493
|
description: parsed.detail ?? t("errors.fallbackDetail"),
|
|
1401
1494
|
hint: t(`errors.${parsed.code}.hint`),
|
|
1495
|
+
retryable: parsed.retryable ?? (parsed.code === "rate_limited" || parsed.code === "request_failed"),
|
|
1402
1496
|
tone: parsed.code === "model_unavailable" || parsed.code === "rate_limited" ? "warning" : "error"
|
|
1403
1497
|
};
|
|
1404
1498
|
};
|
|
@@ -1808,10 +1902,11 @@ const SurveyAssistantHeaderIdentity = ({ indicatorClassName, status, title }) =>
|
|
|
1808
1902
|
})]
|
|
1809
1903
|
})]
|
|
1810
1904
|
});
|
|
1811
|
-
const SurveyAssistantChatPanel = ({ api, applyPolicy, controller, embedded = false, initialLaunch, initialMessages, modelId, models, onInitialLaunchHandled, onModelChange, onFirstSubmit, onTurnSettled, onApplyReceipts, onSettleApply, onReviewChangeSets, onTurnActiveChange, resourceId, surveyId, threadControls, threadId, threadTitle }) => {
|
|
1905
|
+
const SurveyAssistantChatPanel = ({ api, applyPolicy, controller, embedded = false, hasEarlierMessages, initialLaunch, initialMessages, modelId, models, onInitialLaunchHandled, onModelChange, onFirstSubmit, onLoadEarlierMessages, onTurnSettled, onApplyReceipts, onSettleApply, onReviewChangeSets, onTurnActiveChange, resourceId, surveyId, threadControls, threadId, threadTitle }) => {
|
|
1812
1906
|
const t = useSurveyAssistantTranslation();
|
|
1813
|
-
const
|
|
1814
|
-
const
|
|
1907
|
+
const emptyStateContext = getAssistantEmptyStateContext(controller);
|
|
1908
|
+
const assistantQuickPrompts = getAssistantQuickPrompts(t, emptyStateContext);
|
|
1909
|
+
const { applyResultsByChangeId, authorizationError, dismissError, error, isStreaming, latestTurnOutcome, messages, prependMessages, state, status, stop, submit, retry } = useSurveyAssistantSession({
|
|
1815
1910
|
api,
|
|
1816
1911
|
applyPolicy,
|
|
1817
1912
|
controller,
|
|
@@ -1836,6 +1931,20 @@ const SurveyAssistantChatPanel = ({ api, applyPolicy, controller, embedded = fal
|
|
|
1836
1931
|
const promptTextareaRef = useRef(null);
|
|
1837
1932
|
const shouldRestorePromptFocusRef = useRef(false);
|
|
1838
1933
|
const turnWasActiveRef = useRef(false);
|
|
1934
|
+
const [loadingEarlierMessages, setLoadingEarlierMessages] = useState(false);
|
|
1935
|
+
const loadEarlierMessages = useCallback(async () => {
|
|
1936
|
+
if (loadingEarlierMessages) return;
|
|
1937
|
+
setLoadingEarlierMessages(true);
|
|
1938
|
+
try {
|
|
1939
|
+
prependMessages(await onLoadEarlierMessages());
|
|
1940
|
+
} finally {
|
|
1941
|
+
setLoadingEarlierMessages(false);
|
|
1942
|
+
}
|
|
1943
|
+
}, [
|
|
1944
|
+
loadingEarlierMessages,
|
|
1945
|
+
onLoadEarlierMessages,
|
|
1946
|
+
prependMessages
|
|
1947
|
+
]);
|
|
1839
1948
|
const isAssistantTurnSettled = !isStreaming && (state === "completed" || state === "failed" || state === "aborted" || state === "applied");
|
|
1840
1949
|
useEffect(() => {
|
|
1841
1950
|
if (!isAssistantTurnActive) {
|
|
@@ -1943,16 +2052,16 @@ const SurveyAssistantChatPanel = ({ api, applyPolicy, controller, embedded = fal
|
|
|
1943
2052
|
className: "mx-auto w-full max-w-sm",
|
|
1944
2053
|
children: [
|
|
1945
2054
|
/* @__PURE__ */ jsx("div", {
|
|
1946
|
-
className: "mb-3 flex size-
|
|
1947
|
-
children: /* @__PURE__ */ jsx(SparklesIcon, { className: "size-
|
|
2055
|
+
className: "mb-3 flex size-9 items-center justify-center rounded-xl border border-border bg-muted text-foreground shadow-xs",
|
|
2056
|
+
children: /* @__PURE__ */ jsx(SparklesIcon, { className: "size-4" })
|
|
1948
2057
|
}),
|
|
1949
2058
|
/* @__PURE__ */ jsx("h3", {
|
|
1950
2059
|
className: "font-semibold text-foreground text-base tracking-tight",
|
|
1951
|
-
children: t("empty.title")
|
|
2060
|
+
children: t(emptyStateContext === "new-survey" ? "empty.newSurveyTitle" : "empty.title")
|
|
1952
2061
|
}),
|
|
1953
2062
|
/* @__PURE__ */ jsx("p", {
|
|
1954
2063
|
className: "mt-1 text-muted-foreground text-xs leading-relaxed",
|
|
1955
|
-
children: t("empty.description")
|
|
2064
|
+
children: t(emptyStateContext === "new-survey" ? "empty.newSurveyDescription" : "empty.description")
|
|
1956
2065
|
}),
|
|
1957
2066
|
/* @__PURE__ */ jsx("div", {
|
|
1958
2067
|
className: "mt-4 flex flex-col gap-1.5",
|
|
@@ -1981,40 +2090,50 @@ const SurveyAssistantChatPanel = ({ api, applyPolicy, controller, embedded = fal
|
|
|
1981
2090
|
})
|
|
1982
2091
|
]
|
|
1983
2092
|
})
|
|
1984
|
-
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
2093
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2094
|
+
hasEarlierMessages && /* @__PURE__ */ jsxs("button", {
|
|
2095
|
+
className: "mx-auto flex h-8 items-center justify-center rounded-md px-3 text-muted-foreground text-xs hover:bg-muted hover:text-foreground disabled:pointer-events-none",
|
|
2096
|
+
disabled: loadingEarlierMessages || isAssistantTurnActive,
|
|
2097
|
+
onClick: () => void loadEarlierMessages(),
|
|
2098
|
+
type: "button",
|
|
2099
|
+
children: [loadingEarlierMessages && /* @__PURE__ */ jsx(LoaderCircleIcon, { className: "mr-1.5 size-3.5 animate-spin" }), loadingEarlierMessages ? t("conversation.loadingEarlier") : t("conversation.loadEarlier")]
|
|
2100
|
+
}),
|
|
2101
|
+
messages.map((message, index) => {
|
|
2102
|
+
const isLastMessage = index === messages.length - 1;
|
|
2103
|
+
const persistedTurnStatus = getPersistedMessageTurnStatus(message);
|
|
2104
|
+
const terminalTurnStatus = persistedTurnStatus === "aborted" || persistedTurnStatus === "failed" ? persistedTurnStatus : isLastMessage && (state === "aborted" || state === "failed") ? state : void 0;
|
|
2105
|
+
const shouldShowProgress = isAssistantTurnActive && isLastMessage && message.role === "assistant";
|
|
2106
|
+
return /* @__PURE__ */ jsx(Message, {
|
|
2107
|
+
className: "max-w-[96%] gap-1",
|
|
2108
|
+
from: message.role,
|
|
2109
|
+
children: /* @__PURE__ */ jsx(MessageContent, {
|
|
2110
|
+
className: cn(message.role === "assistant" && "w-full space-y-2"),
|
|
2111
|
+
children: hasRenderableParts(message) ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SurveyAssistantMessageParts, {
|
|
2112
|
+
applyResultsByChangeId,
|
|
2113
|
+
isLastMessage,
|
|
2114
|
+
isStreaming: isAssistantTurnActive,
|
|
2115
|
+
message,
|
|
2116
|
+
showProgress: shouldShowProgress,
|
|
2117
|
+
terminalTurnStatus
|
|
2118
|
+
}), isLastMessage && latestTurnOutcome && /* @__PURE__ */ jsx(SurveyAssistantTurnOutcomeNotice, { ...latestTurnOutcome })] }) : shouldShowProgress ? /* @__PURE__ */ jsx(SurveyAssistantProgressIndicator, { message }) : isLastMessage && latestTurnOutcome ? /* @__PURE__ */ jsx(SurveyAssistantTurnOutcomeNotice, { ...latestTurnOutcome }) : state === "aborted" ? /* @__PURE__ */ jsx("span", {
|
|
2119
|
+
className: "text-muted-foreground text-sm",
|
|
2120
|
+
children: t("conversation.stopped")
|
|
2121
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
2122
|
+
className: "text-muted-foreground text-sm",
|
|
2123
|
+
children: t("conversation.incomplete")
|
|
2124
|
+
})
|
|
2125
|
+
})
|
|
2126
|
+
}, message.id);
|
|
2127
|
+
}),
|
|
2128
|
+
showPendingAssistantRow && /* @__PURE__ */ jsx(Message, {
|
|
1990
2129
|
className: "max-w-[96%] gap-1",
|
|
1991
|
-
from:
|
|
2130
|
+
from: "assistant",
|
|
1992
2131
|
children: /* @__PURE__ */ jsx(MessageContent, {
|
|
1993
|
-
className:
|
|
1994
|
-
children:
|
|
1995
|
-
applyResultsByChangeId,
|
|
1996
|
-
isLastMessage,
|
|
1997
|
-
isStreaming: isAssistantTurnActive,
|
|
1998
|
-
message,
|
|
1999
|
-
showProgress: shouldShowProgress,
|
|
2000
|
-
terminalTurnStatus
|
|
2001
|
-
}), isLastMessage && latestTurnOutcome && /* @__PURE__ */ jsx(SurveyAssistantTurnOutcomeNotice, { ...latestTurnOutcome })] }) : shouldShowProgress ? /* @__PURE__ */ jsx(SurveyAssistantProgressIndicator, { message }) : isLastMessage && latestTurnOutcome ? /* @__PURE__ */ jsx(SurveyAssistantTurnOutcomeNotice, { ...latestTurnOutcome }) : state === "aborted" ? /* @__PURE__ */ jsx("span", {
|
|
2002
|
-
className: "text-muted-foreground text-sm",
|
|
2003
|
-
children: t("conversation.stopped")
|
|
2004
|
-
}) : /* @__PURE__ */ jsx("span", {
|
|
2005
|
-
className: "text-muted-foreground text-sm",
|
|
2006
|
-
children: t("conversation.incomplete")
|
|
2007
|
-
})
|
|
2132
|
+
className: "w-full",
|
|
2133
|
+
children: /* @__PURE__ */ jsx(SurveyAssistantProgressIndicator, {})
|
|
2008
2134
|
})
|
|
2009
|
-
}, message.id);
|
|
2010
|
-
}), showPendingAssistantRow && /* @__PURE__ */ jsx(Message, {
|
|
2011
|
-
className: "max-w-[96%] gap-1",
|
|
2012
|
-
from: "assistant",
|
|
2013
|
-
children: /* @__PURE__ */ jsx(MessageContent, {
|
|
2014
|
-
className: "w-full",
|
|
2015
|
-
children: /* @__PURE__ */ jsx(SurveyAssistantProgressIndicator, {})
|
|
2016
2135
|
})
|
|
2017
|
-
|
|
2136
|
+
] })
|
|
2018
2137
|
}), /* @__PURE__ */ jsx(ConversationScrollButton, { className: "bottom-2.5" })]
|
|
2019
2138
|
}),
|
|
2020
2139
|
showAssistantError && /* @__PURE__ */ jsxs("div", {
|
|
@@ -2037,7 +2156,7 @@ const SurveyAssistantChatPanel = ({ api, applyPolicy, controller, embedded = fal
|
|
|
2037
2156
|
className: "mt-1 text-muted-foreground/80",
|
|
2038
2157
|
children: assistantErrorPresentation.hint
|
|
2039
2158
|
}),
|
|
2040
|
-
/* @__PURE__ */ jsx("button", {
|
|
2159
|
+
assistantErrorPresentation.retryable && /* @__PURE__ */ jsx("button", {
|
|
2041
2160
|
className: "mt-1.5 font-medium text-foreground text-xs hover:underline",
|
|
2042
2161
|
onClick: retry,
|
|
2043
2162
|
type: "button",
|
|
@@ -2081,14 +2200,32 @@ const createThreadTitle = (text, fallback) => {
|
|
|
2081
2200
|
const words = normalized.split(" ").slice(0, 8).join(" ");
|
|
2082
2201
|
return words.length > 64 ? `${words.slice(0, 61).trimEnd()}...` : words;
|
|
2083
2202
|
};
|
|
2203
|
+
const mergeThreads = (current, incoming) => {
|
|
2204
|
+
const byId = new Map(current.map((thread) => [thread.id, thread]));
|
|
2205
|
+
for (const thread of incoming) byId.set(thread.id, thread);
|
|
2206
|
+
return [...byId.values()].sort((left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt));
|
|
2207
|
+
};
|
|
2208
|
+
const mergeRecentThreadPage = (current, recent) => {
|
|
2209
|
+
if (recent.length === 0) return [];
|
|
2210
|
+
const oldestRecentUpdate = Math.min(...recent.map((thread) => Date.parse(thread.updatedAt)));
|
|
2211
|
+
return mergeThreads(Number.isFinite(oldestRecentUpdate) ? current.filter((thread) => Date.parse(thread.updatedAt) <= oldestRecentUpdate) : current, recent);
|
|
2212
|
+
};
|
|
2213
|
+
const listThreadPage = async (client, cursor) => {
|
|
2214
|
+
if (client.listPage) return client.listPage(cursor ? { cursor } : void 0);
|
|
2215
|
+
return cursor ? { threads: [] } : { threads: await client.list() };
|
|
2216
|
+
};
|
|
2084
2217
|
const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], onConfirmDeleteThread, onModelChange = () => {}, onTurnActiveChange: onAssistantTurnActiveChange, resourceId, selectedThreadStorageKey, surveyId, threadApi, threadClient: providedThreadClient, threadLauncher, ...sessionProps }) => {
|
|
2085
2218
|
const t = useSurveyAssistantTranslation();
|
|
2086
2219
|
const threadClient = useMemo(() => providedThreadClient ?? createSurveyAssistantThreadClient(threadApi), [providedThreadClient, threadApi]);
|
|
2087
2220
|
const storageKey = selectedThreadStorageKey === false ? null : selectedThreadStorageKey ?? `${SELECTED_THREAD_STORAGE_KEY}:${encodeURIComponent(resourceId)}${surveyId ? `:${encodeURIComponent(surveyId)}` : ""}`;
|
|
2088
2221
|
const [threads, setThreads] = useState([]);
|
|
2222
|
+
const [nextThreadCursor, setNextThreadCursor] = useState();
|
|
2089
2223
|
const [selectedThread, setSelectedThread] = useState(null);
|
|
2090
2224
|
const [initialMessages, setInitialMessages] = useState([]);
|
|
2225
|
+
const [nextMessageCursor, setNextMessageCursor] = useState();
|
|
2091
2226
|
const [historyOpen, setHistoryOpen] = useState(false);
|
|
2227
|
+
const [threadSearch, setThreadSearch] = useState("");
|
|
2228
|
+
const [loadingOlderThreads, setLoadingOlderThreads] = useState(false);
|
|
2092
2229
|
const [editingThreadId, setEditingThreadId] = useState(null);
|
|
2093
2230
|
const [editingTitle, setEditingTitle] = useState("");
|
|
2094
2231
|
const [threadError, setThreadError] = useState(null);
|
|
@@ -2096,21 +2233,25 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2096
2233
|
const [assistantTurnActive, setAssistantTurnActive] = useState(false);
|
|
2097
2234
|
const [initialLaunch, setInitialLaunch] = useState();
|
|
2098
2235
|
const historyControlsRef = useRef(null);
|
|
2236
|
+
const loadingAllThreadsRef = useRef(false);
|
|
2099
2237
|
const selectModel = useCallback((modelId) => {
|
|
2100
2238
|
if (!models.some((model) => model.id === modelId)) return;
|
|
2101
2239
|
onModelChange(modelId);
|
|
2102
2240
|
}, [models, onModelChange]);
|
|
2103
|
-
const selectThread = useCallback(async (thread) => {
|
|
2241
|
+
const selectThread = useCallback(async (thread, reportError = true) => {
|
|
2104
2242
|
setLoadingThread(true);
|
|
2105
2243
|
setThreadError(null);
|
|
2106
2244
|
try {
|
|
2107
2245
|
const transcript = await threadClient.read(thread.id);
|
|
2108
2246
|
setSelectedThread(transcript.thread);
|
|
2109
2247
|
setInitialMessages(transcript.messages);
|
|
2248
|
+
setNextMessageCursor(transcript.nextCursor);
|
|
2110
2249
|
setHistoryOpen(false);
|
|
2111
2250
|
if (storageKey) window.localStorage.setItem(storageKey, thread.id);
|
|
2251
|
+
return transcript.thread;
|
|
2112
2252
|
} catch (error) {
|
|
2113
|
-
setThreadError(parseSurveyAssistantError(error).detail ?? t("errors.fallbackDetail"));
|
|
2253
|
+
if (reportError) setThreadError(parseSurveyAssistantError(error).detail ?? t("errors.fallbackDetail"));
|
|
2254
|
+
return null;
|
|
2114
2255
|
} finally {
|
|
2115
2256
|
setLoadingThread(false);
|
|
2116
2257
|
}
|
|
@@ -2124,9 +2265,10 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2124
2265
|
setThreadError(null);
|
|
2125
2266
|
try {
|
|
2126
2267
|
const thread = await threadClient.create(launch?.title);
|
|
2127
|
-
setThreads((current) => [thread
|
|
2268
|
+
setThreads((current) => mergeThreads(current, [thread]));
|
|
2128
2269
|
setSelectedThread(thread);
|
|
2129
2270
|
setInitialMessages([]);
|
|
2271
|
+
setNextMessageCursor(void 0);
|
|
2130
2272
|
setHistoryOpen(false);
|
|
2131
2273
|
if (storageKey) window.localStorage.setItem(storageKey, thread.id);
|
|
2132
2274
|
return thread;
|
|
@@ -2144,11 +2286,21 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2144
2286
|
]);
|
|
2145
2287
|
useEffect(() => {
|
|
2146
2288
|
let cancelled = false;
|
|
2147
|
-
threadClient
|
|
2289
|
+
listThreadPage(threadClient).then(async (page) => {
|
|
2148
2290
|
if (cancelled) return;
|
|
2291
|
+
const availableThreads = page.threads;
|
|
2149
2292
|
setThreads(availableThreads);
|
|
2293
|
+
setNextThreadCursor(page.nextCursor);
|
|
2150
2294
|
const rememberedId = storageKey ? window.localStorage.getItem(storageKey) : null;
|
|
2151
|
-
const
|
|
2295
|
+
const rememberedThread = availableThreads.find((thread) => thread.id === rememberedId);
|
|
2296
|
+
if (rememberedId && !rememberedThread) {
|
|
2297
|
+
const restored = await selectThread({ id: rememberedId }, false);
|
|
2298
|
+
if (restored) {
|
|
2299
|
+
setThreads((current) => mergeThreads(current, [restored]));
|
|
2300
|
+
return;
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
const initialThread = rememberedThread ?? availableThreads[0];
|
|
2152
2304
|
if (initialThread) await selectThread(initialThread);
|
|
2153
2305
|
else await createThread();
|
|
2154
2306
|
}).catch((error) => {
|
|
@@ -2167,6 +2319,66 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2167
2319
|
t,
|
|
2168
2320
|
threadClient
|
|
2169
2321
|
]);
|
|
2322
|
+
const loadOlderThreads = useCallback(async () => {
|
|
2323
|
+
if (!nextThreadCursor || loadingOlderThreads) return;
|
|
2324
|
+
setLoadingOlderThreads(true);
|
|
2325
|
+
try {
|
|
2326
|
+
const page = await listThreadPage(threadClient, nextThreadCursor);
|
|
2327
|
+
setThreads((current) => mergeThreads(current, page.threads));
|
|
2328
|
+
setNextThreadCursor(page.nextCursor);
|
|
2329
|
+
} catch (error) {
|
|
2330
|
+
setThreadError(parseSurveyAssistantError(error).detail ?? t("errors.fallbackDetail"));
|
|
2331
|
+
} finally {
|
|
2332
|
+
setLoadingOlderThreads(false);
|
|
2333
|
+
}
|
|
2334
|
+
}, [
|
|
2335
|
+
loadingOlderThreads,
|
|
2336
|
+
nextThreadCursor,
|
|
2337
|
+
t,
|
|
2338
|
+
threadClient
|
|
2339
|
+
]);
|
|
2340
|
+
const loadEarlierMessages = useCallback(async () => {
|
|
2341
|
+
if (!selectedThread || !nextMessageCursor) return [];
|
|
2342
|
+
try {
|
|
2343
|
+
const transcript = await threadClient.read(selectedThread.id, nextMessageCursor);
|
|
2344
|
+
setNextMessageCursor(transcript.nextCursor);
|
|
2345
|
+
return transcript.messages;
|
|
2346
|
+
} catch (error) {
|
|
2347
|
+
setThreadError(parseSurveyAssistantError(error).detail ?? t("errors.fallbackDetail"));
|
|
2348
|
+
return [];
|
|
2349
|
+
}
|
|
2350
|
+
}, [
|
|
2351
|
+
nextMessageCursor,
|
|
2352
|
+
selectedThread,
|
|
2353
|
+
t,
|
|
2354
|
+
threadClient
|
|
2355
|
+
]);
|
|
2356
|
+
const loadAllThreadsForSearch = useCallback(async () => {
|
|
2357
|
+
if (!nextThreadCursor || loadingAllThreadsRef.current) return;
|
|
2358
|
+
loadingAllThreadsRef.current = true;
|
|
2359
|
+
setLoadingOlderThreads(true);
|
|
2360
|
+
try {
|
|
2361
|
+
let cursor = nextThreadCursor;
|
|
2362
|
+
while (cursor) {
|
|
2363
|
+
const page = await listThreadPage(threadClient, cursor);
|
|
2364
|
+
setThreads((current) => mergeThreads(current, page.threads));
|
|
2365
|
+
cursor = page.nextCursor;
|
|
2366
|
+
setNextThreadCursor(cursor);
|
|
2367
|
+
}
|
|
2368
|
+
} catch (error) {
|
|
2369
|
+
setThreadError(parseSurveyAssistantError(error).detail ?? t("errors.fallbackDetail"));
|
|
2370
|
+
} finally {
|
|
2371
|
+
loadingAllThreadsRef.current = false;
|
|
2372
|
+
setLoadingOlderThreads(false);
|
|
2373
|
+
}
|
|
2374
|
+
}, [
|
|
2375
|
+
nextThreadCursor,
|
|
2376
|
+
t,
|
|
2377
|
+
threadClient
|
|
2378
|
+
]);
|
|
2379
|
+
useEffect(() => {
|
|
2380
|
+
if (threadSearch.trim()) loadAllThreadsForSearch();
|
|
2381
|
+
}, [loadAllThreadsForSearch, threadSearch]);
|
|
2170
2382
|
useEffect(() => {
|
|
2171
2383
|
if (!threadLauncher || loadingThread) return;
|
|
2172
2384
|
return connectSurveyAssistantThreadLauncher(threadLauncher, async (launch) => {
|
|
@@ -2274,9 +2486,9 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2274
2486
|
}, [initialLaunch]);
|
|
2275
2487
|
const refreshThreadList = useCallback(async (reportError) => {
|
|
2276
2488
|
try {
|
|
2277
|
-
const
|
|
2278
|
-
setThreads(
|
|
2279
|
-
const current =
|
|
2489
|
+
const page = await listThreadPage(threadClient);
|
|
2490
|
+
setThreads((current) => mergeRecentThreadPage(current, page.threads));
|
|
2491
|
+
const current = page.threads.find((thread) => thread.id === selectedThread?.id);
|
|
2280
2492
|
if (current && !editingThreadId) setSelectedThread((selected) => {
|
|
2281
2493
|
if (!selected || selected.id !== current.id) return selected;
|
|
2282
2494
|
return selected.title === current.title && selected.titleMode === current.titleMode && selected.updatedAt === current.updatedAt ? selected : current;
|
|
@@ -2352,6 +2564,8 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2352
2564
|
children: [/* @__PURE__ */ jsx(LoaderCircleIcon, { className: "mr-2 size-4 animate-spin" }), t("panel.loadingChats")]
|
|
2353
2565
|
})]
|
|
2354
2566
|
});
|
|
2567
|
+
const normalizedThreadSearch = threadSearch.trim().toLocaleLowerCase();
|
|
2568
|
+
const visibleThreads = normalizedThreadSearch ? threads.filter((thread) => thread.title.toLocaleLowerCase().includes(normalizedThreadSearch)) : threads;
|
|
2355
2569
|
const threadControls = /* @__PURE__ */ jsxs("div", {
|
|
2356
2570
|
className: "relative flex shrink-0 items-center gap-1",
|
|
2357
2571
|
ref: historyControlsRef,
|
|
@@ -2377,65 +2591,92 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2377
2591
|
}),
|
|
2378
2592
|
historyOpen && /* @__PURE__ */ jsxs("div", {
|
|
2379
2593
|
className: "absolute top-10 right-0 z-30 w-72 overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-lg",
|
|
2380
|
-
children: [
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
className:
|
|
2594
|
+
children: [
|
|
2595
|
+
/* @__PURE__ */ jsx("div", {
|
|
2596
|
+
className: "border-b border-border px-3 py-2 font-medium text-xs",
|
|
2597
|
+
children: t("threads.recent")
|
|
2598
|
+
}),
|
|
2599
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2600
|
+
className: "relative border-b border-border p-2",
|
|
2601
|
+
children: [/* @__PURE__ */ jsx(SearchIcon, { className: "pointer-events-none absolute top-1/2 left-4 size-3.5 -translate-y-1/2 text-muted-foreground" }), /* @__PURE__ */ jsx("input", {
|
|
2602
|
+
"aria-label": t("threads.search"),
|
|
2603
|
+
className: "h-8 w-full rounded-md border border-input bg-background pr-2 pl-8 text-xs outline-none placeholder:text-muted-foreground focus:ring-1 focus:ring-ring",
|
|
2604
|
+
onChange: (event) => setThreadSearch(event.currentTarget.value),
|
|
2605
|
+
placeholder: t("threads.search"),
|
|
2606
|
+
type: "search",
|
|
2607
|
+
value: threadSearch
|
|
2608
|
+
})]
|
|
2609
|
+
}),
|
|
2610
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2611
|
+
className: "max-h-72 overflow-y-auto p-1",
|
|
2387
2612
|
children: [
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
event.
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2613
|
+
visibleThreads.map((thread) => /* @__PURE__ */ jsxs("div", {
|
|
2614
|
+
className: cn("group flex min-h-10 items-center gap-1 rounded-md px-2", thread.id === selectedThread.id ? "bg-muted" : "hover:bg-muted/60"),
|
|
2615
|
+
children: [
|
|
2616
|
+
editingThreadId === thread.id ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("input", {
|
|
2617
|
+
autoFocus: true,
|
|
2618
|
+
className: "min-w-0 flex-1 rounded border border-input bg-background px-1.5 py-1 text-xs outline-none focus:ring-1 focus:ring-ring",
|
|
2619
|
+
onBlur: () => void commitEditingThread(),
|
|
2620
|
+
onChange: (event) => setEditingTitle(event.currentTarget.value),
|
|
2621
|
+
onKeyDown: (event) => {
|
|
2622
|
+
if (event.key === "Enter") {
|
|
2623
|
+
event.preventDefault();
|
|
2624
|
+
commitEditingThread();
|
|
2625
|
+
}
|
|
2626
|
+
if (event.key === "Escape") {
|
|
2627
|
+
event.preventDefault();
|
|
2628
|
+
event.stopPropagation();
|
|
2629
|
+
cancelEditingThread();
|
|
2630
|
+
setHistoryOpen(false);
|
|
2631
|
+
}
|
|
2632
|
+
},
|
|
2633
|
+
value: editingTitle
|
|
2634
|
+
}), thread.titleMode === "manual" && /* @__PURE__ */ jsxs("button", {
|
|
2635
|
+
"aria-label": t("threads.automaticTitle"),
|
|
2636
|
+
className: "flex h-7 shrink-0 items-center gap-1 rounded px-1.5 text-muted-foreground text-xs hover:bg-background hover:text-foreground",
|
|
2637
|
+
onClick: () => void setAutomaticTitle(thread),
|
|
2638
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
2639
|
+
title: t("threads.automaticTitle"),
|
|
2640
|
+
type: "button",
|
|
2641
|
+
children: [/* @__PURE__ */ jsx(SparklesIcon, { className: "size-3" }), /* @__PURE__ */ jsx("span", { children: t("threads.automaticShort") })]
|
|
2642
|
+
})] }) : /* @__PURE__ */ jsx("button", {
|
|
2643
|
+
className: "min-w-0 flex-1 truncate py-2 text-left text-xs",
|
|
2644
|
+
onClick: () => void selectThread(thread),
|
|
2645
|
+
type: "button",
|
|
2646
|
+
children: thread.title
|
|
2647
|
+
}),
|
|
2648
|
+
/* @__PURE__ */ jsx("button", {
|
|
2649
|
+
"aria-label": t("threads.rename", { title: thread.title }),
|
|
2650
|
+
className: "flex size-7 shrink-0 items-center justify-center rounded text-muted-foreground opacity-0 hover:bg-background hover:text-foreground group-hover:opacity-100",
|
|
2651
|
+
onClick: () => beginEditingThread(thread),
|
|
2652
|
+
title: t("threads.renameTitle"),
|
|
2653
|
+
type: "button",
|
|
2654
|
+
children: /* @__PURE__ */ jsx(PencilIcon, { className: "size-3.5" })
|
|
2655
|
+
}),
|
|
2656
|
+
/* @__PURE__ */ jsx("button", {
|
|
2657
|
+
"aria-label": t("threads.delete", { title: thread.title }),
|
|
2658
|
+
className: "flex size-7 shrink-0 items-center justify-center rounded text-muted-foreground opacity-0 hover:bg-background hover:text-foreground group-hover:opacity-100",
|
|
2659
|
+
onClick: () => void deleteThread(thread),
|
|
2660
|
+
title: t("threads.deleteTitle"),
|
|
2661
|
+
type: "button",
|
|
2662
|
+
children: /* @__PURE__ */ jsx(Trash2Icon, { className: "size-3.5" })
|
|
2663
|
+
})
|
|
2664
|
+
]
|
|
2665
|
+
}, thread.id)),
|
|
2666
|
+
visibleThreads.length === 0 && !loadingOlderThreads && /* @__PURE__ */ jsx("div", {
|
|
2667
|
+
className: "px-3 py-5 text-center text-muted-foreground text-xs",
|
|
2668
|
+
children: t("threads.noMatches")
|
|
2427
2669
|
}),
|
|
2428
|
-
/* @__PURE__ */ jsx("button", {
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
onClick: () => void
|
|
2432
|
-
title: t("threads.deleteTitle"),
|
|
2670
|
+
(nextThreadCursor || loadingOlderThreads) && /* @__PURE__ */ jsx("button", {
|
|
2671
|
+
className: "flex h-9 w-full items-center justify-center rounded-md text-muted-foreground text-xs hover:bg-muted hover:text-foreground disabled:pointer-events-none",
|
|
2672
|
+
disabled: loadingOlderThreads || Boolean(normalizedThreadSearch),
|
|
2673
|
+
onClick: () => void loadOlderThreads(),
|
|
2433
2674
|
type: "button",
|
|
2434
|
-
children: /* @__PURE__ */ jsx(
|
|
2675
|
+
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")
|
|
2435
2676
|
})
|
|
2436
2677
|
]
|
|
2437
|
-
}
|
|
2438
|
-
|
|
2678
|
+
})
|
|
2679
|
+
]
|
|
2439
2680
|
})
|
|
2440
2681
|
]
|
|
2441
2682
|
});
|
|
@@ -2444,6 +2685,7 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2444
2685
|
children: [/* @__PURE__ */ createElement(SurveyAssistantChatPanel, {
|
|
2445
2686
|
...sessionProps,
|
|
2446
2687
|
embedded,
|
|
2688
|
+
hasEarlierMessages: Boolean(nextMessageCursor),
|
|
2447
2689
|
initialLaunch: initialLaunch?.input,
|
|
2448
2690
|
initialMessages,
|
|
2449
2691
|
key: selectedThread.id,
|
|
@@ -2452,6 +2694,7 @@ const SurveyAssistantPanelContent = ({ embedded = false, modelId, models = [], o
|
|
|
2452
2694
|
onInitialLaunchHandled: handleInitialLaunchHandled,
|
|
2453
2695
|
onModelChange: selectModel,
|
|
2454
2696
|
onFirstSubmit: handleFirstSubmit,
|
|
2697
|
+
onLoadEarlierMessages: loadEarlierMessages,
|
|
2455
2698
|
onTurnSettled: handleTurnSettled,
|
|
2456
2699
|
onTurnActiveChange: handleTurnActiveChange,
|
|
2457
2700
|
resourceId,
|