@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.js
CHANGED
|
@@ -78,10 +78,18 @@ var DEFAULT_AI_CHAT_LABELS = {
|
|
|
78
78
|
attachmentLimitNotice: "Images exceeded the limit. Only the first 10 images were kept.",
|
|
79
79
|
userRoleLabel: "User",
|
|
80
80
|
assistantRoleLabel: "Assistant",
|
|
81
|
+
expandMessageAriaLabel: "Expand message",
|
|
82
|
+
collapseMessageAriaLabel: "Collapse message",
|
|
83
|
+
expandComposerAriaLabel: "Expand composer",
|
|
84
|
+
collapseComposerAriaLabel: "Collapse composer",
|
|
81
85
|
stoppedResponse: "Response stopped",
|
|
82
86
|
assistantStreamingAriaLabel: "assistant streaming",
|
|
83
87
|
networkError: "Network request failed. Please try again.",
|
|
84
|
-
genericError: "Something went wrong. Please try again."
|
|
88
|
+
genericError: "Something went wrong. Please try again.",
|
|
89
|
+
questionnaireSubmitting: "Submitting...",
|
|
90
|
+
questionnaireSubmitted: "Selection submitted. Waiting for the plan to continue...",
|
|
91
|
+
questionnaireValidationPrefix: "Please complete:",
|
|
92
|
+
questionnaireSubmitFailed: "Failed to submit. Please try again."
|
|
85
93
|
};
|
|
86
94
|
|
|
87
95
|
// src/store/chat-store.ts
|
|
@@ -97,6 +105,24 @@ var resolveSessionTitleFromMessage = (message) => {
|
|
|
97
105
|
}
|
|
98
106
|
return DEFAULT_CHAT_SESSION_TITLE;
|
|
99
107
|
};
|
|
108
|
+
var mergeStreamingBlocks = (existingBlocks, incomingBlocks) => {
|
|
109
|
+
const nextBlocks = [...existingBlocks ?? []];
|
|
110
|
+
incomingBlocks.forEach((incomingBlock) => {
|
|
111
|
+
if (incomingBlock.type !== "questionnaire") {
|
|
112
|
+
nextBlocks.push(incomingBlock);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const existingIndex = nextBlocks.findIndex(
|
|
116
|
+
(block) => block.type === "questionnaire" && block.questionnaire.questionnaireId === incomingBlock.questionnaire.questionnaireId
|
|
117
|
+
);
|
|
118
|
+
if (existingIndex === -1) {
|
|
119
|
+
nextBlocks.push(incomingBlock);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
nextBlocks[existingIndex] = incomingBlock;
|
|
123
|
+
});
|
|
124
|
+
return nextBlocks;
|
|
125
|
+
};
|
|
100
126
|
var finalizeStreamingMessage = (state, sessionId, status, clearError = false) => {
|
|
101
127
|
const message = state.streamingMessageBySession[sessionId];
|
|
102
128
|
const hasRenderableMessagePayload = Boolean(
|
|
@@ -286,10 +312,15 @@ var createChatStore = (initialState) => (0, import_vanilla.createStore)((set, ge
|
|
|
286
312
|
const target = state.streamingMessageBySession[sessionId];
|
|
287
313
|
if (!target)
|
|
288
314
|
return;
|
|
315
|
+
const nextBlocks = patch.blocks !== void 0 ? mergeStreamingBlocks(target.blocks, patch.blocks) : target.blocks;
|
|
289
316
|
set({
|
|
290
317
|
streamingMessageBySession: {
|
|
291
318
|
...state.streamingMessageBySession,
|
|
292
|
-
[sessionId]: {
|
|
319
|
+
[sessionId]: {
|
|
320
|
+
...target,
|
|
321
|
+
...patch,
|
|
322
|
+
...patch.blocks !== void 0 ? { blocks: nextBlocks } : {}
|
|
323
|
+
}
|
|
293
324
|
}
|
|
294
325
|
});
|
|
295
326
|
},
|
|
@@ -509,9 +540,27 @@ var DEFAULT_CHAT_TRANSPORT_ENDPOINTS = {
|
|
|
509
540
|
completions: "/chat/completions",
|
|
510
541
|
terminate: "/chat/terminate"
|
|
511
542
|
};
|
|
543
|
+
var createToolExecutionHeaders = (policy) => {
|
|
544
|
+
if (!policy?.enabled) {
|
|
545
|
+
return {};
|
|
546
|
+
}
|
|
547
|
+
return {
|
|
548
|
+
"X-Tool-Approval-Required": String(Boolean(policy.approvalRequired)),
|
|
549
|
+
...typeof policy.approvalTimeoutSec === "number" ? { "X-Tool-Approval-Timeout": String(policy.approvalTimeoutSec) } : {}
|
|
550
|
+
};
|
|
551
|
+
};
|
|
552
|
+
var createModeDefaultHeaders = (mode) => {
|
|
553
|
+
if (mode === "ask" || mode === "plan") {
|
|
554
|
+
return {
|
|
555
|
+
"X-Tool-Approval-Required": "false"
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
return {};
|
|
559
|
+
};
|
|
512
560
|
var createDefaultChatTransport = ({
|
|
513
561
|
apiBaseUrl,
|
|
514
562
|
authToken,
|
|
563
|
+
toolExecutionPolicy,
|
|
515
564
|
streamHeaders,
|
|
516
565
|
transformStreamPacket,
|
|
517
566
|
endpoints,
|
|
@@ -522,6 +571,10 @@ var createDefaultChatTransport = ({
|
|
|
522
571
|
...DEFAULT_CHAT_TRANSPORT_ENDPOINTS,
|
|
523
572
|
...endpoints
|
|
524
573
|
};
|
|
574
|
+
const resolvedStreamHeaders = {
|
|
575
|
+
...createToolExecutionHeaders(toolExecutionPolicy),
|
|
576
|
+
...streamHeaders
|
|
577
|
+
};
|
|
525
578
|
return {
|
|
526
579
|
getModels: () => getChatModels(client, resolvedEndpoints.models),
|
|
527
580
|
startStream: async ({
|
|
@@ -535,12 +588,16 @@ var createDefaultChatTransport = ({
|
|
|
535
588
|
onDone,
|
|
536
589
|
onError
|
|
537
590
|
}) => {
|
|
591
|
+
const requestHeaders = {
|
|
592
|
+
...createModeDefaultHeaders(mode),
|
|
593
|
+
...resolvedStreamHeaders
|
|
594
|
+
};
|
|
538
595
|
await startChatStream({
|
|
539
596
|
apiBaseUrl,
|
|
540
597
|
endpointPath: resolvedEndpoints.completions,
|
|
541
598
|
sessionId,
|
|
542
599
|
authToken,
|
|
543
|
-
requestHeaders
|
|
600
|
+
requestHeaders,
|
|
544
601
|
model,
|
|
545
602
|
mode,
|
|
546
603
|
content,
|
|
@@ -569,6 +626,8 @@ var AiChatProvider = (props) => {
|
|
|
569
626
|
defaultMode,
|
|
570
627
|
labels,
|
|
571
628
|
renderMessageBlock,
|
|
629
|
+
handleQuestionnaireSubmit,
|
|
630
|
+
handleConfirmationSubmit,
|
|
572
631
|
messageRenderOrder,
|
|
573
632
|
enableImageAttachments = true,
|
|
574
633
|
children
|
|
@@ -624,6 +683,8 @@ var AiChatProvider = (props) => {
|
|
|
624
683
|
sendRef,
|
|
625
684
|
retryRef,
|
|
626
685
|
renderMessageBlock,
|
|
686
|
+
handleQuestionnaireSubmit,
|
|
687
|
+
handleConfirmationSubmit,
|
|
627
688
|
messageRenderOrder,
|
|
628
689
|
transformStreamPacket: defaultTransformStreamPacket,
|
|
629
690
|
enableImageAttachments
|
|
@@ -634,6 +695,8 @@ var AiChatProvider = (props) => {
|
|
|
634
695
|
defaultAuthToken,
|
|
635
696
|
defaultTransformStreamPacket,
|
|
636
697
|
enableImageAttachments,
|
|
698
|
+
handleConfirmationSubmit,
|
|
699
|
+
handleQuestionnaireSubmit,
|
|
637
700
|
labels,
|
|
638
701
|
messageRenderOrder,
|
|
639
702
|
renderMessageBlock,
|
|
@@ -943,7 +1006,7 @@ var getTimelineBlockKey = (block, index) => {
|
|
|
943
1006
|
case "confirmation_card":
|
|
944
1007
|
return `${index}:confirmation_card:${block.proposal.proposalId}`;
|
|
945
1008
|
case "result_summary":
|
|
946
|
-
return `${index}:result_summary:${block.summary.
|
|
1009
|
+
return `${index}:result_summary:${block.summary.summaryId}:${block.summary.status}`;
|
|
947
1010
|
case "questionnaire":
|
|
948
1011
|
return `${index}:questionnaire:${block.questionnaire.questionnaireId}`;
|
|
949
1012
|
case "custom":
|
|
@@ -1235,21 +1298,21 @@ var useTimelineBlockAnchors = ({
|
|
|
1235
1298
|
};
|
|
1236
1299
|
};
|
|
1237
1300
|
|
|
1238
|
-
// src/components/chat-thread/components/
|
|
1301
|
+
// src/components/chat-thread/components/execution-confirmation-card.tsx
|
|
1239
1302
|
var import_styled = __toESM(require("@emotion/styled"));
|
|
1240
1303
|
var import_jsx_runtime2 = require("@emotion/react/jsx-runtime");
|
|
1241
|
-
var
|
|
1304
|
+
var ExecutionConfirmationCard = ({
|
|
1242
1305
|
proposal,
|
|
1243
1306
|
interactive = false,
|
|
1244
1307
|
onApply,
|
|
1245
1308
|
onConfirm,
|
|
1246
1309
|
onRevise
|
|
1247
1310
|
}) => {
|
|
1248
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Card, { "data-testid": "
|
|
1311
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Card, { "data-testid": "execution-confirmation-card", children: [
|
|
1249
1312
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Header, { children: [
|
|
1250
1313
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Eyebrow, { children: "Execution Proposal" }),
|
|
1251
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Title, { children: proposal.
|
|
1252
|
-
proposal.
|
|
1314
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Title, { children: proposal.resourceName }),
|
|
1315
|
+
proposal.executorName ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Subtitle, { children: proposal.executorName }) : null
|
|
1253
1316
|
] }),
|
|
1254
1317
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SummaryList, { children: proposal.parameterSummary.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(SummaryItem, { children: [
|
|
1255
1318
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SummaryLabel, { children: item.label }),
|
|
@@ -1257,21 +1320,13 @@ var PDEAIExecutionConfirmationCard = ({
|
|
|
1257
1320
|
] }, `${item.fieldPath ?? item.label}-${item.value}`)) }),
|
|
1258
1321
|
proposal.warnings?.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Warnings, { children: proposal.warnings.map((warning) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Warning, { children: warning }, warning)) }) : null,
|
|
1259
1322
|
interactive ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Actions, { children: [
|
|
1260
|
-
onApply && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ActionButton, { type: "button", "data-testid": "
|
|
1261
|
-
onConfirm && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1262
|
-
ActionButton,
|
|
1263
|
-
{
|
|
1264
|
-
type: "button",
|
|
1265
|
-
"data-testid": "pde-ai-confirmation-confirm",
|
|
1266
|
-
onClick: onConfirm,
|
|
1267
|
-
children: "Confirm Execution"
|
|
1268
|
-
}
|
|
1269
|
-
),
|
|
1323
|
+
onApply && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ActionButton, { type: "button", "data-testid": "confirmation-apply", onClick: onApply, children: "Apply to Parameters" }),
|
|
1324
|
+
onConfirm && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ActionButton, { type: "button", "data-testid": "confirmation-confirm", onClick: onConfirm, children: "Confirm Execution" }),
|
|
1270
1325
|
onRevise && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1271
1326
|
SecondaryActionButton,
|
|
1272
1327
|
{
|
|
1273
1328
|
type: "button",
|
|
1274
|
-
"data-testid": "
|
|
1329
|
+
"data-testid": "confirmation-revise",
|
|
1275
1330
|
onClick: onRevise,
|
|
1276
1331
|
children: "Revise Plan"
|
|
1277
1332
|
}
|
|
@@ -1368,10 +1423,10 @@ var SecondaryActionButton = (0, import_styled.default)(ActionButton)`
|
|
|
1368
1423
|
border: 1px solid rgba(255, 255, 255, 0.14);
|
|
1369
1424
|
`;
|
|
1370
1425
|
|
|
1371
|
-
// src/components/chat-thread/components/
|
|
1426
|
+
// src/components/chat-thread/components/notice-card.tsx
|
|
1372
1427
|
var import_styled2 = __toESM(require("@emotion/styled"));
|
|
1373
1428
|
var import_jsx_runtime3 = require("@emotion/react/jsx-runtime");
|
|
1374
|
-
var
|
|
1429
|
+
var NoticeCard = ({ text, tone }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Card2, { "data-testid": "notice-card", "data-tone": tone, children: text });
|
|
1375
1430
|
var Card2 = import_styled2.default.div`
|
|
1376
1431
|
padding: 12px 14px;
|
|
1377
1432
|
border-radius: 16px;
|
|
@@ -1397,10 +1452,10 @@ var Card2 = import_styled2.default.div`
|
|
|
1397
1452
|
}
|
|
1398
1453
|
`;
|
|
1399
1454
|
|
|
1400
|
-
// src/components/chat-thread/components/
|
|
1455
|
+
// src/components/chat-thread/components/parameter-summary-card.tsx
|
|
1401
1456
|
var import_styled3 = __toESM(require("@emotion/styled"));
|
|
1402
1457
|
var import_jsx_runtime4 = require("@emotion/react/jsx-runtime");
|
|
1403
|
-
var
|
|
1458
|
+
var ParameterSummaryCard = ({ items }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Card3, { "data-testid": "parameter-summary-card", children: [
|
|
1404
1459
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Title2, { children: "Parameter Summary" }),
|
|
1405
1460
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(List, { children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(ListItem, { children: [
|
|
1406
1461
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Label, { children: item.label }),
|
|
@@ -1444,11 +1499,17 @@ var Value = import_styled3.default.span`
|
|
|
1444
1499
|
text-align: right;
|
|
1445
1500
|
`;
|
|
1446
1501
|
|
|
1447
|
-
// src/components/chat-thread/components/
|
|
1502
|
+
// src/components/chat-thread/components/questionnaire-card.tsx
|
|
1448
1503
|
var import_react7 = require("react");
|
|
1449
1504
|
var import_styled4 = __toESM(require("@emotion/styled"));
|
|
1450
1505
|
var import_jsx_runtime5 = require("@emotion/react/jsx-runtime");
|
|
1451
1506
|
var OTHER_OPTION_VALUE = "__other__";
|
|
1507
|
+
var DEFAULT_QUESTIONNAIRE_CARD_LABELS = {
|
|
1508
|
+
submitting: "Submitting...",
|
|
1509
|
+
submitted: "Selection submitted. Waiting for the plan to continue...",
|
|
1510
|
+
validationPrefix: "Please complete:",
|
|
1511
|
+
submitFailed: "Failed to submit. Please try again."
|
|
1512
|
+
};
|
|
1452
1513
|
var createInitialAnswers = (questionnaire) => ({
|
|
1453
1514
|
...questionnaire.answers ?? {}
|
|
1454
1515
|
});
|
|
@@ -1542,26 +1603,40 @@ var normalizeQuestionAnswer = (question, answer) => {
|
|
|
1542
1603
|
return answer;
|
|
1543
1604
|
}
|
|
1544
1605
|
};
|
|
1545
|
-
var
|
|
1606
|
+
var QuestionnaireCardInner = ({
|
|
1546
1607
|
questionnaire,
|
|
1547
1608
|
interactive = false,
|
|
1548
|
-
onSubmit
|
|
1609
|
+
onSubmit,
|
|
1610
|
+
labels
|
|
1549
1611
|
}) => {
|
|
1550
1612
|
const [answers, setAnswers] = (0, import_react7.useState)(
|
|
1551
1613
|
() => createInitialAnswers(questionnaire)
|
|
1552
1614
|
);
|
|
1553
1615
|
const [errorMessage, setErrorMessage] = (0, import_react7.useState)(null);
|
|
1554
|
-
const
|
|
1616
|
+
const [isSubmitting, setIsSubmitting] = (0, import_react7.useState)(false);
|
|
1617
|
+
const [isSubmitted, setIsSubmitted] = (0, import_react7.useState)(false);
|
|
1618
|
+
const resolvedLabels = {
|
|
1619
|
+
...DEFAULT_QUESTIONNAIRE_CARD_LABELS,
|
|
1620
|
+
...labels
|
|
1621
|
+
};
|
|
1622
|
+
const hasExternalFailureStatus = questionnaire.status === "expired" || questionnaire.status === "failed";
|
|
1623
|
+
const visibleErrorMessage = questionnaire.statusMessage ?? errorMessage;
|
|
1624
|
+
const isInteractionLocked = !interactive || isSubmitting || isSubmitted || hasExternalFailureStatus;
|
|
1625
|
+
const handleSubmit = async () => {
|
|
1626
|
+
if (isSubmitting || isSubmitted) {
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1555
1629
|
const missingQuestions = questionnaire.questions.filter(
|
|
1556
1630
|
(question) => question.required && isMissingRequiredAnswer(question, answers)
|
|
1557
1631
|
);
|
|
1558
1632
|
if (missingQuestions.length > 0) {
|
|
1559
1633
|
setErrorMessage(
|
|
1560
|
-
|
|
1634
|
+
`${resolvedLabels.validationPrefix} ${missingQuestions.map((question) => question.label).join(", ")}`
|
|
1561
1635
|
);
|
|
1562
1636
|
return;
|
|
1563
1637
|
}
|
|
1564
1638
|
setErrorMessage(null);
|
|
1639
|
+
setIsSubmitting(true);
|
|
1565
1640
|
const normalizedAnswers = Object.fromEntries(
|
|
1566
1641
|
questionnaire.questions.flatMap((question) => {
|
|
1567
1642
|
const value = normalizeQuestionAnswer(question, answers[question.id]);
|
|
@@ -1578,11 +1653,18 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1578
1653
|
return [`- ${question.label}: ${formatQuestionAnswer(question, value)}`];
|
|
1579
1654
|
})
|
|
1580
1655
|
];
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1656
|
+
try {
|
|
1657
|
+
await onSubmit?.({
|
|
1658
|
+
questionnaireId: questionnaire.questionnaireId,
|
|
1659
|
+
answers: normalizedAnswers,
|
|
1660
|
+
content: contentLines.join("\n")
|
|
1661
|
+
});
|
|
1662
|
+
setIsSubmitted(true);
|
|
1663
|
+
} catch (error) {
|
|
1664
|
+
setErrorMessage(error instanceof Error ? error.message : resolvedLabels.submitFailed);
|
|
1665
|
+
} finally {
|
|
1666
|
+
setIsSubmitting(false);
|
|
1667
|
+
}
|
|
1586
1668
|
};
|
|
1587
1669
|
const renderQuestion = (question) => {
|
|
1588
1670
|
const renderOptionChoice = ({
|
|
@@ -1597,13 +1679,13 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1597
1679
|
OptionChoiceItem,
|
|
1598
1680
|
{
|
|
1599
1681
|
role: "button",
|
|
1600
|
-
tabIndex:
|
|
1682
|
+
tabIndex: isInteractionLocked ? -1 : 0,
|
|
1601
1683
|
"aria-pressed": isSelected,
|
|
1602
1684
|
"data-selected": isSelected,
|
|
1603
1685
|
"data-tone": tone,
|
|
1604
|
-
"data-testid": `
|
|
1686
|
+
"data-testid": `question-option-${questionId}-${index}`,
|
|
1605
1687
|
onClick: (event) => {
|
|
1606
|
-
if (
|
|
1688
|
+
if (isInteractionLocked) {
|
|
1607
1689
|
return;
|
|
1608
1690
|
}
|
|
1609
1691
|
if (event.target instanceof HTMLElement && event.target.closest("input")) {
|
|
@@ -1612,7 +1694,7 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1612
1694
|
onClick();
|
|
1613
1695
|
},
|
|
1614
1696
|
onKeyDown: (event) => {
|
|
1615
|
-
if (
|
|
1697
|
+
if (isInteractionLocked) {
|
|
1616
1698
|
return;
|
|
1617
1699
|
}
|
|
1618
1700
|
if (event.key !== "Enter" && event.key !== " ") {
|
|
@@ -1671,11 +1753,11 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1671
1753
|
inlineInput: singleSelectDraft.selectedValue === OTHER_OPTION_VALUE ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1672
1754
|
InlineOtherInput,
|
|
1673
1755
|
{
|
|
1674
|
-
"data-testid": `
|
|
1756
|
+
"data-testid": `question-input-${question.id}`,
|
|
1675
1757
|
type: "text",
|
|
1676
1758
|
value: singleSelectDraft.otherValue,
|
|
1677
1759
|
placeholder: "Other",
|
|
1678
|
-
readOnly:
|
|
1760
|
+
readOnly: isInteractionLocked,
|
|
1679
1761
|
onClick: (event) => {
|
|
1680
1762
|
event.stopPropagation();
|
|
1681
1763
|
},
|
|
@@ -1696,11 +1778,11 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1696
1778
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionBody, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1697
1779
|
TextInput,
|
|
1698
1780
|
{
|
|
1699
|
-
"data-testid": `
|
|
1781
|
+
"data-testid": `question-input-${question.id}`,
|
|
1700
1782
|
type: "text",
|
|
1701
1783
|
value: getTextInputValue(answers[question.id]),
|
|
1702
1784
|
placeholder: question.placeholder,
|
|
1703
|
-
readOnly:
|
|
1785
|
+
readOnly: isInteractionLocked,
|
|
1704
1786
|
onChange: (event) => {
|
|
1705
1787
|
setAnswers((current) => updateAnswerValue(current, question.id, event.target.value));
|
|
1706
1788
|
}
|
|
@@ -1711,11 +1793,11 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1711
1793
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1712
1794
|
TextInput,
|
|
1713
1795
|
{
|
|
1714
|
-
"data-testid": `
|
|
1796
|
+
"data-testid": `question-input-${question.id}`,
|
|
1715
1797
|
type: "number",
|
|
1716
1798
|
value: getNumberInputValue(answers[question.id]),
|
|
1717
1799
|
placeholder: question.placeholder,
|
|
1718
|
-
readOnly:
|
|
1800
|
+
readOnly: isInteractionLocked,
|
|
1719
1801
|
onChange: (event) => {
|
|
1720
1802
|
setAnswers(
|
|
1721
1803
|
(current) => updateAnswerValue(
|
|
@@ -1750,7 +1832,7 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1750
1832
|
return null;
|
|
1751
1833
|
}
|
|
1752
1834
|
};
|
|
1753
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Card4, { "data-testid": "
|
|
1835
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Card4, { "data-testid": "questionnaire-card", children: [
|
|
1754
1836
|
questionnaire.title ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Title3, { children: questionnaire.title }) : null,
|
|
1755
1837
|
questionnaire.description ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Description, { children: questionnaire.description }) : null,
|
|
1756
1838
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionList, { children: questionnaire.questions.map((question) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(QuestionCard, { children: [
|
|
@@ -1760,24 +1842,28 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1760
1842
|
] }),
|
|
1761
1843
|
renderQuestion(question)
|
|
1762
1844
|
] }, question.id)) }),
|
|
1763
|
-
|
|
1764
|
-
interactive ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1845
|
+
visibleErrorMessage ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ErrorMessage, { "data-testid": "questionnaire-error", children: visibleErrorMessage }) : null,
|
|
1846
|
+
isSubmitted ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SuccessMessage, { "data-testid": "questionnaire-success", children: resolvedLabels.submitted }) : interactive && !hasExternalFailureStatus ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1765
1847
|
SubmitButton,
|
|
1766
1848
|
{
|
|
1767
1849
|
type: "button",
|
|
1768
|
-
"data-testid": "
|
|
1769
|
-
|
|
1770
|
-
|
|
1850
|
+
"data-testid": "questionnaire-submit",
|
|
1851
|
+
disabled: isInteractionLocked,
|
|
1852
|
+
onClick: () => {
|
|
1853
|
+
void handleSubmit();
|
|
1854
|
+
},
|
|
1855
|
+
children: isSubmitting ? resolvedLabels.submitting : questionnaire.submitLabel ?? "Submit"
|
|
1771
1856
|
}
|
|
1772
1857
|
) : null
|
|
1773
1858
|
] });
|
|
1774
1859
|
};
|
|
1775
1860
|
var getQuestionnaireStateKey = (questionnaire) => JSON.stringify([
|
|
1776
1861
|
questionnaire.questionnaireId,
|
|
1777
|
-
questionnaire.
|
|
1778
|
-
questionnaire.
|
|
1862
|
+
questionnaire.questions,
|
|
1863
|
+
questionnaire.status,
|
|
1864
|
+
questionnaire.statusMessage
|
|
1779
1865
|
]);
|
|
1780
|
-
var
|
|
1866
|
+
var QuestionnaireCard = (props) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionnaireCardInner, { ...props }, getQuestionnaireStateKey(props.questionnaire));
|
|
1781
1867
|
var Card4 = import_styled4.default.section`
|
|
1782
1868
|
display: grid;
|
|
1783
1869
|
gap: 14px;
|
|
@@ -1925,6 +2011,10 @@ var ErrorMessage = import_styled4.default.div`
|
|
|
1925
2011
|
color: rgba(255, 145, 145, 0.96);
|
|
1926
2012
|
font-size: 12px;
|
|
1927
2013
|
`;
|
|
2014
|
+
var SuccessMessage = import_styled4.default.div`
|
|
2015
|
+
color: rgba(164, 255, 210, 0.96);
|
|
2016
|
+
font-size: 12px;
|
|
2017
|
+
`;
|
|
1928
2018
|
var SubmitButton = import_styled4.default.button`
|
|
1929
2019
|
justify-self: flex-start;
|
|
1930
2020
|
border: none;
|
|
@@ -1935,12 +2025,17 @@ var SubmitButton = import_styled4.default.button`
|
|
|
1935
2025
|
font-weight: 700;
|
|
1936
2026
|
padding: 10px 14px;
|
|
1937
2027
|
cursor: pointer;
|
|
2028
|
+
|
|
2029
|
+
&:disabled {
|
|
2030
|
+
cursor: default;
|
|
2031
|
+
opacity: 0.72;
|
|
2032
|
+
}
|
|
1938
2033
|
`;
|
|
1939
2034
|
|
|
1940
|
-
// src/components/chat-thread/components/
|
|
2035
|
+
// src/components/chat-thread/components/result-summary-card.tsx
|
|
1941
2036
|
var import_styled5 = __toESM(require("@emotion/styled"));
|
|
1942
2037
|
var import_jsx_runtime6 = require("@emotion/react/jsx-runtime");
|
|
1943
|
-
var
|
|
2038
|
+
var ResultSummaryCard = ({ summary }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Card5, { "data-testid": "result-summary-card", "data-status": summary.status, children: [
|
|
1944
2039
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Eyebrow2, { children: summary.status }),
|
|
1945
2040
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Headline, { children: summary.headline }),
|
|
1946
2041
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Details, { children: summary.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Detail, { children: detail }, detail)) })
|
|
@@ -2036,6 +2131,7 @@ var ImageViewer = ({ src, alt, onClose }) => {
|
|
|
2036
2131
|
var import_jsx_runtime8 = require("@emotion/react/jsx-runtime");
|
|
2037
2132
|
var MARKDOWN_REMARK_PLUGINS = [import_remark_gfm.default, import_remark_math.default];
|
|
2038
2133
|
var MARKDOWN_REHYPE_PLUGINS = [import_rehype_katex.default];
|
|
2134
|
+
var USER_MESSAGE_COLLAPSE_HEIGHT_PX = 120;
|
|
2039
2135
|
var MARKDOWN_COMPONENTS = {
|
|
2040
2136
|
table: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TableWrapper, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("table", { ...props }) })
|
|
2041
2137
|
};
|
|
@@ -2048,10 +2144,101 @@ var renderMarkdownContent = (content) => /* @__PURE__ */ (0, import_jsx_runtime8
|
|
|
2048
2144
|
children: content
|
|
2049
2145
|
}
|
|
2050
2146
|
);
|
|
2147
|
+
var renderPlainTextContent = (content) => content;
|
|
2148
|
+
var CollapseIcon = ({ expanded }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2149
|
+
"svg",
|
|
2150
|
+
{
|
|
2151
|
+
"aria-hidden": "true",
|
|
2152
|
+
width: "16",
|
|
2153
|
+
height: "16",
|
|
2154
|
+
viewBox: "0 0 16 16",
|
|
2155
|
+
fill: "none",
|
|
2156
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2157
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2158
|
+
"path",
|
|
2159
|
+
{
|
|
2160
|
+
d: "M4 6l4 4 4-4",
|
|
2161
|
+
stroke: "currentColor",
|
|
2162
|
+
strokeWidth: "1.6",
|
|
2163
|
+
strokeLinecap: "round",
|
|
2164
|
+
strokeLinejoin: "round",
|
|
2165
|
+
transform: expanded ? "rotate(180 8 8)" : void 0
|
|
2166
|
+
}
|
|
2167
|
+
)
|
|
2168
|
+
}
|
|
2169
|
+
);
|
|
2170
|
+
var useUserMessageCollapse = ({
|
|
2171
|
+
blocks,
|
|
2172
|
+
displayedBlocks,
|
|
2173
|
+
displayedContent,
|
|
2174
|
+
enabled,
|
|
2175
|
+
freshContent,
|
|
2176
|
+
settledContent
|
|
2177
|
+
}) => {
|
|
2178
|
+
const [isCollapsible, setIsCollapsible] = (0, import_react9.useState)(false);
|
|
2179
|
+
const [isExpanded, setIsExpanded] = (0, import_react9.useState)(false);
|
|
2180
|
+
const [bodyStackElement, setBodyStackElement] = (0, import_react9.useState)(null);
|
|
2181
|
+
const syncCollapseState = (0, import_react9.useCallback)(
|
|
2182
|
+
(element) => {
|
|
2183
|
+
const nextCollapsible = enabled && (element?.scrollHeight ?? 0) > USER_MESSAGE_COLLAPSE_HEIGHT_PX;
|
|
2184
|
+
setIsCollapsible(nextCollapsible);
|
|
2185
|
+
if (!nextCollapsible) {
|
|
2186
|
+
setIsExpanded(false);
|
|
2187
|
+
}
|
|
2188
|
+
},
|
|
2189
|
+
[enabled]
|
|
2190
|
+
);
|
|
2191
|
+
const bodyStackRef = (0, import_react9.useCallback)(
|
|
2192
|
+
(node) => {
|
|
2193
|
+
setBodyStackElement(node);
|
|
2194
|
+
syncCollapseState(node);
|
|
2195
|
+
},
|
|
2196
|
+
[syncCollapseState]
|
|
2197
|
+
);
|
|
2198
|
+
(0, import_react9.useLayoutEffect)(() => {
|
|
2199
|
+
if (!bodyStackElement) {
|
|
2200
|
+
return;
|
|
2201
|
+
}
|
|
2202
|
+
const frameId = requestAnimationFrame(() => {
|
|
2203
|
+
syncCollapseState(bodyStackElement);
|
|
2204
|
+
});
|
|
2205
|
+
return () => {
|
|
2206
|
+
cancelAnimationFrame(frameId);
|
|
2207
|
+
};
|
|
2208
|
+
}, [
|
|
2209
|
+
blocks,
|
|
2210
|
+
bodyStackElement,
|
|
2211
|
+
displayedBlocks,
|
|
2212
|
+
displayedContent,
|
|
2213
|
+
enabled,
|
|
2214
|
+
freshContent,
|
|
2215
|
+
settledContent,
|
|
2216
|
+
syncCollapseState
|
|
2217
|
+
]);
|
|
2218
|
+
(0, import_react9.useLayoutEffect)(() => {
|
|
2219
|
+
if (!bodyStackElement || !enabled || typeof ResizeObserver === "undefined") {
|
|
2220
|
+
return;
|
|
2221
|
+
}
|
|
2222
|
+
const observer = new ResizeObserver(() => {
|
|
2223
|
+
syncCollapseState(bodyStackElement);
|
|
2224
|
+
});
|
|
2225
|
+
observer.observe(bodyStackElement);
|
|
2226
|
+
return () => {
|
|
2227
|
+
observer.disconnect();
|
|
2228
|
+
};
|
|
2229
|
+
}, [bodyStackElement, enabled, syncCollapseState]);
|
|
2230
|
+
return {
|
|
2231
|
+
bodyStackRef,
|
|
2232
|
+
isCollapsed: isCollapsible && !isExpanded,
|
|
2233
|
+
isCollapsible,
|
|
2234
|
+
isExpanded,
|
|
2235
|
+
toggleExpanded: () => setIsExpanded((current) => !current)
|
|
2236
|
+
};
|
|
2237
|
+
};
|
|
2051
2238
|
var createExecutionConfirmationContent = (proposal) => [
|
|
2052
2239
|
"Execution confirmed",
|
|
2053
|
-
`- Equation: ${proposal.
|
|
2054
|
-
...proposal.
|
|
2240
|
+
`- Equation: ${proposal.resourceName}`,
|
|
2241
|
+
...proposal.executorName ? [`- Solver: ${proposal.executorName}`] : [],
|
|
2055
2242
|
`- Proposal ID: ${proposal.proposalId}`
|
|
2056
2243
|
].join("\n");
|
|
2057
2244
|
var areChatAttachmentsEqual = (previousAttachments, nextAttachments) => {
|
|
@@ -2073,10 +2260,10 @@ var areParameterSummaryItemsEqual = (previousItems, nextItems) => previousItems.
|
|
|
2073
2260
|
const nextItem = nextItems[index];
|
|
2074
2261
|
return item.label === nextItem?.label && item.value === nextItem.value && item.fieldPath === nextItem.fieldPath;
|
|
2075
2262
|
});
|
|
2076
|
-
var areExecutionProposalsEqual = (previousProposal, nextProposal) => previousProposal.proposalId === nextProposal.proposalId && previousProposal.
|
|
2263
|
+
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(
|
|
2077
2264
|
(warning, index) => warning === nextProposal.warnings?.[index]
|
|
2078
2265
|
);
|
|
2079
|
-
var areResultSummariesEqual = (previousSummary, nextSummary) => previousSummary.
|
|
2266
|
+
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]);
|
|
2080
2267
|
var areStringArraysEqual = (previousValues, nextValues) => previousValues.length === nextValues.length && previousValues.every((value, index) => value === nextValues[index]);
|
|
2081
2268
|
var areQuestionAnswersEqual = (previousAnswer, nextAnswer) => {
|
|
2082
2269
|
if (Array.isArray(previousAnswer) || Array.isArray(nextAnswer)) {
|
|
@@ -2117,7 +2304,7 @@ var arePlanQuestionsEqual = (previousQuestion, nextQuestion) => {
|
|
|
2117
2304
|
return false;
|
|
2118
2305
|
}
|
|
2119
2306
|
};
|
|
2120
|
-
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(
|
|
2307
|
+
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(
|
|
2121
2308
|
(question, index) => arePlanQuestionsEqual(question, nextQuestionnaire.questions[index])
|
|
2122
2309
|
) && areQuestionAnswerMapsEqual(previousQuestionnaire.answers, nextQuestionnaire.answers);
|
|
2123
2310
|
var areMessageBlocksEqual = (previousBlocks, nextBlocks) => {
|
|
@@ -2198,6 +2385,8 @@ var ChatMessageItemView = ({
|
|
|
2198
2385
|
const canSubmitConfirmation = isPlanMode && typeof onConfirmationSubmit === "function";
|
|
2199
2386
|
const canSubmitQuestionnaire = isPlanMode && typeof onQuestionnaireSubmit === "function";
|
|
2200
2387
|
const shouldShowStreamingCaret = isAssistantStreaming && (!shouldRenderStructuredBlocks || hasTextContent);
|
|
2388
|
+
const isUserMessage = message.role === "user";
|
|
2389
|
+
const messageRenderMode = isUserMessage ? "plain-text" : "markdown";
|
|
2201
2390
|
const timelineConsumedText = messageRenderOrder === "timeline" ? getTimelineConsumedText(blocks) : "";
|
|
2202
2391
|
const hasConsumedTimelineText = timelineConsumedText.length > 0 && displayedContent.startsWith(timelineConsumedText);
|
|
2203
2392
|
const timelineDisplayedContent = hasConsumedTimelineText ? displayedContent.slice(timelineConsumedText.length) : displayedContent;
|
|
@@ -2214,6 +2403,21 @@ var ChatMessageItemView = ({
|
|
|
2214
2403
|
message,
|
|
2215
2404
|
messageRenderOrder
|
|
2216
2405
|
});
|
|
2406
|
+
const {
|
|
2407
|
+
bodyStackRef,
|
|
2408
|
+
isCollapsed: isUserMessageCollapsed,
|
|
2409
|
+
isCollapsible: isUserMessageCollapsible,
|
|
2410
|
+
isExpanded: isUserMessageExpanded,
|
|
2411
|
+
toggleExpanded: toggleUserMessageExpanded
|
|
2412
|
+
} = useUserMessageCollapse({
|
|
2413
|
+
blocks,
|
|
2414
|
+
displayedBlocks,
|
|
2415
|
+
displayedContent,
|
|
2416
|
+
enabled: isUserMessage,
|
|
2417
|
+
freshContent,
|
|
2418
|
+
settledContent
|
|
2419
|
+
});
|
|
2420
|
+
const renderMessageContent = (content) => messageRenderMode === "plain-text" ? renderPlainTextContent(content) : renderMarkdownContent(content);
|
|
2217
2421
|
const renderChatMessageBlock = (block, index) => {
|
|
2218
2422
|
switch (block.type) {
|
|
2219
2423
|
case "markdown":
|
|
@@ -2222,17 +2426,18 @@ var ChatMessageItemView = ({
|
|
|
2222
2426
|
{
|
|
2223
2427
|
"data-testid": `chat-message-block-${index}`,
|
|
2224
2428
|
"data-block-tone": "settled",
|
|
2225
|
-
|
|
2429
|
+
"data-render-mode": messageRenderMode,
|
|
2430
|
+
children: renderMessageContent(block.text)
|
|
2226
2431
|
},
|
|
2227
2432
|
`markdown-${index}`
|
|
2228
2433
|
);
|
|
2229
2434
|
case "notice":
|
|
2230
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2435
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(NoticeCard, { text: block.text, tone: block.tone }) }, `notice-${index}`);
|
|
2231
2436
|
case "parameter_summary":
|
|
2232
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2437
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ParameterSummaryCard, { items: block.items }) }, `parameter-summary-${index}`);
|
|
2233
2438
|
case "confirmation_card":
|
|
2234
2439
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2235
|
-
|
|
2440
|
+
ExecutionConfirmationCard,
|
|
2236
2441
|
{
|
|
2237
2442
|
proposal: block.proposal,
|
|
2238
2443
|
interactive: isPlanMode,
|
|
@@ -2244,13 +2449,19 @@ var ChatMessageItemView = ({
|
|
|
2244
2449
|
}
|
|
2245
2450
|
) }, `confirmation-card-${index}`);
|
|
2246
2451
|
case "result_summary":
|
|
2247
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2452
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ResultSummaryCard, { summary: block.summary }) }, `result-summary-${index}`);
|
|
2248
2453
|
case "questionnaire":
|
|
2249
2454
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2250
|
-
|
|
2455
|
+
QuestionnaireCard,
|
|
2251
2456
|
{
|
|
2252
2457
|
questionnaire: block.questionnaire,
|
|
2253
2458
|
interactive: canSubmitQuestionnaire,
|
|
2459
|
+
labels: {
|
|
2460
|
+
submitting: labels.questionnaireSubmitting,
|
|
2461
|
+
submitted: labels.questionnaireSubmitted,
|
|
2462
|
+
validationPrefix: labels.questionnaireValidationPrefix,
|
|
2463
|
+
submitFailed: labels.questionnaireSubmitFailed
|
|
2464
|
+
},
|
|
2254
2465
|
onSubmit: canSubmitQuestionnaire ? (submission) => onQuestionnaireSubmit({
|
|
2255
2466
|
...submission,
|
|
2256
2467
|
sourceMessageId: message.id
|
|
@@ -2283,14 +2494,31 @@ var ChatMessageItemView = ({
|
|
|
2283
2494
|
"data-testid": block.tone === "fresh" ? "chat-message-fresh-block" : "chat-message-settled-block",
|
|
2284
2495
|
"data-block-tone": block.tone,
|
|
2285
2496
|
"data-block-index": index,
|
|
2286
|
-
|
|
2497
|
+
"data-render-mode": messageRenderMode,
|
|
2498
|
+
children: renderMessageContent(block.content)
|
|
2287
2499
|
},
|
|
2288
2500
|
`${block.tone}-${index}`
|
|
2289
2501
|
)),
|
|
2290
|
-
!textBlocks.some((block) => block.content) && !settledText && !freshText && Boolean(textContent) ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2502
|
+
!textBlocks.some((block) => block.content) && !settledText && !freshText && Boolean(textContent) ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2503
|
+
ContentBlock,
|
|
2504
|
+
{
|
|
2505
|
+
"data-testid": "chat-message-settled-block",
|
|
2506
|
+
"data-block-tone": "settled",
|
|
2507
|
+
"data-render-mode": messageRenderMode,
|
|
2508
|
+
children: renderMessageContent(textContent)
|
|
2509
|
+
}
|
|
2510
|
+
) : null
|
|
2291
2511
|
] });
|
|
2292
2512
|
};
|
|
2293
|
-
const renderStaticTextSegment = (content) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2513
|
+
const renderStaticTextSegment = (content) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2514
|
+
ContentBlock,
|
|
2515
|
+
{
|
|
2516
|
+
"data-testid": "chat-message-settled-block",
|
|
2517
|
+
"data-block-tone": "settled",
|
|
2518
|
+
"data-render-mode": messageRenderMode,
|
|
2519
|
+
children: renderMessageContent(content)
|
|
2520
|
+
}
|
|
2521
|
+
);
|
|
2294
2522
|
const bodySegments = (() => {
|
|
2295
2523
|
if (!shouldRenderStructuredBlocks && hasTextContent) {
|
|
2296
2524
|
return [{ type: "text" }];
|
|
@@ -2348,21 +2576,40 @@ var ChatMessageItemView = ({
|
|
|
2348
2576
|
}
|
|
2349
2577
|
) : null,
|
|
2350
2578
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Role, { children: message.role === "user" ? labels.userRoleLabel : labels.assistantRoleLabel }),
|
|
2579
|
+
isUserMessageCollapsible ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2580
|
+
CollapseToggle,
|
|
2581
|
+
{
|
|
2582
|
+
type: "button",
|
|
2583
|
+
"data-testid": "chat-message-collapse-toggle",
|
|
2584
|
+
"aria-label": isUserMessageExpanded ? labels.collapseMessageAriaLabel : labels.expandMessageAriaLabel,
|
|
2585
|
+
"aria-expanded": isUserMessageExpanded,
|
|
2586
|
+
onClick: toggleUserMessageExpanded,
|
|
2587
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CollapseIcon, { expanded: isUserMessageExpanded })
|
|
2588
|
+
}
|
|
2589
|
+
) : null,
|
|
2351
2590
|
isStoppedAssistant ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StatusTag, { "data-testid": "chat-message-stopped-tag", children: labels.stoppedResponse }) : null
|
|
2352
2591
|
] }),
|
|
2353
2592
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Content, { "data-testid": "chat-message-content", children: [
|
|
2354
|
-
shouldRenderStructuredBlocks || hasTextContent ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2355
|
-
|
|
2593
|
+
shouldRenderStructuredBlocks || hasTextContent ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2594
|
+
ContentStack,
|
|
2356
2595
|
{
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2596
|
+
ref: bodyStackRef,
|
|
2597
|
+
"data-testid": "chat-message-body-stack",
|
|
2598
|
+
"data-collapsed": isUserMessageCollapsed,
|
|
2599
|
+
children: bodySegments.map((segment, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2600
|
+
ContentSegment,
|
|
2601
|
+
{
|
|
2602
|
+
"data-testid": "chat-message-content-segment",
|
|
2603
|
+
children: segment.type === "block" ? renderChatMessageBlock(segment.block, segment.index) : segment.type === "text" ? segment.content !== void 0 ? segment.useTimelineSegmentation ? renderTextContent({
|
|
2604
|
+
content: segment.content,
|
|
2605
|
+
displayedBlocks: segment.displayedBlocks,
|
|
2606
|
+
useTimelineSegmentation: true
|
|
2607
|
+
}) : renderStaticTextSegment(segment.content) : renderTextContent() : renderStaticTextSegment(segment.content)
|
|
2608
|
+
},
|
|
2609
|
+
segment.type === "text" ? `text-${index}` : segment.type === "markdown" ? `markdown-${index}` : `${segment.block.type}-${segment.index}`
|
|
2610
|
+
))
|
|
2611
|
+
}
|
|
2612
|
+
) : null,
|
|
2366
2613
|
attachments.length ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AttachmentGrid, { "data-testid": "chat-message-attachment-grid", children: attachments.map((attachment) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2367
2614
|
AttachmentButton,
|
|
2368
2615
|
{
|
|
@@ -2447,6 +2694,29 @@ var StatusTag = import_styled7.default.span`
|
|
|
2447
2694
|
letter-spacing: 0.02em;
|
|
2448
2695
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
|
|
2449
2696
|
`;
|
|
2697
|
+
var CollapseToggle = import_styled7.default.button`
|
|
2698
|
+
margin-left: auto;
|
|
2699
|
+
width: 28px;
|
|
2700
|
+
height: 28px;
|
|
2701
|
+
display: inline-flex;
|
|
2702
|
+
align-items: center;
|
|
2703
|
+
justify-content: center;
|
|
2704
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
2705
|
+
border-radius: 999px;
|
|
2706
|
+
background: rgba(255, 255, 255, 0.06);
|
|
2707
|
+
color: rgba(255, 255, 255, 0.72);
|
|
2708
|
+
cursor: pointer;
|
|
2709
|
+
transition:
|
|
2710
|
+
background 160ms ease-out,
|
|
2711
|
+
border-color 160ms ease-out,
|
|
2712
|
+
color 160ms ease-out;
|
|
2713
|
+
|
|
2714
|
+
&:hover {
|
|
2715
|
+
background: rgba(255, 255, 255, 0.1);
|
|
2716
|
+
border-color: rgba(255, 255, 255, 0.18);
|
|
2717
|
+
color: rgba(255, 255, 255, 0.92);
|
|
2718
|
+
}
|
|
2719
|
+
`;
|
|
2450
2720
|
var Content = import_styled7.default.div`
|
|
2451
2721
|
color: rgba(255, 255, 255, 0.92);
|
|
2452
2722
|
line-height: 1.6;
|
|
@@ -2491,6 +2761,11 @@ var ContentStack = import_styled7.default.div`
|
|
|
2491
2761
|
display: flex;
|
|
2492
2762
|
flex-direction: column;
|
|
2493
2763
|
gap: 16px;
|
|
2764
|
+
|
|
2765
|
+
&[data-collapsed='true'] {
|
|
2766
|
+
max-height: ${USER_MESSAGE_COLLAPSE_HEIGHT_PX}px;
|
|
2767
|
+
overflow: hidden;
|
|
2768
|
+
}
|
|
2494
2769
|
`;
|
|
2495
2770
|
var ContentSegment = import_styled7.default.div`
|
|
2496
2771
|
min-width: 0;
|
|
@@ -2504,6 +2779,11 @@ var ContentBlock = import_styled7.default.div`
|
|
|
2504
2779
|
margin-top: 16px;
|
|
2505
2780
|
}
|
|
2506
2781
|
|
|
2782
|
+
&[data-render-mode='plain-text'] {
|
|
2783
|
+
white-space: pre-wrap;
|
|
2784
|
+
overflow-wrap: anywhere;
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2507
2787
|
&[data-block-tone='fresh'] {
|
|
2508
2788
|
opacity: 0.85;
|
|
2509
2789
|
filter: brightness(0.82) saturate(0.88);
|
|
@@ -2911,7 +3191,14 @@ var ChatThread = () => {
|
|
|
2911
3191
|
const error = useChatStore((s) => s.errorBySession[s.activeSessionId ?? ""]);
|
|
2912
3192
|
const updateQA = useChatStore((s) => s.updateQuestionnaireAnswers);
|
|
2913
3193
|
const clearSessionError = useChatStore((s) => s.clearSessionError);
|
|
2914
|
-
const {
|
|
3194
|
+
const {
|
|
3195
|
+
sendRef,
|
|
3196
|
+
retryRef,
|
|
3197
|
+
renderMessageBlock,
|
|
3198
|
+
handleQuestionnaireSubmit: customQuestionnaireSubmit,
|
|
3199
|
+
handleConfirmationSubmit: customConfirmationSubmit,
|
|
3200
|
+
labels
|
|
3201
|
+
} = useChatContext();
|
|
2915
3202
|
const handleRetry = (0, import_react11.useCallback)(() => {
|
|
2916
3203
|
if (!activeSessionId)
|
|
2917
3204
|
return;
|
|
@@ -2919,7 +3206,25 @@ var ChatThread = () => {
|
|
|
2919
3206
|
void retryRef.current();
|
|
2920
3207
|
}, [activeSessionId, clearSessionError, retryRef]);
|
|
2921
3208
|
const handleQuestionnaireSubmit = (0, import_react11.useCallback)(
|
|
2922
|
-
(submission) => {
|
|
3209
|
+
async (submission) => {
|
|
3210
|
+
if (customQuestionnaireSubmit) {
|
|
3211
|
+
const handled = await customQuestionnaireSubmit(submission, {
|
|
3212
|
+
sessionId: activeSessionId ?? void 0,
|
|
3213
|
+
mode: activeSessionMode
|
|
3214
|
+
});
|
|
3215
|
+
if (handled !== false) {
|
|
3216
|
+
if (activeSessionId && submission.sourceMessageId) {
|
|
3217
|
+
updateQA(
|
|
3218
|
+
activeSessionId,
|
|
3219
|
+
submission.sourceMessageId,
|
|
3220
|
+
submission.questionnaireId,
|
|
3221
|
+
submission.answers
|
|
3222
|
+
);
|
|
3223
|
+
}
|
|
3224
|
+
return;
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
await sendRef.current(submission.content);
|
|
2923
3228
|
if (activeSessionId && submission.sourceMessageId) {
|
|
2924
3229
|
updateQA(
|
|
2925
3230
|
activeSessionId,
|
|
@@ -2928,15 +3233,23 @@ var ChatThread = () => {
|
|
|
2928
3233
|
submission.answers
|
|
2929
3234
|
);
|
|
2930
3235
|
}
|
|
2931
|
-
void sendRef.current(submission.content);
|
|
2932
3236
|
},
|
|
2933
|
-
[activeSessionId, updateQA, sendRef]
|
|
3237
|
+
[activeSessionId, activeSessionMode, updateQA, sendRef, customQuestionnaireSubmit]
|
|
2934
3238
|
);
|
|
2935
|
-
const
|
|
2936
|
-
(submission) => {
|
|
2937
|
-
|
|
3239
|
+
const handleConfirmation = (0, import_react11.useCallback)(
|
|
3240
|
+
async (submission) => {
|
|
3241
|
+
if (customConfirmationSubmit) {
|
|
3242
|
+
const handled = await customConfirmationSubmit(submission, {
|
|
3243
|
+
sessionId: activeSessionId ?? void 0,
|
|
3244
|
+
mode: activeSessionMode
|
|
3245
|
+
});
|
|
3246
|
+
if (handled !== false) {
|
|
3247
|
+
return;
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
await sendRef.current(submission.content);
|
|
2938
3251
|
},
|
|
2939
|
-
[sendRef]
|
|
3252
|
+
[activeSessionId, activeSessionMode, sendRef, customConfirmationSubmit]
|
|
2940
3253
|
);
|
|
2941
3254
|
if (!hasSessions || messages.length === 0 && !streamingMessage) {
|
|
2942
3255
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ChatThreadEmptyState, {});
|
|
@@ -2950,7 +3263,7 @@ var ChatThread = () => {
|
|
|
2950
3263
|
error,
|
|
2951
3264
|
retryButtonLabel: labels.retryButton,
|
|
2952
3265
|
onRetry: handleRetry,
|
|
2953
|
-
onConfirmationSubmit:
|
|
3266
|
+
onConfirmationSubmit: handleConfirmation,
|
|
2954
3267
|
onQuestionnaireSubmit: handleQuestionnaireSubmit,
|
|
2955
3268
|
renderMessageBlock
|
|
2956
3269
|
}
|
|
@@ -2964,6 +3277,7 @@ var Container = import_styled9.default.div`
|
|
|
2964
3277
|
min-height: 0;
|
|
2965
3278
|
overflow: auto;
|
|
2966
3279
|
padding: 24px;
|
|
3280
|
+
margin-bottom: 24px;
|
|
2967
3281
|
overscroll-behavior: contain;
|
|
2968
3282
|
|
|
2969
3283
|
&::-webkit-scrollbar {
|
|
@@ -4043,6 +4357,27 @@ var StopSpinner = import_styled13.default.span`
|
|
|
4043
4357
|
|
|
4044
4358
|
// src/components/chat-composer/index.tsx
|
|
4045
4359
|
var import_jsx_runtime15 = require("@emotion/react/jsx-runtime");
|
|
4360
|
+
var CHAT_COMPOSER_LINE_HEIGHT_PX = 20;
|
|
4361
|
+
var CHAT_COMPOSER_MAX_ROWS = 7;
|
|
4362
|
+
var CHAT_COMPOSER_PADDING_TOP_PX = 8;
|
|
4363
|
+
var CHAT_COMPOSER_PADDING_BOTTOM_PX = 12;
|
|
4364
|
+
var CHAT_COMPOSER_PADDING_BLOCK_PX = CHAT_COMPOSER_PADDING_TOP_PX + CHAT_COMPOSER_PADDING_BOTTOM_PX;
|
|
4365
|
+
var CHAT_COMPOSER_MIN_ROWS = 4;
|
|
4366
|
+
var CHAT_COMPOSER_EXPANDED_MAX_ROWS = 60;
|
|
4367
|
+
var CHAT_COMPOSER_EXPANDED_MAX_VIEWPORT_RATIO = 0.7;
|
|
4368
|
+
var CHAT_COMPOSER_EXPANDED_RESERVED_SPACE_PX = 96;
|
|
4369
|
+
var CHAT_COMPOSER_MAX_HEIGHT_PX = CHAT_COMPOSER_MAX_ROWS * CHAT_COMPOSER_LINE_HEIGHT_PX + CHAT_COMPOSER_PADDING_BLOCK_PX;
|
|
4370
|
+
var CHAT_COMPOSER_EXPANDED_ROWS_HEIGHT_PX = CHAT_COMPOSER_EXPANDED_MAX_ROWS * CHAT_COMPOSER_LINE_HEIGHT_PX + CHAT_COMPOSER_PADDING_BLOCK_PX;
|
|
4371
|
+
var getExpandedComposerHeightPx = () => {
|
|
4372
|
+
if (typeof window === "undefined") {
|
|
4373
|
+
return CHAT_COMPOSER_EXPANDED_ROWS_HEIGHT_PX;
|
|
4374
|
+
}
|
|
4375
|
+
const viewportLimitedHeight = window.innerHeight * CHAT_COMPOSER_EXPANDED_MAX_VIEWPORT_RATIO - CHAT_COMPOSER_EXPANDED_RESERVED_SPACE_PX;
|
|
4376
|
+
return Math.max(
|
|
4377
|
+
CHAT_COMPOSER_MAX_HEIGHT_PX,
|
|
4378
|
+
Math.floor(Math.min(CHAT_COMPOSER_EXPANDED_ROWS_HEIGHT_PX, viewportLimitedHeight))
|
|
4379
|
+
);
|
|
4380
|
+
};
|
|
4046
4381
|
var PlusIcon = () => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4047
4382
|
"svg",
|
|
4048
4383
|
{
|
|
@@ -4055,6 +4390,36 @@ var PlusIcon = () => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
|
4055
4390
|
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M8 3v10M3 8h10", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round" })
|
|
4056
4391
|
}
|
|
4057
4392
|
);
|
|
4393
|
+
var ComposerExpandIcon = ({ expanded }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4394
|
+
"svg",
|
|
4395
|
+
{
|
|
4396
|
+
"aria-hidden": "true",
|
|
4397
|
+
width: "16",
|
|
4398
|
+
height: "16",
|
|
4399
|
+
viewBox: "0 0 16 16",
|
|
4400
|
+
fill: "none",
|
|
4401
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4402
|
+
children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4403
|
+
"path",
|
|
4404
|
+
{
|
|
4405
|
+
d: "M14 6h-4V2M10 6l4-4M2 10h4v4M6 10l-4 4",
|
|
4406
|
+
stroke: "currentColor",
|
|
4407
|
+
strokeWidth: "1.5",
|
|
4408
|
+
strokeLinecap: "round",
|
|
4409
|
+
strokeLinejoin: "round"
|
|
4410
|
+
}
|
|
4411
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4412
|
+
"path",
|
|
4413
|
+
{
|
|
4414
|
+
d: "M10 2h4v4M14 2L9 7M6 14H2v-4M2 14l5-5",
|
|
4415
|
+
stroke: "currentColor",
|
|
4416
|
+
strokeWidth: "1.5",
|
|
4417
|
+
strokeLinecap: "round",
|
|
4418
|
+
strokeLinejoin: "round"
|
|
4419
|
+
}
|
|
4420
|
+
)
|
|
4421
|
+
}
|
|
4422
|
+
);
|
|
4058
4423
|
var ChatComposerView = ({
|
|
4059
4424
|
value,
|
|
4060
4425
|
placeholder,
|
|
@@ -4071,6 +4436,8 @@ var ChatComposerView = ({
|
|
|
4071
4436
|
isStopping,
|
|
4072
4437
|
enableImageAttachments,
|
|
4073
4438
|
modeLabels,
|
|
4439
|
+
expandComposerAriaLabel,
|
|
4440
|
+
collapseComposerAriaLabel,
|
|
4074
4441
|
onValueChange,
|
|
4075
4442
|
onPickImages,
|
|
4076
4443
|
onPasteImages,
|
|
@@ -4082,6 +4449,9 @@ var ChatComposerView = ({
|
|
|
4082
4449
|
onSend
|
|
4083
4450
|
}) => {
|
|
4084
4451
|
const imageInputRef = (0, import_react15.useRef)(null);
|
|
4452
|
+
const inputRef = (0, import_react15.useRef)(null);
|
|
4453
|
+
const [isComposerExpandable, setIsComposerExpandable] = (0, import_react15.useState)(false);
|
|
4454
|
+
const [isComposerExpanded, setIsComposerExpanded] = (0, import_react15.useState)(false);
|
|
4085
4455
|
const canSend = canSendChatMessage({
|
|
4086
4456
|
value,
|
|
4087
4457
|
attachmentCount: attachments.length,
|
|
@@ -4089,6 +4459,26 @@ var ChatComposerView = ({
|
|
|
4089
4459
|
isModelsError,
|
|
4090
4460
|
hasModels
|
|
4091
4461
|
});
|
|
4462
|
+
(0, import_react15.useLayoutEffect)(() => {
|
|
4463
|
+
const element = inputRef.current;
|
|
4464
|
+
if (!element) {
|
|
4465
|
+
return;
|
|
4466
|
+
}
|
|
4467
|
+
if (!isComposerExpanded) {
|
|
4468
|
+
element.style.height = "0px";
|
|
4469
|
+
}
|
|
4470
|
+
const scrollHeight = element.scrollHeight;
|
|
4471
|
+
const nextExpandable = scrollHeight > CHAT_COMPOSER_MAX_HEIGHT_PX;
|
|
4472
|
+
const expandedHeight = getExpandedComposerHeightPx();
|
|
4473
|
+
const nextHeight = isComposerExpanded ? expandedHeight : Math.min(scrollHeight, CHAT_COMPOSER_MAX_HEIGHT_PX);
|
|
4474
|
+
setIsComposerExpandable(nextExpandable);
|
|
4475
|
+
element.style.height = `${nextHeight}px`;
|
|
4476
|
+
element.style.overflowY = !isComposerExpanded && scrollHeight > CHAT_COMPOSER_MAX_HEIGHT_PX ? "auto" : "hidden";
|
|
4477
|
+
}, [isComposerExpanded, value]);
|
|
4478
|
+
const handleSend = async () => {
|
|
4479
|
+
setIsComposerExpanded(false);
|
|
4480
|
+
await onSend();
|
|
4481
|
+
};
|
|
4092
4482
|
const handleKeyDown = (event) => {
|
|
4093
4483
|
if (shouldStopChatComposer({ key: event.key, shiftKey: event.shiftKey, isStreaming })) {
|
|
4094
4484
|
event.preventDefault();
|
|
@@ -4098,7 +4488,7 @@ var ChatComposerView = ({
|
|
|
4098
4488
|
if (!shouldSubmitChatComposer({ key: event.key, shiftKey: event.shiftKey, canSend }))
|
|
4099
4489
|
return;
|
|
4100
4490
|
event.preventDefault();
|
|
4101
|
-
void
|
|
4491
|
+
void handleSend();
|
|
4102
4492
|
};
|
|
4103
4493
|
const handlePickImages = (event) => {
|
|
4104
4494
|
if (event.target.files?.length)
|
|
@@ -4133,60 +4523,77 @@ var ChatComposerView = ({
|
|
|
4133
4523
|
}
|
|
4134
4524
|
),
|
|
4135
4525
|
attachmentNotice === "limit_reached" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AttachmentNotice, { "data-testid": "chat-composer-attachment-notice", children: attachmentLimitNotice }) : null,
|
|
4136
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
"data-testid": "chat-composer-input",
|
|
4140
|
-
value,
|
|
4141
|
-
onChange: (event) => onValueChange(event.target.value),
|
|
4142
|
-
onKeyDown: handleKeyDown,
|
|
4143
|
-
onPaste: enableImageAttachments ? handlePaste : void 0,
|
|
4144
|
-
placeholder
|
|
4145
|
-
}
|
|
4146
|
-
),
|
|
4147
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Footer, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Actions2, { "data-testid": "chat-composer-actions", children: [
|
|
4148
|
-
enableImageAttachments ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4149
|
-
AttachButton,
|
|
4526
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(InputArea, { "data-testid": "chat-composer-input-area", children: [
|
|
4527
|
+
isComposerExpanded || isComposerExpandable ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4528
|
+
ComposerExpandButton,
|
|
4150
4529
|
{
|
|
4151
4530
|
type: "button",
|
|
4152
|
-
"data-testid": "chat-composer-
|
|
4153
|
-
"aria-label":
|
|
4154
|
-
|
|
4155
|
-
|
|
4531
|
+
"data-testid": "chat-composer-expand-toggle",
|
|
4532
|
+
"aria-label": isComposerExpanded ? collapseComposerAriaLabel : expandComposerAriaLabel,
|
|
4533
|
+
"aria-expanded": isComposerExpanded,
|
|
4534
|
+
onClick: () => setIsComposerExpanded((current) => !current),
|
|
4535
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ComposerExpandIcon, { expanded: isComposerExpanded })
|
|
4156
4536
|
}
|
|
4157
4537
|
) : null,
|
|
4158
4538
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4159
|
-
|
|
4160
|
-
{
|
|
4161
|
-
value: selectedMode,
|
|
4162
|
-
disabled: isStreaming,
|
|
4163
|
-
labels: modeLabels,
|
|
4164
|
-
onChange: onSelectedModeChange
|
|
4165
|
-
}
|
|
4166
|
-
),
|
|
4167
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4168
|
-
ChatModelControl,
|
|
4539
|
+
Input,
|
|
4169
4540
|
{
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4541
|
+
ref: inputRef,
|
|
4542
|
+
"data-testid": "chat-composer-input",
|
|
4543
|
+
"data-expanded": isComposerExpanded,
|
|
4544
|
+
value,
|
|
4545
|
+
onChange: (event) => onValueChange(event.target.value),
|
|
4546
|
+
onKeyDown: handleKeyDown,
|
|
4547
|
+
onPaste: enableImageAttachments ? handlePaste : void 0,
|
|
4548
|
+
placeholder
|
|
4177
4549
|
}
|
|
4178
|
-
)
|
|
4179
|
-
|
|
4180
|
-
|
|
4550
|
+
)
|
|
4551
|
+
] }),
|
|
4552
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Footer, { children: [
|
|
4553
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(LeadingActions, { "data-testid": "chat-composer-leading-actions", children: enableImageAttachments ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4554
|
+
AttachButton,
|
|
4181
4555
|
{
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4556
|
+
type: "button",
|
|
4557
|
+
"data-testid": "chat-composer-attach-image",
|
|
4558
|
+
"aria-label": "Attach image",
|
|
4559
|
+
onClick: () => imageInputRef.current?.click(),
|
|
4560
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PlusIcon, {})
|
|
4187
4561
|
}
|
|
4188
|
-
)
|
|
4189
|
-
|
|
4562
|
+
) : null }),
|
|
4563
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(TrailingActions, { "data-testid": "chat-composer-trailing-actions", children: [
|
|
4564
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4565
|
+
ChatModeControl,
|
|
4566
|
+
{
|
|
4567
|
+
value: selectedMode,
|
|
4568
|
+
disabled: isStreaming,
|
|
4569
|
+
labels: modeLabels,
|
|
4570
|
+
onChange: onSelectedModeChange
|
|
4571
|
+
}
|
|
4572
|
+
),
|
|
4573
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4574
|
+
ChatModelControl,
|
|
4575
|
+
{
|
|
4576
|
+
selectedModel,
|
|
4577
|
+
availableModels,
|
|
4578
|
+
isModelsLoading,
|
|
4579
|
+
isModelsError,
|
|
4580
|
+
hasModels,
|
|
4581
|
+
onSelectedModelChange,
|
|
4582
|
+
onReloadModels
|
|
4583
|
+
}
|
|
4584
|
+
),
|
|
4585
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4586
|
+
ChatSendActions,
|
|
4587
|
+
{
|
|
4588
|
+
canSend,
|
|
4589
|
+
isStreaming,
|
|
4590
|
+
isStopping,
|
|
4591
|
+
onStop,
|
|
4592
|
+
onSend: handleSend
|
|
4593
|
+
}
|
|
4594
|
+
)
|
|
4595
|
+
] })
|
|
4596
|
+
] })
|
|
4190
4597
|
] }) });
|
|
4191
4598
|
};
|
|
4192
4599
|
var ChatComposer = () => {
|
|
@@ -4222,6 +4629,8 @@ var ChatComposer = () => {
|
|
|
4222
4629
|
isStopping: state.isStopping,
|
|
4223
4630
|
enableImageAttachments,
|
|
4224
4631
|
modeLabels,
|
|
4632
|
+
expandComposerAriaLabel: labels.expandComposerAriaLabel,
|
|
4633
|
+
collapseComposerAriaLabel: labels.collapseComposerAriaLabel,
|
|
4225
4634
|
onValueChange: actions.setValue,
|
|
4226
4635
|
onPickImages: actions.pickImages,
|
|
4227
4636
|
onPasteImages: actions.pasteImages,
|
|
@@ -4238,6 +4647,16 @@ var Container2 = import_styled14.default.div`
|
|
|
4238
4647
|
padding: 0 16px 16px;
|
|
4239
4648
|
`;
|
|
4240
4649
|
var Surface = import_styled14.default.div`
|
|
4650
|
+
display: grid;
|
|
4651
|
+
grid-template-columns: minmax(0, 1fr);
|
|
4652
|
+
grid-template-areas:
|
|
4653
|
+
'attachments'
|
|
4654
|
+
'notice'
|
|
4655
|
+
'input'
|
|
4656
|
+
'footer';
|
|
4657
|
+
width: 100%;
|
|
4658
|
+
max-width: 760px;
|
|
4659
|
+
margin: 0 auto;
|
|
4241
4660
|
background: var(--border-color);
|
|
4242
4661
|
border-radius: 20px;
|
|
4243
4662
|
border: 1px solid var(--border-hover);
|
|
@@ -4247,6 +4666,7 @@ var Surface = import_styled14.default.div`
|
|
|
4247
4666
|
backdrop-filter: blur(10px);
|
|
4248
4667
|
`;
|
|
4249
4668
|
var AttachmentNotice = import_styled14.default.div`
|
|
4669
|
+
grid-area: notice;
|
|
4250
4670
|
margin: 10px 12px 0;
|
|
4251
4671
|
padding: 8px 10px;
|
|
4252
4672
|
border-radius: 10px;
|
|
@@ -4256,19 +4676,45 @@ var AttachmentNotice = import_styled14.default.div`
|
|
|
4256
4676
|
font-size: 12px;
|
|
4257
4677
|
line-height: 1.4;
|
|
4258
4678
|
`;
|
|
4679
|
+
var InputArea = import_styled14.default.div`
|
|
4680
|
+
grid-area: input;
|
|
4681
|
+
position: relative;
|
|
4682
|
+
`;
|
|
4259
4683
|
var Input = import_styled14.default.textarea`
|
|
4684
|
+
--textarea-line-height: ${CHAT_COMPOSER_LINE_HEIGHT_PX}px;
|
|
4685
|
+
--textarea-min-rows: ${CHAT_COMPOSER_MIN_ROWS};
|
|
4686
|
+
--textarea-max-rows: ${CHAT_COMPOSER_MAX_ROWS};
|
|
4687
|
+
--textarea-expanded-max-rows: ${CHAT_COMPOSER_EXPANDED_MAX_ROWS};
|
|
4688
|
+
--textarea-padding-top: ${CHAT_COMPOSER_PADDING_TOP_PX}px;
|
|
4689
|
+
--textarea-padding-bottom: ${CHAT_COMPOSER_PADDING_BOTTOM_PX}px;
|
|
4690
|
+
--textarea-padding-block: calc(var(--textarea-padding-top) + var(--textarea-padding-bottom));
|
|
4691
|
+
--textarea-max-height: calc(
|
|
4692
|
+
var(--textarea-max-rows) * var(--textarea-line-height) + var(--textarea-padding-block)
|
|
4693
|
+
);
|
|
4694
|
+
--textarea-expanded-max-height: min(
|
|
4695
|
+
calc(
|
|
4696
|
+
var(--textarea-expanded-max-rows) * var(--textarea-line-height) +
|
|
4697
|
+
var(--textarea-padding-block)
|
|
4698
|
+
),
|
|
4699
|
+
calc(70vh - ${CHAT_COMPOSER_EXPANDED_RESERVED_SPACE_PX}px)
|
|
4700
|
+
);
|
|
4260
4701
|
width: 100%;
|
|
4261
|
-
min-height:
|
|
4702
|
+
min-height: calc(
|
|
4703
|
+
var(--textarea-min-rows) * var(--textarea-line-height) + var(--textarea-padding-block)
|
|
4704
|
+
);
|
|
4705
|
+
max-height: var(--textarea-max-height);
|
|
4706
|
+
box-sizing: border-box;
|
|
4262
4707
|
resize: none;
|
|
4263
4708
|
appearance: none;
|
|
4264
4709
|
border: 0;
|
|
4265
4710
|
outline: 0;
|
|
4266
4711
|
background: transparent;
|
|
4267
|
-
padding:
|
|
4712
|
+
padding: var(--textarea-padding-top) 44px var(--textarea-padding-bottom) 12px;
|
|
4268
4713
|
font-weight: 400;
|
|
4269
4714
|
font-size: 14px;
|
|
4270
4715
|
color: var(--text-primary);
|
|
4271
|
-
line-height:
|
|
4716
|
+
line-height: var(--textarea-line-height);
|
|
4717
|
+
overflow-y: hidden;
|
|
4272
4718
|
|
|
4273
4719
|
&::placeholder {
|
|
4274
4720
|
color: var(--text-secondary);
|
|
@@ -4277,19 +4723,50 @@ var Input = import_styled14.default.textarea`
|
|
|
4277
4723
|
&::-webkit-resizer {
|
|
4278
4724
|
display: none;
|
|
4279
4725
|
}
|
|
4726
|
+
|
|
4727
|
+
&[data-expanded='true'] {
|
|
4728
|
+
max-height: var(--textarea-expanded-max-height);
|
|
4729
|
+
}
|
|
4730
|
+
`;
|
|
4731
|
+
var ComposerExpandButton = import_styled14.default.button`
|
|
4732
|
+
position: absolute;
|
|
4733
|
+
top: 8px;
|
|
4734
|
+
right: 10px;
|
|
4735
|
+
width: 28px;
|
|
4736
|
+
height: 28px;
|
|
4737
|
+
display: grid;
|
|
4738
|
+
place-items: center;
|
|
4739
|
+
border: none;
|
|
4740
|
+
border-radius: 999px;
|
|
4741
|
+
background: transparent;
|
|
4742
|
+
color: rgba(255, 255, 255, 0.72);
|
|
4743
|
+
cursor: pointer;
|
|
4744
|
+
z-index: 1;
|
|
4745
|
+
|
|
4746
|
+
&:hover {
|
|
4747
|
+
background: rgba(255, 255, 255, 0.08);
|
|
4748
|
+
color: rgba(255, 255, 255, 0.92);
|
|
4749
|
+
}
|
|
4280
4750
|
`;
|
|
4281
4751
|
var Footer = import_styled14.default.div`
|
|
4282
|
-
|
|
4752
|
+
grid-area: footer;
|
|
4753
|
+
display: grid;
|
|
4754
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
4283
4755
|
align-items: flex-end;
|
|
4284
|
-
justify-content: stretch;
|
|
4285
4756
|
gap: 16px;
|
|
4286
4757
|
padding: 0 14px 14px;
|
|
4287
4758
|
`;
|
|
4288
|
-
var
|
|
4759
|
+
var LeadingActions = import_styled14.default.div`
|
|
4760
|
+
display: flex;
|
|
4761
|
+
align-items: center;
|
|
4762
|
+
justify-content: flex-start;
|
|
4763
|
+
gap: 8px;
|
|
4764
|
+
min-width: 0;
|
|
4765
|
+
`;
|
|
4766
|
+
var TrailingActions = import_styled14.default.div`
|
|
4289
4767
|
display: flex;
|
|
4290
4768
|
align-items: center;
|
|
4291
4769
|
flex-wrap: wrap;
|
|
4292
|
-
width: 100%;
|
|
4293
4770
|
min-width: 0;
|
|
4294
4771
|
justify-content: flex-end;
|
|
4295
4772
|
gap: 8px;
|