@xinghunm/ai-chat 0.4.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +82 -12
- package/dist/index.d.ts +82 -12
- package/dist/index.js +636 -143
- package/dist/index.mjs +651 -158
- package/package.json +1 -1
package/dist/index.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,40 @@ 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 === "custom" && incomingBlock.blockKey) {
|
|
112
|
+
const mergePolicy = incomingBlock.mergePolicy ?? "append";
|
|
113
|
+
if (mergePolicy !== "append") {
|
|
114
|
+
const existingIndex2 = nextBlocks.findIndex(
|
|
115
|
+
(block) => block.type === "custom" && block.blockKey === incomingBlock.blockKey
|
|
116
|
+
);
|
|
117
|
+
if (existingIndex2 !== -1) {
|
|
118
|
+
if (mergePolicy === "replace") {
|
|
119
|
+
nextBlocks[existingIndex2] = incomingBlock;
|
|
120
|
+
}
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
nextBlocks.push(incomingBlock);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (incomingBlock.type !== "questionnaire") {
|
|
128
|
+
nextBlocks.push(incomingBlock);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const existingIndex = nextBlocks.findIndex(
|
|
132
|
+
(block) => block.type === "questionnaire" && block.questionnaire.questionnaireId === incomingBlock.questionnaire.questionnaireId
|
|
133
|
+
);
|
|
134
|
+
if (existingIndex === -1) {
|
|
135
|
+
nextBlocks.push(incomingBlock);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
nextBlocks[existingIndex] = incomingBlock;
|
|
139
|
+
});
|
|
140
|
+
return nextBlocks;
|
|
141
|
+
};
|
|
100
142
|
var finalizeStreamingMessage = (state, sessionId, status, clearError = false) => {
|
|
101
143
|
const message = state.streamingMessageBySession[sessionId];
|
|
102
144
|
const hasRenderableMessagePayload = Boolean(
|
|
@@ -286,10 +328,15 @@ var createChatStore = (initialState) => (0, import_vanilla.createStore)((set, ge
|
|
|
286
328
|
const target = state.streamingMessageBySession[sessionId];
|
|
287
329
|
if (!target)
|
|
288
330
|
return;
|
|
331
|
+
const nextBlocks = patch.blocks !== void 0 ? mergeStreamingBlocks(target.blocks, patch.blocks) : target.blocks;
|
|
289
332
|
set({
|
|
290
333
|
streamingMessageBySession: {
|
|
291
334
|
...state.streamingMessageBySession,
|
|
292
|
-
[sessionId]: {
|
|
335
|
+
[sessionId]: {
|
|
336
|
+
...target,
|
|
337
|
+
...patch,
|
|
338
|
+
...patch.blocks !== void 0 ? { blocks: nextBlocks } : {}
|
|
339
|
+
}
|
|
293
340
|
}
|
|
294
341
|
});
|
|
295
342
|
},
|
|
@@ -509,9 +556,27 @@ var DEFAULT_CHAT_TRANSPORT_ENDPOINTS = {
|
|
|
509
556
|
completions: "/chat/completions",
|
|
510
557
|
terminate: "/chat/terminate"
|
|
511
558
|
};
|
|
559
|
+
var createToolExecutionHeaders = (policy) => {
|
|
560
|
+
if (!policy?.enabled) {
|
|
561
|
+
return {};
|
|
562
|
+
}
|
|
563
|
+
return {
|
|
564
|
+
"X-Tool-Approval-Required": String(Boolean(policy.approvalRequired)),
|
|
565
|
+
...typeof policy.approvalTimeoutSec === "number" ? { "X-Tool-Approval-Timeout": String(policy.approvalTimeoutSec) } : {}
|
|
566
|
+
};
|
|
567
|
+
};
|
|
568
|
+
var createModeDefaultHeaders = (mode) => {
|
|
569
|
+
if (mode === "ask" || mode === "plan") {
|
|
570
|
+
return {
|
|
571
|
+
"X-Tool-Approval-Required": "false"
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
return {};
|
|
575
|
+
};
|
|
512
576
|
var createDefaultChatTransport = ({
|
|
513
577
|
apiBaseUrl,
|
|
514
578
|
authToken,
|
|
579
|
+
toolExecutionPolicy,
|
|
515
580
|
streamHeaders,
|
|
516
581
|
transformStreamPacket,
|
|
517
582
|
endpoints,
|
|
@@ -522,6 +587,10 @@ var createDefaultChatTransport = ({
|
|
|
522
587
|
...DEFAULT_CHAT_TRANSPORT_ENDPOINTS,
|
|
523
588
|
...endpoints
|
|
524
589
|
};
|
|
590
|
+
const resolvedStreamHeaders = {
|
|
591
|
+
...createToolExecutionHeaders(toolExecutionPolicy),
|
|
592
|
+
...streamHeaders
|
|
593
|
+
};
|
|
525
594
|
return {
|
|
526
595
|
getModels: () => getChatModels(client, resolvedEndpoints.models),
|
|
527
596
|
startStream: async ({
|
|
@@ -535,12 +604,16 @@ var createDefaultChatTransport = ({
|
|
|
535
604
|
onDone,
|
|
536
605
|
onError
|
|
537
606
|
}) => {
|
|
607
|
+
const requestHeaders = {
|
|
608
|
+
...createModeDefaultHeaders(mode),
|
|
609
|
+
...resolvedStreamHeaders
|
|
610
|
+
};
|
|
538
611
|
await startChatStream({
|
|
539
612
|
apiBaseUrl,
|
|
540
613
|
endpointPath: resolvedEndpoints.completions,
|
|
541
614
|
sessionId,
|
|
542
615
|
authToken,
|
|
543
|
-
requestHeaders
|
|
616
|
+
requestHeaders,
|
|
544
617
|
model,
|
|
545
618
|
mode,
|
|
546
619
|
content,
|
|
@@ -569,6 +642,8 @@ var AiChatProvider = (props) => {
|
|
|
569
642
|
defaultMode,
|
|
570
643
|
labels,
|
|
571
644
|
renderMessageBlock,
|
|
645
|
+
handleQuestionnaireSubmit,
|
|
646
|
+
handleConfirmationSubmit,
|
|
572
647
|
messageRenderOrder,
|
|
573
648
|
enableImageAttachments = true,
|
|
574
649
|
children
|
|
@@ -624,6 +699,8 @@ var AiChatProvider = (props) => {
|
|
|
624
699
|
sendRef,
|
|
625
700
|
retryRef,
|
|
626
701
|
renderMessageBlock,
|
|
702
|
+
handleQuestionnaireSubmit,
|
|
703
|
+
handleConfirmationSubmit,
|
|
627
704
|
messageRenderOrder,
|
|
628
705
|
transformStreamPacket: defaultTransformStreamPacket,
|
|
629
706
|
enableImageAttachments
|
|
@@ -634,6 +711,8 @@ var AiChatProvider = (props) => {
|
|
|
634
711
|
defaultAuthToken,
|
|
635
712
|
defaultTransformStreamPacket,
|
|
636
713
|
enableImageAttachments,
|
|
714
|
+
handleConfirmationSubmit,
|
|
715
|
+
handleQuestionnaireSubmit,
|
|
637
716
|
labels,
|
|
638
717
|
messageRenderOrder,
|
|
639
718
|
renderMessageBlock,
|
|
@@ -943,11 +1022,11 @@ var getTimelineBlockKey = (block, index) => {
|
|
|
943
1022
|
case "confirmation_card":
|
|
944
1023
|
return `${index}:confirmation_card:${block.proposal.proposalId}`;
|
|
945
1024
|
case "result_summary":
|
|
946
|
-
return `${index}:result_summary:${block.summary.
|
|
1025
|
+
return `${index}:result_summary:${block.summary.summaryId}:${block.summary.status}`;
|
|
947
1026
|
case "questionnaire":
|
|
948
1027
|
return `${index}:questionnaire:${block.questionnaire.questionnaireId}`;
|
|
949
1028
|
case "custom":
|
|
950
|
-
return `${index}:custom:${block.kind}:${stringifyTimelineKeyPart(block.data)}`;
|
|
1029
|
+
return block.blockKey ? `custom:${block.blockKey}` : `${index}:custom:${block.kind}:${stringifyTimelineKeyPart(block.data)}`;
|
|
951
1030
|
default:
|
|
952
1031
|
return null;
|
|
953
1032
|
}
|
|
@@ -1235,21 +1314,21 @@ var useTimelineBlockAnchors = ({
|
|
|
1235
1314
|
};
|
|
1236
1315
|
};
|
|
1237
1316
|
|
|
1238
|
-
// src/components/chat-thread/components/
|
|
1317
|
+
// src/components/chat-thread/components/execution-confirmation-card.tsx
|
|
1239
1318
|
var import_styled = __toESM(require("@emotion/styled"));
|
|
1240
1319
|
var import_jsx_runtime2 = require("@emotion/react/jsx-runtime");
|
|
1241
|
-
var
|
|
1320
|
+
var ExecutionConfirmationCard = ({
|
|
1242
1321
|
proposal,
|
|
1243
1322
|
interactive = false,
|
|
1244
1323
|
onApply,
|
|
1245
1324
|
onConfirm,
|
|
1246
1325
|
onRevise
|
|
1247
1326
|
}) => {
|
|
1248
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Card, { "data-testid": "
|
|
1327
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Card, { "data-testid": "execution-confirmation-card", children: [
|
|
1249
1328
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Header, { children: [
|
|
1250
1329
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Eyebrow, { children: "Execution Proposal" }),
|
|
1251
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Title, { children: proposal.
|
|
1252
|
-
proposal.
|
|
1330
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Title, { children: proposal.resourceName }),
|
|
1331
|
+
proposal.executorName ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Subtitle, { children: proposal.executorName }) : null
|
|
1253
1332
|
] }),
|
|
1254
1333
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SummaryList, { children: proposal.parameterSummary.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(SummaryItem, { children: [
|
|
1255
1334
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SummaryLabel, { children: item.label }),
|
|
@@ -1257,21 +1336,13 @@ var PDEAIExecutionConfirmationCard = ({
|
|
|
1257
1336
|
] }, `${item.fieldPath ?? item.label}-${item.value}`)) }),
|
|
1258
1337
|
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
1338
|
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
|
-
),
|
|
1339
|
+
onApply && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ActionButton, { type: "button", "data-testid": "confirmation-apply", onClick: onApply, children: "Apply to Parameters" }),
|
|
1340
|
+
onConfirm && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ActionButton, { type: "button", "data-testid": "confirmation-confirm", onClick: onConfirm, children: "Confirm Execution" }),
|
|
1270
1341
|
onRevise && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1271
1342
|
SecondaryActionButton,
|
|
1272
1343
|
{
|
|
1273
1344
|
type: "button",
|
|
1274
|
-
"data-testid": "
|
|
1345
|
+
"data-testid": "confirmation-revise",
|
|
1275
1346
|
onClick: onRevise,
|
|
1276
1347
|
children: "Revise Plan"
|
|
1277
1348
|
}
|
|
@@ -1368,10 +1439,10 @@ var SecondaryActionButton = (0, import_styled.default)(ActionButton)`
|
|
|
1368
1439
|
border: 1px solid rgba(255, 255, 255, 0.14);
|
|
1369
1440
|
`;
|
|
1370
1441
|
|
|
1371
|
-
// src/components/chat-thread/components/
|
|
1442
|
+
// src/components/chat-thread/components/notice-card.tsx
|
|
1372
1443
|
var import_styled2 = __toESM(require("@emotion/styled"));
|
|
1373
1444
|
var import_jsx_runtime3 = require("@emotion/react/jsx-runtime");
|
|
1374
|
-
var
|
|
1445
|
+
var NoticeCard = ({ text, tone }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Card2, { "data-testid": "notice-card", "data-tone": tone, children: text });
|
|
1375
1446
|
var Card2 = import_styled2.default.div`
|
|
1376
1447
|
padding: 12px 14px;
|
|
1377
1448
|
border-radius: 16px;
|
|
@@ -1397,10 +1468,10 @@ var Card2 = import_styled2.default.div`
|
|
|
1397
1468
|
}
|
|
1398
1469
|
`;
|
|
1399
1470
|
|
|
1400
|
-
// src/components/chat-thread/components/
|
|
1471
|
+
// src/components/chat-thread/components/parameter-summary-card.tsx
|
|
1401
1472
|
var import_styled3 = __toESM(require("@emotion/styled"));
|
|
1402
1473
|
var import_jsx_runtime4 = require("@emotion/react/jsx-runtime");
|
|
1403
|
-
var
|
|
1474
|
+
var ParameterSummaryCard = ({ items }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Card3, { "data-testid": "parameter-summary-card", children: [
|
|
1404
1475
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Title2, { children: "Parameter Summary" }),
|
|
1405
1476
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(List, { children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(ListItem, { children: [
|
|
1406
1477
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Label, { children: item.label }),
|
|
@@ -1444,11 +1515,17 @@ var Value = import_styled3.default.span`
|
|
|
1444
1515
|
text-align: right;
|
|
1445
1516
|
`;
|
|
1446
1517
|
|
|
1447
|
-
// src/components/chat-thread/components/
|
|
1518
|
+
// src/components/chat-thread/components/questionnaire-card.tsx
|
|
1448
1519
|
var import_react7 = require("react");
|
|
1449
1520
|
var import_styled4 = __toESM(require("@emotion/styled"));
|
|
1450
1521
|
var import_jsx_runtime5 = require("@emotion/react/jsx-runtime");
|
|
1451
1522
|
var OTHER_OPTION_VALUE = "__other__";
|
|
1523
|
+
var DEFAULT_QUESTIONNAIRE_CARD_LABELS = {
|
|
1524
|
+
submitting: "Submitting...",
|
|
1525
|
+
submitted: "Selection submitted. Waiting for the plan to continue...",
|
|
1526
|
+
validationPrefix: "Please complete:",
|
|
1527
|
+
submitFailed: "Failed to submit. Please try again."
|
|
1528
|
+
};
|
|
1452
1529
|
var createInitialAnswers = (questionnaire) => ({
|
|
1453
1530
|
...questionnaire.answers ?? {}
|
|
1454
1531
|
});
|
|
@@ -1542,26 +1619,40 @@ var normalizeQuestionAnswer = (question, answer) => {
|
|
|
1542
1619
|
return answer;
|
|
1543
1620
|
}
|
|
1544
1621
|
};
|
|
1545
|
-
var
|
|
1622
|
+
var QuestionnaireCardInner = ({
|
|
1546
1623
|
questionnaire,
|
|
1547
1624
|
interactive = false,
|
|
1548
|
-
onSubmit
|
|
1625
|
+
onSubmit,
|
|
1626
|
+
labels
|
|
1549
1627
|
}) => {
|
|
1550
1628
|
const [answers, setAnswers] = (0, import_react7.useState)(
|
|
1551
1629
|
() => createInitialAnswers(questionnaire)
|
|
1552
1630
|
);
|
|
1553
1631
|
const [errorMessage, setErrorMessage] = (0, import_react7.useState)(null);
|
|
1554
|
-
const
|
|
1632
|
+
const [isSubmitting, setIsSubmitting] = (0, import_react7.useState)(false);
|
|
1633
|
+
const [isSubmitted, setIsSubmitted] = (0, import_react7.useState)(false);
|
|
1634
|
+
const resolvedLabels = {
|
|
1635
|
+
...DEFAULT_QUESTIONNAIRE_CARD_LABELS,
|
|
1636
|
+
...labels
|
|
1637
|
+
};
|
|
1638
|
+
const hasExternalFailureStatus = questionnaire.status === "expired" || questionnaire.status === "failed";
|
|
1639
|
+
const visibleErrorMessage = questionnaire.statusMessage ?? errorMessage;
|
|
1640
|
+
const isInteractionLocked = !interactive || isSubmitting || isSubmitted || hasExternalFailureStatus;
|
|
1641
|
+
const handleSubmit = async () => {
|
|
1642
|
+
if (isSubmitting || isSubmitted) {
|
|
1643
|
+
return;
|
|
1644
|
+
}
|
|
1555
1645
|
const missingQuestions = questionnaire.questions.filter(
|
|
1556
1646
|
(question) => question.required && isMissingRequiredAnswer(question, answers)
|
|
1557
1647
|
);
|
|
1558
1648
|
if (missingQuestions.length > 0) {
|
|
1559
1649
|
setErrorMessage(
|
|
1560
|
-
|
|
1650
|
+
`${resolvedLabels.validationPrefix} ${missingQuestions.map((question) => question.label).join(", ")}`
|
|
1561
1651
|
);
|
|
1562
1652
|
return;
|
|
1563
1653
|
}
|
|
1564
1654
|
setErrorMessage(null);
|
|
1655
|
+
setIsSubmitting(true);
|
|
1565
1656
|
const normalizedAnswers = Object.fromEntries(
|
|
1566
1657
|
questionnaire.questions.flatMap((question) => {
|
|
1567
1658
|
const value = normalizeQuestionAnswer(question, answers[question.id]);
|
|
@@ -1578,11 +1669,18 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1578
1669
|
return [`- ${question.label}: ${formatQuestionAnswer(question, value)}`];
|
|
1579
1670
|
})
|
|
1580
1671
|
];
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1672
|
+
try {
|
|
1673
|
+
await onSubmit?.({
|
|
1674
|
+
questionnaireId: questionnaire.questionnaireId,
|
|
1675
|
+
answers: normalizedAnswers,
|
|
1676
|
+
content: contentLines.join("\n")
|
|
1677
|
+
});
|
|
1678
|
+
setIsSubmitted(true);
|
|
1679
|
+
} catch (error) {
|
|
1680
|
+
setErrorMessage(error instanceof Error ? error.message : resolvedLabels.submitFailed);
|
|
1681
|
+
} finally {
|
|
1682
|
+
setIsSubmitting(false);
|
|
1683
|
+
}
|
|
1586
1684
|
};
|
|
1587
1685
|
const renderQuestion = (question) => {
|
|
1588
1686
|
const renderOptionChoice = ({
|
|
@@ -1597,13 +1695,13 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1597
1695
|
OptionChoiceItem,
|
|
1598
1696
|
{
|
|
1599
1697
|
role: "button",
|
|
1600
|
-
tabIndex:
|
|
1698
|
+
tabIndex: isInteractionLocked ? -1 : 0,
|
|
1601
1699
|
"aria-pressed": isSelected,
|
|
1602
1700
|
"data-selected": isSelected,
|
|
1603
1701
|
"data-tone": tone,
|
|
1604
|
-
"data-testid": `
|
|
1702
|
+
"data-testid": `question-option-${questionId}-${index}`,
|
|
1605
1703
|
onClick: (event) => {
|
|
1606
|
-
if (
|
|
1704
|
+
if (isInteractionLocked) {
|
|
1607
1705
|
return;
|
|
1608
1706
|
}
|
|
1609
1707
|
if (event.target instanceof HTMLElement && event.target.closest("input")) {
|
|
@@ -1612,7 +1710,7 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1612
1710
|
onClick();
|
|
1613
1711
|
},
|
|
1614
1712
|
onKeyDown: (event) => {
|
|
1615
|
-
if (
|
|
1713
|
+
if (isInteractionLocked) {
|
|
1616
1714
|
return;
|
|
1617
1715
|
}
|
|
1618
1716
|
if (event.key !== "Enter" && event.key !== " ") {
|
|
@@ -1671,11 +1769,11 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1671
1769
|
inlineInput: singleSelectDraft.selectedValue === OTHER_OPTION_VALUE ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1672
1770
|
InlineOtherInput,
|
|
1673
1771
|
{
|
|
1674
|
-
"data-testid": `
|
|
1772
|
+
"data-testid": `question-input-${question.id}`,
|
|
1675
1773
|
type: "text",
|
|
1676
1774
|
value: singleSelectDraft.otherValue,
|
|
1677
1775
|
placeholder: "Other",
|
|
1678
|
-
readOnly:
|
|
1776
|
+
readOnly: isInteractionLocked,
|
|
1679
1777
|
onClick: (event) => {
|
|
1680
1778
|
event.stopPropagation();
|
|
1681
1779
|
},
|
|
@@ -1696,11 +1794,11 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1696
1794
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionBody, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1697
1795
|
TextInput,
|
|
1698
1796
|
{
|
|
1699
|
-
"data-testid": `
|
|
1797
|
+
"data-testid": `question-input-${question.id}`,
|
|
1700
1798
|
type: "text",
|
|
1701
1799
|
value: getTextInputValue(answers[question.id]),
|
|
1702
1800
|
placeholder: question.placeholder,
|
|
1703
|
-
readOnly:
|
|
1801
|
+
readOnly: isInteractionLocked,
|
|
1704
1802
|
onChange: (event) => {
|
|
1705
1803
|
setAnswers((current) => updateAnswerValue(current, question.id, event.target.value));
|
|
1706
1804
|
}
|
|
@@ -1711,11 +1809,11 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1711
1809
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1712
1810
|
TextInput,
|
|
1713
1811
|
{
|
|
1714
|
-
"data-testid": `
|
|
1812
|
+
"data-testid": `question-input-${question.id}`,
|
|
1715
1813
|
type: "number",
|
|
1716
1814
|
value: getNumberInputValue(answers[question.id]),
|
|
1717
1815
|
placeholder: question.placeholder,
|
|
1718
|
-
readOnly:
|
|
1816
|
+
readOnly: isInteractionLocked,
|
|
1719
1817
|
onChange: (event) => {
|
|
1720
1818
|
setAnswers(
|
|
1721
1819
|
(current) => updateAnswerValue(
|
|
@@ -1750,7 +1848,7 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1750
1848
|
return null;
|
|
1751
1849
|
}
|
|
1752
1850
|
};
|
|
1753
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Card4, { "data-testid": "
|
|
1851
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Card4, { "data-testid": "questionnaire-card", children: [
|
|
1754
1852
|
questionnaire.title ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Title3, { children: questionnaire.title }) : null,
|
|
1755
1853
|
questionnaire.description ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Description, { children: questionnaire.description }) : null,
|
|
1756
1854
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionList, { children: questionnaire.questions.map((question) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(QuestionCard, { children: [
|
|
@@ -1760,24 +1858,28 @@ var PDEAIQuestionnaireCardInner = ({
|
|
|
1760
1858
|
] }),
|
|
1761
1859
|
renderQuestion(question)
|
|
1762
1860
|
] }, question.id)) }),
|
|
1763
|
-
|
|
1764
|
-
interactive ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1861
|
+
visibleErrorMessage ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ErrorMessage, { "data-testid": "questionnaire-error", children: visibleErrorMessage }) : null,
|
|
1862
|
+
isSubmitted ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SuccessMessage, { "data-testid": "questionnaire-success", children: resolvedLabels.submitted }) : interactive && !hasExternalFailureStatus ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1765
1863
|
SubmitButton,
|
|
1766
1864
|
{
|
|
1767
1865
|
type: "button",
|
|
1768
|
-
"data-testid": "
|
|
1769
|
-
|
|
1770
|
-
|
|
1866
|
+
"data-testid": "questionnaire-submit",
|
|
1867
|
+
disabled: isInteractionLocked,
|
|
1868
|
+
onClick: () => {
|
|
1869
|
+
void handleSubmit();
|
|
1870
|
+
},
|
|
1871
|
+
children: isSubmitting ? resolvedLabels.submitting : questionnaire.submitLabel ?? "Submit"
|
|
1771
1872
|
}
|
|
1772
1873
|
) : null
|
|
1773
1874
|
] });
|
|
1774
1875
|
};
|
|
1775
1876
|
var getQuestionnaireStateKey = (questionnaire) => JSON.stringify([
|
|
1776
1877
|
questionnaire.questionnaireId,
|
|
1777
|
-
questionnaire.
|
|
1778
|
-
questionnaire.
|
|
1878
|
+
questionnaire.questions,
|
|
1879
|
+
questionnaire.status,
|
|
1880
|
+
questionnaire.statusMessage
|
|
1779
1881
|
]);
|
|
1780
|
-
var
|
|
1882
|
+
var QuestionnaireCard = (props) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionnaireCardInner, { ...props }, getQuestionnaireStateKey(props.questionnaire));
|
|
1781
1883
|
var Card4 = import_styled4.default.section`
|
|
1782
1884
|
display: grid;
|
|
1783
1885
|
gap: 14px;
|
|
@@ -1925,6 +2027,10 @@ var ErrorMessage = import_styled4.default.div`
|
|
|
1925
2027
|
color: rgba(255, 145, 145, 0.96);
|
|
1926
2028
|
font-size: 12px;
|
|
1927
2029
|
`;
|
|
2030
|
+
var SuccessMessage = import_styled4.default.div`
|
|
2031
|
+
color: rgba(164, 255, 210, 0.96);
|
|
2032
|
+
font-size: 12px;
|
|
2033
|
+
`;
|
|
1928
2034
|
var SubmitButton = import_styled4.default.button`
|
|
1929
2035
|
justify-self: flex-start;
|
|
1930
2036
|
border: none;
|
|
@@ -1935,12 +2041,17 @@ var SubmitButton = import_styled4.default.button`
|
|
|
1935
2041
|
font-weight: 700;
|
|
1936
2042
|
padding: 10px 14px;
|
|
1937
2043
|
cursor: pointer;
|
|
2044
|
+
|
|
2045
|
+
&:disabled {
|
|
2046
|
+
cursor: default;
|
|
2047
|
+
opacity: 0.72;
|
|
2048
|
+
}
|
|
1938
2049
|
`;
|
|
1939
2050
|
|
|
1940
|
-
// src/components/chat-thread/components/
|
|
2051
|
+
// src/components/chat-thread/components/result-summary-card.tsx
|
|
1941
2052
|
var import_styled5 = __toESM(require("@emotion/styled"));
|
|
1942
2053
|
var import_jsx_runtime6 = require("@emotion/react/jsx-runtime");
|
|
1943
|
-
var
|
|
2054
|
+
var ResultSummaryCard = ({ summary }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Card5, { "data-testid": "result-summary-card", "data-status": summary.status, children: [
|
|
1944
2055
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Eyebrow2, { children: summary.status }),
|
|
1945
2056
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Headline, { children: summary.headline }),
|
|
1946
2057
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Details, { children: summary.details.map((detail) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Detail, { children: detail }, detail)) })
|
|
@@ -2036,6 +2147,7 @@ var ImageViewer = ({ src, alt, onClose }) => {
|
|
|
2036
2147
|
var import_jsx_runtime8 = require("@emotion/react/jsx-runtime");
|
|
2037
2148
|
var MARKDOWN_REMARK_PLUGINS = [import_remark_gfm.default, import_remark_math.default];
|
|
2038
2149
|
var MARKDOWN_REHYPE_PLUGINS = [import_rehype_katex.default];
|
|
2150
|
+
var USER_MESSAGE_COLLAPSE_HEIGHT_PX = 120;
|
|
2039
2151
|
var MARKDOWN_COMPONENTS = {
|
|
2040
2152
|
table: ({ node: _node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TableWrapper, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("table", { ...props }) })
|
|
2041
2153
|
};
|
|
@@ -2048,10 +2160,101 @@ var renderMarkdownContent = (content) => /* @__PURE__ */ (0, import_jsx_runtime8
|
|
|
2048
2160
|
children: content
|
|
2049
2161
|
}
|
|
2050
2162
|
);
|
|
2163
|
+
var renderPlainTextContent = (content) => content;
|
|
2164
|
+
var CollapseIcon = ({ expanded }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2165
|
+
"svg",
|
|
2166
|
+
{
|
|
2167
|
+
"aria-hidden": "true",
|
|
2168
|
+
width: "16",
|
|
2169
|
+
height: "16",
|
|
2170
|
+
viewBox: "0 0 16 16",
|
|
2171
|
+
fill: "none",
|
|
2172
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2173
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2174
|
+
"path",
|
|
2175
|
+
{
|
|
2176
|
+
d: "M4 6l4 4 4-4",
|
|
2177
|
+
stroke: "currentColor",
|
|
2178
|
+
strokeWidth: "1.6",
|
|
2179
|
+
strokeLinecap: "round",
|
|
2180
|
+
strokeLinejoin: "round",
|
|
2181
|
+
transform: expanded ? "rotate(180 8 8)" : void 0
|
|
2182
|
+
}
|
|
2183
|
+
)
|
|
2184
|
+
}
|
|
2185
|
+
);
|
|
2186
|
+
var useUserMessageCollapse = ({
|
|
2187
|
+
blocks,
|
|
2188
|
+
displayedBlocks,
|
|
2189
|
+
displayedContent,
|
|
2190
|
+
enabled,
|
|
2191
|
+
freshContent,
|
|
2192
|
+
settledContent
|
|
2193
|
+
}) => {
|
|
2194
|
+
const [isCollapsible, setIsCollapsible] = (0, import_react9.useState)(false);
|
|
2195
|
+
const [isExpanded, setIsExpanded] = (0, import_react9.useState)(false);
|
|
2196
|
+
const [bodyStackElement, setBodyStackElement] = (0, import_react9.useState)(null);
|
|
2197
|
+
const syncCollapseState = (0, import_react9.useCallback)(
|
|
2198
|
+
(element) => {
|
|
2199
|
+
const nextCollapsible = enabled && (element?.scrollHeight ?? 0) > USER_MESSAGE_COLLAPSE_HEIGHT_PX;
|
|
2200
|
+
setIsCollapsible(nextCollapsible);
|
|
2201
|
+
if (!nextCollapsible) {
|
|
2202
|
+
setIsExpanded(false);
|
|
2203
|
+
}
|
|
2204
|
+
},
|
|
2205
|
+
[enabled]
|
|
2206
|
+
);
|
|
2207
|
+
const bodyStackRef = (0, import_react9.useCallback)(
|
|
2208
|
+
(node) => {
|
|
2209
|
+
setBodyStackElement(node);
|
|
2210
|
+
syncCollapseState(node);
|
|
2211
|
+
},
|
|
2212
|
+
[syncCollapseState]
|
|
2213
|
+
);
|
|
2214
|
+
(0, import_react9.useLayoutEffect)(() => {
|
|
2215
|
+
if (!bodyStackElement) {
|
|
2216
|
+
return;
|
|
2217
|
+
}
|
|
2218
|
+
const frameId = requestAnimationFrame(() => {
|
|
2219
|
+
syncCollapseState(bodyStackElement);
|
|
2220
|
+
});
|
|
2221
|
+
return () => {
|
|
2222
|
+
cancelAnimationFrame(frameId);
|
|
2223
|
+
};
|
|
2224
|
+
}, [
|
|
2225
|
+
blocks,
|
|
2226
|
+
bodyStackElement,
|
|
2227
|
+
displayedBlocks,
|
|
2228
|
+
displayedContent,
|
|
2229
|
+
enabled,
|
|
2230
|
+
freshContent,
|
|
2231
|
+
settledContent,
|
|
2232
|
+
syncCollapseState
|
|
2233
|
+
]);
|
|
2234
|
+
(0, import_react9.useLayoutEffect)(() => {
|
|
2235
|
+
if (!bodyStackElement || !enabled || typeof ResizeObserver === "undefined") {
|
|
2236
|
+
return;
|
|
2237
|
+
}
|
|
2238
|
+
const observer = new ResizeObserver(() => {
|
|
2239
|
+
syncCollapseState(bodyStackElement);
|
|
2240
|
+
});
|
|
2241
|
+
observer.observe(bodyStackElement);
|
|
2242
|
+
return () => {
|
|
2243
|
+
observer.disconnect();
|
|
2244
|
+
};
|
|
2245
|
+
}, [bodyStackElement, enabled, syncCollapseState]);
|
|
2246
|
+
return {
|
|
2247
|
+
bodyStackRef,
|
|
2248
|
+
isCollapsed: isCollapsible && !isExpanded,
|
|
2249
|
+
isCollapsible,
|
|
2250
|
+
isExpanded,
|
|
2251
|
+
toggleExpanded: () => setIsExpanded((current) => !current)
|
|
2252
|
+
};
|
|
2253
|
+
};
|
|
2051
2254
|
var createExecutionConfirmationContent = (proposal) => [
|
|
2052
2255
|
"Execution confirmed",
|
|
2053
|
-
`- Equation: ${proposal.
|
|
2054
|
-
...proposal.
|
|
2256
|
+
`- Equation: ${proposal.resourceName}`,
|
|
2257
|
+
...proposal.executorName ? [`- Solver: ${proposal.executorName}`] : [],
|
|
2055
2258
|
`- Proposal ID: ${proposal.proposalId}`
|
|
2056
2259
|
].join("\n");
|
|
2057
2260
|
var areChatAttachmentsEqual = (previousAttachments, nextAttachments) => {
|
|
@@ -2073,10 +2276,10 @@ var areParameterSummaryItemsEqual = (previousItems, nextItems) => previousItems.
|
|
|
2073
2276
|
const nextItem = nextItems[index];
|
|
2074
2277
|
return item.label === nextItem?.label && item.value === nextItem.value && item.fieldPath === nextItem.fieldPath;
|
|
2075
2278
|
});
|
|
2076
|
-
var areExecutionProposalsEqual = (previousProposal, nextProposal) => previousProposal.proposalId === nextProposal.proposalId && previousProposal.
|
|
2279
|
+
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
2280
|
(warning, index) => warning === nextProposal.warnings?.[index]
|
|
2078
2281
|
);
|
|
2079
|
-
var areResultSummariesEqual = (previousSummary, nextSummary) => previousSummary.
|
|
2282
|
+
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
2283
|
var areStringArraysEqual = (previousValues, nextValues) => previousValues.length === nextValues.length && previousValues.every((value, index) => value === nextValues[index]);
|
|
2081
2284
|
var areQuestionAnswersEqual = (previousAnswer, nextAnswer) => {
|
|
2082
2285
|
if (Array.isArray(previousAnswer) || Array.isArray(nextAnswer)) {
|
|
@@ -2117,7 +2320,7 @@ var arePlanQuestionsEqual = (previousQuestion, nextQuestion) => {
|
|
|
2117
2320
|
return false;
|
|
2118
2321
|
}
|
|
2119
2322
|
};
|
|
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(
|
|
2323
|
+
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
2324
|
(question, index) => arePlanQuestionsEqual(question, nextQuestionnaire.questions[index])
|
|
2122
2325
|
) && areQuestionAnswerMapsEqual(previousQuestionnaire.answers, nextQuestionnaire.answers);
|
|
2123
2326
|
var areMessageBlocksEqual = (previousBlocks, nextBlocks) => {
|
|
@@ -2198,6 +2401,8 @@ var ChatMessageItemView = ({
|
|
|
2198
2401
|
const canSubmitConfirmation = isPlanMode && typeof onConfirmationSubmit === "function";
|
|
2199
2402
|
const canSubmitQuestionnaire = isPlanMode && typeof onQuestionnaireSubmit === "function";
|
|
2200
2403
|
const shouldShowStreamingCaret = isAssistantStreaming && (!shouldRenderStructuredBlocks || hasTextContent);
|
|
2404
|
+
const isUserMessage = message.role === "user";
|
|
2405
|
+
const messageRenderMode = isUserMessage ? "plain-text" : "markdown";
|
|
2201
2406
|
const timelineConsumedText = messageRenderOrder === "timeline" ? getTimelineConsumedText(blocks) : "";
|
|
2202
2407
|
const hasConsumedTimelineText = timelineConsumedText.length > 0 && displayedContent.startsWith(timelineConsumedText);
|
|
2203
2408
|
const timelineDisplayedContent = hasConsumedTimelineText ? displayedContent.slice(timelineConsumedText.length) : displayedContent;
|
|
@@ -2214,6 +2419,21 @@ var ChatMessageItemView = ({
|
|
|
2214
2419
|
message,
|
|
2215
2420
|
messageRenderOrder
|
|
2216
2421
|
});
|
|
2422
|
+
const {
|
|
2423
|
+
bodyStackRef,
|
|
2424
|
+
isCollapsed: isUserMessageCollapsed,
|
|
2425
|
+
isCollapsible: isUserMessageCollapsible,
|
|
2426
|
+
isExpanded: isUserMessageExpanded,
|
|
2427
|
+
toggleExpanded: toggleUserMessageExpanded
|
|
2428
|
+
} = useUserMessageCollapse({
|
|
2429
|
+
blocks,
|
|
2430
|
+
displayedBlocks,
|
|
2431
|
+
displayedContent,
|
|
2432
|
+
enabled: isUserMessage,
|
|
2433
|
+
freshContent,
|
|
2434
|
+
settledContent
|
|
2435
|
+
});
|
|
2436
|
+
const renderMessageContent = (content) => messageRenderMode === "plain-text" ? renderPlainTextContent(content) : renderMarkdownContent(content);
|
|
2217
2437
|
const renderChatMessageBlock = (block, index) => {
|
|
2218
2438
|
switch (block.type) {
|
|
2219
2439
|
case "markdown":
|
|
@@ -2222,17 +2442,18 @@ var ChatMessageItemView = ({
|
|
|
2222
2442
|
{
|
|
2223
2443
|
"data-testid": `chat-message-block-${index}`,
|
|
2224
2444
|
"data-block-tone": "settled",
|
|
2225
|
-
|
|
2445
|
+
"data-render-mode": messageRenderMode,
|
|
2446
|
+
children: renderMessageContent(block.text)
|
|
2226
2447
|
},
|
|
2227
2448
|
`markdown-${index}`
|
|
2228
2449
|
);
|
|
2229
2450
|
case "notice":
|
|
2230
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2451
|
+
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
2452
|
case "parameter_summary":
|
|
2232
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2453
|
+
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
2454
|
case "confirmation_card":
|
|
2234
2455
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2235
|
-
|
|
2456
|
+
ExecutionConfirmationCard,
|
|
2236
2457
|
{
|
|
2237
2458
|
proposal: block.proposal,
|
|
2238
2459
|
interactive: isPlanMode,
|
|
@@ -2244,13 +2465,19 @@ var ChatMessageItemView = ({
|
|
|
2244
2465
|
}
|
|
2245
2466
|
) }, `confirmation-card-${index}`);
|
|
2246
2467
|
case "result_summary":
|
|
2247
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2468
|
+
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
2469
|
case "questionnaire":
|
|
2249
2470
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2250
|
-
|
|
2471
|
+
QuestionnaireCard,
|
|
2251
2472
|
{
|
|
2252
2473
|
questionnaire: block.questionnaire,
|
|
2253
2474
|
interactive: canSubmitQuestionnaire,
|
|
2475
|
+
labels: {
|
|
2476
|
+
submitting: labels.questionnaireSubmitting,
|
|
2477
|
+
submitted: labels.questionnaireSubmitted,
|
|
2478
|
+
validationPrefix: labels.questionnaireValidationPrefix,
|
|
2479
|
+
submitFailed: labels.questionnaireSubmitFailed
|
|
2480
|
+
},
|
|
2254
2481
|
onSubmit: canSubmitQuestionnaire ? (submission) => onQuestionnaireSubmit({
|
|
2255
2482
|
...submission,
|
|
2256
2483
|
sourceMessageId: message.id
|
|
@@ -2283,14 +2510,31 @@ var ChatMessageItemView = ({
|
|
|
2283
2510
|
"data-testid": block.tone === "fresh" ? "chat-message-fresh-block" : "chat-message-settled-block",
|
|
2284
2511
|
"data-block-tone": block.tone,
|
|
2285
2512
|
"data-block-index": index,
|
|
2286
|
-
|
|
2513
|
+
"data-render-mode": messageRenderMode,
|
|
2514
|
+
children: renderMessageContent(block.content)
|
|
2287
2515
|
},
|
|
2288
2516
|
`${block.tone}-${index}`
|
|
2289
2517
|
)),
|
|
2290
|
-
!textBlocks.some((block) => block.content) && !settledText && !freshText && Boolean(textContent) ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2518
|
+
!textBlocks.some((block) => block.content) && !settledText && !freshText && Boolean(textContent) ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2519
|
+
ContentBlock,
|
|
2520
|
+
{
|
|
2521
|
+
"data-testid": "chat-message-settled-block",
|
|
2522
|
+
"data-block-tone": "settled",
|
|
2523
|
+
"data-render-mode": messageRenderMode,
|
|
2524
|
+
children: renderMessageContent(textContent)
|
|
2525
|
+
}
|
|
2526
|
+
) : null
|
|
2291
2527
|
] });
|
|
2292
2528
|
};
|
|
2293
|
-
const renderStaticTextSegment = (content) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2529
|
+
const renderStaticTextSegment = (content) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2530
|
+
ContentBlock,
|
|
2531
|
+
{
|
|
2532
|
+
"data-testid": "chat-message-settled-block",
|
|
2533
|
+
"data-block-tone": "settled",
|
|
2534
|
+
"data-render-mode": messageRenderMode,
|
|
2535
|
+
children: renderMessageContent(content)
|
|
2536
|
+
}
|
|
2537
|
+
);
|
|
2294
2538
|
const bodySegments = (() => {
|
|
2295
2539
|
if (!shouldRenderStructuredBlocks && hasTextContent) {
|
|
2296
2540
|
return [{ type: "text" }];
|
|
@@ -2348,21 +2592,40 @@ var ChatMessageItemView = ({
|
|
|
2348
2592
|
}
|
|
2349
2593
|
) : null,
|
|
2350
2594
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Role, { children: message.role === "user" ? labels.userRoleLabel : labels.assistantRoleLabel }),
|
|
2595
|
+
isUserMessageCollapsible ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2596
|
+
CollapseToggle,
|
|
2597
|
+
{
|
|
2598
|
+
type: "button",
|
|
2599
|
+
"data-testid": "chat-message-collapse-toggle",
|
|
2600
|
+
"aria-label": isUserMessageExpanded ? labels.collapseMessageAriaLabel : labels.expandMessageAriaLabel,
|
|
2601
|
+
"aria-expanded": isUserMessageExpanded,
|
|
2602
|
+
onClick: toggleUserMessageExpanded,
|
|
2603
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CollapseIcon, { expanded: isUserMessageExpanded })
|
|
2604
|
+
}
|
|
2605
|
+
) : null,
|
|
2351
2606
|
isStoppedAssistant ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StatusTag, { "data-testid": "chat-message-stopped-tag", children: labels.stoppedResponse }) : null
|
|
2352
2607
|
] }),
|
|
2353
2608
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Content, { "data-testid": "chat-message-content", children: [
|
|
2354
|
-
shouldRenderStructuredBlocks || hasTextContent ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2355
|
-
|
|
2609
|
+
shouldRenderStructuredBlocks || hasTextContent ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2610
|
+
ContentStack,
|
|
2356
2611
|
{
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2612
|
+
ref: bodyStackRef,
|
|
2613
|
+
"data-testid": "chat-message-body-stack",
|
|
2614
|
+
"data-collapsed": isUserMessageCollapsed,
|
|
2615
|
+
children: bodySegments.map((segment, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2616
|
+
ContentSegment,
|
|
2617
|
+
{
|
|
2618
|
+
"data-testid": "chat-message-content-segment",
|
|
2619
|
+
children: segment.type === "block" ? renderChatMessageBlock(segment.block, segment.index) : segment.type === "text" ? segment.content !== void 0 ? segment.useTimelineSegmentation ? renderTextContent({
|
|
2620
|
+
content: segment.content,
|
|
2621
|
+
displayedBlocks: segment.displayedBlocks,
|
|
2622
|
+
useTimelineSegmentation: true
|
|
2623
|
+
}) : renderStaticTextSegment(segment.content) : renderTextContent() : renderStaticTextSegment(segment.content)
|
|
2624
|
+
},
|
|
2625
|
+
segment.type === "text" ? `text-${index}` : segment.type === "markdown" ? `markdown-${index}` : `${segment.block.type}-${segment.index}`
|
|
2626
|
+
))
|
|
2627
|
+
}
|
|
2628
|
+
) : null,
|
|
2366
2629
|
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
2630
|
AttachmentButton,
|
|
2368
2631
|
{
|
|
@@ -2447,6 +2710,29 @@ var StatusTag = import_styled7.default.span`
|
|
|
2447
2710
|
letter-spacing: 0.02em;
|
|
2448
2711
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
|
|
2449
2712
|
`;
|
|
2713
|
+
var CollapseToggle = import_styled7.default.button`
|
|
2714
|
+
margin-left: auto;
|
|
2715
|
+
width: 28px;
|
|
2716
|
+
height: 28px;
|
|
2717
|
+
display: inline-flex;
|
|
2718
|
+
align-items: center;
|
|
2719
|
+
justify-content: center;
|
|
2720
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
2721
|
+
border-radius: 999px;
|
|
2722
|
+
background: rgba(255, 255, 255, 0.06);
|
|
2723
|
+
color: rgba(255, 255, 255, 0.72);
|
|
2724
|
+
cursor: pointer;
|
|
2725
|
+
transition:
|
|
2726
|
+
background 160ms ease-out,
|
|
2727
|
+
border-color 160ms ease-out,
|
|
2728
|
+
color 160ms ease-out;
|
|
2729
|
+
|
|
2730
|
+
&:hover {
|
|
2731
|
+
background: rgba(255, 255, 255, 0.1);
|
|
2732
|
+
border-color: rgba(255, 255, 255, 0.18);
|
|
2733
|
+
color: rgba(255, 255, 255, 0.92);
|
|
2734
|
+
}
|
|
2735
|
+
`;
|
|
2450
2736
|
var Content = import_styled7.default.div`
|
|
2451
2737
|
color: rgba(255, 255, 255, 0.92);
|
|
2452
2738
|
line-height: 1.6;
|
|
@@ -2491,6 +2777,11 @@ var ContentStack = import_styled7.default.div`
|
|
|
2491
2777
|
display: flex;
|
|
2492
2778
|
flex-direction: column;
|
|
2493
2779
|
gap: 16px;
|
|
2780
|
+
|
|
2781
|
+
&[data-collapsed='true'] {
|
|
2782
|
+
max-height: ${USER_MESSAGE_COLLAPSE_HEIGHT_PX}px;
|
|
2783
|
+
overflow: hidden;
|
|
2784
|
+
}
|
|
2494
2785
|
`;
|
|
2495
2786
|
var ContentSegment = import_styled7.default.div`
|
|
2496
2787
|
min-width: 0;
|
|
@@ -2504,6 +2795,11 @@ var ContentBlock = import_styled7.default.div`
|
|
|
2504
2795
|
margin-top: 16px;
|
|
2505
2796
|
}
|
|
2506
2797
|
|
|
2798
|
+
&[data-render-mode='plain-text'] {
|
|
2799
|
+
white-space: pre-wrap;
|
|
2800
|
+
overflow-wrap: anywhere;
|
|
2801
|
+
}
|
|
2802
|
+
|
|
2507
2803
|
&[data-block-tone='fresh'] {
|
|
2508
2804
|
opacity: 0.85;
|
|
2509
2805
|
filter: brightness(0.82) saturate(0.88);
|
|
@@ -2911,7 +3207,14 @@ var ChatThread = () => {
|
|
|
2911
3207
|
const error = useChatStore((s) => s.errorBySession[s.activeSessionId ?? ""]);
|
|
2912
3208
|
const updateQA = useChatStore((s) => s.updateQuestionnaireAnswers);
|
|
2913
3209
|
const clearSessionError = useChatStore((s) => s.clearSessionError);
|
|
2914
|
-
const {
|
|
3210
|
+
const {
|
|
3211
|
+
sendRef,
|
|
3212
|
+
retryRef,
|
|
3213
|
+
renderMessageBlock,
|
|
3214
|
+
handleQuestionnaireSubmit: customQuestionnaireSubmit,
|
|
3215
|
+
handleConfirmationSubmit: customConfirmationSubmit,
|
|
3216
|
+
labels
|
|
3217
|
+
} = useChatContext();
|
|
2915
3218
|
const handleRetry = (0, import_react11.useCallback)(() => {
|
|
2916
3219
|
if (!activeSessionId)
|
|
2917
3220
|
return;
|
|
@@ -2919,7 +3222,25 @@ var ChatThread = () => {
|
|
|
2919
3222
|
void retryRef.current();
|
|
2920
3223
|
}, [activeSessionId, clearSessionError, retryRef]);
|
|
2921
3224
|
const handleQuestionnaireSubmit = (0, import_react11.useCallback)(
|
|
2922
|
-
(submission) => {
|
|
3225
|
+
async (submission) => {
|
|
3226
|
+
if (customQuestionnaireSubmit) {
|
|
3227
|
+
const handled = await customQuestionnaireSubmit(submission, {
|
|
3228
|
+
sessionId: activeSessionId ?? void 0,
|
|
3229
|
+
mode: activeSessionMode
|
|
3230
|
+
});
|
|
3231
|
+
if (handled !== false) {
|
|
3232
|
+
if (activeSessionId && submission.sourceMessageId) {
|
|
3233
|
+
updateQA(
|
|
3234
|
+
activeSessionId,
|
|
3235
|
+
submission.sourceMessageId,
|
|
3236
|
+
submission.questionnaireId,
|
|
3237
|
+
submission.answers
|
|
3238
|
+
);
|
|
3239
|
+
}
|
|
3240
|
+
return;
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
await sendRef.current(submission.content);
|
|
2923
3244
|
if (activeSessionId && submission.sourceMessageId) {
|
|
2924
3245
|
updateQA(
|
|
2925
3246
|
activeSessionId,
|
|
@@ -2928,15 +3249,23 @@ var ChatThread = () => {
|
|
|
2928
3249
|
submission.answers
|
|
2929
3250
|
);
|
|
2930
3251
|
}
|
|
2931
|
-
void sendRef.current(submission.content);
|
|
2932
3252
|
},
|
|
2933
|
-
[activeSessionId, updateQA, sendRef]
|
|
3253
|
+
[activeSessionId, activeSessionMode, updateQA, sendRef, customQuestionnaireSubmit]
|
|
2934
3254
|
);
|
|
2935
|
-
const
|
|
2936
|
-
(submission) => {
|
|
2937
|
-
|
|
3255
|
+
const handleConfirmation = (0, import_react11.useCallback)(
|
|
3256
|
+
async (submission) => {
|
|
3257
|
+
if (customConfirmationSubmit) {
|
|
3258
|
+
const handled = await customConfirmationSubmit(submission, {
|
|
3259
|
+
sessionId: activeSessionId ?? void 0,
|
|
3260
|
+
mode: activeSessionMode
|
|
3261
|
+
});
|
|
3262
|
+
if (handled !== false) {
|
|
3263
|
+
return;
|
|
3264
|
+
}
|
|
3265
|
+
}
|
|
3266
|
+
await sendRef.current(submission.content);
|
|
2938
3267
|
},
|
|
2939
|
-
[sendRef]
|
|
3268
|
+
[activeSessionId, activeSessionMode, sendRef, customConfirmationSubmit]
|
|
2940
3269
|
);
|
|
2941
3270
|
if (!hasSessions || messages.length === 0 && !streamingMessage) {
|
|
2942
3271
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ChatThreadEmptyState, {});
|
|
@@ -2950,7 +3279,7 @@ var ChatThread = () => {
|
|
|
2950
3279
|
error,
|
|
2951
3280
|
retryButtonLabel: labels.retryButton,
|
|
2952
3281
|
onRetry: handleRetry,
|
|
2953
|
-
onConfirmationSubmit:
|
|
3282
|
+
onConfirmationSubmit: handleConfirmation,
|
|
2954
3283
|
onQuestionnaireSubmit: handleQuestionnaireSubmit,
|
|
2955
3284
|
renderMessageBlock
|
|
2956
3285
|
}
|
|
@@ -2964,6 +3293,7 @@ var Container = import_styled9.default.div`
|
|
|
2964
3293
|
min-height: 0;
|
|
2965
3294
|
overflow: auto;
|
|
2966
3295
|
padding: 24px;
|
|
3296
|
+
margin-bottom: 24px;
|
|
2967
3297
|
overscroll-behavior: contain;
|
|
2968
3298
|
|
|
2969
3299
|
&::-webkit-scrollbar {
|
|
@@ -4043,6 +4373,27 @@ var StopSpinner = import_styled13.default.span`
|
|
|
4043
4373
|
|
|
4044
4374
|
// src/components/chat-composer/index.tsx
|
|
4045
4375
|
var import_jsx_runtime15 = require("@emotion/react/jsx-runtime");
|
|
4376
|
+
var CHAT_COMPOSER_LINE_HEIGHT_PX = 20;
|
|
4377
|
+
var CHAT_COMPOSER_MAX_ROWS = 7;
|
|
4378
|
+
var CHAT_COMPOSER_PADDING_TOP_PX = 8;
|
|
4379
|
+
var CHAT_COMPOSER_PADDING_BOTTOM_PX = 12;
|
|
4380
|
+
var CHAT_COMPOSER_PADDING_BLOCK_PX = CHAT_COMPOSER_PADDING_TOP_PX + CHAT_COMPOSER_PADDING_BOTTOM_PX;
|
|
4381
|
+
var CHAT_COMPOSER_MIN_ROWS = 4;
|
|
4382
|
+
var CHAT_COMPOSER_EXPANDED_MAX_ROWS = 60;
|
|
4383
|
+
var CHAT_COMPOSER_EXPANDED_MAX_VIEWPORT_RATIO = 0.7;
|
|
4384
|
+
var CHAT_COMPOSER_EXPANDED_RESERVED_SPACE_PX = 96;
|
|
4385
|
+
var CHAT_COMPOSER_MAX_HEIGHT_PX = CHAT_COMPOSER_MAX_ROWS * CHAT_COMPOSER_LINE_HEIGHT_PX + CHAT_COMPOSER_PADDING_BLOCK_PX;
|
|
4386
|
+
var CHAT_COMPOSER_EXPANDED_ROWS_HEIGHT_PX = CHAT_COMPOSER_EXPANDED_MAX_ROWS * CHAT_COMPOSER_LINE_HEIGHT_PX + CHAT_COMPOSER_PADDING_BLOCK_PX;
|
|
4387
|
+
var getExpandedComposerHeightPx = () => {
|
|
4388
|
+
if (typeof window === "undefined") {
|
|
4389
|
+
return CHAT_COMPOSER_EXPANDED_ROWS_HEIGHT_PX;
|
|
4390
|
+
}
|
|
4391
|
+
const viewportLimitedHeight = window.innerHeight * CHAT_COMPOSER_EXPANDED_MAX_VIEWPORT_RATIO - CHAT_COMPOSER_EXPANDED_RESERVED_SPACE_PX;
|
|
4392
|
+
return Math.max(
|
|
4393
|
+
CHAT_COMPOSER_MAX_HEIGHT_PX,
|
|
4394
|
+
Math.floor(Math.min(CHAT_COMPOSER_EXPANDED_ROWS_HEIGHT_PX, viewportLimitedHeight))
|
|
4395
|
+
);
|
|
4396
|
+
};
|
|
4046
4397
|
var PlusIcon = () => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4047
4398
|
"svg",
|
|
4048
4399
|
{
|
|
@@ -4055,6 +4406,36 @@ var PlusIcon = () => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
|
4055
4406
|
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M8 3v10M3 8h10", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round" })
|
|
4056
4407
|
}
|
|
4057
4408
|
);
|
|
4409
|
+
var ComposerExpandIcon = ({ expanded }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4410
|
+
"svg",
|
|
4411
|
+
{
|
|
4412
|
+
"aria-hidden": "true",
|
|
4413
|
+
width: "16",
|
|
4414
|
+
height: "16",
|
|
4415
|
+
viewBox: "0 0 16 16",
|
|
4416
|
+
fill: "none",
|
|
4417
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4418
|
+
children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4419
|
+
"path",
|
|
4420
|
+
{
|
|
4421
|
+
d: "M14 6h-4V2M10 6l4-4M2 10h4v4M6 10l-4 4",
|
|
4422
|
+
stroke: "currentColor",
|
|
4423
|
+
strokeWidth: "1.5",
|
|
4424
|
+
strokeLinecap: "round",
|
|
4425
|
+
strokeLinejoin: "round"
|
|
4426
|
+
}
|
|
4427
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4428
|
+
"path",
|
|
4429
|
+
{
|
|
4430
|
+
d: "M10 2h4v4M14 2L9 7M6 14H2v-4M2 14l5-5",
|
|
4431
|
+
stroke: "currentColor",
|
|
4432
|
+
strokeWidth: "1.5",
|
|
4433
|
+
strokeLinecap: "round",
|
|
4434
|
+
strokeLinejoin: "round"
|
|
4435
|
+
}
|
|
4436
|
+
)
|
|
4437
|
+
}
|
|
4438
|
+
);
|
|
4058
4439
|
var ChatComposerView = ({
|
|
4059
4440
|
value,
|
|
4060
4441
|
placeholder,
|
|
@@ -4071,6 +4452,8 @@ var ChatComposerView = ({
|
|
|
4071
4452
|
isStopping,
|
|
4072
4453
|
enableImageAttachments,
|
|
4073
4454
|
modeLabels,
|
|
4455
|
+
expandComposerAriaLabel,
|
|
4456
|
+
collapseComposerAriaLabel,
|
|
4074
4457
|
onValueChange,
|
|
4075
4458
|
onPickImages,
|
|
4076
4459
|
onPasteImages,
|
|
@@ -4082,6 +4465,9 @@ var ChatComposerView = ({
|
|
|
4082
4465
|
onSend
|
|
4083
4466
|
}) => {
|
|
4084
4467
|
const imageInputRef = (0, import_react15.useRef)(null);
|
|
4468
|
+
const inputRef = (0, import_react15.useRef)(null);
|
|
4469
|
+
const [isComposerExpandable, setIsComposerExpandable] = (0, import_react15.useState)(false);
|
|
4470
|
+
const [isComposerExpanded, setIsComposerExpanded] = (0, import_react15.useState)(false);
|
|
4085
4471
|
const canSend = canSendChatMessage({
|
|
4086
4472
|
value,
|
|
4087
4473
|
attachmentCount: attachments.length,
|
|
@@ -4089,6 +4475,26 @@ var ChatComposerView = ({
|
|
|
4089
4475
|
isModelsError,
|
|
4090
4476
|
hasModels
|
|
4091
4477
|
});
|
|
4478
|
+
(0, import_react15.useLayoutEffect)(() => {
|
|
4479
|
+
const element = inputRef.current;
|
|
4480
|
+
if (!element) {
|
|
4481
|
+
return;
|
|
4482
|
+
}
|
|
4483
|
+
if (!isComposerExpanded) {
|
|
4484
|
+
element.style.height = "0px";
|
|
4485
|
+
}
|
|
4486
|
+
const scrollHeight = element.scrollHeight;
|
|
4487
|
+
const nextExpandable = scrollHeight > CHAT_COMPOSER_MAX_HEIGHT_PX;
|
|
4488
|
+
const expandedHeight = getExpandedComposerHeightPx();
|
|
4489
|
+
const nextHeight = isComposerExpanded ? expandedHeight : Math.min(scrollHeight, CHAT_COMPOSER_MAX_HEIGHT_PX);
|
|
4490
|
+
setIsComposerExpandable(nextExpandable);
|
|
4491
|
+
element.style.height = `${nextHeight}px`;
|
|
4492
|
+
element.style.overflowY = !isComposerExpanded && scrollHeight > CHAT_COMPOSER_MAX_HEIGHT_PX ? "auto" : "hidden";
|
|
4493
|
+
}, [isComposerExpanded, value]);
|
|
4494
|
+
const handleSend = async () => {
|
|
4495
|
+
setIsComposerExpanded(false);
|
|
4496
|
+
await onSend();
|
|
4497
|
+
};
|
|
4092
4498
|
const handleKeyDown = (event) => {
|
|
4093
4499
|
if (shouldStopChatComposer({ key: event.key, shiftKey: event.shiftKey, isStreaming })) {
|
|
4094
4500
|
event.preventDefault();
|
|
@@ -4098,7 +4504,7 @@ var ChatComposerView = ({
|
|
|
4098
4504
|
if (!shouldSubmitChatComposer({ key: event.key, shiftKey: event.shiftKey, canSend }))
|
|
4099
4505
|
return;
|
|
4100
4506
|
event.preventDefault();
|
|
4101
|
-
void
|
|
4507
|
+
void handleSend();
|
|
4102
4508
|
};
|
|
4103
4509
|
const handlePickImages = (event) => {
|
|
4104
4510
|
if (event.target.files?.length)
|
|
@@ -4133,60 +4539,77 @@ var ChatComposerView = ({
|
|
|
4133
4539
|
}
|
|
4134
4540
|
),
|
|
4135
4541
|
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,
|
|
4542
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(InputArea, { "data-testid": "chat-composer-input-area", children: [
|
|
4543
|
+
isComposerExpanded || isComposerExpandable ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4544
|
+
ComposerExpandButton,
|
|
4150
4545
|
{
|
|
4151
4546
|
type: "button",
|
|
4152
|
-
"data-testid": "chat-composer-
|
|
4153
|
-
"aria-label":
|
|
4154
|
-
|
|
4155
|
-
|
|
4547
|
+
"data-testid": "chat-composer-expand-toggle",
|
|
4548
|
+
"aria-label": isComposerExpanded ? collapseComposerAriaLabel : expandComposerAriaLabel,
|
|
4549
|
+
"aria-expanded": isComposerExpanded,
|
|
4550
|
+
onClick: () => setIsComposerExpanded((current) => !current),
|
|
4551
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ComposerExpandIcon, { expanded: isComposerExpanded })
|
|
4156
4552
|
}
|
|
4157
4553
|
) : null,
|
|
4158
4554
|
/* @__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,
|
|
4555
|
+
Input,
|
|
4169
4556
|
{
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4557
|
+
ref: inputRef,
|
|
4558
|
+
"data-testid": "chat-composer-input",
|
|
4559
|
+
"data-expanded": isComposerExpanded,
|
|
4560
|
+
value,
|
|
4561
|
+
onChange: (event) => onValueChange(event.target.value),
|
|
4562
|
+
onKeyDown: handleKeyDown,
|
|
4563
|
+
onPaste: enableImageAttachments ? handlePaste : void 0,
|
|
4564
|
+
placeholder
|
|
4177
4565
|
}
|
|
4178
|
-
)
|
|
4179
|
-
|
|
4180
|
-
|
|
4566
|
+
)
|
|
4567
|
+
] }),
|
|
4568
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Footer, { children: [
|
|
4569
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(LeadingActions, { "data-testid": "chat-composer-leading-actions", children: enableImageAttachments ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4570
|
+
AttachButton,
|
|
4181
4571
|
{
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4572
|
+
type: "button",
|
|
4573
|
+
"data-testid": "chat-composer-attach-image",
|
|
4574
|
+
"aria-label": "Attach image",
|
|
4575
|
+
onClick: () => imageInputRef.current?.click(),
|
|
4576
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PlusIcon, {})
|
|
4187
4577
|
}
|
|
4188
|
-
)
|
|
4189
|
-
|
|
4578
|
+
) : null }),
|
|
4579
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(TrailingActions, { "data-testid": "chat-composer-trailing-actions", children: [
|
|
4580
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4581
|
+
ChatModeControl,
|
|
4582
|
+
{
|
|
4583
|
+
value: selectedMode,
|
|
4584
|
+
disabled: isStreaming,
|
|
4585
|
+
labels: modeLabels,
|
|
4586
|
+
onChange: onSelectedModeChange
|
|
4587
|
+
}
|
|
4588
|
+
),
|
|
4589
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4590
|
+
ChatModelControl,
|
|
4591
|
+
{
|
|
4592
|
+
selectedModel,
|
|
4593
|
+
availableModels,
|
|
4594
|
+
isModelsLoading,
|
|
4595
|
+
isModelsError,
|
|
4596
|
+
hasModels,
|
|
4597
|
+
onSelectedModelChange,
|
|
4598
|
+
onReloadModels
|
|
4599
|
+
}
|
|
4600
|
+
),
|
|
4601
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4602
|
+
ChatSendActions,
|
|
4603
|
+
{
|
|
4604
|
+
canSend,
|
|
4605
|
+
isStreaming,
|
|
4606
|
+
isStopping,
|
|
4607
|
+
onStop,
|
|
4608
|
+
onSend: handleSend
|
|
4609
|
+
}
|
|
4610
|
+
)
|
|
4611
|
+
] })
|
|
4612
|
+
] })
|
|
4190
4613
|
] }) });
|
|
4191
4614
|
};
|
|
4192
4615
|
var ChatComposer = () => {
|
|
@@ -4222,6 +4645,8 @@ var ChatComposer = () => {
|
|
|
4222
4645
|
isStopping: state.isStopping,
|
|
4223
4646
|
enableImageAttachments,
|
|
4224
4647
|
modeLabels,
|
|
4648
|
+
expandComposerAriaLabel: labels.expandComposerAriaLabel,
|
|
4649
|
+
collapseComposerAriaLabel: labels.collapseComposerAriaLabel,
|
|
4225
4650
|
onValueChange: actions.setValue,
|
|
4226
4651
|
onPickImages: actions.pickImages,
|
|
4227
4652
|
onPasteImages: actions.pasteImages,
|
|
@@ -4238,6 +4663,16 @@ var Container2 = import_styled14.default.div`
|
|
|
4238
4663
|
padding: 0 16px 16px;
|
|
4239
4664
|
`;
|
|
4240
4665
|
var Surface = import_styled14.default.div`
|
|
4666
|
+
display: grid;
|
|
4667
|
+
grid-template-columns: minmax(0, 1fr);
|
|
4668
|
+
grid-template-areas:
|
|
4669
|
+
'attachments'
|
|
4670
|
+
'notice'
|
|
4671
|
+
'input'
|
|
4672
|
+
'footer';
|
|
4673
|
+
width: 100%;
|
|
4674
|
+
max-width: 760px;
|
|
4675
|
+
margin: 0 auto;
|
|
4241
4676
|
background: var(--border-color);
|
|
4242
4677
|
border-radius: 20px;
|
|
4243
4678
|
border: 1px solid var(--border-hover);
|
|
@@ -4247,6 +4682,7 @@ var Surface = import_styled14.default.div`
|
|
|
4247
4682
|
backdrop-filter: blur(10px);
|
|
4248
4683
|
`;
|
|
4249
4684
|
var AttachmentNotice = import_styled14.default.div`
|
|
4685
|
+
grid-area: notice;
|
|
4250
4686
|
margin: 10px 12px 0;
|
|
4251
4687
|
padding: 8px 10px;
|
|
4252
4688
|
border-radius: 10px;
|
|
@@ -4256,19 +4692,45 @@ var AttachmentNotice = import_styled14.default.div`
|
|
|
4256
4692
|
font-size: 12px;
|
|
4257
4693
|
line-height: 1.4;
|
|
4258
4694
|
`;
|
|
4695
|
+
var InputArea = import_styled14.default.div`
|
|
4696
|
+
grid-area: input;
|
|
4697
|
+
position: relative;
|
|
4698
|
+
`;
|
|
4259
4699
|
var Input = import_styled14.default.textarea`
|
|
4700
|
+
--textarea-line-height: ${CHAT_COMPOSER_LINE_HEIGHT_PX}px;
|
|
4701
|
+
--textarea-min-rows: ${CHAT_COMPOSER_MIN_ROWS};
|
|
4702
|
+
--textarea-max-rows: ${CHAT_COMPOSER_MAX_ROWS};
|
|
4703
|
+
--textarea-expanded-max-rows: ${CHAT_COMPOSER_EXPANDED_MAX_ROWS};
|
|
4704
|
+
--textarea-padding-top: ${CHAT_COMPOSER_PADDING_TOP_PX}px;
|
|
4705
|
+
--textarea-padding-bottom: ${CHAT_COMPOSER_PADDING_BOTTOM_PX}px;
|
|
4706
|
+
--textarea-padding-block: calc(var(--textarea-padding-top) + var(--textarea-padding-bottom));
|
|
4707
|
+
--textarea-max-height: calc(
|
|
4708
|
+
var(--textarea-max-rows) * var(--textarea-line-height) + var(--textarea-padding-block)
|
|
4709
|
+
);
|
|
4710
|
+
--textarea-expanded-max-height: min(
|
|
4711
|
+
calc(
|
|
4712
|
+
var(--textarea-expanded-max-rows) * var(--textarea-line-height) +
|
|
4713
|
+
var(--textarea-padding-block)
|
|
4714
|
+
),
|
|
4715
|
+
calc(70vh - ${CHAT_COMPOSER_EXPANDED_RESERVED_SPACE_PX}px)
|
|
4716
|
+
);
|
|
4260
4717
|
width: 100%;
|
|
4261
|
-
min-height:
|
|
4718
|
+
min-height: calc(
|
|
4719
|
+
var(--textarea-min-rows) * var(--textarea-line-height) + var(--textarea-padding-block)
|
|
4720
|
+
);
|
|
4721
|
+
max-height: var(--textarea-max-height);
|
|
4722
|
+
box-sizing: border-box;
|
|
4262
4723
|
resize: none;
|
|
4263
4724
|
appearance: none;
|
|
4264
4725
|
border: 0;
|
|
4265
4726
|
outline: 0;
|
|
4266
4727
|
background: transparent;
|
|
4267
|
-
padding:
|
|
4728
|
+
padding: var(--textarea-padding-top) 44px var(--textarea-padding-bottom) 12px;
|
|
4268
4729
|
font-weight: 400;
|
|
4269
4730
|
font-size: 14px;
|
|
4270
4731
|
color: var(--text-primary);
|
|
4271
|
-
line-height:
|
|
4732
|
+
line-height: var(--textarea-line-height);
|
|
4733
|
+
overflow-y: hidden;
|
|
4272
4734
|
|
|
4273
4735
|
&::placeholder {
|
|
4274
4736
|
color: var(--text-secondary);
|
|
@@ -4277,19 +4739,50 @@ var Input = import_styled14.default.textarea`
|
|
|
4277
4739
|
&::-webkit-resizer {
|
|
4278
4740
|
display: none;
|
|
4279
4741
|
}
|
|
4742
|
+
|
|
4743
|
+
&[data-expanded='true'] {
|
|
4744
|
+
max-height: var(--textarea-expanded-max-height);
|
|
4745
|
+
}
|
|
4746
|
+
`;
|
|
4747
|
+
var ComposerExpandButton = import_styled14.default.button`
|
|
4748
|
+
position: absolute;
|
|
4749
|
+
top: 8px;
|
|
4750
|
+
right: 10px;
|
|
4751
|
+
width: 28px;
|
|
4752
|
+
height: 28px;
|
|
4753
|
+
display: grid;
|
|
4754
|
+
place-items: center;
|
|
4755
|
+
border: none;
|
|
4756
|
+
border-radius: 999px;
|
|
4757
|
+
background: transparent;
|
|
4758
|
+
color: rgba(255, 255, 255, 0.72);
|
|
4759
|
+
cursor: pointer;
|
|
4760
|
+
z-index: 1;
|
|
4761
|
+
|
|
4762
|
+
&:hover {
|
|
4763
|
+
background: rgba(255, 255, 255, 0.08);
|
|
4764
|
+
color: rgba(255, 255, 255, 0.92);
|
|
4765
|
+
}
|
|
4280
4766
|
`;
|
|
4281
4767
|
var Footer = import_styled14.default.div`
|
|
4282
|
-
|
|
4768
|
+
grid-area: footer;
|
|
4769
|
+
display: grid;
|
|
4770
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
4283
4771
|
align-items: flex-end;
|
|
4284
|
-
justify-content: stretch;
|
|
4285
4772
|
gap: 16px;
|
|
4286
4773
|
padding: 0 14px 14px;
|
|
4287
4774
|
`;
|
|
4288
|
-
var
|
|
4775
|
+
var LeadingActions = import_styled14.default.div`
|
|
4776
|
+
display: flex;
|
|
4777
|
+
align-items: center;
|
|
4778
|
+
justify-content: flex-start;
|
|
4779
|
+
gap: 8px;
|
|
4780
|
+
min-width: 0;
|
|
4781
|
+
`;
|
|
4782
|
+
var TrailingActions = import_styled14.default.div`
|
|
4289
4783
|
display: flex;
|
|
4290
4784
|
align-items: center;
|
|
4291
4785
|
flex-wrap: wrap;
|
|
4292
|
-
width: 100%;
|
|
4293
4786
|
min-width: 0;
|
|
4294
4787
|
justify-content: flex-end;
|
|
4295
4788
|
gap: 8px;
|