@xinghunm/ai-chat 0.4.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +82 -12
- package/dist/index.d.ts +82 -12
- package/dist/index.js +636 -143
- package/dist/index.mjs +651 -158
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -31,10 +31,18 @@ var DEFAULT_AI_CHAT_LABELS = {
|
|
|
31
31
|
attachmentLimitNotice: "Images exceeded the limit. Only the first 10 images were kept.",
|
|
32
32
|
userRoleLabel: "User",
|
|
33
33
|
assistantRoleLabel: "Assistant",
|
|
34
|
+
expandMessageAriaLabel: "Expand message",
|
|
35
|
+
collapseMessageAriaLabel: "Collapse message",
|
|
36
|
+
expandComposerAriaLabel: "Expand composer",
|
|
37
|
+
collapseComposerAriaLabel: "Collapse composer",
|
|
34
38
|
stoppedResponse: "Response stopped",
|
|
35
39
|
assistantStreamingAriaLabel: "assistant streaming",
|
|
36
40
|
networkError: "Network request failed. Please try again.",
|
|
37
|
-
genericError: "Something went wrong. Please try again."
|
|
41
|
+
genericError: "Something went wrong. Please try again.",
|
|
42
|
+
questionnaireSubmitting: "Submitting...",
|
|
43
|
+
questionnaireSubmitted: "Selection submitted. Waiting for the plan to continue...",
|
|
44
|
+
questionnaireValidationPrefix: "Please complete:",
|
|
45
|
+
questionnaireSubmitFailed: "Failed to submit. Please try again."
|
|
38
46
|
};
|
|
39
47
|
|
|
40
48
|
// src/store/chat-store.ts
|
|
@@ -50,6 +58,40 @@ var resolveSessionTitleFromMessage = (message) => {
|
|
|
50
58
|
}
|
|
51
59
|
return DEFAULT_CHAT_SESSION_TITLE;
|
|
52
60
|
};
|
|
61
|
+
var mergeStreamingBlocks = (existingBlocks, incomingBlocks) => {
|
|
62
|
+
const nextBlocks = [...existingBlocks ?? []];
|
|
63
|
+
incomingBlocks.forEach((incomingBlock) => {
|
|
64
|
+
if (incomingBlock.type === "custom" && incomingBlock.blockKey) {
|
|
65
|
+
const mergePolicy = incomingBlock.mergePolicy ?? "append";
|
|
66
|
+
if (mergePolicy !== "append") {
|
|
67
|
+
const existingIndex2 = nextBlocks.findIndex(
|
|
68
|
+
(block) => block.type === "custom" && block.blockKey === incomingBlock.blockKey
|
|
69
|
+
);
|
|
70
|
+
if (existingIndex2 !== -1) {
|
|
71
|
+
if (mergePolicy === "replace") {
|
|
72
|
+
nextBlocks[existingIndex2] = incomingBlock;
|
|
73
|
+
}
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
nextBlocks.push(incomingBlock);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (incomingBlock.type !== "questionnaire") {
|
|
81
|
+
nextBlocks.push(incomingBlock);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const existingIndex = nextBlocks.findIndex(
|
|
85
|
+
(block) => block.type === "questionnaire" && block.questionnaire.questionnaireId === incomingBlock.questionnaire.questionnaireId
|
|
86
|
+
);
|
|
87
|
+
if (existingIndex === -1) {
|
|
88
|
+
nextBlocks.push(incomingBlock);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
nextBlocks[existingIndex] = incomingBlock;
|
|
92
|
+
});
|
|
93
|
+
return nextBlocks;
|
|
94
|
+
};
|
|
53
95
|
var finalizeStreamingMessage = (state, sessionId, status, clearError = false) => {
|
|
54
96
|
const message = state.streamingMessageBySession[sessionId];
|
|
55
97
|
const hasRenderableMessagePayload = Boolean(
|
|
@@ -239,10 +281,15 @@ var createChatStore = (initialState) => createStore((set, get) => ({
|
|
|
239
281
|
const target = state.streamingMessageBySession[sessionId];
|
|
240
282
|
if (!target)
|
|
241
283
|
return;
|
|
284
|
+
const nextBlocks = patch.blocks !== void 0 ? mergeStreamingBlocks(target.blocks, patch.blocks) : target.blocks;
|
|
242
285
|
set({
|
|
243
286
|
streamingMessageBySession: {
|
|
244
287
|
...state.streamingMessageBySession,
|
|
245
|
-
[sessionId]: {
|
|
288
|
+
[sessionId]: {
|
|
289
|
+
...target,
|
|
290
|
+
...patch,
|
|
291
|
+
...patch.blocks !== void 0 ? { blocks: nextBlocks } : {}
|
|
292
|
+
}
|
|
246
293
|
}
|
|
247
294
|
});
|
|
248
295
|
},
|
|
@@ -462,9 +509,27 @@ var DEFAULT_CHAT_TRANSPORT_ENDPOINTS = {
|
|
|
462
509
|
completions: "/chat/completions",
|
|
463
510
|
terminate: "/chat/terminate"
|
|
464
511
|
};
|
|
512
|
+
var createToolExecutionHeaders = (policy) => {
|
|
513
|
+
if (!policy?.enabled) {
|
|
514
|
+
return {};
|
|
515
|
+
}
|
|
516
|
+
return {
|
|
517
|
+
"X-Tool-Approval-Required": String(Boolean(policy.approvalRequired)),
|
|
518
|
+
...typeof policy.approvalTimeoutSec === "number" ? { "X-Tool-Approval-Timeout": String(policy.approvalTimeoutSec) } : {}
|
|
519
|
+
};
|
|
520
|
+
};
|
|
521
|
+
var createModeDefaultHeaders = (mode) => {
|
|
522
|
+
if (mode === "ask" || mode === "plan") {
|
|
523
|
+
return {
|
|
524
|
+
"X-Tool-Approval-Required": "false"
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
return {};
|
|
528
|
+
};
|
|
465
529
|
var createDefaultChatTransport = ({
|
|
466
530
|
apiBaseUrl,
|
|
467
531
|
authToken,
|
|
532
|
+
toolExecutionPolicy,
|
|
468
533
|
streamHeaders,
|
|
469
534
|
transformStreamPacket,
|
|
470
535
|
endpoints,
|
|
@@ -475,6 +540,10 @@ var createDefaultChatTransport = ({
|
|
|
475
540
|
...DEFAULT_CHAT_TRANSPORT_ENDPOINTS,
|
|
476
541
|
...endpoints
|
|
477
542
|
};
|
|
543
|
+
const resolvedStreamHeaders = {
|
|
544
|
+
...createToolExecutionHeaders(toolExecutionPolicy),
|
|
545
|
+
...streamHeaders
|
|
546
|
+
};
|
|
478
547
|
return {
|
|
479
548
|
getModels: () => getChatModels(client, resolvedEndpoints.models),
|
|
480
549
|
startStream: async ({
|
|
@@ -488,12 +557,16 @@ var createDefaultChatTransport = ({
|
|
|
488
557
|
onDone,
|
|
489
558
|
onError
|
|
490
559
|
}) => {
|
|
560
|
+
const requestHeaders = {
|
|
561
|
+
...createModeDefaultHeaders(mode),
|
|
562
|
+
...resolvedStreamHeaders
|
|
563
|
+
};
|
|
491
564
|
await startChatStream({
|
|
492
565
|
apiBaseUrl,
|
|
493
566
|
endpointPath: resolvedEndpoints.completions,
|
|
494
567
|
sessionId,
|
|
495
568
|
authToken,
|
|
496
|
-
requestHeaders
|
|
569
|
+
requestHeaders,
|
|
497
570
|
model,
|
|
498
571
|
mode,
|
|
499
572
|
content,
|
|
@@ -522,6 +595,8 @@ var AiChatProvider = (props) => {
|
|
|
522
595
|
defaultMode,
|
|
523
596
|
labels,
|
|
524
597
|
renderMessageBlock,
|
|
598
|
+
handleQuestionnaireSubmit,
|
|
599
|
+
handleConfirmationSubmit,
|
|
525
600
|
messageRenderOrder,
|
|
526
601
|
enableImageAttachments = true,
|
|
527
602
|
children
|
|
@@ -577,6 +652,8 @@ var AiChatProvider = (props) => {
|
|
|
577
652
|
sendRef,
|
|
578
653
|
retryRef,
|
|
579
654
|
renderMessageBlock,
|
|
655
|
+
handleQuestionnaireSubmit,
|
|
656
|
+
handleConfirmationSubmit,
|
|
580
657
|
messageRenderOrder,
|
|
581
658
|
transformStreamPacket: defaultTransformStreamPacket,
|
|
582
659
|
enableImageAttachments
|
|
@@ -587,6 +664,8 @@ var AiChatProvider = (props) => {
|
|
|
587
664
|
defaultAuthToken,
|
|
588
665
|
defaultTransformStreamPacket,
|
|
589
666
|
enableImageAttachments,
|
|
667
|
+
handleConfirmationSubmit,
|
|
668
|
+
handleQuestionnaireSubmit,
|
|
590
669
|
labels,
|
|
591
670
|
messageRenderOrder,
|
|
592
671
|
renderMessageBlock,
|
|
@@ -600,7 +679,7 @@ var AiChatProvider = (props) => {
|
|
|
600
679
|
};
|
|
601
680
|
|
|
602
681
|
// src/components/chat-thread/index.tsx
|
|
603
|
-
import { useCallback as
|
|
682
|
+
import { useCallback as useCallback3, useLayoutEffect as useLayoutEffect2, useMemo as useMemo4, useRef as useRef4, useState as useState4 } from "react";
|
|
604
683
|
import styled9 from "@emotion/styled";
|
|
605
684
|
|
|
606
685
|
// src/context/use-chat-context.ts
|
|
@@ -621,7 +700,7 @@ var useChatStore = (selector) => {
|
|
|
621
700
|
var CHAT_THREAD_SCROLL_TOP_GAP = 16;
|
|
622
701
|
|
|
623
702
|
// src/components/chat-thread/components/chat-message-item.tsx
|
|
624
|
-
import { Fragment, memo, useState as useState3 } from "react";
|
|
703
|
+
import { Fragment, memo, useCallback as useCallback2, useLayoutEffect, useState as useState3 } from "react";
|
|
625
704
|
import styled7 from "@emotion/styled";
|
|
626
705
|
import { keyframes } from "@emotion/react";
|
|
627
706
|
import ReactMarkdown from "react-markdown";
|
|
@@ -896,11 +975,11 @@ var getTimelineBlockKey = (block, index) => {
|
|
|
896
975
|
case "confirmation_card":
|
|
897
976
|
return `${index}:confirmation_card:${block.proposal.proposalId}`;
|
|
898
977
|
case "result_summary":
|
|
899
|
-
return `${index}:result_summary:${block.summary.
|
|
978
|
+
return `${index}:result_summary:${block.summary.summaryId}:${block.summary.status}`;
|
|
900
979
|
case "questionnaire":
|
|
901
980
|
return `${index}:questionnaire:${block.questionnaire.questionnaireId}`;
|
|
902
981
|
case "custom":
|
|
903
|
-
return `${index}:custom:${block.kind}:${stringifyTimelineKeyPart(block.data)}`;
|
|
982
|
+
return block.blockKey ? `custom:${block.blockKey}` : `${index}:custom:${block.kind}:${stringifyTimelineKeyPart(block.data)}`;
|
|
904
983
|
default:
|
|
905
984
|
return null;
|
|
906
985
|
}
|
|
@@ -1188,21 +1267,21 @@ var useTimelineBlockAnchors = ({
|
|
|
1188
1267
|
};
|
|
1189
1268
|
};
|
|
1190
1269
|
|
|
1191
|
-
// src/components/chat-thread/components/
|
|
1270
|
+
// src/components/chat-thread/components/execution-confirmation-card.tsx
|
|
1192
1271
|
import styled from "@emotion/styled";
|
|
1193
1272
|
import { jsx as jsx2, jsxs } from "@emotion/react/jsx-runtime";
|
|
1194
|
-
var
|
|
1273
|
+
var ExecutionConfirmationCard = ({
|
|
1195
1274
|
proposal,
|
|
1196
1275
|
interactive = false,
|
|
1197
1276
|
onApply,
|
|
1198
1277
|
onConfirm,
|
|
1199
1278
|
onRevise
|
|
1200
1279
|
}) => {
|
|
1201
|
-
return /* @__PURE__ */ jsxs(Card, { "data-testid": "
|
|
1280
|
+
return /* @__PURE__ */ jsxs(Card, { "data-testid": "execution-confirmation-card", children: [
|
|
1202
1281
|
/* @__PURE__ */ jsxs(Header, { children: [
|
|
1203
1282
|
/* @__PURE__ */ jsx2(Eyebrow, { children: "Execution Proposal" }),
|
|
1204
|
-
/* @__PURE__ */ jsx2(Title, { children: proposal.
|
|
1205
|
-
proposal.
|
|
1283
|
+
/* @__PURE__ */ jsx2(Title, { children: proposal.resourceName }),
|
|
1284
|
+
proposal.executorName ? /* @__PURE__ */ jsx2(Subtitle, { children: proposal.executorName }) : null
|
|
1206
1285
|
] }),
|
|
1207
1286
|
/* @__PURE__ */ jsx2(SummaryList, { children: proposal.parameterSummary.map((item) => /* @__PURE__ */ jsxs(SummaryItem, { children: [
|
|
1208
1287
|
/* @__PURE__ */ jsx2(SummaryLabel, { children: item.label }),
|
|
@@ -1210,21 +1289,13 @@ var PDEAIExecutionConfirmationCard = ({
|
|
|
1210
1289
|
] }, `${item.fieldPath ?? item.label}-${item.value}`)) }),
|
|
1211
1290
|
proposal.warnings?.length ? /* @__PURE__ */ jsx2(Warnings, { children: proposal.warnings.map((warning) => /* @__PURE__ */ jsx2(Warning, { children: warning }, warning)) }) : null,
|
|
1212
1291
|
interactive ? /* @__PURE__ */ jsxs(Actions, { children: [
|
|
1213
|
-
onApply && /* @__PURE__ */ jsx2(ActionButton, { type: "button", "data-testid": "
|
|
1214
|
-
onConfirm && /* @__PURE__ */ jsx2(
|
|
1215
|
-
ActionButton,
|
|
1216
|
-
{
|
|
1217
|
-
type: "button",
|
|
1218
|
-
"data-testid": "pde-ai-confirmation-confirm",
|
|
1219
|
-
onClick: onConfirm,
|
|
1220
|
-
children: "Confirm Execution"
|
|
1221
|
-
}
|
|
1222
|
-
),
|
|
1292
|
+
onApply && /* @__PURE__ */ jsx2(ActionButton, { type: "button", "data-testid": "confirmation-apply", onClick: onApply, children: "Apply to Parameters" }),
|
|
1293
|
+
onConfirm && /* @__PURE__ */ jsx2(ActionButton, { type: "button", "data-testid": "confirmation-confirm", onClick: onConfirm, children: "Confirm Execution" }),
|
|
1223
1294
|
onRevise && /* @__PURE__ */ jsx2(
|
|
1224
1295
|
SecondaryActionButton,
|
|
1225
1296
|
{
|
|
1226
1297
|
type: "button",
|
|
1227
|
-
"data-testid": "
|
|
1298
|
+
"data-testid": "confirmation-revise",
|
|
1228
1299
|
onClick: onRevise,
|
|
1229
1300
|
children: "Revise Plan"
|
|
1230
1301
|
}
|
|
@@ -1321,10 +1392,10 @@ var SecondaryActionButton = styled(ActionButton)`
|
|
|
1321
1392
|
border: 1px solid rgba(255, 255, 255, 0.14);
|
|
1322
1393
|
`;
|
|
1323
1394
|
|
|
1324
|
-
// src/components/chat-thread/components/
|
|
1395
|
+
// src/components/chat-thread/components/notice-card.tsx
|
|
1325
1396
|
import styled2 from "@emotion/styled";
|
|
1326
1397
|
import { jsx as jsx3 } from "@emotion/react/jsx-runtime";
|
|
1327
|
-
var
|
|
1398
|
+
var NoticeCard = ({ text, tone }) => /* @__PURE__ */ jsx3(Card2, { "data-testid": "notice-card", "data-tone": tone, children: text });
|
|
1328
1399
|
var Card2 = styled2.div`
|
|
1329
1400
|
padding: 12px 14px;
|
|
1330
1401
|
border-radius: 16px;
|
|
@@ -1350,10 +1421,10 @@ var Card2 = styled2.div`
|
|
|
1350
1421
|
}
|
|
1351
1422
|
`;
|
|
1352
1423
|
|
|
1353
|
-
// src/components/chat-thread/components/
|
|
1424
|
+
// src/components/chat-thread/components/parameter-summary-card.tsx
|
|
1354
1425
|
import styled3 from "@emotion/styled";
|
|
1355
1426
|
import { jsx as jsx4, jsxs as jsxs2 } from "@emotion/react/jsx-runtime";
|
|
1356
|
-
var
|
|
1427
|
+
var ParameterSummaryCard = ({ items }) => /* @__PURE__ */ jsxs2(Card3, { "data-testid": "parameter-summary-card", children: [
|
|
1357
1428
|
/* @__PURE__ */ jsx4(Title2, { children: "Parameter Summary" }),
|
|
1358
1429
|
/* @__PURE__ */ jsx4(List, { children: items.map((item) => /* @__PURE__ */ jsxs2(ListItem, { children: [
|
|
1359
1430
|
/* @__PURE__ */ jsx4(Label, { children: item.label }),
|
|
@@ -1397,11 +1468,17 @@ var Value = styled3.span`
|
|
|
1397
1468
|
text-align: right;
|
|
1398
1469
|
`;
|
|
1399
1470
|
|
|
1400
|
-
// src/components/chat-thread/components/
|
|
1471
|
+
// src/components/chat-thread/components/questionnaire-card.tsx
|
|
1401
1472
|
import { useState as useState2 } from "react";
|
|
1402
1473
|
import styled4 from "@emotion/styled";
|
|
1403
1474
|
import { jsx as jsx5, jsxs as jsxs3 } from "@emotion/react/jsx-runtime";
|
|
1404
1475
|
var OTHER_OPTION_VALUE = "__other__";
|
|
1476
|
+
var DEFAULT_QUESTIONNAIRE_CARD_LABELS = {
|
|
1477
|
+
submitting: "Submitting...",
|
|
1478
|
+
submitted: "Selection submitted. Waiting for the plan to continue...",
|
|
1479
|
+
validationPrefix: "Please complete:",
|
|
1480
|
+
submitFailed: "Failed to submit. Please try again."
|
|
1481
|
+
};
|
|
1405
1482
|
var createInitialAnswers = (questionnaire) => ({
|
|
1406
1483
|
...questionnaire.answers ?? {}
|
|
1407
1484
|
});
|
|
@@ -1495,26 +1572,40 @@ var normalizeQuestionAnswer = (question, answer) => {
|
|
|
1495
1572
|
return answer;
|
|
1496
1573
|
}
|
|
1497
1574
|
};
|
|
1498
|
-
var
|
|
1575
|
+
var QuestionnaireCardInner = ({
|
|
1499
1576
|
questionnaire,
|
|
1500
1577
|
interactive = false,
|
|
1501
|
-
onSubmit
|
|
1578
|
+
onSubmit,
|
|
1579
|
+
labels
|
|
1502
1580
|
}) => {
|
|
1503
1581
|
const [answers, setAnswers] = useState2(
|
|
1504
1582
|
() => createInitialAnswers(questionnaire)
|
|
1505
1583
|
);
|
|
1506
1584
|
const [errorMessage, setErrorMessage] = useState2(null);
|
|
1507
|
-
const
|
|
1585
|
+
const [isSubmitting, setIsSubmitting] = useState2(false);
|
|
1586
|
+
const [isSubmitted, setIsSubmitted] = useState2(false);
|
|
1587
|
+
const resolvedLabels = {
|
|
1588
|
+
...DEFAULT_QUESTIONNAIRE_CARD_LABELS,
|
|
1589
|
+
...labels
|
|
1590
|
+
};
|
|
1591
|
+
const hasExternalFailureStatus = questionnaire.status === "expired" || questionnaire.status === "failed";
|
|
1592
|
+
const visibleErrorMessage = questionnaire.statusMessage ?? errorMessage;
|
|
1593
|
+
const isInteractionLocked = !interactive || isSubmitting || isSubmitted || hasExternalFailureStatus;
|
|
1594
|
+
const handleSubmit = async () => {
|
|
1595
|
+
if (isSubmitting || isSubmitted) {
|
|
1596
|
+
return;
|
|
1597
|
+
}
|
|
1508
1598
|
const missingQuestions = questionnaire.questions.filter(
|
|
1509
1599
|
(question) => question.required && isMissingRequiredAnswer(question, answers)
|
|
1510
1600
|
);
|
|
1511
1601
|
if (missingQuestions.length > 0) {
|
|
1512
1602
|
setErrorMessage(
|
|
1513
|
-
|
|
1603
|
+
`${resolvedLabels.validationPrefix} ${missingQuestions.map((question) => question.label).join(", ")}`
|
|
1514
1604
|
);
|
|
1515
1605
|
return;
|
|
1516
1606
|
}
|
|
1517
1607
|
setErrorMessage(null);
|
|
1608
|
+
setIsSubmitting(true);
|
|
1518
1609
|
const normalizedAnswers = Object.fromEntries(
|
|
1519
1610
|
questionnaire.questions.flatMap((question) => {
|
|
1520
1611
|
const value = normalizeQuestionAnswer(question, answers[question.id]);
|
|
@@ -1531,11 +1622,18 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1531
1622
|
return [`- ${question.label}: ${formatQuestionAnswer(question, value)}`];
|
|
1532
1623
|
})
|
|
1533
1624
|
];
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1625
|
+
try {
|
|
1626
|
+
await onSubmit?.({
|
|
1627
|
+
questionnaireId: questionnaire.questionnaireId,
|
|
1628
|
+
answers: normalizedAnswers,
|
|
1629
|
+
content: contentLines.join("\n")
|
|
1630
|
+
});
|
|
1631
|
+
setIsSubmitted(true);
|
|
1632
|
+
} catch (error) {
|
|
1633
|
+
setErrorMessage(error instanceof Error ? error.message : resolvedLabels.submitFailed);
|
|
1634
|
+
} finally {
|
|
1635
|
+
setIsSubmitting(false);
|
|
1636
|
+
}
|
|
1539
1637
|
};
|
|
1540
1638
|
const renderQuestion = (question) => {
|
|
1541
1639
|
const renderOptionChoice = ({
|
|
@@ -1550,13 +1648,13 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1550
1648
|
OptionChoiceItem,
|
|
1551
1649
|
{
|
|
1552
1650
|
role: "button",
|
|
1553
|
-
tabIndex:
|
|
1651
|
+
tabIndex: isInteractionLocked ? -1 : 0,
|
|
1554
1652
|
"aria-pressed": isSelected,
|
|
1555
1653
|
"data-selected": isSelected,
|
|
1556
1654
|
"data-tone": tone,
|
|
1557
|
-
"data-testid": `
|
|
1655
|
+
"data-testid": `question-option-${questionId}-${index}`,
|
|
1558
1656
|
onClick: (event) => {
|
|
1559
|
-
if (
|
|
1657
|
+
if (isInteractionLocked) {
|
|
1560
1658
|
return;
|
|
1561
1659
|
}
|
|
1562
1660
|
if (event.target instanceof HTMLElement && event.target.closest("input")) {
|
|
@@ -1565,7 +1663,7 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1565
1663
|
onClick();
|
|
1566
1664
|
},
|
|
1567
1665
|
onKeyDown: (event) => {
|
|
1568
|
-
if (
|
|
1666
|
+
if (isInteractionLocked) {
|
|
1569
1667
|
return;
|
|
1570
1668
|
}
|
|
1571
1669
|
if (event.key !== "Enter" && event.key !== " ") {
|
|
@@ -1624,11 +1722,11 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1624
1722
|
inlineInput: singleSelectDraft.selectedValue === OTHER_OPTION_VALUE ? /* @__PURE__ */ jsx5(
|
|
1625
1723
|
InlineOtherInput,
|
|
1626
1724
|
{
|
|
1627
|
-
"data-testid": `
|
|
1725
|
+
"data-testid": `question-input-${question.id}`,
|
|
1628
1726
|
type: "text",
|
|
1629
1727
|
value: singleSelectDraft.otherValue,
|
|
1630
1728
|
placeholder: "Other",
|
|
1631
|
-
readOnly:
|
|
1729
|
+
readOnly: isInteractionLocked,
|
|
1632
1730
|
onClick: (event) => {
|
|
1633
1731
|
event.stopPropagation();
|
|
1634
1732
|
},
|
|
@@ -1649,11 +1747,11 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1649
1747
|
return /* @__PURE__ */ jsx5(QuestionBody, { children: /* @__PURE__ */ jsx5(
|
|
1650
1748
|
TextInput,
|
|
1651
1749
|
{
|
|
1652
|
-
"data-testid": `
|
|
1750
|
+
"data-testid": `question-input-${question.id}`,
|
|
1653
1751
|
type: "text",
|
|
1654
1752
|
value: getTextInputValue(answers[question.id]),
|
|
1655
1753
|
placeholder: question.placeholder,
|
|
1656
|
-
readOnly:
|
|
1754
|
+
readOnly: isInteractionLocked,
|
|
1657
1755
|
onChange: (event) => {
|
|
1658
1756
|
setAnswers((current) => updateAnswerValue(current, question.id, event.target.value));
|
|
1659
1757
|
}
|
|
@@ -1664,11 +1762,11 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1664
1762
|
/* @__PURE__ */ jsx5(
|
|
1665
1763
|
TextInput,
|
|
1666
1764
|
{
|
|
1667
|
-
"data-testid": `
|
|
1765
|
+
"data-testid": `question-input-${question.id}`,
|
|
1668
1766
|
type: "number",
|
|
1669
1767
|
value: getNumberInputValue(answers[question.id]),
|
|
1670
1768
|
placeholder: question.placeholder,
|
|
1671
|
-
readOnly:
|
|
1769
|
+
readOnly: isInteractionLocked,
|
|
1672
1770
|
onChange: (event) => {
|
|
1673
1771
|
setAnswers(
|
|
1674
1772
|
(current) => updateAnswerValue(
|
|
@@ -1703,7 +1801,7 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1703
1801
|
return null;
|
|
1704
1802
|
}
|
|
1705
1803
|
};
|
|
1706
|
-
return /* @__PURE__ */ jsxs3(Card4, { "data-testid": "
|
|
1804
|
+
return /* @__PURE__ */ jsxs3(Card4, { "data-testid": "questionnaire-card", children: [
|
|
1707
1805
|
questionnaire.title ? /* @__PURE__ */ jsx5(Title3, { children: questionnaire.title }) : null,
|
|
1708
1806
|
questionnaire.description ? /* @__PURE__ */ jsx5(Description, { children: questionnaire.description }) : null,
|
|
1709
1807
|
/* @__PURE__ */ jsx5(QuestionList, { children: questionnaire.questions.map((question) => /* @__PURE__ */ jsxs3(QuestionCard, { children: [
|
|
@@ -1713,24 +1811,28 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1713
1811
|
] }),
|
|
1714
1812
|
renderQuestion(question)
|
|
1715
1813
|
] }, question.id)) }),
|
|
1716
|
-
|
|
1717
|
-
interactive ? /* @__PURE__ */ jsx5(
|
|
1814
|
+
visibleErrorMessage ? /* @__PURE__ */ jsx5(ErrorMessage, { "data-testid": "questionnaire-error", children: visibleErrorMessage }) : null,
|
|
1815
|
+
isSubmitted ? /* @__PURE__ */ jsx5(SuccessMessage, { "data-testid": "questionnaire-success", children: resolvedLabels.submitted }) : interactive && !hasExternalFailureStatus ? /* @__PURE__ */ jsx5(
|
|
1718
1816
|
SubmitButton,
|
|
1719
1817
|
{
|
|
1720
1818
|
type: "button",
|
|
1721
|
-
"data-testid": "
|
|
1722
|
-
|
|
1723
|
-
|
|
1819
|
+
"data-testid": "questionnaire-submit",
|
|
1820
|
+
disabled: isInteractionLocked,
|
|
1821
|
+
onClick: () => {
|
|
1822
|
+
void handleSubmit();
|
|
1823
|
+
},
|
|
1824
|
+
children: isSubmitting ? resolvedLabels.submitting : questionnaire.submitLabel ?? "Submit"
|
|
1724
1825
|
}
|
|
1725
1826
|
) : null
|
|
1726
1827
|
] });
|
|
1727
1828
|
};
|
|
1728
1829
|
var getQuestionnaireStateKey = (questionnaire) => JSON.stringify([
|
|
1729
1830
|
questionnaire.questionnaireId,
|
|
1730
|
-
questionnaire.
|
|
1731
|
-
questionnaire.
|
|
1831
|
+
questionnaire.questions,
|
|
1832
|
+
questionnaire.status,
|
|
1833
|
+
questionnaire.statusMessage
|
|
1732
1834
|
]);
|
|
1733
|
-
var
|
|
1835
|
+
var QuestionnaireCard = (props) => /* @__PURE__ */ jsx5(QuestionnaireCardInner, { ...props }, getQuestionnaireStateKey(props.questionnaire));
|
|
1734
1836
|
var Card4 = styled4.section`
|
|
1735
1837
|
display: grid;
|
|
1736
1838
|
gap: 14px;
|
|
@@ -1878,6 +1980,10 @@ var ErrorMessage = styled4.div`
|
|
|
1878
1980
|
color: rgba(255, 145, 145, 0.96);
|
|
1879
1981
|
font-size: 12px;
|
|
1880
1982
|
`;
|
|
1983
|
+
var SuccessMessage = styled4.div`
|
|
1984
|
+
color: rgba(164, 255, 210, 0.96);
|
|
1985
|
+
font-size: 12px;
|
|
1986
|
+
`;
|
|
1881
1987
|
var SubmitButton = styled4.button`
|
|
1882
1988
|
justify-self: flex-start;
|
|
1883
1989
|
border: none;
|
|
@@ -1888,12 +1994,17 @@ var SubmitButton = styled4.button`
|
|
|
1888
1994
|
font-weight: 700;
|
|
1889
1995
|
padding: 10px 14px;
|
|
1890
1996
|
cursor: pointer;
|
|
1997
|
+
|
|
1998
|
+
&:disabled {
|
|
1999
|
+
cursor: default;
|
|
2000
|
+
opacity: 0.72;
|
|
2001
|
+
}
|
|
1891
2002
|
`;
|
|
1892
2003
|
|
|
1893
|
-
// src/components/chat-thread/components/
|
|
2004
|
+
// src/components/chat-thread/components/result-summary-card.tsx
|
|
1894
2005
|
import styled5 from "@emotion/styled";
|
|
1895
2006
|
import { jsx as jsx6, jsxs as jsxs4 } from "@emotion/react/jsx-runtime";
|
|
1896
|
-
var
|
|
2007
|
+
var ResultSummaryCard = ({ summary }) => /* @__PURE__ */ jsxs4(Card5, { "data-testid": "result-summary-card", "data-status": summary.status, children: [
|
|
1897
2008
|
/* @__PURE__ */ jsx6(Eyebrow2, { children: summary.status }),
|
|
1898
2009
|
/* @__PURE__ */ jsx6(Headline, { children: summary.headline }),
|
|
1899
2010
|
/* @__PURE__ */ jsx6(Details, { children: summary.details.map((detail) => /* @__PURE__ */ jsx6(Detail, { children: detail }, detail)) })
|
|
@@ -1989,6 +2100,7 @@ var ImageViewer = ({ src, alt, onClose }) => {
|
|
|
1989
2100
|
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs5 } from "@emotion/react/jsx-runtime";
|
|
1990
2101
|
var MARKDOWN_REMARK_PLUGINS = [remarkGfm, remarkMath];
|
|
1991
2102
|
var MARKDOWN_REHYPE_PLUGINS = [rehypeKatex];
|
|
2103
|
+
var USER_MESSAGE_COLLAPSE_HEIGHT_PX = 120;
|
|
1992
2104
|
var MARKDOWN_COMPONENTS = {
|
|
1993
2105
|
table: ({ node: _node, ...props }) => /* @__PURE__ */ jsx8(TableWrapper, { children: /* @__PURE__ */ jsx8("table", { ...props }) })
|
|
1994
2106
|
};
|
|
@@ -2001,10 +2113,101 @@ var renderMarkdownContent = (content) => /* @__PURE__ */ jsx8(
|
|
|
2001
2113
|
children: content
|
|
2002
2114
|
}
|
|
2003
2115
|
);
|
|
2116
|
+
var renderPlainTextContent = (content) => content;
|
|
2117
|
+
var CollapseIcon = ({ expanded }) => /* @__PURE__ */ jsx8(
|
|
2118
|
+
"svg",
|
|
2119
|
+
{
|
|
2120
|
+
"aria-hidden": "true",
|
|
2121
|
+
width: "16",
|
|
2122
|
+
height: "16",
|
|
2123
|
+
viewBox: "0 0 16 16",
|
|
2124
|
+
fill: "none",
|
|
2125
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2126
|
+
children: /* @__PURE__ */ jsx8(
|
|
2127
|
+
"path",
|
|
2128
|
+
{
|
|
2129
|
+
d: "M4 6l4 4 4-4",
|
|
2130
|
+
stroke: "currentColor",
|
|
2131
|
+
strokeWidth: "1.6",
|
|
2132
|
+
strokeLinecap: "round",
|
|
2133
|
+
strokeLinejoin: "round",
|
|
2134
|
+
transform: expanded ? "rotate(180 8 8)" : void 0
|
|
2135
|
+
}
|
|
2136
|
+
)
|
|
2137
|
+
}
|
|
2138
|
+
);
|
|
2139
|
+
var useUserMessageCollapse = ({
|
|
2140
|
+
blocks,
|
|
2141
|
+
displayedBlocks,
|
|
2142
|
+
displayedContent,
|
|
2143
|
+
enabled,
|
|
2144
|
+
freshContent,
|
|
2145
|
+
settledContent
|
|
2146
|
+
}) => {
|
|
2147
|
+
const [isCollapsible, setIsCollapsible] = useState3(false);
|
|
2148
|
+
const [isExpanded, setIsExpanded] = useState3(false);
|
|
2149
|
+
const [bodyStackElement, setBodyStackElement] = useState3(null);
|
|
2150
|
+
const syncCollapseState = useCallback2(
|
|
2151
|
+
(element) => {
|
|
2152
|
+
const nextCollapsible = enabled && (element?.scrollHeight ?? 0) > USER_MESSAGE_COLLAPSE_HEIGHT_PX;
|
|
2153
|
+
setIsCollapsible(nextCollapsible);
|
|
2154
|
+
if (!nextCollapsible) {
|
|
2155
|
+
setIsExpanded(false);
|
|
2156
|
+
}
|
|
2157
|
+
},
|
|
2158
|
+
[enabled]
|
|
2159
|
+
);
|
|
2160
|
+
const bodyStackRef = useCallback2(
|
|
2161
|
+
(node) => {
|
|
2162
|
+
setBodyStackElement(node);
|
|
2163
|
+
syncCollapseState(node);
|
|
2164
|
+
},
|
|
2165
|
+
[syncCollapseState]
|
|
2166
|
+
);
|
|
2167
|
+
useLayoutEffect(() => {
|
|
2168
|
+
if (!bodyStackElement) {
|
|
2169
|
+
return;
|
|
2170
|
+
}
|
|
2171
|
+
const frameId = requestAnimationFrame(() => {
|
|
2172
|
+
syncCollapseState(bodyStackElement);
|
|
2173
|
+
});
|
|
2174
|
+
return () => {
|
|
2175
|
+
cancelAnimationFrame(frameId);
|
|
2176
|
+
};
|
|
2177
|
+
}, [
|
|
2178
|
+
blocks,
|
|
2179
|
+
bodyStackElement,
|
|
2180
|
+
displayedBlocks,
|
|
2181
|
+
displayedContent,
|
|
2182
|
+
enabled,
|
|
2183
|
+
freshContent,
|
|
2184
|
+
settledContent,
|
|
2185
|
+
syncCollapseState
|
|
2186
|
+
]);
|
|
2187
|
+
useLayoutEffect(() => {
|
|
2188
|
+
if (!bodyStackElement || !enabled || typeof ResizeObserver === "undefined") {
|
|
2189
|
+
return;
|
|
2190
|
+
}
|
|
2191
|
+
const observer = new ResizeObserver(() => {
|
|
2192
|
+
syncCollapseState(bodyStackElement);
|
|
2193
|
+
});
|
|
2194
|
+
observer.observe(bodyStackElement);
|
|
2195
|
+
return () => {
|
|
2196
|
+
observer.disconnect();
|
|
2197
|
+
};
|
|
2198
|
+
}, [bodyStackElement, enabled, syncCollapseState]);
|
|
2199
|
+
return {
|
|
2200
|
+
bodyStackRef,
|
|
2201
|
+
isCollapsed: isCollapsible && !isExpanded,
|
|
2202
|
+
isCollapsible,
|
|
2203
|
+
isExpanded,
|
|
2204
|
+
toggleExpanded: () => setIsExpanded((current) => !current)
|
|
2205
|
+
};
|
|
2206
|
+
};
|
|
2004
2207
|
var createExecutionConfirmationContent = (proposal) => [
|
|
2005
2208
|
"Execution confirmed",
|
|
2006
|
-
`- Equation: ${proposal.
|
|
2007
|
-
...proposal.
|
|
2209
|
+
`- Equation: ${proposal.resourceName}`,
|
|
2210
|
+
...proposal.executorName ? [`- Solver: ${proposal.executorName}`] : [],
|
|
2008
2211
|
`- Proposal ID: ${proposal.proposalId}`
|
|
2009
2212
|
].join("\n");
|
|
2010
2213
|
var areChatAttachmentsEqual = (previousAttachments, nextAttachments) => {
|
|
@@ -2026,10 +2229,10 @@ var areParameterSummaryItemsEqual = (previousItems, nextItems) => previousItems.
|
|
|
2026
2229
|
const nextItem = nextItems[index];
|
|
2027
2230
|
return item.label === nextItem?.label && item.value === nextItem.value && item.fieldPath === nextItem.fieldPath;
|
|
2028
2231
|
});
|
|
2029
|
-
var areExecutionProposalsEqual = (previousProposal, nextProposal) => previousProposal.proposalId === nextProposal.proposalId && previousProposal.
|
|
2232
|
+
var areExecutionProposalsEqual = (previousProposal, nextProposal) => previousProposal.proposalId === nextProposal.proposalId && previousProposal.resourceKey === nextProposal.resourceKey && previousProposal.resourceName === nextProposal.resourceName && previousProposal.executorName === nextProposal.executorName && previousProposal.requiresConfirmation === nextProposal.requiresConfirmation && areParameterSummaryItemsEqual(previousProposal.parameterSummary, nextProposal.parameterSummary) && (previousProposal.warnings ?? []).length === (nextProposal.warnings ?? []).length && (previousProposal.warnings ?? []).every(
|
|
2030
2233
|
(warning, index) => warning === nextProposal.warnings?.[index]
|
|
2031
2234
|
);
|
|
2032
|
-
var areResultSummariesEqual = (previousSummary, nextSummary) => previousSummary.
|
|
2235
|
+
var areResultSummariesEqual = (previousSummary, nextSummary) => previousSummary.summaryId === nextSummary.summaryId && previousSummary.status === nextSummary.status && previousSummary.headline === nextSummary.headline && previousSummary.details.length === nextSummary.details.length && previousSummary.details.every((detail, index) => detail === nextSummary.details[index]);
|
|
2033
2236
|
var areStringArraysEqual = (previousValues, nextValues) => previousValues.length === nextValues.length && previousValues.every((value, index) => value === nextValues[index]);
|
|
2034
2237
|
var areQuestionAnswersEqual = (previousAnswer, nextAnswer) => {
|
|
2035
2238
|
if (Array.isArray(previousAnswer) || Array.isArray(nextAnswer)) {
|
|
@@ -2070,7 +2273,7 @@ var arePlanQuestionsEqual = (previousQuestion, nextQuestion) => {
|
|
|
2070
2273
|
return false;
|
|
2071
2274
|
}
|
|
2072
2275
|
};
|
|
2073
|
-
var areQuestionnairesEqual = (previousQuestionnaire, nextQuestionnaire) => previousQuestionnaire.questionnaireId === nextQuestionnaire.questionnaireId && previousQuestionnaire.title === nextQuestionnaire.title && previousQuestionnaire.description === nextQuestionnaire.description && previousQuestionnaire.submitLabel === nextQuestionnaire.submitLabel && previousQuestionnaire.questions.length === nextQuestionnaire.questions.length && previousQuestionnaire.questions.every(
|
|
2276
|
+
var areQuestionnairesEqual = (previousQuestionnaire, nextQuestionnaire) => previousQuestionnaire.questionnaireId === nextQuestionnaire.questionnaireId && previousQuestionnaire.title === nextQuestionnaire.title && previousQuestionnaire.description === nextQuestionnaire.description && previousQuestionnaire.submitLabel === nextQuestionnaire.submitLabel && previousQuestionnaire.status === nextQuestionnaire.status && previousQuestionnaire.statusMessage === nextQuestionnaire.statusMessage && previousQuestionnaire.questions.length === nextQuestionnaire.questions.length && previousQuestionnaire.questions.every(
|
|
2074
2277
|
(question, index) => arePlanQuestionsEqual(question, nextQuestionnaire.questions[index])
|
|
2075
2278
|
) && areQuestionAnswerMapsEqual(previousQuestionnaire.answers, nextQuestionnaire.answers);
|
|
2076
2279
|
var areMessageBlocksEqual = (previousBlocks, nextBlocks) => {
|
|
@@ -2151,6 +2354,8 @@ var ChatMessageItemView = ({
|
|
|
2151
2354
|
const canSubmitConfirmation = isPlanMode && typeof onConfirmationSubmit === "function";
|
|
2152
2355
|
const canSubmitQuestionnaire = isPlanMode && typeof onQuestionnaireSubmit === "function";
|
|
2153
2356
|
const shouldShowStreamingCaret = isAssistantStreaming && (!shouldRenderStructuredBlocks || hasTextContent);
|
|
2357
|
+
const isUserMessage = message.role === "user";
|
|
2358
|
+
const messageRenderMode = isUserMessage ? "plain-text" : "markdown";
|
|
2154
2359
|
const timelineConsumedText = messageRenderOrder === "timeline" ? getTimelineConsumedText(blocks) : "";
|
|
2155
2360
|
const hasConsumedTimelineText = timelineConsumedText.length > 0 && displayedContent.startsWith(timelineConsumedText);
|
|
2156
2361
|
const timelineDisplayedContent = hasConsumedTimelineText ? displayedContent.slice(timelineConsumedText.length) : displayedContent;
|
|
@@ -2167,6 +2372,21 @@ var ChatMessageItemView = ({
|
|
|
2167
2372
|
message,
|
|
2168
2373
|
messageRenderOrder
|
|
2169
2374
|
});
|
|
2375
|
+
const {
|
|
2376
|
+
bodyStackRef,
|
|
2377
|
+
isCollapsed: isUserMessageCollapsed,
|
|
2378
|
+
isCollapsible: isUserMessageCollapsible,
|
|
2379
|
+
isExpanded: isUserMessageExpanded,
|
|
2380
|
+
toggleExpanded: toggleUserMessageExpanded
|
|
2381
|
+
} = useUserMessageCollapse({
|
|
2382
|
+
blocks,
|
|
2383
|
+
displayedBlocks,
|
|
2384
|
+
displayedContent,
|
|
2385
|
+
enabled: isUserMessage,
|
|
2386
|
+
freshContent,
|
|
2387
|
+
settledContent
|
|
2388
|
+
});
|
|
2389
|
+
const renderMessageContent = (content) => messageRenderMode === "plain-text" ? renderPlainTextContent(content) : renderMarkdownContent(content);
|
|
2170
2390
|
const renderChatMessageBlock = (block, index) => {
|
|
2171
2391
|
switch (block.type) {
|
|
2172
2392
|
case "markdown":
|
|
@@ -2175,17 +2395,18 @@ var ChatMessageItemView = ({
|
|
|
2175
2395
|
{
|
|
2176
2396
|
"data-testid": `chat-message-block-${index}`,
|
|
2177
2397
|
"data-block-tone": "settled",
|
|
2178
|
-
|
|
2398
|
+
"data-render-mode": messageRenderMode,
|
|
2399
|
+
children: renderMessageContent(block.text)
|
|
2179
2400
|
},
|
|
2180
2401
|
`markdown-${index}`
|
|
2181
2402
|
);
|
|
2182
2403
|
case "notice":
|
|
2183
|
-
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(
|
|
2404
|
+
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(NoticeCard, { text: block.text, tone: block.tone }) }, `notice-${index}`);
|
|
2184
2405
|
case "parameter_summary":
|
|
2185
|
-
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(
|
|
2406
|
+
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(ParameterSummaryCard, { items: block.items }) }, `parameter-summary-${index}`);
|
|
2186
2407
|
case "confirmation_card":
|
|
2187
2408
|
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(
|
|
2188
|
-
|
|
2409
|
+
ExecutionConfirmationCard,
|
|
2189
2410
|
{
|
|
2190
2411
|
proposal: block.proposal,
|
|
2191
2412
|
interactive: isPlanMode,
|
|
@@ -2197,13 +2418,19 @@ var ChatMessageItemView = ({
|
|
|
2197
2418
|
}
|
|
2198
2419
|
) }, `confirmation-card-${index}`);
|
|
2199
2420
|
case "result_summary":
|
|
2200
|
-
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(
|
|
2421
|
+
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(ResultSummaryCard, { summary: block.summary }) }, `result-summary-${index}`);
|
|
2201
2422
|
case "questionnaire":
|
|
2202
2423
|
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(
|
|
2203
|
-
|
|
2424
|
+
QuestionnaireCard,
|
|
2204
2425
|
{
|
|
2205
2426
|
questionnaire: block.questionnaire,
|
|
2206
2427
|
interactive: canSubmitQuestionnaire,
|
|
2428
|
+
labels: {
|
|
2429
|
+
submitting: labels.questionnaireSubmitting,
|
|
2430
|
+
submitted: labels.questionnaireSubmitted,
|
|
2431
|
+
validationPrefix: labels.questionnaireValidationPrefix,
|
|
2432
|
+
submitFailed: labels.questionnaireSubmitFailed
|
|
2433
|
+
},
|
|
2207
2434
|
onSubmit: canSubmitQuestionnaire ? (submission) => onQuestionnaireSubmit({
|
|
2208
2435
|
...submission,
|
|
2209
2436
|
sourceMessageId: message.id
|
|
@@ -2236,14 +2463,31 @@ var ChatMessageItemView = ({
|
|
|
2236
2463
|
"data-testid": block.tone === "fresh" ? "chat-message-fresh-block" : "chat-message-settled-block",
|
|
2237
2464
|
"data-block-tone": block.tone,
|
|
2238
2465
|
"data-block-index": index,
|
|
2239
|
-
|
|
2466
|
+
"data-render-mode": messageRenderMode,
|
|
2467
|
+
children: renderMessageContent(block.content)
|
|
2240
2468
|
},
|
|
2241
2469
|
`${block.tone}-${index}`
|
|
2242
2470
|
)),
|
|
2243
|
-
!textBlocks.some((block) => block.content) && !settledText && !freshText && Boolean(textContent) ? /* @__PURE__ */ jsx8(
|
|
2471
|
+
!textBlocks.some((block) => block.content) && !settledText && !freshText && Boolean(textContent) ? /* @__PURE__ */ jsx8(
|
|
2472
|
+
ContentBlock,
|
|
2473
|
+
{
|
|
2474
|
+
"data-testid": "chat-message-settled-block",
|
|
2475
|
+
"data-block-tone": "settled",
|
|
2476
|
+
"data-render-mode": messageRenderMode,
|
|
2477
|
+
children: renderMessageContent(textContent)
|
|
2478
|
+
}
|
|
2479
|
+
) : null
|
|
2244
2480
|
] });
|
|
2245
2481
|
};
|
|
2246
|
-
const renderStaticTextSegment = (content) => /* @__PURE__ */ jsx8(
|
|
2482
|
+
const renderStaticTextSegment = (content) => /* @__PURE__ */ jsx8(
|
|
2483
|
+
ContentBlock,
|
|
2484
|
+
{
|
|
2485
|
+
"data-testid": "chat-message-settled-block",
|
|
2486
|
+
"data-block-tone": "settled",
|
|
2487
|
+
"data-render-mode": messageRenderMode,
|
|
2488
|
+
children: renderMessageContent(content)
|
|
2489
|
+
}
|
|
2490
|
+
);
|
|
2247
2491
|
const bodySegments = (() => {
|
|
2248
2492
|
if (!shouldRenderStructuredBlocks && hasTextContent) {
|
|
2249
2493
|
return [{ type: "text" }];
|
|
@@ -2301,21 +2545,40 @@ var ChatMessageItemView = ({
|
|
|
2301
2545
|
}
|
|
2302
2546
|
) : null,
|
|
2303
2547
|
/* @__PURE__ */ jsx8(Role, { children: message.role === "user" ? labels.userRoleLabel : labels.assistantRoleLabel }),
|
|
2548
|
+
isUserMessageCollapsible ? /* @__PURE__ */ jsx8(
|
|
2549
|
+
CollapseToggle,
|
|
2550
|
+
{
|
|
2551
|
+
type: "button",
|
|
2552
|
+
"data-testid": "chat-message-collapse-toggle",
|
|
2553
|
+
"aria-label": isUserMessageExpanded ? labels.collapseMessageAriaLabel : labels.expandMessageAriaLabel,
|
|
2554
|
+
"aria-expanded": isUserMessageExpanded,
|
|
2555
|
+
onClick: toggleUserMessageExpanded,
|
|
2556
|
+
children: /* @__PURE__ */ jsx8(CollapseIcon, { expanded: isUserMessageExpanded })
|
|
2557
|
+
}
|
|
2558
|
+
) : null,
|
|
2304
2559
|
isStoppedAssistant ? /* @__PURE__ */ jsx8(StatusTag, { "data-testid": "chat-message-stopped-tag", children: labels.stoppedResponse }) : null
|
|
2305
2560
|
] }),
|
|
2306
2561
|
/* @__PURE__ */ jsxs5(Content, { "data-testid": "chat-message-content", children: [
|
|
2307
|
-
shouldRenderStructuredBlocks || hasTextContent ? /* @__PURE__ */ jsx8(
|
|
2308
|
-
|
|
2562
|
+
shouldRenderStructuredBlocks || hasTextContent ? /* @__PURE__ */ jsx8(
|
|
2563
|
+
ContentStack,
|
|
2309
2564
|
{
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2565
|
+
ref: bodyStackRef,
|
|
2566
|
+
"data-testid": "chat-message-body-stack",
|
|
2567
|
+
"data-collapsed": isUserMessageCollapsed,
|
|
2568
|
+
children: bodySegments.map((segment, index) => /* @__PURE__ */ jsx8(
|
|
2569
|
+
ContentSegment,
|
|
2570
|
+
{
|
|
2571
|
+
"data-testid": "chat-message-content-segment",
|
|
2572
|
+
children: segment.type === "block" ? renderChatMessageBlock(segment.block, segment.index) : segment.type === "text" ? segment.content !== void 0 ? segment.useTimelineSegmentation ? renderTextContent({
|
|
2573
|
+
content: segment.content,
|
|
2574
|
+
displayedBlocks: segment.displayedBlocks,
|
|
2575
|
+
useTimelineSegmentation: true
|
|
2576
|
+
}) : renderStaticTextSegment(segment.content) : renderTextContent() : renderStaticTextSegment(segment.content)
|
|
2577
|
+
},
|
|
2578
|
+
segment.type === "text" ? `text-${index}` : segment.type === "markdown" ? `markdown-${index}` : `${segment.block.type}-${segment.index}`
|
|
2579
|
+
))
|
|
2580
|
+
}
|
|
2581
|
+
) : null,
|
|
2319
2582
|
attachments.length ? /* @__PURE__ */ jsx8(AttachmentGrid, { "data-testid": "chat-message-attachment-grid", children: attachments.map((attachment) => /* @__PURE__ */ jsx8(
|
|
2320
2583
|
AttachmentButton,
|
|
2321
2584
|
{
|
|
@@ -2400,6 +2663,29 @@ var StatusTag = styled7.span`
|
|
|
2400
2663
|
letter-spacing: 0.02em;
|
|
2401
2664
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
|
|
2402
2665
|
`;
|
|
2666
|
+
var CollapseToggle = styled7.button`
|
|
2667
|
+
margin-left: auto;
|
|
2668
|
+
width: 28px;
|
|
2669
|
+
height: 28px;
|
|
2670
|
+
display: inline-flex;
|
|
2671
|
+
align-items: center;
|
|
2672
|
+
justify-content: center;
|
|
2673
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
2674
|
+
border-radius: 999px;
|
|
2675
|
+
background: rgba(255, 255, 255, 0.06);
|
|
2676
|
+
color: rgba(255, 255, 255, 0.72);
|
|
2677
|
+
cursor: pointer;
|
|
2678
|
+
transition:
|
|
2679
|
+
background 160ms ease-out,
|
|
2680
|
+
border-color 160ms ease-out,
|
|
2681
|
+
color 160ms ease-out;
|
|
2682
|
+
|
|
2683
|
+
&:hover {
|
|
2684
|
+
background: rgba(255, 255, 255, 0.1);
|
|
2685
|
+
border-color: rgba(255, 255, 255, 0.18);
|
|
2686
|
+
color: rgba(255, 255, 255, 0.92);
|
|
2687
|
+
}
|
|
2688
|
+
`;
|
|
2403
2689
|
var Content = styled7.div`
|
|
2404
2690
|
color: rgba(255, 255, 255, 0.92);
|
|
2405
2691
|
line-height: 1.6;
|
|
@@ -2444,6 +2730,11 @@ var ContentStack = styled7.div`
|
|
|
2444
2730
|
display: flex;
|
|
2445
2731
|
flex-direction: column;
|
|
2446
2732
|
gap: 16px;
|
|
2733
|
+
|
|
2734
|
+
&[data-collapsed='true'] {
|
|
2735
|
+
max-height: ${USER_MESSAGE_COLLAPSE_HEIGHT_PX}px;
|
|
2736
|
+
overflow: hidden;
|
|
2737
|
+
}
|
|
2447
2738
|
`;
|
|
2448
2739
|
var ContentSegment = styled7.div`
|
|
2449
2740
|
min-width: 0;
|
|
@@ -2457,6 +2748,11 @@ var ContentBlock = styled7.div`
|
|
|
2457
2748
|
margin-top: 16px;
|
|
2458
2749
|
}
|
|
2459
2750
|
|
|
2751
|
+
&[data-render-mode='plain-text'] {
|
|
2752
|
+
white-space: pre-wrap;
|
|
2753
|
+
overflow-wrap: anywhere;
|
|
2754
|
+
}
|
|
2755
|
+
|
|
2460
2756
|
&[data-block-tone='fresh'] {
|
|
2461
2757
|
opacity: 0.85;
|
|
2462
2758
|
filter: brightness(0.82) saturate(0.88);
|
|
@@ -2718,7 +3014,7 @@ var ChatThreadView = ({
|
|
|
2718
3014
|
const latestUserMessageRef = useRef4(null);
|
|
2719
3015
|
const reservedSpaceFrameRef = useRef4(null);
|
|
2720
3016
|
const [latestTurnMinHeight, setLatestTurnMinHeight] = useState4(0);
|
|
2721
|
-
const measureLatestTurnMinHeight =
|
|
3017
|
+
const measureLatestTurnMinHeight = useCallback3(() => {
|
|
2722
3018
|
const container = containerRef.current;
|
|
2723
3019
|
if (!container)
|
|
2724
3020
|
return;
|
|
@@ -2728,7 +3024,7 @@ var ChatThreadView = ({
|
|
|
2728
3024
|
const nextMinHeight = Math.max(0, container.clientHeight - paddingTop - paddingBottom);
|
|
2729
3025
|
setLatestTurnMinHeight((current) => current === nextMinHeight ? current : nextMinHeight);
|
|
2730
3026
|
}, []);
|
|
2731
|
-
const scrollLatestUserMessageToTop =
|
|
3027
|
+
const scrollLatestUserMessageToTop = useCallback3(() => {
|
|
2732
3028
|
const container = containerRef.current;
|
|
2733
3029
|
const target = latestUserMessageRef.current;
|
|
2734
3030
|
if (!container || !target)
|
|
@@ -2748,7 +3044,7 @@ var ChatThreadView = ({
|
|
|
2748
3044
|
}
|
|
2749
3045
|
container.scrollTop = nextScrollTop;
|
|
2750
3046
|
}, []);
|
|
2751
|
-
|
|
3047
|
+
useLayoutEffect2(() => {
|
|
2752
3048
|
if (reservedSpaceFrameRef.current !== null) {
|
|
2753
3049
|
window.cancelAnimationFrame(reservedSpaceFrameRef.current);
|
|
2754
3050
|
reservedSpaceFrameRef.current = null;
|
|
@@ -2777,7 +3073,7 @@ var ChatThreadView = ({
|
|
|
2777
3073
|
}
|
|
2778
3074
|
};
|
|
2779
3075
|
}, [latestUserMessageId, measureLatestTurnMinHeight, scrollLatestUserMessageToTop]);
|
|
2780
|
-
|
|
3076
|
+
useLayoutEffect2(() => {
|
|
2781
3077
|
if (!latestUserMessageId)
|
|
2782
3078
|
return;
|
|
2783
3079
|
const handleResize = () => {
|
|
@@ -2864,15 +3160,40 @@ var ChatThread = () => {
|
|
|
2864
3160
|
const error = useChatStore((s) => s.errorBySession[s.activeSessionId ?? ""]);
|
|
2865
3161
|
const updateQA = useChatStore((s) => s.updateQuestionnaireAnswers);
|
|
2866
3162
|
const clearSessionError = useChatStore((s) => s.clearSessionError);
|
|
2867
|
-
const {
|
|
2868
|
-
|
|
3163
|
+
const {
|
|
3164
|
+
sendRef,
|
|
3165
|
+
retryRef,
|
|
3166
|
+
renderMessageBlock,
|
|
3167
|
+
handleQuestionnaireSubmit: customQuestionnaireSubmit,
|
|
3168
|
+
handleConfirmationSubmit: customConfirmationSubmit,
|
|
3169
|
+
labels
|
|
3170
|
+
} = useChatContext();
|
|
3171
|
+
const handleRetry = useCallback3(() => {
|
|
2869
3172
|
if (!activeSessionId)
|
|
2870
3173
|
return;
|
|
2871
3174
|
clearSessionError(activeSessionId);
|
|
2872
3175
|
void retryRef.current();
|
|
2873
3176
|
}, [activeSessionId, clearSessionError, retryRef]);
|
|
2874
|
-
const handleQuestionnaireSubmit =
|
|
2875
|
-
(submission) => {
|
|
3177
|
+
const handleQuestionnaireSubmit = useCallback3(
|
|
3178
|
+
async (submission) => {
|
|
3179
|
+
if (customQuestionnaireSubmit) {
|
|
3180
|
+
const handled = await customQuestionnaireSubmit(submission, {
|
|
3181
|
+
sessionId: activeSessionId ?? void 0,
|
|
3182
|
+
mode: activeSessionMode
|
|
3183
|
+
});
|
|
3184
|
+
if (handled !== false) {
|
|
3185
|
+
if (activeSessionId && submission.sourceMessageId) {
|
|
3186
|
+
updateQA(
|
|
3187
|
+
activeSessionId,
|
|
3188
|
+
submission.sourceMessageId,
|
|
3189
|
+
submission.questionnaireId,
|
|
3190
|
+
submission.answers
|
|
3191
|
+
);
|
|
3192
|
+
}
|
|
3193
|
+
return;
|
|
3194
|
+
}
|
|
3195
|
+
}
|
|
3196
|
+
await sendRef.current(submission.content);
|
|
2876
3197
|
if (activeSessionId && submission.sourceMessageId) {
|
|
2877
3198
|
updateQA(
|
|
2878
3199
|
activeSessionId,
|
|
@@ -2881,15 +3202,23 @@ var ChatThread = () => {
|
|
|
2881
3202
|
submission.answers
|
|
2882
3203
|
);
|
|
2883
3204
|
}
|
|
2884
|
-
void sendRef.current(submission.content);
|
|
2885
3205
|
},
|
|
2886
|
-
[activeSessionId, updateQA, sendRef]
|
|
3206
|
+
[activeSessionId, activeSessionMode, updateQA, sendRef, customQuestionnaireSubmit]
|
|
2887
3207
|
);
|
|
2888
|
-
const
|
|
2889
|
-
(submission) => {
|
|
2890
|
-
|
|
3208
|
+
const handleConfirmation = useCallback3(
|
|
3209
|
+
async (submission) => {
|
|
3210
|
+
if (customConfirmationSubmit) {
|
|
3211
|
+
const handled = await customConfirmationSubmit(submission, {
|
|
3212
|
+
sessionId: activeSessionId ?? void 0,
|
|
3213
|
+
mode: activeSessionMode
|
|
3214
|
+
});
|
|
3215
|
+
if (handled !== false) {
|
|
3216
|
+
return;
|
|
3217
|
+
}
|
|
3218
|
+
}
|
|
3219
|
+
await sendRef.current(submission.content);
|
|
2891
3220
|
},
|
|
2892
|
-
[sendRef]
|
|
3221
|
+
[activeSessionId, activeSessionMode, sendRef, customConfirmationSubmit]
|
|
2893
3222
|
);
|
|
2894
3223
|
if (!hasSessions || messages.length === 0 && !streamingMessage) {
|
|
2895
3224
|
return /* @__PURE__ */ jsx10(ChatThreadEmptyState, {});
|
|
@@ -2903,7 +3232,7 @@ var ChatThread = () => {
|
|
|
2903
3232
|
error,
|
|
2904
3233
|
retryButtonLabel: labels.retryButton,
|
|
2905
3234
|
onRetry: handleRetry,
|
|
2906
|
-
onConfirmationSubmit:
|
|
3235
|
+
onConfirmationSubmit: handleConfirmation,
|
|
2907
3236
|
onQuestionnaireSubmit: handleQuestionnaireSubmit,
|
|
2908
3237
|
renderMessageBlock
|
|
2909
3238
|
}
|
|
@@ -2917,6 +3246,7 @@ var Container = styled9.div`
|
|
|
2917
3246
|
min-height: 0;
|
|
2918
3247
|
overflow: auto;
|
|
2919
3248
|
padding: 24px;
|
|
3249
|
+
margin-bottom: 24px;
|
|
2920
3250
|
overscroll-behavior: contain;
|
|
2921
3251
|
|
|
2922
3252
|
&::-webkit-scrollbar {
|
|
@@ -2970,7 +3300,7 @@ var RetryButton = styled9.button`
|
|
|
2970
3300
|
`;
|
|
2971
3301
|
|
|
2972
3302
|
// src/components/chat-composer/index.tsx
|
|
2973
|
-
import { useEffect as useEffect6, useRef as useRef7 } from "react";
|
|
3303
|
+
import { useEffect as useEffect6, useLayoutEffect as useLayoutEffect3, useRef as useRef7, useState as useState8 } from "react";
|
|
2974
3304
|
import styled14 from "@emotion/styled";
|
|
2975
3305
|
|
|
2976
3306
|
// src/components/chat-composer/lib/chat-composer.ts
|
|
@@ -3082,7 +3412,7 @@ var resolveSendSession = ({
|
|
|
3082
3412
|
};
|
|
3083
3413
|
|
|
3084
3414
|
// src/components/chat-composer/hooks/use-chat-composer.ts
|
|
3085
|
-
import { useCallback as
|
|
3415
|
+
import { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef6, useState as useState6 } from "react";
|
|
3086
3416
|
|
|
3087
3417
|
// src/components/chat-composer/hooks/use-composer-attachments.ts
|
|
3088
3418
|
import { useEffect as useEffect4, useRef as useRef5, useState as useState5 } from "react";
|
|
@@ -3220,7 +3550,7 @@ var useChatComposer = () => {
|
|
|
3220
3550
|
const [availableModels, setAvailableModels] = useState6([]);
|
|
3221
3551
|
const [isModelsLoading, setIsModelsLoading] = useState6(true);
|
|
3222
3552
|
const [isModelsError, setIsModelsError] = useState6(false);
|
|
3223
|
-
const fetchModels =
|
|
3553
|
+
const fetchModels = useCallback4(async () => {
|
|
3224
3554
|
setIsModelsLoading(true);
|
|
3225
3555
|
setIsModelsError(false);
|
|
3226
3556
|
try {
|
|
@@ -3275,7 +3605,7 @@ var useChatComposer = () => {
|
|
|
3275
3605
|
stopRequestRef.current.timeoutId = null;
|
|
3276
3606
|
}
|
|
3277
3607
|
};
|
|
3278
|
-
const clearStopRequest =
|
|
3608
|
+
const clearStopRequest = useCallback4((sessionId) => {
|
|
3279
3609
|
if (!stopRequestRef.current)
|
|
3280
3610
|
return;
|
|
3281
3611
|
if (sessionId && stopRequestRef.current.sessionId !== sessionId)
|
|
@@ -3283,7 +3613,7 @@ var useChatComposer = () => {
|
|
|
3283
3613
|
clearStopTimeout(sessionId);
|
|
3284
3614
|
stopRequestRef.current = null;
|
|
3285
3615
|
}, []);
|
|
3286
|
-
const finalizeStop =
|
|
3616
|
+
const finalizeStop = useCallback4(
|
|
3287
3617
|
(sessionId) => {
|
|
3288
3618
|
if (stopRequestRef.current?.sessionId === sessionId) {
|
|
3289
3619
|
if (stopRequestRef.current.finalized)
|
|
@@ -3298,7 +3628,7 @@ var useChatComposer = () => {
|
|
|
3298
3628
|
},
|
|
3299
3629
|
[clearStopRequest, finalizeStoppedStreamingMessage]
|
|
3300
3630
|
);
|
|
3301
|
-
const runStream =
|
|
3631
|
+
const runStream = useCallback4(
|
|
3302
3632
|
async ({
|
|
3303
3633
|
localSessionId,
|
|
3304
3634
|
sessionId,
|
|
@@ -3387,7 +3717,7 @@ var useChatComposer = () => {
|
|
|
3387
3717
|
setSessionError
|
|
3388
3718
|
]
|
|
3389
3719
|
);
|
|
3390
|
-
const send =
|
|
3720
|
+
const send = useCallback4(
|
|
3391
3721
|
async (contentOverride) => {
|
|
3392
3722
|
const content = (contentOverride ?? value).trim();
|
|
3393
3723
|
const hasText = Boolean(content);
|
|
@@ -3996,6 +4326,27 @@ var StopSpinner = styled13.span`
|
|
|
3996
4326
|
|
|
3997
4327
|
// src/components/chat-composer/index.tsx
|
|
3998
4328
|
import { jsx as jsx15, jsxs as jsxs10 } from "@emotion/react/jsx-runtime";
|
|
4329
|
+
var CHAT_COMPOSER_LINE_HEIGHT_PX = 20;
|
|
4330
|
+
var CHAT_COMPOSER_MAX_ROWS = 7;
|
|
4331
|
+
var CHAT_COMPOSER_PADDING_TOP_PX = 8;
|
|
4332
|
+
var CHAT_COMPOSER_PADDING_BOTTOM_PX = 12;
|
|
4333
|
+
var CHAT_COMPOSER_PADDING_BLOCK_PX = CHAT_COMPOSER_PADDING_TOP_PX + CHAT_COMPOSER_PADDING_BOTTOM_PX;
|
|
4334
|
+
var CHAT_COMPOSER_MIN_ROWS = 4;
|
|
4335
|
+
var CHAT_COMPOSER_EXPANDED_MAX_ROWS = 60;
|
|
4336
|
+
var CHAT_COMPOSER_EXPANDED_MAX_VIEWPORT_RATIO = 0.7;
|
|
4337
|
+
var CHAT_COMPOSER_EXPANDED_RESERVED_SPACE_PX = 96;
|
|
4338
|
+
var CHAT_COMPOSER_MAX_HEIGHT_PX = CHAT_COMPOSER_MAX_ROWS * CHAT_COMPOSER_LINE_HEIGHT_PX + CHAT_COMPOSER_PADDING_BLOCK_PX;
|
|
4339
|
+
var CHAT_COMPOSER_EXPANDED_ROWS_HEIGHT_PX = CHAT_COMPOSER_EXPANDED_MAX_ROWS * CHAT_COMPOSER_LINE_HEIGHT_PX + CHAT_COMPOSER_PADDING_BLOCK_PX;
|
|
4340
|
+
var getExpandedComposerHeightPx = () => {
|
|
4341
|
+
if (typeof window === "undefined") {
|
|
4342
|
+
return CHAT_COMPOSER_EXPANDED_ROWS_HEIGHT_PX;
|
|
4343
|
+
}
|
|
4344
|
+
const viewportLimitedHeight = window.innerHeight * CHAT_COMPOSER_EXPANDED_MAX_VIEWPORT_RATIO - CHAT_COMPOSER_EXPANDED_RESERVED_SPACE_PX;
|
|
4345
|
+
return Math.max(
|
|
4346
|
+
CHAT_COMPOSER_MAX_HEIGHT_PX,
|
|
4347
|
+
Math.floor(Math.min(CHAT_COMPOSER_EXPANDED_ROWS_HEIGHT_PX, viewportLimitedHeight))
|
|
4348
|
+
);
|
|
4349
|
+
};
|
|
3999
4350
|
var PlusIcon = () => /* @__PURE__ */ jsx15(
|
|
4000
4351
|
"svg",
|
|
4001
4352
|
{
|
|
@@ -4008,6 +4359,36 @@ var PlusIcon = () => /* @__PURE__ */ jsx15(
|
|
|
4008
4359
|
children: /* @__PURE__ */ jsx15("path", { d: "M8 3v10M3 8h10", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round" })
|
|
4009
4360
|
}
|
|
4010
4361
|
);
|
|
4362
|
+
var ComposerExpandIcon = ({ expanded }) => /* @__PURE__ */ jsx15(
|
|
4363
|
+
"svg",
|
|
4364
|
+
{
|
|
4365
|
+
"aria-hidden": "true",
|
|
4366
|
+
width: "16",
|
|
4367
|
+
height: "16",
|
|
4368
|
+
viewBox: "0 0 16 16",
|
|
4369
|
+
fill: "none",
|
|
4370
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4371
|
+
children: expanded ? /* @__PURE__ */ jsx15(
|
|
4372
|
+
"path",
|
|
4373
|
+
{
|
|
4374
|
+
d: "M14 6h-4V2M10 6l4-4M2 10h4v4M6 10l-4 4",
|
|
4375
|
+
stroke: "currentColor",
|
|
4376
|
+
strokeWidth: "1.5",
|
|
4377
|
+
strokeLinecap: "round",
|
|
4378
|
+
strokeLinejoin: "round"
|
|
4379
|
+
}
|
|
4380
|
+
) : /* @__PURE__ */ jsx15(
|
|
4381
|
+
"path",
|
|
4382
|
+
{
|
|
4383
|
+
d: "M10 2h4v4M14 2L9 7M6 14H2v-4M2 14l5-5",
|
|
4384
|
+
stroke: "currentColor",
|
|
4385
|
+
strokeWidth: "1.5",
|
|
4386
|
+
strokeLinecap: "round",
|
|
4387
|
+
strokeLinejoin: "round"
|
|
4388
|
+
}
|
|
4389
|
+
)
|
|
4390
|
+
}
|
|
4391
|
+
);
|
|
4011
4392
|
var ChatComposerView = ({
|
|
4012
4393
|
value,
|
|
4013
4394
|
placeholder,
|
|
@@ -4024,6 +4405,8 @@ var ChatComposerView = ({
|
|
|
4024
4405
|
isStopping,
|
|
4025
4406
|
enableImageAttachments,
|
|
4026
4407
|
modeLabels,
|
|
4408
|
+
expandComposerAriaLabel,
|
|
4409
|
+
collapseComposerAriaLabel,
|
|
4027
4410
|
onValueChange,
|
|
4028
4411
|
onPickImages,
|
|
4029
4412
|
onPasteImages,
|
|
@@ -4035,6 +4418,9 @@ var ChatComposerView = ({
|
|
|
4035
4418
|
onSend
|
|
4036
4419
|
}) => {
|
|
4037
4420
|
const imageInputRef = useRef7(null);
|
|
4421
|
+
const inputRef = useRef7(null);
|
|
4422
|
+
const [isComposerExpandable, setIsComposerExpandable] = useState8(false);
|
|
4423
|
+
const [isComposerExpanded, setIsComposerExpanded] = useState8(false);
|
|
4038
4424
|
const canSend = canSendChatMessage({
|
|
4039
4425
|
value,
|
|
4040
4426
|
attachmentCount: attachments.length,
|
|
@@ -4042,6 +4428,26 @@ var ChatComposerView = ({
|
|
|
4042
4428
|
isModelsError,
|
|
4043
4429
|
hasModels
|
|
4044
4430
|
});
|
|
4431
|
+
useLayoutEffect3(() => {
|
|
4432
|
+
const element = inputRef.current;
|
|
4433
|
+
if (!element) {
|
|
4434
|
+
return;
|
|
4435
|
+
}
|
|
4436
|
+
if (!isComposerExpanded) {
|
|
4437
|
+
element.style.height = "0px";
|
|
4438
|
+
}
|
|
4439
|
+
const scrollHeight = element.scrollHeight;
|
|
4440
|
+
const nextExpandable = scrollHeight > CHAT_COMPOSER_MAX_HEIGHT_PX;
|
|
4441
|
+
const expandedHeight = getExpandedComposerHeightPx();
|
|
4442
|
+
const nextHeight = isComposerExpanded ? expandedHeight : Math.min(scrollHeight, CHAT_COMPOSER_MAX_HEIGHT_PX);
|
|
4443
|
+
setIsComposerExpandable(nextExpandable);
|
|
4444
|
+
element.style.height = `${nextHeight}px`;
|
|
4445
|
+
element.style.overflowY = !isComposerExpanded && scrollHeight > CHAT_COMPOSER_MAX_HEIGHT_PX ? "auto" : "hidden";
|
|
4446
|
+
}, [isComposerExpanded, value]);
|
|
4447
|
+
const handleSend = async () => {
|
|
4448
|
+
setIsComposerExpanded(false);
|
|
4449
|
+
await onSend();
|
|
4450
|
+
};
|
|
4045
4451
|
const handleKeyDown = (event) => {
|
|
4046
4452
|
if (shouldStopChatComposer({ key: event.key, shiftKey: event.shiftKey, isStreaming })) {
|
|
4047
4453
|
event.preventDefault();
|
|
@@ -4051,7 +4457,7 @@ var ChatComposerView = ({
|
|
|
4051
4457
|
if (!shouldSubmitChatComposer({ key: event.key, shiftKey: event.shiftKey, canSend }))
|
|
4052
4458
|
return;
|
|
4053
4459
|
event.preventDefault();
|
|
4054
|
-
void
|
|
4460
|
+
void handleSend();
|
|
4055
4461
|
};
|
|
4056
4462
|
const handlePickImages = (event) => {
|
|
4057
4463
|
if (event.target.files?.length)
|
|
@@ -4086,60 +4492,77 @@ var ChatComposerView = ({
|
|
|
4086
4492
|
}
|
|
4087
4493
|
),
|
|
4088
4494
|
attachmentNotice === "limit_reached" ? /* @__PURE__ */ jsx15(AttachmentNotice, { "data-testid": "chat-composer-attachment-notice", children: attachmentLimitNotice }) : null,
|
|
4089
|
-
/* @__PURE__ */
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
"data-testid": "chat-composer-input",
|
|
4093
|
-
value,
|
|
4094
|
-
onChange: (event) => onValueChange(event.target.value),
|
|
4095
|
-
onKeyDown: handleKeyDown,
|
|
4096
|
-
onPaste: enableImageAttachments ? handlePaste : void 0,
|
|
4097
|
-
placeholder
|
|
4098
|
-
}
|
|
4099
|
-
),
|
|
4100
|
-
/* @__PURE__ */ jsx15(Footer, { children: /* @__PURE__ */ jsxs10(Actions2, { "data-testid": "chat-composer-actions", children: [
|
|
4101
|
-
enableImageAttachments ? /* @__PURE__ */ jsx15(
|
|
4102
|
-
AttachButton,
|
|
4495
|
+
/* @__PURE__ */ jsxs10(InputArea, { "data-testid": "chat-composer-input-area", children: [
|
|
4496
|
+
isComposerExpanded || isComposerExpandable ? /* @__PURE__ */ jsx15(
|
|
4497
|
+
ComposerExpandButton,
|
|
4103
4498
|
{
|
|
4104
4499
|
type: "button",
|
|
4105
|
-
"data-testid": "chat-composer-
|
|
4106
|
-
"aria-label":
|
|
4107
|
-
|
|
4108
|
-
|
|
4500
|
+
"data-testid": "chat-composer-expand-toggle",
|
|
4501
|
+
"aria-label": isComposerExpanded ? collapseComposerAriaLabel : expandComposerAriaLabel,
|
|
4502
|
+
"aria-expanded": isComposerExpanded,
|
|
4503
|
+
onClick: () => setIsComposerExpanded((current) => !current),
|
|
4504
|
+
children: /* @__PURE__ */ jsx15(ComposerExpandIcon, { expanded: isComposerExpanded })
|
|
4109
4505
|
}
|
|
4110
4506
|
) : null,
|
|
4111
4507
|
/* @__PURE__ */ jsx15(
|
|
4112
|
-
|
|
4113
|
-
{
|
|
4114
|
-
value: selectedMode,
|
|
4115
|
-
disabled: isStreaming,
|
|
4116
|
-
labels: modeLabels,
|
|
4117
|
-
onChange: onSelectedModeChange
|
|
4118
|
-
}
|
|
4119
|
-
),
|
|
4120
|
-
/* @__PURE__ */ jsx15(
|
|
4121
|
-
ChatModelControl,
|
|
4508
|
+
Input,
|
|
4122
4509
|
{
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4510
|
+
ref: inputRef,
|
|
4511
|
+
"data-testid": "chat-composer-input",
|
|
4512
|
+
"data-expanded": isComposerExpanded,
|
|
4513
|
+
value,
|
|
4514
|
+
onChange: (event) => onValueChange(event.target.value),
|
|
4515
|
+
onKeyDown: handleKeyDown,
|
|
4516
|
+
onPaste: enableImageAttachments ? handlePaste : void 0,
|
|
4517
|
+
placeholder
|
|
4130
4518
|
}
|
|
4131
|
-
)
|
|
4132
|
-
|
|
4133
|
-
|
|
4519
|
+
)
|
|
4520
|
+
] }),
|
|
4521
|
+
/* @__PURE__ */ jsxs10(Footer, { children: [
|
|
4522
|
+
/* @__PURE__ */ jsx15(LeadingActions, { "data-testid": "chat-composer-leading-actions", children: enableImageAttachments ? /* @__PURE__ */ jsx15(
|
|
4523
|
+
AttachButton,
|
|
4134
4524
|
{
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4525
|
+
type: "button",
|
|
4526
|
+
"data-testid": "chat-composer-attach-image",
|
|
4527
|
+
"aria-label": "Attach image",
|
|
4528
|
+
onClick: () => imageInputRef.current?.click(),
|
|
4529
|
+
children: /* @__PURE__ */ jsx15(PlusIcon, {})
|
|
4140
4530
|
}
|
|
4141
|
-
)
|
|
4142
|
-
|
|
4531
|
+
) : null }),
|
|
4532
|
+
/* @__PURE__ */ jsxs10(TrailingActions, { "data-testid": "chat-composer-trailing-actions", children: [
|
|
4533
|
+
/* @__PURE__ */ jsx15(
|
|
4534
|
+
ChatModeControl,
|
|
4535
|
+
{
|
|
4536
|
+
value: selectedMode,
|
|
4537
|
+
disabled: isStreaming,
|
|
4538
|
+
labels: modeLabels,
|
|
4539
|
+
onChange: onSelectedModeChange
|
|
4540
|
+
}
|
|
4541
|
+
),
|
|
4542
|
+
/* @__PURE__ */ jsx15(
|
|
4543
|
+
ChatModelControl,
|
|
4544
|
+
{
|
|
4545
|
+
selectedModel,
|
|
4546
|
+
availableModels,
|
|
4547
|
+
isModelsLoading,
|
|
4548
|
+
isModelsError,
|
|
4549
|
+
hasModels,
|
|
4550
|
+
onSelectedModelChange,
|
|
4551
|
+
onReloadModels
|
|
4552
|
+
}
|
|
4553
|
+
),
|
|
4554
|
+
/* @__PURE__ */ jsx15(
|
|
4555
|
+
ChatSendActions,
|
|
4556
|
+
{
|
|
4557
|
+
canSend,
|
|
4558
|
+
isStreaming,
|
|
4559
|
+
isStopping,
|
|
4560
|
+
onStop,
|
|
4561
|
+
onSend: handleSend
|
|
4562
|
+
}
|
|
4563
|
+
)
|
|
4564
|
+
] })
|
|
4565
|
+
] })
|
|
4143
4566
|
] }) });
|
|
4144
4567
|
};
|
|
4145
4568
|
var ChatComposer = () => {
|
|
@@ -4175,6 +4598,8 @@ var ChatComposer = () => {
|
|
|
4175
4598
|
isStopping: state.isStopping,
|
|
4176
4599
|
enableImageAttachments,
|
|
4177
4600
|
modeLabels,
|
|
4601
|
+
expandComposerAriaLabel: labels.expandComposerAriaLabel,
|
|
4602
|
+
collapseComposerAriaLabel: labels.collapseComposerAriaLabel,
|
|
4178
4603
|
onValueChange: actions.setValue,
|
|
4179
4604
|
onPickImages: actions.pickImages,
|
|
4180
4605
|
onPasteImages: actions.pasteImages,
|
|
@@ -4191,6 +4616,16 @@ var Container2 = styled14.div`
|
|
|
4191
4616
|
padding: 0 16px 16px;
|
|
4192
4617
|
`;
|
|
4193
4618
|
var Surface = styled14.div`
|
|
4619
|
+
display: grid;
|
|
4620
|
+
grid-template-columns: minmax(0, 1fr);
|
|
4621
|
+
grid-template-areas:
|
|
4622
|
+
'attachments'
|
|
4623
|
+
'notice'
|
|
4624
|
+
'input'
|
|
4625
|
+
'footer';
|
|
4626
|
+
width: 100%;
|
|
4627
|
+
max-width: 760px;
|
|
4628
|
+
margin: 0 auto;
|
|
4194
4629
|
background: var(--border-color);
|
|
4195
4630
|
border-radius: 20px;
|
|
4196
4631
|
border: 1px solid var(--border-hover);
|
|
@@ -4200,6 +4635,7 @@ var Surface = styled14.div`
|
|
|
4200
4635
|
backdrop-filter: blur(10px);
|
|
4201
4636
|
`;
|
|
4202
4637
|
var AttachmentNotice = styled14.div`
|
|
4638
|
+
grid-area: notice;
|
|
4203
4639
|
margin: 10px 12px 0;
|
|
4204
4640
|
padding: 8px 10px;
|
|
4205
4641
|
border-radius: 10px;
|
|
@@ -4209,19 +4645,45 @@ var AttachmentNotice = styled14.div`
|
|
|
4209
4645
|
font-size: 12px;
|
|
4210
4646
|
line-height: 1.4;
|
|
4211
4647
|
`;
|
|
4648
|
+
var InputArea = styled14.div`
|
|
4649
|
+
grid-area: input;
|
|
4650
|
+
position: relative;
|
|
4651
|
+
`;
|
|
4212
4652
|
var Input = styled14.textarea`
|
|
4653
|
+
--textarea-line-height: ${CHAT_COMPOSER_LINE_HEIGHT_PX}px;
|
|
4654
|
+
--textarea-min-rows: ${CHAT_COMPOSER_MIN_ROWS};
|
|
4655
|
+
--textarea-max-rows: ${CHAT_COMPOSER_MAX_ROWS};
|
|
4656
|
+
--textarea-expanded-max-rows: ${CHAT_COMPOSER_EXPANDED_MAX_ROWS};
|
|
4657
|
+
--textarea-padding-top: ${CHAT_COMPOSER_PADDING_TOP_PX}px;
|
|
4658
|
+
--textarea-padding-bottom: ${CHAT_COMPOSER_PADDING_BOTTOM_PX}px;
|
|
4659
|
+
--textarea-padding-block: calc(var(--textarea-padding-top) + var(--textarea-padding-bottom));
|
|
4660
|
+
--textarea-max-height: calc(
|
|
4661
|
+
var(--textarea-max-rows) * var(--textarea-line-height) + var(--textarea-padding-block)
|
|
4662
|
+
);
|
|
4663
|
+
--textarea-expanded-max-height: min(
|
|
4664
|
+
calc(
|
|
4665
|
+
var(--textarea-expanded-max-rows) * var(--textarea-line-height) +
|
|
4666
|
+
var(--textarea-padding-block)
|
|
4667
|
+
),
|
|
4668
|
+
calc(70vh - ${CHAT_COMPOSER_EXPANDED_RESERVED_SPACE_PX}px)
|
|
4669
|
+
);
|
|
4213
4670
|
width: 100%;
|
|
4214
|
-
min-height:
|
|
4671
|
+
min-height: calc(
|
|
4672
|
+
var(--textarea-min-rows) * var(--textarea-line-height) + var(--textarea-padding-block)
|
|
4673
|
+
);
|
|
4674
|
+
max-height: var(--textarea-max-height);
|
|
4675
|
+
box-sizing: border-box;
|
|
4215
4676
|
resize: none;
|
|
4216
4677
|
appearance: none;
|
|
4217
4678
|
border: 0;
|
|
4218
4679
|
outline: 0;
|
|
4219
4680
|
background: transparent;
|
|
4220
|
-
padding:
|
|
4681
|
+
padding: var(--textarea-padding-top) 44px var(--textarea-padding-bottom) 12px;
|
|
4221
4682
|
font-weight: 400;
|
|
4222
4683
|
font-size: 14px;
|
|
4223
4684
|
color: var(--text-primary);
|
|
4224
|
-
line-height:
|
|
4685
|
+
line-height: var(--textarea-line-height);
|
|
4686
|
+
overflow-y: hidden;
|
|
4225
4687
|
|
|
4226
4688
|
&::placeholder {
|
|
4227
4689
|
color: var(--text-secondary);
|
|
@@ -4230,19 +4692,50 @@ var Input = styled14.textarea`
|
|
|
4230
4692
|
&::-webkit-resizer {
|
|
4231
4693
|
display: none;
|
|
4232
4694
|
}
|
|
4695
|
+
|
|
4696
|
+
&[data-expanded='true'] {
|
|
4697
|
+
max-height: var(--textarea-expanded-max-height);
|
|
4698
|
+
}
|
|
4699
|
+
`;
|
|
4700
|
+
var ComposerExpandButton = styled14.button`
|
|
4701
|
+
position: absolute;
|
|
4702
|
+
top: 8px;
|
|
4703
|
+
right: 10px;
|
|
4704
|
+
width: 28px;
|
|
4705
|
+
height: 28px;
|
|
4706
|
+
display: grid;
|
|
4707
|
+
place-items: center;
|
|
4708
|
+
border: none;
|
|
4709
|
+
border-radius: 999px;
|
|
4710
|
+
background: transparent;
|
|
4711
|
+
color: rgba(255, 255, 255, 0.72);
|
|
4712
|
+
cursor: pointer;
|
|
4713
|
+
z-index: 1;
|
|
4714
|
+
|
|
4715
|
+
&:hover {
|
|
4716
|
+
background: rgba(255, 255, 255, 0.08);
|
|
4717
|
+
color: rgba(255, 255, 255, 0.92);
|
|
4718
|
+
}
|
|
4233
4719
|
`;
|
|
4234
4720
|
var Footer = styled14.div`
|
|
4235
|
-
|
|
4721
|
+
grid-area: footer;
|
|
4722
|
+
display: grid;
|
|
4723
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
4236
4724
|
align-items: flex-end;
|
|
4237
|
-
justify-content: stretch;
|
|
4238
4725
|
gap: 16px;
|
|
4239
4726
|
padding: 0 14px 14px;
|
|
4240
4727
|
`;
|
|
4241
|
-
var
|
|
4728
|
+
var LeadingActions = styled14.div`
|
|
4729
|
+
display: flex;
|
|
4730
|
+
align-items: center;
|
|
4731
|
+
justify-content: flex-start;
|
|
4732
|
+
gap: 8px;
|
|
4733
|
+
min-width: 0;
|
|
4734
|
+
`;
|
|
4735
|
+
var TrailingActions = styled14.div`
|
|
4242
4736
|
display: flex;
|
|
4243
4737
|
align-items: center;
|
|
4244
4738
|
flex-wrap: wrap;
|
|
4245
|
-
width: 100%;
|
|
4246
4739
|
min-width: 0;
|
|
4247
4740
|
justify-content: flex-end;
|
|
4248
4741
|
gap: 8px;
|