@xinghunm/ai-chat 0.4.0 → 1.0.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/dist/index.d.mts +56 -7
- package/dist/index.d.ts +56 -7
- package/dist/index.js +619 -142
- package/dist/index.mjs +634 -157
- 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,24 @@ 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 !== "questionnaire") {
|
|
65
|
+
nextBlocks.push(incomingBlock);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const existingIndex = nextBlocks.findIndex(
|
|
69
|
+
(block) => block.type === "questionnaire" && block.questionnaire.questionnaireId === incomingBlock.questionnaire.questionnaireId
|
|
70
|
+
);
|
|
71
|
+
if (existingIndex === -1) {
|
|
72
|
+
nextBlocks.push(incomingBlock);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
nextBlocks[existingIndex] = incomingBlock;
|
|
76
|
+
});
|
|
77
|
+
return nextBlocks;
|
|
78
|
+
};
|
|
53
79
|
var finalizeStreamingMessage = (state, sessionId, status, clearError = false) => {
|
|
54
80
|
const message = state.streamingMessageBySession[sessionId];
|
|
55
81
|
const hasRenderableMessagePayload = Boolean(
|
|
@@ -239,10 +265,15 @@ var createChatStore = (initialState) => createStore((set, get) => ({
|
|
|
239
265
|
const target = state.streamingMessageBySession[sessionId];
|
|
240
266
|
if (!target)
|
|
241
267
|
return;
|
|
268
|
+
const nextBlocks = patch.blocks !== void 0 ? mergeStreamingBlocks(target.blocks, patch.blocks) : target.blocks;
|
|
242
269
|
set({
|
|
243
270
|
streamingMessageBySession: {
|
|
244
271
|
...state.streamingMessageBySession,
|
|
245
|
-
[sessionId]: {
|
|
272
|
+
[sessionId]: {
|
|
273
|
+
...target,
|
|
274
|
+
...patch,
|
|
275
|
+
...patch.blocks !== void 0 ? { blocks: nextBlocks } : {}
|
|
276
|
+
}
|
|
246
277
|
}
|
|
247
278
|
});
|
|
248
279
|
},
|
|
@@ -462,9 +493,27 @@ var DEFAULT_CHAT_TRANSPORT_ENDPOINTS = {
|
|
|
462
493
|
completions: "/chat/completions",
|
|
463
494
|
terminate: "/chat/terminate"
|
|
464
495
|
};
|
|
496
|
+
var createToolExecutionHeaders = (policy) => {
|
|
497
|
+
if (!policy?.enabled) {
|
|
498
|
+
return {};
|
|
499
|
+
}
|
|
500
|
+
return {
|
|
501
|
+
"X-Tool-Approval-Required": String(Boolean(policy.approvalRequired)),
|
|
502
|
+
...typeof policy.approvalTimeoutSec === "number" ? { "X-Tool-Approval-Timeout": String(policy.approvalTimeoutSec) } : {}
|
|
503
|
+
};
|
|
504
|
+
};
|
|
505
|
+
var createModeDefaultHeaders = (mode) => {
|
|
506
|
+
if (mode === "ask" || mode === "plan") {
|
|
507
|
+
return {
|
|
508
|
+
"X-Tool-Approval-Required": "false"
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
return {};
|
|
512
|
+
};
|
|
465
513
|
var createDefaultChatTransport = ({
|
|
466
514
|
apiBaseUrl,
|
|
467
515
|
authToken,
|
|
516
|
+
toolExecutionPolicy,
|
|
468
517
|
streamHeaders,
|
|
469
518
|
transformStreamPacket,
|
|
470
519
|
endpoints,
|
|
@@ -475,6 +524,10 @@ var createDefaultChatTransport = ({
|
|
|
475
524
|
...DEFAULT_CHAT_TRANSPORT_ENDPOINTS,
|
|
476
525
|
...endpoints
|
|
477
526
|
};
|
|
527
|
+
const resolvedStreamHeaders = {
|
|
528
|
+
...createToolExecutionHeaders(toolExecutionPolicy),
|
|
529
|
+
...streamHeaders
|
|
530
|
+
};
|
|
478
531
|
return {
|
|
479
532
|
getModels: () => getChatModels(client, resolvedEndpoints.models),
|
|
480
533
|
startStream: async ({
|
|
@@ -488,12 +541,16 @@ var createDefaultChatTransport = ({
|
|
|
488
541
|
onDone,
|
|
489
542
|
onError
|
|
490
543
|
}) => {
|
|
544
|
+
const requestHeaders = {
|
|
545
|
+
...createModeDefaultHeaders(mode),
|
|
546
|
+
...resolvedStreamHeaders
|
|
547
|
+
};
|
|
491
548
|
await startChatStream({
|
|
492
549
|
apiBaseUrl,
|
|
493
550
|
endpointPath: resolvedEndpoints.completions,
|
|
494
551
|
sessionId,
|
|
495
552
|
authToken,
|
|
496
|
-
requestHeaders
|
|
553
|
+
requestHeaders,
|
|
497
554
|
model,
|
|
498
555
|
mode,
|
|
499
556
|
content,
|
|
@@ -522,6 +579,8 @@ var AiChatProvider = (props) => {
|
|
|
522
579
|
defaultMode,
|
|
523
580
|
labels,
|
|
524
581
|
renderMessageBlock,
|
|
582
|
+
handleQuestionnaireSubmit,
|
|
583
|
+
handleConfirmationSubmit,
|
|
525
584
|
messageRenderOrder,
|
|
526
585
|
enableImageAttachments = true,
|
|
527
586
|
children
|
|
@@ -577,6 +636,8 @@ var AiChatProvider = (props) => {
|
|
|
577
636
|
sendRef,
|
|
578
637
|
retryRef,
|
|
579
638
|
renderMessageBlock,
|
|
639
|
+
handleQuestionnaireSubmit,
|
|
640
|
+
handleConfirmationSubmit,
|
|
580
641
|
messageRenderOrder,
|
|
581
642
|
transformStreamPacket: defaultTransformStreamPacket,
|
|
582
643
|
enableImageAttachments
|
|
@@ -587,6 +648,8 @@ var AiChatProvider = (props) => {
|
|
|
587
648
|
defaultAuthToken,
|
|
588
649
|
defaultTransformStreamPacket,
|
|
589
650
|
enableImageAttachments,
|
|
651
|
+
handleConfirmationSubmit,
|
|
652
|
+
handleQuestionnaireSubmit,
|
|
590
653
|
labels,
|
|
591
654
|
messageRenderOrder,
|
|
592
655
|
renderMessageBlock,
|
|
@@ -600,7 +663,7 @@ var AiChatProvider = (props) => {
|
|
|
600
663
|
};
|
|
601
664
|
|
|
602
665
|
// src/components/chat-thread/index.tsx
|
|
603
|
-
import { useCallback as
|
|
666
|
+
import { useCallback as useCallback3, useLayoutEffect as useLayoutEffect2, useMemo as useMemo4, useRef as useRef4, useState as useState4 } from "react";
|
|
604
667
|
import styled9 from "@emotion/styled";
|
|
605
668
|
|
|
606
669
|
// src/context/use-chat-context.ts
|
|
@@ -621,7 +684,7 @@ var useChatStore = (selector) => {
|
|
|
621
684
|
var CHAT_THREAD_SCROLL_TOP_GAP = 16;
|
|
622
685
|
|
|
623
686
|
// src/components/chat-thread/components/chat-message-item.tsx
|
|
624
|
-
import { Fragment, memo, useState as useState3 } from "react";
|
|
687
|
+
import { Fragment, memo, useCallback as useCallback2, useLayoutEffect, useState as useState3 } from "react";
|
|
625
688
|
import styled7 from "@emotion/styled";
|
|
626
689
|
import { keyframes } from "@emotion/react";
|
|
627
690
|
import ReactMarkdown from "react-markdown";
|
|
@@ -896,7 +959,7 @@ var getTimelineBlockKey = (block, index) => {
|
|
|
896
959
|
case "confirmation_card":
|
|
897
960
|
return `${index}:confirmation_card:${block.proposal.proposalId}`;
|
|
898
961
|
case "result_summary":
|
|
899
|
-
return `${index}:result_summary:${block.summary.
|
|
962
|
+
return `${index}:result_summary:${block.summary.summaryId}:${block.summary.status}`;
|
|
900
963
|
case "questionnaire":
|
|
901
964
|
return `${index}:questionnaire:${block.questionnaire.questionnaireId}`;
|
|
902
965
|
case "custom":
|
|
@@ -1188,21 +1251,21 @@ var useTimelineBlockAnchors = ({
|
|
|
1188
1251
|
};
|
|
1189
1252
|
};
|
|
1190
1253
|
|
|
1191
|
-
// src/components/chat-thread/components/
|
|
1254
|
+
// src/components/chat-thread/components/execution-confirmation-card.tsx
|
|
1192
1255
|
import styled from "@emotion/styled";
|
|
1193
1256
|
import { jsx as jsx2, jsxs } from "@emotion/react/jsx-runtime";
|
|
1194
|
-
var
|
|
1257
|
+
var ExecutionConfirmationCard = ({
|
|
1195
1258
|
proposal,
|
|
1196
1259
|
interactive = false,
|
|
1197
1260
|
onApply,
|
|
1198
1261
|
onConfirm,
|
|
1199
1262
|
onRevise
|
|
1200
1263
|
}) => {
|
|
1201
|
-
return /* @__PURE__ */ jsxs(Card, { "data-testid": "
|
|
1264
|
+
return /* @__PURE__ */ jsxs(Card, { "data-testid": "execution-confirmation-card", children: [
|
|
1202
1265
|
/* @__PURE__ */ jsxs(Header, { children: [
|
|
1203
1266
|
/* @__PURE__ */ jsx2(Eyebrow, { children: "Execution Proposal" }),
|
|
1204
|
-
/* @__PURE__ */ jsx2(Title, { children: proposal.
|
|
1205
|
-
proposal.
|
|
1267
|
+
/* @__PURE__ */ jsx2(Title, { children: proposal.resourceName }),
|
|
1268
|
+
proposal.executorName ? /* @__PURE__ */ jsx2(Subtitle, { children: proposal.executorName }) : null
|
|
1206
1269
|
] }),
|
|
1207
1270
|
/* @__PURE__ */ jsx2(SummaryList, { children: proposal.parameterSummary.map((item) => /* @__PURE__ */ jsxs(SummaryItem, { children: [
|
|
1208
1271
|
/* @__PURE__ */ jsx2(SummaryLabel, { children: item.label }),
|
|
@@ -1210,21 +1273,13 @@ var PDEAIExecutionConfirmationCard = ({
|
|
|
1210
1273
|
] }, `${item.fieldPath ?? item.label}-${item.value}`)) }),
|
|
1211
1274
|
proposal.warnings?.length ? /* @__PURE__ */ jsx2(Warnings, { children: proposal.warnings.map((warning) => /* @__PURE__ */ jsx2(Warning, { children: warning }, warning)) }) : null,
|
|
1212
1275
|
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
|
-
),
|
|
1276
|
+
onApply && /* @__PURE__ */ jsx2(ActionButton, { type: "button", "data-testid": "confirmation-apply", onClick: onApply, children: "Apply to Parameters" }),
|
|
1277
|
+
onConfirm && /* @__PURE__ */ jsx2(ActionButton, { type: "button", "data-testid": "confirmation-confirm", onClick: onConfirm, children: "Confirm Execution" }),
|
|
1223
1278
|
onRevise && /* @__PURE__ */ jsx2(
|
|
1224
1279
|
SecondaryActionButton,
|
|
1225
1280
|
{
|
|
1226
1281
|
type: "button",
|
|
1227
|
-
"data-testid": "
|
|
1282
|
+
"data-testid": "confirmation-revise",
|
|
1228
1283
|
onClick: onRevise,
|
|
1229
1284
|
children: "Revise Plan"
|
|
1230
1285
|
}
|
|
@@ -1321,10 +1376,10 @@ var SecondaryActionButton = styled(ActionButton)`
|
|
|
1321
1376
|
border: 1px solid rgba(255, 255, 255, 0.14);
|
|
1322
1377
|
`;
|
|
1323
1378
|
|
|
1324
|
-
// src/components/chat-thread/components/
|
|
1379
|
+
// src/components/chat-thread/components/notice-card.tsx
|
|
1325
1380
|
import styled2 from "@emotion/styled";
|
|
1326
1381
|
import { jsx as jsx3 } from "@emotion/react/jsx-runtime";
|
|
1327
|
-
var
|
|
1382
|
+
var NoticeCard = ({ text, tone }) => /* @__PURE__ */ jsx3(Card2, { "data-testid": "notice-card", "data-tone": tone, children: text });
|
|
1328
1383
|
var Card2 = styled2.div`
|
|
1329
1384
|
padding: 12px 14px;
|
|
1330
1385
|
border-radius: 16px;
|
|
@@ -1350,10 +1405,10 @@ var Card2 = styled2.div`
|
|
|
1350
1405
|
}
|
|
1351
1406
|
`;
|
|
1352
1407
|
|
|
1353
|
-
// src/components/chat-thread/components/
|
|
1408
|
+
// src/components/chat-thread/components/parameter-summary-card.tsx
|
|
1354
1409
|
import styled3 from "@emotion/styled";
|
|
1355
1410
|
import { jsx as jsx4, jsxs as jsxs2 } from "@emotion/react/jsx-runtime";
|
|
1356
|
-
var
|
|
1411
|
+
var ParameterSummaryCard = ({ items }) => /* @__PURE__ */ jsxs2(Card3, { "data-testid": "parameter-summary-card", children: [
|
|
1357
1412
|
/* @__PURE__ */ jsx4(Title2, { children: "Parameter Summary" }),
|
|
1358
1413
|
/* @__PURE__ */ jsx4(List, { children: items.map((item) => /* @__PURE__ */ jsxs2(ListItem, { children: [
|
|
1359
1414
|
/* @__PURE__ */ jsx4(Label, { children: item.label }),
|
|
@@ -1397,11 +1452,17 @@ var Value = styled3.span`
|
|
|
1397
1452
|
text-align: right;
|
|
1398
1453
|
`;
|
|
1399
1454
|
|
|
1400
|
-
// src/components/chat-thread/components/
|
|
1455
|
+
// src/components/chat-thread/components/questionnaire-card.tsx
|
|
1401
1456
|
import { useState as useState2 } from "react";
|
|
1402
1457
|
import styled4 from "@emotion/styled";
|
|
1403
1458
|
import { jsx as jsx5, jsxs as jsxs3 } from "@emotion/react/jsx-runtime";
|
|
1404
1459
|
var OTHER_OPTION_VALUE = "__other__";
|
|
1460
|
+
var DEFAULT_QUESTIONNAIRE_CARD_LABELS = {
|
|
1461
|
+
submitting: "Submitting...",
|
|
1462
|
+
submitted: "Selection submitted. Waiting for the plan to continue...",
|
|
1463
|
+
validationPrefix: "Please complete:",
|
|
1464
|
+
submitFailed: "Failed to submit. Please try again."
|
|
1465
|
+
};
|
|
1405
1466
|
var createInitialAnswers = (questionnaire) => ({
|
|
1406
1467
|
...questionnaire.answers ?? {}
|
|
1407
1468
|
});
|
|
@@ -1495,26 +1556,40 @@ var normalizeQuestionAnswer = (question, answer) => {
|
|
|
1495
1556
|
return answer;
|
|
1496
1557
|
}
|
|
1497
1558
|
};
|
|
1498
|
-
var
|
|
1559
|
+
var QuestionnaireCardInner = ({
|
|
1499
1560
|
questionnaire,
|
|
1500
1561
|
interactive = false,
|
|
1501
|
-
onSubmit
|
|
1562
|
+
onSubmit,
|
|
1563
|
+
labels
|
|
1502
1564
|
}) => {
|
|
1503
1565
|
const [answers, setAnswers] = useState2(
|
|
1504
1566
|
() => createInitialAnswers(questionnaire)
|
|
1505
1567
|
);
|
|
1506
1568
|
const [errorMessage, setErrorMessage] = useState2(null);
|
|
1507
|
-
const
|
|
1569
|
+
const [isSubmitting, setIsSubmitting] = useState2(false);
|
|
1570
|
+
const [isSubmitted, setIsSubmitted] = useState2(false);
|
|
1571
|
+
const resolvedLabels = {
|
|
1572
|
+
...DEFAULT_QUESTIONNAIRE_CARD_LABELS,
|
|
1573
|
+
...labels
|
|
1574
|
+
};
|
|
1575
|
+
const hasExternalFailureStatus = questionnaire.status === "expired" || questionnaire.status === "failed";
|
|
1576
|
+
const visibleErrorMessage = questionnaire.statusMessage ?? errorMessage;
|
|
1577
|
+
const isInteractionLocked = !interactive || isSubmitting || isSubmitted || hasExternalFailureStatus;
|
|
1578
|
+
const handleSubmit = async () => {
|
|
1579
|
+
if (isSubmitting || isSubmitted) {
|
|
1580
|
+
return;
|
|
1581
|
+
}
|
|
1508
1582
|
const missingQuestions = questionnaire.questions.filter(
|
|
1509
1583
|
(question) => question.required && isMissingRequiredAnswer(question, answers)
|
|
1510
1584
|
);
|
|
1511
1585
|
if (missingQuestions.length > 0) {
|
|
1512
1586
|
setErrorMessage(
|
|
1513
|
-
|
|
1587
|
+
`${resolvedLabels.validationPrefix} ${missingQuestions.map((question) => question.label).join(", ")}`
|
|
1514
1588
|
);
|
|
1515
1589
|
return;
|
|
1516
1590
|
}
|
|
1517
1591
|
setErrorMessage(null);
|
|
1592
|
+
setIsSubmitting(true);
|
|
1518
1593
|
const normalizedAnswers = Object.fromEntries(
|
|
1519
1594
|
questionnaire.questions.flatMap((question) => {
|
|
1520
1595
|
const value = normalizeQuestionAnswer(question, answers[question.id]);
|
|
@@ -1531,11 +1606,18 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1531
1606
|
return [`- ${question.label}: ${formatQuestionAnswer(question, value)}`];
|
|
1532
1607
|
})
|
|
1533
1608
|
];
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1609
|
+
try {
|
|
1610
|
+
await onSubmit?.({
|
|
1611
|
+
questionnaireId: questionnaire.questionnaireId,
|
|
1612
|
+
answers: normalizedAnswers,
|
|
1613
|
+
content: contentLines.join("\n")
|
|
1614
|
+
});
|
|
1615
|
+
setIsSubmitted(true);
|
|
1616
|
+
} catch (error) {
|
|
1617
|
+
setErrorMessage(error instanceof Error ? error.message : resolvedLabels.submitFailed);
|
|
1618
|
+
} finally {
|
|
1619
|
+
setIsSubmitting(false);
|
|
1620
|
+
}
|
|
1539
1621
|
};
|
|
1540
1622
|
const renderQuestion = (question) => {
|
|
1541
1623
|
const renderOptionChoice = ({
|
|
@@ -1550,13 +1632,13 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1550
1632
|
OptionChoiceItem,
|
|
1551
1633
|
{
|
|
1552
1634
|
role: "button",
|
|
1553
|
-
tabIndex:
|
|
1635
|
+
tabIndex: isInteractionLocked ? -1 : 0,
|
|
1554
1636
|
"aria-pressed": isSelected,
|
|
1555
1637
|
"data-selected": isSelected,
|
|
1556
1638
|
"data-tone": tone,
|
|
1557
|
-
"data-testid": `
|
|
1639
|
+
"data-testid": `question-option-${questionId}-${index}`,
|
|
1558
1640
|
onClick: (event) => {
|
|
1559
|
-
if (
|
|
1641
|
+
if (isInteractionLocked) {
|
|
1560
1642
|
return;
|
|
1561
1643
|
}
|
|
1562
1644
|
if (event.target instanceof HTMLElement && event.target.closest("input")) {
|
|
@@ -1565,7 +1647,7 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1565
1647
|
onClick();
|
|
1566
1648
|
},
|
|
1567
1649
|
onKeyDown: (event) => {
|
|
1568
|
-
if (
|
|
1650
|
+
if (isInteractionLocked) {
|
|
1569
1651
|
return;
|
|
1570
1652
|
}
|
|
1571
1653
|
if (event.key !== "Enter" && event.key !== " ") {
|
|
@@ -1624,11 +1706,11 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1624
1706
|
inlineInput: singleSelectDraft.selectedValue === OTHER_OPTION_VALUE ? /* @__PURE__ */ jsx5(
|
|
1625
1707
|
InlineOtherInput,
|
|
1626
1708
|
{
|
|
1627
|
-
"data-testid": `
|
|
1709
|
+
"data-testid": `question-input-${question.id}`,
|
|
1628
1710
|
type: "text",
|
|
1629
1711
|
value: singleSelectDraft.otherValue,
|
|
1630
1712
|
placeholder: "Other",
|
|
1631
|
-
readOnly:
|
|
1713
|
+
readOnly: isInteractionLocked,
|
|
1632
1714
|
onClick: (event) => {
|
|
1633
1715
|
event.stopPropagation();
|
|
1634
1716
|
},
|
|
@@ -1649,11 +1731,11 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1649
1731
|
return /* @__PURE__ */ jsx5(QuestionBody, { children: /* @__PURE__ */ jsx5(
|
|
1650
1732
|
TextInput,
|
|
1651
1733
|
{
|
|
1652
|
-
"data-testid": `
|
|
1734
|
+
"data-testid": `question-input-${question.id}`,
|
|
1653
1735
|
type: "text",
|
|
1654
1736
|
value: getTextInputValue(answers[question.id]),
|
|
1655
1737
|
placeholder: question.placeholder,
|
|
1656
|
-
readOnly:
|
|
1738
|
+
readOnly: isInteractionLocked,
|
|
1657
1739
|
onChange: (event) => {
|
|
1658
1740
|
setAnswers((current) => updateAnswerValue(current, question.id, event.target.value));
|
|
1659
1741
|
}
|
|
@@ -1664,11 +1746,11 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1664
1746
|
/* @__PURE__ */ jsx5(
|
|
1665
1747
|
TextInput,
|
|
1666
1748
|
{
|
|
1667
|
-
"data-testid": `
|
|
1749
|
+
"data-testid": `question-input-${question.id}`,
|
|
1668
1750
|
type: "number",
|
|
1669
1751
|
value: getNumberInputValue(answers[question.id]),
|
|
1670
1752
|
placeholder: question.placeholder,
|
|
1671
|
-
readOnly:
|
|
1753
|
+
readOnly: isInteractionLocked,
|
|
1672
1754
|
onChange: (event) => {
|
|
1673
1755
|
setAnswers(
|
|
1674
1756
|
(current) => updateAnswerValue(
|
|
@@ -1703,7 +1785,7 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1703
1785
|
return null;
|
|
1704
1786
|
}
|
|
1705
1787
|
};
|
|
1706
|
-
return /* @__PURE__ */ jsxs3(Card4, { "data-testid": "
|
|
1788
|
+
return /* @__PURE__ */ jsxs3(Card4, { "data-testid": "questionnaire-card", children: [
|
|
1707
1789
|
questionnaire.title ? /* @__PURE__ */ jsx5(Title3, { children: questionnaire.title }) : null,
|
|
1708
1790
|
questionnaire.description ? /* @__PURE__ */ jsx5(Description, { children: questionnaire.description }) : null,
|
|
1709
1791
|
/* @__PURE__ */ jsx5(QuestionList, { children: questionnaire.questions.map((question) => /* @__PURE__ */ jsxs3(QuestionCard, { children: [
|
|
@@ -1713,24 +1795,28 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1713
1795
|
] }),
|
|
1714
1796
|
renderQuestion(question)
|
|
1715
1797
|
] }, question.id)) }),
|
|
1716
|
-
|
|
1717
|
-
interactive ? /* @__PURE__ */ jsx5(
|
|
1798
|
+
visibleErrorMessage ? /* @__PURE__ */ jsx5(ErrorMessage, { "data-testid": "questionnaire-error", children: visibleErrorMessage }) : null,
|
|
1799
|
+
isSubmitted ? /* @__PURE__ */ jsx5(SuccessMessage, { "data-testid": "questionnaire-success", children: resolvedLabels.submitted }) : interactive && !hasExternalFailureStatus ? /* @__PURE__ */ jsx5(
|
|
1718
1800
|
SubmitButton,
|
|
1719
1801
|
{
|
|
1720
1802
|
type: "button",
|
|
1721
|
-
"data-testid": "
|
|
1722
|
-
|
|
1723
|
-
|
|
1803
|
+
"data-testid": "questionnaire-submit",
|
|
1804
|
+
disabled: isInteractionLocked,
|
|
1805
|
+
onClick: () => {
|
|
1806
|
+
void handleSubmit();
|
|
1807
|
+
},
|
|
1808
|
+
children: isSubmitting ? resolvedLabels.submitting : questionnaire.submitLabel ?? "Submit"
|
|
1724
1809
|
}
|
|
1725
1810
|
) : null
|
|
1726
1811
|
] });
|
|
1727
1812
|
};
|
|
1728
1813
|
var getQuestionnaireStateKey = (questionnaire) => JSON.stringify([
|
|
1729
1814
|
questionnaire.questionnaireId,
|
|
1730
|
-
questionnaire.
|
|
1731
|
-
questionnaire.
|
|
1815
|
+
questionnaire.questions,
|
|
1816
|
+
questionnaire.status,
|
|
1817
|
+
questionnaire.statusMessage
|
|
1732
1818
|
]);
|
|
1733
|
-
var
|
|
1819
|
+
var QuestionnaireCard = (props) => /* @__PURE__ */ jsx5(QuestionnaireCardInner, { ...props }, getQuestionnaireStateKey(props.questionnaire));
|
|
1734
1820
|
var Card4 = styled4.section`
|
|
1735
1821
|
display: grid;
|
|
1736
1822
|
gap: 14px;
|
|
@@ -1878,6 +1964,10 @@ var ErrorMessage = styled4.div`
|
|
|
1878
1964
|
color: rgba(255, 145, 145, 0.96);
|
|
1879
1965
|
font-size: 12px;
|
|
1880
1966
|
`;
|
|
1967
|
+
var SuccessMessage = styled4.div`
|
|
1968
|
+
color: rgba(164, 255, 210, 0.96);
|
|
1969
|
+
font-size: 12px;
|
|
1970
|
+
`;
|
|
1881
1971
|
var SubmitButton = styled4.button`
|
|
1882
1972
|
justify-self: flex-start;
|
|
1883
1973
|
border: none;
|
|
@@ -1888,12 +1978,17 @@ var SubmitButton = styled4.button`
|
|
|
1888
1978
|
font-weight: 700;
|
|
1889
1979
|
padding: 10px 14px;
|
|
1890
1980
|
cursor: pointer;
|
|
1981
|
+
|
|
1982
|
+
&:disabled {
|
|
1983
|
+
cursor: default;
|
|
1984
|
+
opacity: 0.72;
|
|
1985
|
+
}
|
|
1891
1986
|
`;
|
|
1892
1987
|
|
|
1893
|
-
// src/components/chat-thread/components/
|
|
1988
|
+
// src/components/chat-thread/components/result-summary-card.tsx
|
|
1894
1989
|
import styled5 from "@emotion/styled";
|
|
1895
1990
|
import { jsx as jsx6, jsxs as jsxs4 } from "@emotion/react/jsx-runtime";
|
|
1896
|
-
var
|
|
1991
|
+
var ResultSummaryCard = ({ summary }) => /* @__PURE__ */ jsxs4(Card5, { "data-testid": "result-summary-card", "data-status": summary.status, children: [
|
|
1897
1992
|
/* @__PURE__ */ jsx6(Eyebrow2, { children: summary.status }),
|
|
1898
1993
|
/* @__PURE__ */ jsx6(Headline, { children: summary.headline }),
|
|
1899
1994
|
/* @__PURE__ */ jsx6(Details, { children: summary.details.map((detail) => /* @__PURE__ */ jsx6(Detail, { children: detail }, detail)) })
|
|
@@ -1989,6 +2084,7 @@ var ImageViewer = ({ src, alt, onClose }) => {
|
|
|
1989
2084
|
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs5 } from "@emotion/react/jsx-runtime";
|
|
1990
2085
|
var MARKDOWN_REMARK_PLUGINS = [remarkGfm, remarkMath];
|
|
1991
2086
|
var MARKDOWN_REHYPE_PLUGINS = [rehypeKatex];
|
|
2087
|
+
var USER_MESSAGE_COLLAPSE_HEIGHT_PX = 120;
|
|
1992
2088
|
var MARKDOWN_COMPONENTS = {
|
|
1993
2089
|
table: ({ node: _node, ...props }) => /* @__PURE__ */ jsx8(TableWrapper, { children: /* @__PURE__ */ jsx8("table", { ...props }) })
|
|
1994
2090
|
};
|
|
@@ -2001,10 +2097,101 @@ var renderMarkdownContent = (content) => /* @__PURE__ */ jsx8(
|
|
|
2001
2097
|
children: content
|
|
2002
2098
|
}
|
|
2003
2099
|
);
|
|
2100
|
+
var renderPlainTextContent = (content) => content;
|
|
2101
|
+
var CollapseIcon = ({ expanded }) => /* @__PURE__ */ jsx8(
|
|
2102
|
+
"svg",
|
|
2103
|
+
{
|
|
2104
|
+
"aria-hidden": "true",
|
|
2105
|
+
width: "16",
|
|
2106
|
+
height: "16",
|
|
2107
|
+
viewBox: "0 0 16 16",
|
|
2108
|
+
fill: "none",
|
|
2109
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2110
|
+
children: /* @__PURE__ */ jsx8(
|
|
2111
|
+
"path",
|
|
2112
|
+
{
|
|
2113
|
+
d: "M4 6l4 4 4-4",
|
|
2114
|
+
stroke: "currentColor",
|
|
2115
|
+
strokeWidth: "1.6",
|
|
2116
|
+
strokeLinecap: "round",
|
|
2117
|
+
strokeLinejoin: "round",
|
|
2118
|
+
transform: expanded ? "rotate(180 8 8)" : void 0
|
|
2119
|
+
}
|
|
2120
|
+
)
|
|
2121
|
+
}
|
|
2122
|
+
);
|
|
2123
|
+
var useUserMessageCollapse = ({
|
|
2124
|
+
blocks,
|
|
2125
|
+
displayedBlocks,
|
|
2126
|
+
displayedContent,
|
|
2127
|
+
enabled,
|
|
2128
|
+
freshContent,
|
|
2129
|
+
settledContent
|
|
2130
|
+
}) => {
|
|
2131
|
+
const [isCollapsible, setIsCollapsible] = useState3(false);
|
|
2132
|
+
const [isExpanded, setIsExpanded] = useState3(false);
|
|
2133
|
+
const [bodyStackElement, setBodyStackElement] = useState3(null);
|
|
2134
|
+
const syncCollapseState = useCallback2(
|
|
2135
|
+
(element) => {
|
|
2136
|
+
const nextCollapsible = enabled && (element?.scrollHeight ?? 0) > USER_MESSAGE_COLLAPSE_HEIGHT_PX;
|
|
2137
|
+
setIsCollapsible(nextCollapsible);
|
|
2138
|
+
if (!nextCollapsible) {
|
|
2139
|
+
setIsExpanded(false);
|
|
2140
|
+
}
|
|
2141
|
+
},
|
|
2142
|
+
[enabled]
|
|
2143
|
+
);
|
|
2144
|
+
const bodyStackRef = useCallback2(
|
|
2145
|
+
(node) => {
|
|
2146
|
+
setBodyStackElement(node);
|
|
2147
|
+
syncCollapseState(node);
|
|
2148
|
+
},
|
|
2149
|
+
[syncCollapseState]
|
|
2150
|
+
);
|
|
2151
|
+
useLayoutEffect(() => {
|
|
2152
|
+
if (!bodyStackElement) {
|
|
2153
|
+
return;
|
|
2154
|
+
}
|
|
2155
|
+
const frameId = requestAnimationFrame(() => {
|
|
2156
|
+
syncCollapseState(bodyStackElement);
|
|
2157
|
+
});
|
|
2158
|
+
return () => {
|
|
2159
|
+
cancelAnimationFrame(frameId);
|
|
2160
|
+
};
|
|
2161
|
+
}, [
|
|
2162
|
+
blocks,
|
|
2163
|
+
bodyStackElement,
|
|
2164
|
+
displayedBlocks,
|
|
2165
|
+
displayedContent,
|
|
2166
|
+
enabled,
|
|
2167
|
+
freshContent,
|
|
2168
|
+
settledContent,
|
|
2169
|
+
syncCollapseState
|
|
2170
|
+
]);
|
|
2171
|
+
useLayoutEffect(() => {
|
|
2172
|
+
if (!bodyStackElement || !enabled || typeof ResizeObserver === "undefined") {
|
|
2173
|
+
return;
|
|
2174
|
+
}
|
|
2175
|
+
const observer = new ResizeObserver(() => {
|
|
2176
|
+
syncCollapseState(bodyStackElement);
|
|
2177
|
+
});
|
|
2178
|
+
observer.observe(bodyStackElement);
|
|
2179
|
+
return () => {
|
|
2180
|
+
observer.disconnect();
|
|
2181
|
+
};
|
|
2182
|
+
}, [bodyStackElement, enabled, syncCollapseState]);
|
|
2183
|
+
return {
|
|
2184
|
+
bodyStackRef,
|
|
2185
|
+
isCollapsed: isCollapsible && !isExpanded,
|
|
2186
|
+
isCollapsible,
|
|
2187
|
+
isExpanded,
|
|
2188
|
+
toggleExpanded: () => setIsExpanded((current) => !current)
|
|
2189
|
+
};
|
|
2190
|
+
};
|
|
2004
2191
|
var createExecutionConfirmationContent = (proposal) => [
|
|
2005
2192
|
"Execution confirmed",
|
|
2006
|
-
`- Equation: ${proposal.
|
|
2007
|
-
...proposal.
|
|
2193
|
+
`- Equation: ${proposal.resourceName}`,
|
|
2194
|
+
...proposal.executorName ? [`- Solver: ${proposal.executorName}`] : [],
|
|
2008
2195
|
`- Proposal ID: ${proposal.proposalId}`
|
|
2009
2196
|
].join("\n");
|
|
2010
2197
|
var areChatAttachmentsEqual = (previousAttachments, nextAttachments) => {
|
|
@@ -2026,10 +2213,10 @@ var areParameterSummaryItemsEqual = (previousItems, nextItems) => previousItems.
|
|
|
2026
2213
|
const nextItem = nextItems[index];
|
|
2027
2214
|
return item.label === nextItem?.label && item.value === nextItem.value && item.fieldPath === nextItem.fieldPath;
|
|
2028
2215
|
});
|
|
2029
|
-
var areExecutionProposalsEqual = (previousProposal, nextProposal) => previousProposal.proposalId === nextProposal.proposalId && previousProposal.
|
|
2216
|
+
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
2217
|
(warning, index) => warning === nextProposal.warnings?.[index]
|
|
2031
2218
|
);
|
|
2032
|
-
var areResultSummariesEqual = (previousSummary, nextSummary) => previousSummary.
|
|
2219
|
+
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
2220
|
var areStringArraysEqual = (previousValues, nextValues) => previousValues.length === nextValues.length && previousValues.every((value, index) => value === nextValues[index]);
|
|
2034
2221
|
var areQuestionAnswersEqual = (previousAnswer, nextAnswer) => {
|
|
2035
2222
|
if (Array.isArray(previousAnswer) || Array.isArray(nextAnswer)) {
|
|
@@ -2070,7 +2257,7 @@ var arePlanQuestionsEqual = (previousQuestion, nextQuestion) => {
|
|
|
2070
2257
|
return false;
|
|
2071
2258
|
}
|
|
2072
2259
|
};
|
|
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(
|
|
2260
|
+
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
2261
|
(question, index) => arePlanQuestionsEqual(question, nextQuestionnaire.questions[index])
|
|
2075
2262
|
) && areQuestionAnswerMapsEqual(previousQuestionnaire.answers, nextQuestionnaire.answers);
|
|
2076
2263
|
var areMessageBlocksEqual = (previousBlocks, nextBlocks) => {
|
|
@@ -2151,6 +2338,8 @@ var ChatMessageItemView = ({
|
|
|
2151
2338
|
const canSubmitConfirmation = isPlanMode && typeof onConfirmationSubmit === "function";
|
|
2152
2339
|
const canSubmitQuestionnaire = isPlanMode && typeof onQuestionnaireSubmit === "function";
|
|
2153
2340
|
const shouldShowStreamingCaret = isAssistantStreaming && (!shouldRenderStructuredBlocks || hasTextContent);
|
|
2341
|
+
const isUserMessage = message.role === "user";
|
|
2342
|
+
const messageRenderMode = isUserMessage ? "plain-text" : "markdown";
|
|
2154
2343
|
const timelineConsumedText = messageRenderOrder === "timeline" ? getTimelineConsumedText(blocks) : "";
|
|
2155
2344
|
const hasConsumedTimelineText = timelineConsumedText.length > 0 && displayedContent.startsWith(timelineConsumedText);
|
|
2156
2345
|
const timelineDisplayedContent = hasConsumedTimelineText ? displayedContent.slice(timelineConsumedText.length) : displayedContent;
|
|
@@ -2167,6 +2356,21 @@ var ChatMessageItemView = ({
|
|
|
2167
2356
|
message,
|
|
2168
2357
|
messageRenderOrder
|
|
2169
2358
|
});
|
|
2359
|
+
const {
|
|
2360
|
+
bodyStackRef,
|
|
2361
|
+
isCollapsed: isUserMessageCollapsed,
|
|
2362
|
+
isCollapsible: isUserMessageCollapsible,
|
|
2363
|
+
isExpanded: isUserMessageExpanded,
|
|
2364
|
+
toggleExpanded: toggleUserMessageExpanded
|
|
2365
|
+
} = useUserMessageCollapse({
|
|
2366
|
+
blocks,
|
|
2367
|
+
displayedBlocks,
|
|
2368
|
+
displayedContent,
|
|
2369
|
+
enabled: isUserMessage,
|
|
2370
|
+
freshContent,
|
|
2371
|
+
settledContent
|
|
2372
|
+
});
|
|
2373
|
+
const renderMessageContent = (content) => messageRenderMode === "plain-text" ? renderPlainTextContent(content) : renderMarkdownContent(content);
|
|
2170
2374
|
const renderChatMessageBlock = (block, index) => {
|
|
2171
2375
|
switch (block.type) {
|
|
2172
2376
|
case "markdown":
|
|
@@ -2175,17 +2379,18 @@ var ChatMessageItemView = ({
|
|
|
2175
2379
|
{
|
|
2176
2380
|
"data-testid": `chat-message-block-${index}`,
|
|
2177
2381
|
"data-block-tone": "settled",
|
|
2178
|
-
|
|
2382
|
+
"data-render-mode": messageRenderMode,
|
|
2383
|
+
children: renderMessageContent(block.text)
|
|
2179
2384
|
},
|
|
2180
2385
|
`markdown-${index}`
|
|
2181
2386
|
);
|
|
2182
2387
|
case "notice":
|
|
2183
|
-
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(
|
|
2388
|
+
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(NoticeCard, { text: block.text, tone: block.tone }) }, `notice-${index}`);
|
|
2184
2389
|
case "parameter_summary":
|
|
2185
|
-
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(
|
|
2390
|
+
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(ParameterSummaryCard, { items: block.items }) }, `parameter-summary-${index}`);
|
|
2186
2391
|
case "confirmation_card":
|
|
2187
2392
|
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(
|
|
2188
|
-
|
|
2393
|
+
ExecutionConfirmationCard,
|
|
2189
2394
|
{
|
|
2190
2395
|
proposal: block.proposal,
|
|
2191
2396
|
interactive: isPlanMode,
|
|
@@ -2197,13 +2402,19 @@ var ChatMessageItemView = ({
|
|
|
2197
2402
|
}
|
|
2198
2403
|
) }, `confirmation-card-${index}`);
|
|
2199
2404
|
case "result_summary":
|
|
2200
|
-
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(
|
|
2405
|
+
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(ResultSummaryCard, { summary: block.summary }) }, `result-summary-${index}`);
|
|
2201
2406
|
case "questionnaire":
|
|
2202
2407
|
return /* @__PURE__ */ jsx8(Fragment, { children: /* @__PURE__ */ jsx8(
|
|
2203
|
-
|
|
2408
|
+
QuestionnaireCard,
|
|
2204
2409
|
{
|
|
2205
2410
|
questionnaire: block.questionnaire,
|
|
2206
2411
|
interactive: canSubmitQuestionnaire,
|
|
2412
|
+
labels: {
|
|
2413
|
+
submitting: labels.questionnaireSubmitting,
|
|
2414
|
+
submitted: labels.questionnaireSubmitted,
|
|
2415
|
+
validationPrefix: labels.questionnaireValidationPrefix,
|
|
2416
|
+
submitFailed: labels.questionnaireSubmitFailed
|
|
2417
|
+
},
|
|
2207
2418
|
onSubmit: canSubmitQuestionnaire ? (submission) => onQuestionnaireSubmit({
|
|
2208
2419
|
...submission,
|
|
2209
2420
|
sourceMessageId: message.id
|
|
@@ -2236,14 +2447,31 @@ var ChatMessageItemView = ({
|
|
|
2236
2447
|
"data-testid": block.tone === "fresh" ? "chat-message-fresh-block" : "chat-message-settled-block",
|
|
2237
2448
|
"data-block-tone": block.tone,
|
|
2238
2449
|
"data-block-index": index,
|
|
2239
|
-
|
|
2450
|
+
"data-render-mode": messageRenderMode,
|
|
2451
|
+
children: renderMessageContent(block.content)
|
|
2240
2452
|
},
|
|
2241
2453
|
`${block.tone}-${index}`
|
|
2242
2454
|
)),
|
|
2243
|
-
!textBlocks.some((block) => block.content) && !settledText && !freshText && Boolean(textContent) ? /* @__PURE__ */ jsx8(
|
|
2455
|
+
!textBlocks.some((block) => block.content) && !settledText && !freshText && Boolean(textContent) ? /* @__PURE__ */ jsx8(
|
|
2456
|
+
ContentBlock,
|
|
2457
|
+
{
|
|
2458
|
+
"data-testid": "chat-message-settled-block",
|
|
2459
|
+
"data-block-tone": "settled",
|
|
2460
|
+
"data-render-mode": messageRenderMode,
|
|
2461
|
+
children: renderMessageContent(textContent)
|
|
2462
|
+
}
|
|
2463
|
+
) : null
|
|
2244
2464
|
] });
|
|
2245
2465
|
};
|
|
2246
|
-
const renderStaticTextSegment = (content) => /* @__PURE__ */ jsx8(
|
|
2466
|
+
const renderStaticTextSegment = (content) => /* @__PURE__ */ jsx8(
|
|
2467
|
+
ContentBlock,
|
|
2468
|
+
{
|
|
2469
|
+
"data-testid": "chat-message-settled-block",
|
|
2470
|
+
"data-block-tone": "settled",
|
|
2471
|
+
"data-render-mode": messageRenderMode,
|
|
2472
|
+
children: renderMessageContent(content)
|
|
2473
|
+
}
|
|
2474
|
+
);
|
|
2247
2475
|
const bodySegments = (() => {
|
|
2248
2476
|
if (!shouldRenderStructuredBlocks && hasTextContent) {
|
|
2249
2477
|
return [{ type: "text" }];
|
|
@@ -2301,21 +2529,40 @@ var ChatMessageItemView = ({
|
|
|
2301
2529
|
}
|
|
2302
2530
|
) : null,
|
|
2303
2531
|
/* @__PURE__ */ jsx8(Role, { children: message.role === "user" ? labels.userRoleLabel : labels.assistantRoleLabel }),
|
|
2532
|
+
isUserMessageCollapsible ? /* @__PURE__ */ jsx8(
|
|
2533
|
+
CollapseToggle,
|
|
2534
|
+
{
|
|
2535
|
+
type: "button",
|
|
2536
|
+
"data-testid": "chat-message-collapse-toggle",
|
|
2537
|
+
"aria-label": isUserMessageExpanded ? labels.collapseMessageAriaLabel : labels.expandMessageAriaLabel,
|
|
2538
|
+
"aria-expanded": isUserMessageExpanded,
|
|
2539
|
+
onClick: toggleUserMessageExpanded,
|
|
2540
|
+
children: /* @__PURE__ */ jsx8(CollapseIcon, { expanded: isUserMessageExpanded })
|
|
2541
|
+
}
|
|
2542
|
+
) : null,
|
|
2304
2543
|
isStoppedAssistant ? /* @__PURE__ */ jsx8(StatusTag, { "data-testid": "chat-message-stopped-tag", children: labels.stoppedResponse }) : null
|
|
2305
2544
|
] }),
|
|
2306
2545
|
/* @__PURE__ */ jsxs5(Content, { "data-testid": "chat-message-content", children: [
|
|
2307
|
-
shouldRenderStructuredBlocks || hasTextContent ? /* @__PURE__ */ jsx8(
|
|
2308
|
-
|
|
2546
|
+
shouldRenderStructuredBlocks || hasTextContent ? /* @__PURE__ */ jsx8(
|
|
2547
|
+
ContentStack,
|
|
2309
2548
|
{
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2549
|
+
ref: bodyStackRef,
|
|
2550
|
+
"data-testid": "chat-message-body-stack",
|
|
2551
|
+
"data-collapsed": isUserMessageCollapsed,
|
|
2552
|
+
children: bodySegments.map((segment, index) => /* @__PURE__ */ jsx8(
|
|
2553
|
+
ContentSegment,
|
|
2554
|
+
{
|
|
2555
|
+
"data-testid": "chat-message-content-segment",
|
|
2556
|
+
children: segment.type === "block" ? renderChatMessageBlock(segment.block, segment.index) : segment.type === "text" ? segment.content !== void 0 ? segment.useTimelineSegmentation ? renderTextContent({
|
|
2557
|
+
content: segment.content,
|
|
2558
|
+
displayedBlocks: segment.displayedBlocks,
|
|
2559
|
+
useTimelineSegmentation: true
|
|
2560
|
+
}) : renderStaticTextSegment(segment.content) : renderTextContent() : renderStaticTextSegment(segment.content)
|
|
2561
|
+
},
|
|
2562
|
+
segment.type === "text" ? `text-${index}` : segment.type === "markdown" ? `markdown-${index}` : `${segment.block.type}-${segment.index}`
|
|
2563
|
+
))
|
|
2564
|
+
}
|
|
2565
|
+
) : null,
|
|
2319
2566
|
attachments.length ? /* @__PURE__ */ jsx8(AttachmentGrid, { "data-testid": "chat-message-attachment-grid", children: attachments.map((attachment) => /* @__PURE__ */ jsx8(
|
|
2320
2567
|
AttachmentButton,
|
|
2321
2568
|
{
|
|
@@ -2400,6 +2647,29 @@ var StatusTag = styled7.span`
|
|
|
2400
2647
|
letter-spacing: 0.02em;
|
|
2401
2648
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
|
|
2402
2649
|
`;
|
|
2650
|
+
var CollapseToggle = styled7.button`
|
|
2651
|
+
margin-left: auto;
|
|
2652
|
+
width: 28px;
|
|
2653
|
+
height: 28px;
|
|
2654
|
+
display: inline-flex;
|
|
2655
|
+
align-items: center;
|
|
2656
|
+
justify-content: center;
|
|
2657
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
2658
|
+
border-radius: 999px;
|
|
2659
|
+
background: rgba(255, 255, 255, 0.06);
|
|
2660
|
+
color: rgba(255, 255, 255, 0.72);
|
|
2661
|
+
cursor: pointer;
|
|
2662
|
+
transition:
|
|
2663
|
+
background 160ms ease-out,
|
|
2664
|
+
border-color 160ms ease-out,
|
|
2665
|
+
color 160ms ease-out;
|
|
2666
|
+
|
|
2667
|
+
&:hover {
|
|
2668
|
+
background: rgba(255, 255, 255, 0.1);
|
|
2669
|
+
border-color: rgba(255, 255, 255, 0.18);
|
|
2670
|
+
color: rgba(255, 255, 255, 0.92);
|
|
2671
|
+
}
|
|
2672
|
+
`;
|
|
2403
2673
|
var Content = styled7.div`
|
|
2404
2674
|
color: rgba(255, 255, 255, 0.92);
|
|
2405
2675
|
line-height: 1.6;
|
|
@@ -2444,6 +2714,11 @@ var ContentStack = styled7.div`
|
|
|
2444
2714
|
display: flex;
|
|
2445
2715
|
flex-direction: column;
|
|
2446
2716
|
gap: 16px;
|
|
2717
|
+
|
|
2718
|
+
&[data-collapsed='true'] {
|
|
2719
|
+
max-height: ${USER_MESSAGE_COLLAPSE_HEIGHT_PX}px;
|
|
2720
|
+
overflow: hidden;
|
|
2721
|
+
}
|
|
2447
2722
|
`;
|
|
2448
2723
|
var ContentSegment = styled7.div`
|
|
2449
2724
|
min-width: 0;
|
|
@@ -2457,6 +2732,11 @@ var ContentBlock = styled7.div`
|
|
|
2457
2732
|
margin-top: 16px;
|
|
2458
2733
|
}
|
|
2459
2734
|
|
|
2735
|
+
&[data-render-mode='plain-text'] {
|
|
2736
|
+
white-space: pre-wrap;
|
|
2737
|
+
overflow-wrap: anywhere;
|
|
2738
|
+
}
|
|
2739
|
+
|
|
2460
2740
|
&[data-block-tone='fresh'] {
|
|
2461
2741
|
opacity: 0.85;
|
|
2462
2742
|
filter: brightness(0.82) saturate(0.88);
|
|
@@ -2718,7 +2998,7 @@ var ChatThreadView = ({
|
|
|
2718
2998
|
const latestUserMessageRef = useRef4(null);
|
|
2719
2999
|
const reservedSpaceFrameRef = useRef4(null);
|
|
2720
3000
|
const [latestTurnMinHeight, setLatestTurnMinHeight] = useState4(0);
|
|
2721
|
-
const measureLatestTurnMinHeight =
|
|
3001
|
+
const measureLatestTurnMinHeight = useCallback3(() => {
|
|
2722
3002
|
const container = containerRef.current;
|
|
2723
3003
|
if (!container)
|
|
2724
3004
|
return;
|
|
@@ -2728,7 +3008,7 @@ var ChatThreadView = ({
|
|
|
2728
3008
|
const nextMinHeight = Math.max(0, container.clientHeight - paddingTop - paddingBottom);
|
|
2729
3009
|
setLatestTurnMinHeight((current) => current === nextMinHeight ? current : nextMinHeight);
|
|
2730
3010
|
}, []);
|
|
2731
|
-
const scrollLatestUserMessageToTop =
|
|
3011
|
+
const scrollLatestUserMessageToTop = useCallback3(() => {
|
|
2732
3012
|
const container = containerRef.current;
|
|
2733
3013
|
const target = latestUserMessageRef.current;
|
|
2734
3014
|
if (!container || !target)
|
|
@@ -2748,7 +3028,7 @@ var ChatThreadView = ({
|
|
|
2748
3028
|
}
|
|
2749
3029
|
container.scrollTop = nextScrollTop;
|
|
2750
3030
|
}, []);
|
|
2751
|
-
|
|
3031
|
+
useLayoutEffect2(() => {
|
|
2752
3032
|
if (reservedSpaceFrameRef.current !== null) {
|
|
2753
3033
|
window.cancelAnimationFrame(reservedSpaceFrameRef.current);
|
|
2754
3034
|
reservedSpaceFrameRef.current = null;
|
|
@@ -2777,7 +3057,7 @@ var ChatThreadView = ({
|
|
|
2777
3057
|
}
|
|
2778
3058
|
};
|
|
2779
3059
|
}, [latestUserMessageId, measureLatestTurnMinHeight, scrollLatestUserMessageToTop]);
|
|
2780
|
-
|
|
3060
|
+
useLayoutEffect2(() => {
|
|
2781
3061
|
if (!latestUserMessageId)
|
|
2782
3062
|
return;
|
|
2783
3063
|
const handleResize = () => {
|
|
@@ -2864,15 +3144,40 @@ var ChatThread = () => {
|
|
|
2864
3144
|
const error = useChatStore((s) => s.errorBySession[s.activeSessionId ?? ""]);
|
|
2865
3145
|
const updateQA = useChatStore((s) => s.updateQuestionnaireAnswers);
|
|
2866
3146
|
const clearSessionError = useChatStore((s) => s.clearSessionError);
|
|
2867
|
-
const {
|
|
2868
|
-
|
|
3147
|
+
const {
|
|
3148
|
+
sendRef,
|
|
3149
|
+
retryRef,
|
|
3150
|
+
renderMessageBlock,
|
|
3151
|
+
handleQuestionnaireSubmit: customQuestionnaireSubmit,
|
|
3152
|
+
handleConfirmationSubmit: customConfirmationSubmit,
|
|
3153
|
+
labels
|
|
3154
|
+
} = useChatContext();
|
|
3155
|
+
const handleRetry = useCallback3(() => {
|
|
2869
3156
|
if (!activeSessionId)
|
|
2870
3157
|
return;
|
|
2871
3158
|
clearSessionError(activeSessionId);
|
|
2872
3159
|
void retryRef.current();
|
|
2873
3160
|
}, [activeSessionId, clearSessionError, retryRef]);
|
|
2874
|
-
const handleQuestionnaireSubmit =
|
|
2875
|
-
(submission) => {
|
|
3161
|
+
const handleQuestionnaireSubmit = useCallback3(
|
|
3162
|
+
async (submission) => {
|
|
3163
|
+
if (customQuestionnaireSubmit) {
|
|
3164
|
+
const handled = await customQuestionnaireSubmit(submission, {
|
|
3165
|
+
sessionId: activeSessionId ?? void 0,
|
|
3166
|
+
mode: activeSessionMode
|
|
3167
|
+
});
|
|
3168
|
+
if (handled !== false) {
|
|
3169
|
+
if (activeSessionId && submission.sourceMessageId) {
|
|
3170
|
+
updateQA(
|
|
3171
|
+
activeSessionId,
|
|
3172
|
+
submission.sourceMessageId,
|
|
3173
|
+
submission.questionnaireId,
|
|
3174
|
+
submission.answers
|
|
3175
|
+
);
|
|
3176
|
+
}
|
|
3177
|
+
return;
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
await sendRef.current(submission.content);
|
|
2876
3181
|
if (activeSessionId && submission.sourceMessageId) {
|
|
2877
3182
|
updateQA(
|
|
2878
3183
|
activeSessionId,
|
|
@@ -2881,15 +3186,23 @@ var ChatThread = () => {
|
|
|
2881
3186
|
submission.answers
|
|
2882
3187
|
);
|
|
2883
3188
|
}
|
|
2884
|
-
void sendRef.current(submission.content);
|
|
2885
3189
|
},
|
|
2886
|
-
[activeSessionId, updateQA, sendRef]
|
|
3190
|
+
[activeSessionId, activeSessionMode, updateQA, sendRef, customQuestionnaireSubmit]
|
|
2887
3191
|
);
|
|
2888
|
-
const
|
|
2889
|
-
(submission) => {
|
|
2890
|
-
|
|
3192
|
+
const handleConfirmation = useCallback3(
|
|
3193
|
+
async (submission) => {
|
|
3194
|
+
if (customConfirmationSubmit) {
|
|
3195
|
+
const handled = await customConfirmationSubmit(submission, {
|
|
3196
|
+
sessionId: activeSessionId ?? void 0,
|
|
3197
|
+
mode: activeSessionMode
|
|
3198
|
+
});
|
|
3199
|
+
if (handled !== false) {
|
|
3200
|
+
return;
|
|
3201
|
+
}
|
|
3202
|
+
}
|
|
3203
|
+
await sendRef.current(submission.content);
|
|
2891
3204
|
},
|
|
2892
|
-
[sendRef]
|
|
3205
|
+
[activeSessionId, activeSessionMode, sendRef, customConfirmationSubmit]
|
|
2893
3206
|
);
|
|
2894
3207
|
if (!hasSessions || messages.length === 0 && !streamingMessage) {
|
|
2895
3208
|
return /* @__PURE__ */ jsx10(ChatThreadEmptyState, {});
|
|
@@ -2903,7 +3216,7 @@ var ChatThread = () => {
|
|
|
2903
3216
|
error,
|
|
2904
3217
|
retryButtonLabel: labels.retryButton,
|
|
2905
3218
|
onRetry: handleRetry,
|
|
2906
|
-
onConfirmationSubmit:
|
|
3219
|
+
onConfirmationSubmit: handleConfirmation,
|
|
2907
3220
|
onQuestionnaireSubmit: handleQuestionnaireSubmit,
|
|
2908
3221
|
renderMessageBlock
|
|
2909
3222
|
}
|
|
@@ -2917,6 +3230,7 @@ var Container = styled9.div`
|
|
|
2917
3230
|
min-height: 0;
|
|
2918
3231
|
overflow: auto;
|
|
2919
3232
|
padding: 24px;
|
|
3233
|
+
margin-bottom: 24px;
|
|
2920
3234
|
overscroll-behavior: contain;
|
|
2921
3235
|
|
|
2922
3236
|
&::-webkit-scrollbar {
|
|
@@ -2970,7 +3284,7 @@ var RetryButton = styled9.button`
|
|
|
2970
3284
|
`;
|
|
2971
3285
|
|
|
2972
3286
|
// src/components/chat-composer/index.tsx
|
|
2973
|
-
import { useEffect as useEffect6, useRef as useRef7 } from "react";
|
|
3287
|
+
import { useEffect as useEffect6, useLayoutEffect as useLayoutEffect3, useRef as useRef7, useState as useState8 } from "react";
|
|
2974
3288
|
import styled14 from "@emotion/styled";
|
|
2975
3289
|
|
|
2976
3290
|
// src/components/chat-composer/lib/chat-composer.ts
|
|
@@ -3082,7 +3396,7 @@ var resolveSendSession = ({
|
|
|
3082
3396
|
};
|
|
3083
3397
|
|
|
3084
3398
|
// src/components/chat-composer/hooks/use-chat-composer.ts
|
|
3085
|
-
import { useCallback as
|
|
3399
|
+
import { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef6, useState as useState6 } from "react";
|
|
3086
3400
|
|
|
3087
3401
|
// src/components/chat-composer/hooks/use-composer-attachments.ts
|
|
3088
3402
|
import { useEffect as useEffect4, useRef as useRef5, useState as useState5 } from "react";
|
|
@@ -3220,7 +3534,7 @@ var useChatComposer = () => {
|
|
|
3220
3534
|
const [availableModels, setAvailableModels] = useState6([]);
|
|
3221
3535
|
const [isModelsLoading, setIsModelsLoading] = useState6(true);
|
|
3222
3536
|
const [isModelsError, setIsModelsError] = useState6(false);
|
|
3223
|
-
const fetchModels =
|
|
3537
|
+
const fetchModels = useCallback4(async () => {
|
|
3224
3538
|
setIsModelsLoading(true);
|
|
3225
3539
|
setIsModelsError(false);
|
|
3226
3540
|
try {
|
|
@@ -3275,7 +3589,7 @@ var useChatComposer = () => {
|
|
|
3275
3589
|
stopRequestRef.current.timeoutId = null;
|
|
3276
3590
|
}
|
|
3277
3591
|
};
|
|
3278
|
-
const clearStopRequest =
|
|
3592
|
+
const clearStopRequest = useCallback4((sessionId) => {
|
|
3279
3593
|
if (!stopRequestRef.current)
|
|
3280
3594
|
return;
|
|
3281
3595
|
if (sessionId && stopRequestRef.current.sessionId !== sessionId)
|
|
@@ -3283,7 +3597,7 @@ var useChatComposer = () => {
|
|
|
3283
3597
|
clearStopTimeout(sessionId);
|
|
3284
3598
|
stopRequestRef.current = null;
|
|
3285
3599
|
}, []);
|
|
3286
|
-
const finalizeStop =
|
|
3600
|
+
const finalizeStop = useCallback4(
|
|
3287
3601
|
(sessionId) => {
|
|
3288
3602
|
if (stopRequestRef.current?.sessionId === sessionId) {
|
|
3289
3603
|
if (stopRequestRef.current.finalized)
|
|
@@ -3298,7 +3612,7 @@ var useChatComposer = () => {
|
|
|
3298
3612
|
},
|
|
3299
3613
|
[clearStopRequest, finalizeStoppedStreamingMessage]
|
|
3300
3614
|
);
|
|
3301
|
-
const runStream =
|
|
3615
|
+
const runStream = useCallback4(
|
|
3302
3616
|
async ({
|
|
3303
3617
|
localSessionId,
|
|
3304
3618
|
sessionId,
|
|
@@ -3387,7 +3701,7 @@ var useChatComposer = () => {
|
|
|
3387
3701
|
setSessionError
|
|
3388
3702
|
]
|
|
3389
3703
|
);
|
|
3390
|
-
const send =
|
|
3704
|
+
const send = useCallback4(
|
|
3391
3705
|
async (contentOverride) => {
|
|
3392
3706
|
const content = (contentOverride ?? value).trim();
|
|
3393
3707
|
const hasText = Boolean(content);
|
|
@@ -3996,6 +4310,27 @@ var StopSpinner = styled13.span`
|
|
|
3996
4310
|
|
|
3997
4311
|
// src/components/chat-composer/index.tsx
|
|
3998
4312
|
import { jsx as jsx15, jsxs as jsxs10 } from "@emotion/react/jsx-runtime";
|
|
4313
|
+
var CHAT_COMPOSER_LINE_HEIGHT_PX = 20;
|
|
4314
|
+
var CHAT_COMPOSER_MAX_ROWS = 7;
|
|
4315
|
+
var CHAT_COMPOSER_PADDING_TOP_PX = 8;
|
|
4316
|
+
var CHAT_COMPOSER_PADDING_BOTTOM_PX = 12;
|
|
4317
|
+
var CHAT_COMPOSER_PADDING_BLOCK_PX = CHAT_COMPOSER_PADDING_TOP_PX + CHAT_COMPOSER_PADDING_BOTTOM_PX;
|
|
4318
|
+
var CHAT_COMPOSER_MIN_ROWS = 4;
|
|
4319
|
+
var CHAT_COMPOSER_EXPANDED_MAX_ROWS = 60;
|
|
4320
|
+
var CHAT_COMPOSER_EXPANDED_MAX_VIEWPORT_RATIO = 0.7;
|
|
4321
|
+
var CHAT_COMPOSER_EXPANDED_RESERVED_SPACE_PX = 96;
|
|
4322
|
+
var CHAT_COMPOSER_MAX_HEIGHT_PX = CHAT_COMPOSER_MAX_ROWS * CHAT_COMPOSER_LINE_HEIGHT_PX + CHAT_COMPOSER_PADDING_BLOCK_PX;
|
|
4323
|
+
var CHAT_COMPOSER_EXPANDED_ROWS_HEIGHT_PX = CHAT_COMPOSER_EXPANDED_MAX_ROWS * CHAT_COMPOSER_LINE_HEIGHT_PX + CHAT_COMPOSER_PADDING_BLOCK_PX;
|
|
4324
|
+
var getExpandedComposerHeightPx = () => {
|
|
4325
|
+
if (typeof window === "undefined") {
|
|
4326
|
+
return CHAT_COMPOSER_EXPANDED_ROWS_HEIGHT_PX;
|
|
4327
|
+
}
|
|
4328
|
+
const viewportLimitedHeight = window.innerHeight * CHAT_COMPOSER_EXPANDED_MAX_VIEWPORT_RATIO - CHAT_COMPOSER_EXPANDED_RESERVED_SPACE_PX;
|
|
4329
|
+
return Math.max(
|
|
4330
|
+
CHAT_COMPOSER_MAX_HEIGHT_PX,
|
|
4331
|
+
Math.floor(Math.min(CHAT_COMPOSER_EXPANDED_ROWS_HEIGHT_PX, viewportLimitedHeight))
|
|
4332
|
+
);
|
|
4333
|
+
};
|
|
3999
4334
|
var PlusIcon = () => /* @__PURE__ */ jsx15(
|
|
4000
4335
|
"svg",
|
|
4001
4336
|
{
|
|
@@ -4008,6 +4343,36 @@ var PlusIcon = () => /* @__PURE__ */ jsx15(
|
|
|
4008
4343
|
children: /* @__PURE__ */ jsx15("path", { d: "M8 3v10M3 8h10", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round" })
|
|
4009
4344
|
}
|
|
4010
4345
|
);
|
|
4346
|
+
var ComposerExpandIcon = ({ expanded }) => /* @__PURE__ */ jsx15(
|
|
4347
|
+
"svg",
|
|
4348
|
+
{
|
|
4349
|
+
"aria-hidden": "true",
|
|
4350
|
+
width: "16",
|
|
4351
|
+
height: "16",
|
|
4352
|
+
viewBox: "0 0 16 16",
|
|
4353
|
+
fill: "none",
|
|
4354
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4355
|
+
children: expanded ? /* @__PURE__ */ jsx15(
|
|
4356
|
+
"path",
|
|
4357
|
+
{
|
|
4358
|
+
d: "M14 6h-4V2M10 6l4-4M2 10h4v4M6 10l-4 4",
|
|
4359
|
+
stroke: "currentColor",
|
|
4360
|
+
strokeWidth: "1.5",
|
|
4361
|
+
strokeLinecap: "round",
|
|
4362
|
+
strokeLinejoin: "round"
|
|
4363
|
+
}
|
|
4364
|
+
) : /* @__PURE__ */ jsx15(
|
|
4365
|
+
"path",
|
|
4366
|
+
{
|
|
4367
|
+
d: "M10 2h4v4M14 2L9 7M6 14H2v-4M2 14l5-5",
|
|
4368
|
+
stroke: "currentColor",
|
|
4369
|
+
strokeWidth: "1.5",
|
|
4370
|
+
strokeLinecap: "round",
|
|
4371
|
+
strokeLinejoin: "round"
|
|
4372
|
+
}
|
|
4373
|
+
)
|
|
4374
|
+
}
|
|
4375
|
+
);
|
|
4011
4376
|
var ChatComposerView = ({
|
|
4012
4377
|
value,
|
|
4013
4378
|
placeholder,
|
|
@@ -4024,6 +4389,8 @@ var ChatComposerView = ({
|
|
|
4024
4389
|
isStopping,
|
|
4025
4390
|
enableImageAttachments,
|
|
4026
4391
|
modeLabels,
|
|
4392
|
+
expandComposerAriaLabel,
|
|
4393
|
+
collapseComposerAriaLabel,
|
|
4027
4394
|
onValueChange,
|
|
4028
4395
|
onPickImages,
|
|
4029
4396
|
onPasteImages,
|
|
@@ -4035,6 +4402,9 @@ var ChatComposerView = ({
|
|
|
4035
4402
|
onSend
|
|
4036
4403
|
}) => {
|
|
4037
4404
|
const imageInputRef = useRef7(null);
|
|
4405
|
+
const inputRef = useRef7(null);
|
|
4406
|
+
const [isComposerExpandable, setIsComposerExpandable] = useState8(false);
|
|
4407
|
+
const [isComposerExpanded, setIsComposerExpanded] = useState8(false);
|
|
4038
4408
|
const canSend = canSendChatMessage({
|
|
4039
4409
|
value,
|
|
4040
4410
|
attachmentCount: attachments.length,
|
|
@@ -4042,6 +4412,26 @@ var ChatComposerView = ({
|
|
|
4042
4412
|
isModelsError,
|
|
4043
4413
|
hasModels
|
|
4044
4414
|
});
|
|
4415
|
+
useLayoutEffect3(() => {
|
|
4416
|
+
const element = inputRef.current;
|
|
4417
|
+
if (!element) {
|
|
4418
|
+
return;
|
|
4419
|
+
}
|
|
4420
|
+
if (!isComposerExpanded) {
|
|
4421
|
+
element.style.height = "0px";
|
|
4422
|
+
}
|
|
4423
|
+
const scrollHeight = element.scrollHeight;
|
|
4424
|
+
const nextExpandable = scrollHeight > CHAT_COMPOSER_MAX_HEIGHT_PX;
|
|
4425
|
+
const expandedHeight = getExpandedComposerHeightPx();
|
|
4426
|
+
const nextHeight = isComposerExpanded ? expandedHeight : Math.min(scrollHeight, CHAT_COMPOSER_MAX_HEIGHT_PX);
|
|
4427
|
+
setIsComposerExpandable(nextExpandable);
|
|
4428
|
+
element.style.height = `${nextHeight}px`;
|
|
4429
|
+
element.style.overflowY = !isComposerExpanded && scrollHeight > CHAT_COMPOSER_MAX_HEIGHT_PX ? "auto" : "hidden";
|
|
4430
|
+
}, [isComposerExpanded, value]);
|
|
4431
|
+
const handleSend = async () => {
|
|
4432
|
+
setIsComposerExpanded(false);
|
|
4433
|
+
await onSend();
|
|
4434
|
+
};
|
|
4045
4435
|
const handleKeyDown = (event) => {
|
|
4046
4436
|
if (shouldStopChatComposer({ key: event.key, shiftKey: event.shiftKey, isStreaming })) {
|
|
4047
4437
|
event.preventDefault();
|
|
@@ -4051,7 +4441,7 @@ var ChatComposerView = ({
|
|
|
4051
4441
|
if (!shouldSubmitChatComposer({ key: event.key, shiftKey: event.shiftKey, canSend }))
|
|
4052
4442
|
return;
|
|
4053
4443
|
event.preventDefault();
|
|
4054
|
-
void
|
|
4444
|
+
void handleSend();
|
|
4055
4445
|
};
|
|
4056
4446
|
const handlePickImages = (event) => {
|
|
4057
4447
|
if (event.target.files?.length)
|
|
@@ -4086,60 +4476,77 @@ var ChatComposerView = ({
|
|
|
4086
4476
|
}
|
|
4087
4477
|
),
|
|
4088
4478
|
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,
|
|
4479
|
+
/* @__PURE__ */ jsxs10(InputArea, { "data-testid": "chat-composer-input-area", children: [
|
|
4480
|
+
isComposerExpanded || isComposerExpandable ? /* @__PURE__ */ jsx15(
|
|
4481
|
+
ComposerExpandButton,
|
|
4103
4482
|
{
|
|
4104
4483
|
type: "button",
|
|
4105
|
-
"data-testid": "chat-composer-
|
|
4106
|
-
"aria-label":
|
|
4107
|
-
|
|
4108
|
-
|
|
4484
|
+
"data-testid": "chat-composer-expand-toggle",
|
|
4485
|
+
"aria-label": isComposerExpanded ? collapseComposerAriaLabel : expandComposerAriaLabel,
|
|
4486
|
+
"aria-expanded": isComposerExpanded,
|
|
4487
|
+
onClick: () => setIsComposerExpanded((current) => !current),
|
|
4488
|
+
children: /* @__PURE__ */ jsx15(ComposerExpandIcon, { expanded: isComposerExpanded })
|
|
4109
4489
|
}
|
|
4110
4490
|
) : null,
|
|
4111
4491
|
/* @__PURE__ */ jsx15(
|
|
4112
|
-
|
|
4492
|
+
Input,
|
|
4113
4493
|
{
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4494
|
+
ref: inputRef,
|
|
4495
|
+
"data-testid": "chat-composer-input",
|
|
4496
|
+
"data-expanded": isComposerExpanded,
|
|
4497
|
+
value,
|
|
4498
|
+
onChange: (event) => onValueChange(event.target.value),
|
|
4499
|
+
onKeyDown: handleKeyDown,
|
|
4500
|
+
onPaste: enableImageAttachments ? handlePaste : void 0,
|
|
4501
|
+
placeholder
|
|
4118
4502
|
}
|
|
4119
|
-
)
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
availableModels,
|
|
4125
|
-
isModelsLoading,
|
|
4126
|
-
isModelsError,
|
|
4127
|
-
hasModels,
|
|
4128
|
-
onSelectedModelChange,
|
|
4129
|
-
onReloadModels
|
|
4130
|
-
}
|
|
4131
|
-
),
|
|
4132
|
-
/* @__PURE__ */ jsx15(
|
|
4133
|
-
ChatSendActions,
|
|
4503
|
+
)
|
|
4504
|
+
] }),
|
|
4505
|
+
/* @__PURE__ */ jsxs10(Footer, { children: [
|
|
4506
|
+
/* @__PURE__ */ jsx15(LeadingActions, { "data-testid": "chat-composer-leading-actions", children: enableImageAttachments ? /* @__PURE__ */ jsx15(
|
|
4507
|
+
AttachButton,
|
|
4134
4508
|
{
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4509
|
+
type: "button",
|
|
4510
|
+
"data-testid": "chat-composer-attach-image",
|
|
4511
|
+
"aria-label": "Attach image",
|
|
4512
|
+
onClick: () => imageInputRef.current?.click(),
|
|
4513
|
+
children: /* @__PURE__ */ jsx15(PlusIcon, {})
|
|
4140
4514
|
}
|
|
4141
|
-
)
|
|
4142
|
-
|
|
4515
|
+
) : null }),
|
|
4516
|
+
/* @__PURE__ */ jsxs10(TrailingActions, { "data-testid": "chat-composer-trailing-actions", children: [
|
|
4517
|
+
/* @__PURE__ */ jsx15(
|
|
4518
|
+
ChatModeControl,
|
|
4519
|
+
{
|
|
4520
|
+
value: selectedMode,
|
|
4521
|
+
disabled: isStreaming,
|
|
4522
|
+
labels: modeLabels,
|
|
4523
|
+
onChange: onSelectedModeChange
|
|
4524
|
+
}
|
|
4525
|
+
),
|
|
4526
|
+
/* @__PURE__ */ jsx15(
|
|
4527
|
+
ChatModelControl,
|
|
4528
|
+
{
|
|
4529
|
+
selectedModel,
|
|
4530
|
+
availableModels,
|
|
4531
|
+
isModelsLoading,
|
|
4532
|
+
isModelsError,
|
|
4533
|
+
hasModels,
|
|
4534
|
+
onSelectedModelChange,
|
|
4535
|
+
onReloadModels
|
|
4536
|
+
}
|
|
4537
|
+
),
|
|
4538
|
+
/* @__PURE__ */ jsx15(
|
|
4539
|
+
ChatSendActions,
|
|
4540
|
+
{
|
|
4541
|
+
canSend,
|
|
4542
|
+
isStreaming,
|
|
4543
|
+
isStopping,
|
|
4544
|
+
onStop,
|
|
4545
|
+
onSend: handleSend
|
|
4546
|
+
}
|
|
4547
|
+
)
|
|
4548
|
+
] })
|
|
4549
|
+
] })
|
|
4143
4550
|
] }) });
|
|
4144
4551
|
};
|
|
4145
4552
|
var ChatComposer = () => {
|
|
@@ -4175,6 +4582,8 @@ var ChatComposer = () => {
|
|
|
4175
4582
|
isStopping: state.isStopping,
|
|
4176
4583
|
enableImageAttachments,
|
|
4177
4584
|
modeLabels,
|
|
4585
|
+
expandComposerAriaLabel: labels.expandComposerAriaLabel,
|
|
4586
|
+
collapseComposerAriaLabel: labels.collapseComposerAriaLabel,
|
|
4178
4587
|
onValueChange: actions.setValue,
|
|
4179
4588
|
onPickImages: actions.pickImages,
|
|
4180
4589
|
onPasteImages: actions.pasteImages,
|
|
@@ -4191,6 +4600,16 @@ var Container2 = styled14.div`
|
|
|
4191
4600
|
padding: 0 16px 16px;
|
|
4192
4601
|
`;
|
|
4193
4602
|
var Surface = styled14.div`
|
|
4603
|
+
display: grid;
|
|
4604
|
+
grid-template-columns: minmax(0, 1fr);
|
|
4605
|
+
grid-template-areas:
|
|
4606
|
+
'attachments'
|
|
4607
|
+
'notice'
|
|
4608
|
+
'input'
|
|
4609
|
+
'footer';
|
|
4610
|
+
width: 100%;
|
|
4611
|
+
max-width: 760px;
|
|
4612
|
+
margin: 0 auto;
|
|
4194
4613
|
background: var(--border-color);
|
|
4195
4614
|
border-radius: 20px;
|
|
4196
4615
|
border: 1px solid var(--border-hover);
|
|
@@ -4200,6 +4619,7 @@ var Surface = styled14.div`
|
|
|
4200
4619
|
backdrop-filter: blur(10px);
|
|
4201
4620
|
`;
|
|
4202
4621
|
var AttachmentNotice = styled14.div`
|
|
4622
|
+
grid-area: notice;
|
|
4203
4623
|
margin: 10px 12px 0;
|
|
4204
4624
|
padding: 8px 10px;
|
|
4205
4625
|
border-radius: 10px;
|
|
@@ -4209,19 +4629,45 @@ var AttachmentNotice = styled14.div`
|
|
|
4209
4629
|
font-size: 12px;
|
|
4210
4630
|
line-height: 1.4;
|
|
4211
4631
|
`;
|
|
4632
|
+
var InputArea = styled14.div`
|
|
4633
|
+
grid-area: input;
|
|
4634
|
+
position: relative;
|
|
4635
|
+
`;
|
|
4212
4636
|
var Input = styled14.textarea`
|
|
4637
|
+
--textarea-line-height: ${CHAT_COMPOSER_LINE_HEIGHT_PX}px;
|
|
4638
|
+
--textarea-min-rows: ${CHAT_COMPOSER_MIN_ROWS};
|
|
4639
|
+
--textarea-max-rows: ${CHAT_COMPOSER_MAX_ROWS};
|
|
4640
|
+
--textarea-expanded-max-rows: ${CHAT_COMPOSER_EXPANDED_MAX_ROWS};
|
|
4641
|
+
--textarea-padding-top: ${CHAT_COMPOSER_PADDING_TOP_PX}px;
|
|
4642
|
+
--textarea-padding-bottom: ${CHAT_COMPOSER_PADDING_BOTTOM_PX}px;
|
|
4643
|
+
--textarea-padding-block: calc(var(--textarea-padding-top) + var(--textarea-padding-bottom));
|
|
4644
|
+
--textarea-max-height: calc(
|
|
4645
|
+
var(--textarea-max-rows) * var(--textarea-line-height) + var(--textarea-padding-block)
|
|
4646
|
+
);
|
|
4647
|
+
--textarea-expanded-max-height: min(
|
|
4648
|
+
calc(
|
|
4649
|
+
var(--textarea-expanded-max-rows) * var(--textarea-line-height) +
|
|
4650
|
+
var(--textarea-padding-block)
|
|
4651
|
+
),
|
|
4652
|
+
calc(70vh - ${CHAT_COMPOSER_EXPANDED_RESERVED_SPACE_PX}px)
|
|
4653
|
+
);
|
|
4213
4654
|
width: 100%;
|
|
4214
|
-
min-height:
|
|
4655
|
+
min-height: calc(
|
|
4656
|
+
var(--textarea-min-rows) * var(--textarea-line-height) + var(--textarea-padding-block)
|
|
4657
|
+
);
|
|
4658
|
+
max-height: var(--textarea-max-height);
|
|
4659
|
+
box-sizing: border-box;
|
|
4215
4660
|
resize: none;
|
|
4216
4661
|
appearance: none;
|
|
4217
4662
|
border: 0;
|
|
4218
4663
|
outline: 0;
|
|
4219
4664
|
background: transparent;
|
|
4220
|
-
padding:
|
|
4665
|
+
padding: var(--textarea-padding-top) 44px var(--textarea-padding-bottom) 12px;
|
|
4221
4666
|
font-weight: 400;
|
|
4222
4667
|
font-size: 14px;
|
|
4223
4668
|
color: var(--text-primary);
|
|
4224
|
-
line-height:
|
|
4669
|
+
line-height: var(--textarea-line-height);
|
|
4670
|
+
overflow-y: hidden;
|
|
4225
4671
|
|
|
4226
4672
|
&::placeholder {
|
|
4227
4673
|
color: var(--text-secondary);
|
|
@@ -4230,19 +4676,50 @@ var Input = styled14.textarea`
|
|
|
4230
4676
|
&::-webkit-resizer {
|
|
4231
4677
|
display: none;
|
|
4232
4678
|
}
|
|
4679
|
+
|
|
4680
|
+
&[data-expanded='true'] {
|
|
4681
|
+
max-height: var(--textarea-expanded-max-height);
|
|
4682
|
+
}
|
|
4683
|
+
`;
|
|
4684
|
+
var ComposerExpandButton = styled14.button`
|
|
4685
|
+
position: absolute;
|
|
4686
|
+
top: 8px;
|
|
4687
|
+
right: 10px;
|
|
4688
|
+
width: 28px;
|
|
4689
|
+
height: 28px;
|
|
4690
|
+
display: grid;
|
|
4691
|
+
place-items: center;
|
|
4692
|
+
border: none;
|
|
4693
|
+
border-radius: 999px;
|
|
4694
|
+
background: transparent;
|
|
4695
|
+
color: rgba(255, 255, 255, 0.72);
|
|
4696
|
+
cursor: pointer;
|
|
4697
|
+
z-index: 1;
|
|
4698
|
+
|
|
4699
|
+
&:hover {
|
|
4700
|
+
background: rgba(255, 255, 255, 0.08);
|
|
4701
|
+
color: rgba(255, 255, 255, 0.92);
|
|
4702
|
+
}
|
|
4233
4703
|
`;
|
|
4234
4704
|
var Footer = styled14.div`
|
|
4235
|
-
|
|
4705
|
+
grid-area: footer;
|
|
4706
|
+
display: grid;
|
|
4707
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
4236
4708
|
align-items: flex-end;
|
|
4237
|
-
justify-content: stretch;
|
|
4238
4709
|
gap: 16px;
|
|
4239
4710
|
padding: 0 14px 14px;
|
|
4240
4711
|
`;
|
|
4241
|
-
var
|
|
4712
|
+
var LeadingActions = styled14.div`
|
|
4713
|
+
display: flex;
|
|
4714
|
+
align-items: center;
|
|
4715
|
+
justify-content: flex-start;
|
|
4716
|
+
gap: 8px;
|
|
4717
|
+
min-width: 0;
|
|
4718
|
+
`;
|
|
4719
|
+
var TrailingActions = styled14.div`
|
|
4242
4720
|
display: flex;
|
|
4243
4721
|
align-items: center;
|
|
4244
4722
|
flex-wrap: wrap;
|
|
4245
|
-
width: 100%;
|
|
4246
4723
|
min-width: 0;
|
|
4247
4724
|
justify-content: flex-end;
|
|
4248
4725
|
gap: 8px;
|