@xinghunm/ai-chat 1.1.2 → 1.2.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/README.md +31 -1
- package/dist/index.d.mts +63 -6
- package/dist/index.d.ts +63 -6
- package/dist/index.js +391 -154
- package/dist/index.mjs +383 -146
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -49,6 +49,28 @@ var DEFAULT_AI_CHAT_LABELS = {
|
|
|
49
49
|
questionnaireOtherPlaceholder: "Other"
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
+
// src/lib/chat-session.ts
|
|
53
|
+
var DRAFT_CHAT_SESSION_ID_PREFIX = "draft-session-";
|
|
54
|
+
var draftChatSessionSequence = 0;
|
|
55
|
+
var createDraftChatSessionId = () => `${DRAFT_CHAT_SESSION_ID_PREFIX}${Date.now()}-${draftChatSessionSequence++}`;
|
|
56
|
+
var isDraftChatSessionId = (sessionId) => Boolean(sessionId?.startsWith(DRAFT_CHAT_SESSION_ID_PREFIX));
|
|
57
|
+
var createDraftChatSession = ({
|
|
58
|
+
model,
|
|
59
|
+
mode = DEFAULT_CHAT_AGENT_MODE,
|
|
60
|
+
nowIso: nowIso2,
|
|
61
|
+
createSessionId = createDraftChatSessionId
|
|
62
|
+
}) => {
|
|
63
|
+
const iso = nowIso2();
|
|
64
|
+
return {
|
|
65
|
+
sessionId: createSessionId(),
|
|
66
|
+
title: "New Chat",
|
|
67
|
+
createdAt: iso,
|
|
68
|
+
updatedAt: iso,
|
|
69
|
+
model,
|
|
70
|
+
mode
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
|
|
52
74
|
// src/store/chat-store.ts
|
|
53
75
|
var DEFAULT_CHAT_SESSION_TITLE = "New Chat";
|
|
54
76
|
var IMAGE_MESSAGE_SESSION_TITLE = "Image message";
|
|
@@ -182,6 +204,15 @@ var createChatStore = (initialState) => createStore((set, get) => ({
|
|
|
182
204
|
isStoppingBySession: nextIsStoppingBySession
|
|
183
205
|
});
|
|
184
206
|
},
|
|
207
|
+
startNewChat: () => {
|
|
208
|
+
const state = get();
|
|
209
|
+
const session = createDraftChatSession({
|
|
210
|
+
model: "",
|
|
211
|
+
mode: state.preferredMode,
|
|
212
|
+
nowIso: () => (/* @__PURE__ */ new Date()).toISOString()
|
|
213
|
+
});
|
|
214
|
+
get().createSession(session);
|
|
215
|
+
},
|
|
185
216
|
setActiveSession: (sessionId) => {
|
|
186
217
|
set({ activeSessionId: sessionId });
|
|
187
218
|
},
|
|
@@ -444,6 +475,7 @@ var startChatStream = async ({
|
|
|
444
475
|
sessionId,
|
|
445
476
|
authToken,
|
|
446
477
|
requestHeaders,
|
|
478
|
+
requestBody,
|
|
447
479
|
model,
|
|
448
480
|
mode,
|
|
449
481
|
content,
|
|
@@ -465,12 +497,14 @@ var startChatStream = async ({
|
|
|
465
497
|
const response = await fetch(`${apiBaseUrl}${endpointPath}`, {
|
|
466
498
|
method: "POST",
|
|
467
499
|
headers,
|
|
468
|
-
body: JSON.stringify(
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
500
|
+
body: JSON.stringify(
|
|
501
|
+
requestBody ?? {
|
|
502
|
+
model,
|
|
503
|
+
mode,
|
|
504
|
+
stream: true,
|
|
505
|
+
messages: [{ role: "user", content }]
|
|
506
|
+
}
|
|
507
|
+
),
|
|
474
508
|
signal
|
|
475
509
|
});
|
|
476
510
|
const contentType = response.headers.get("content-type") ?? "";
|
|
@@ -546,11 +580,70 @@ var createModeDefaultHeaders = (mode) => {
|
|
|
546
580
|
}
|
|
547
581
|
return {};
|
|
548
582
|
};
|
|
583
|
+
var readFileAsDataUrl = (file) => new Promise((resolve, reject) => {
|
|
584
|
+
const reader = new FileReader();
|
|
585
|
+
reader.onload = () => {
|
|
586
|
+
if (typeof reader.result === "string") {
|
|
587
|
+
resolve(reader.result);
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
reject(new Error(`Failed to read image attachment: ${file.name}`));
|
|
591
|
+
};
|
|
592
|
+
reader.onerror = () => {
|
|
593
|
+
reject(new Error(`Failed to read image attachment: ${file.name}`));
|
|
594
|
+
};
|
|
595
|
+
reader.readAsDataURL(file);
|
|
596
|
+
});
|
|
597
|
+
var resolveAttachmentDataUrl = async (attachment) => {
|
|
598
|
+
if (attachment.file) {
|
|
599
|
+
return readFileAsDataUrl(attachment.file);
|
|
600
|
+
}
|
|
601
|
+
if (attachment.previewUrl.startsWith("data:image/")) {
|
|
602
|
+
return attachment.previewUrl;
|
|
603
|
+
}
|
|
604
|
+
throw new Error(`Attachment is missing file data: ${attachment.name}`);
|
|
605
|
+
};
|
|
606
|
+
var createDefaultRequestBody = async ({
|
|
607
|
+
model,
|
|
608
|
+
mode,
|
|
609
|
+
content,
|
|
610
|
+
attachments
|
|
611
|
+
}) => {
|
|
612
|
+
const hasAttachments = Boolean(attachments?.length);
|
|
613
|
+
if (!hasAttachments) {
|
|
614
|
+
return {
|
|
615
|
+
model,
|
|
616
|
+
mode,
|
|
617
|
+
stream: true,
|
|
618
|
+
messages: [{ role: "user", content }]
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
const imageParts = await Promise.all(
|
|
622
|
+
(attachments ?? []).map(async (attachment) => ({
|
|
623
|
+
type: "image_url",
|
|
624
|
+
image_url: {
|
|
625
|
+
url: await resolveAttachmentDataUrl(attachment)
|
|
626
|
+
}
|
|
627
|
+
}))
|
|
628
|
+
);
|
|
629
|
+
const messageContent = [
|
|
630
|
+
...content ? [{ type: "text", text: content }] : [],
|
|
631
|
+
...imageParts
|
|
632
|
+
];
|
|
633
|
+
return {
|
|
634
|
+
model,
|
|
635
|
+
mode,
|
|
636
|
+
stream: true,
|
|
637
|
+
messages: [{ role: "user", content: messageContent }]
|
|
638
|
+
};
|
|
639
|
+
};
|
|
549
640
|
var createDefaultChatTransport = ({
|
|
550
641
|
apiBaseUrl,
|
|
551
642
|
authToken,
|
|
552
643
|
toolExecutionPolicy,
|
|
553
644
|
streamHeaders,
|
|
645
|
+
resolveModels,
|
|
646
|
+
buildRequestBody,
|
|
554
647
|
transformStreamPacket,
|
|
555
648
|
endpoints,
|
|
556
649
|
axiosInstance
|
|
@@ -565,12 +658,13 @@ var createDefaultChatTransport = ({
|
|
|
565
658
|
...streamHeaders
|
|
566
659
|
};
|
|
567
660
|
return {
|
|
568
|
-
getModels: () => getChatModels(client, resolvedEndpoints.models),
|
|
661
|
+
getModels: () => resolveModels?.() ?? getChatModels(client, resolvedEndpoints.models),
|
|
569
662
|
startStream: async ({
|
|
570
663
|
sessionId,
|
|
571
664
|
model,
|
|
572
665
|
mode,
|
|
573
666
|
content,
|
|
667
|
+
attachments,
|
|
574
668
|
signal,
|
|
575
669
|
onUpdate,
|
|
576
670
|
onSessionId,
|
|
@@ -581,12 +675,20 @@ var createDefaultChatTransport = ({
|
|
|
581
675
|
...createModeDefaultHeaders(mode),
|
|
582
676
|
...resolvedStreamHeaders
|
|
583
677
|
};
|
|
678
|
+
const requestBody = buildRequestBody ? buildRequestBody({
|
|
679
|
+
sessionId,
|
|
680
|
+
model,
|
|
681
|
+
mode,
|
|
682
|
+
content,
|
|
683
|
+
attachments
|
|
684
|
+
}) : await createDefaultRequestBody({ model, mode, content, attachments });
|
|
584
685
|
await startChatStream({
|
|
585
686
|
apiBaseUrl,
|
|
586
687
|
endpointPath: resolvedEndpoints.completions,
|
|
587
688
|
sessionId,
|
|
588
689
|
authToken,
|
|
589
690
|
requestHeaders,
|
|
691
|
+
requestBody,
|
|
590
692
|
model,
|
|
591
693
|
mode,
|
|
592
694
|
content,
|
|
@@ -628,6 +730,8 @@ var AiChatProvider = (props) => {
|
|
|
628
730
|
});
|
|
629
731
|
const retryRef = useRef(async () => {
|
|
630
732
|
});
|
|
733
|
+
const stopRef = useRef(async (_sessionId) => {
|
|
734
|
+
});
|
|
631
735
|
const defaultApiBaseUrl = "apiBaseUrl" in props ? props.apiBaseUrl : void 0;
|
|
632
736
|
const defaultAuthToken = "authToken" in props ? props.authToken : void 0;
|
|
633
737
|
const defaultTransformStreamPacket = "transformStreamPacket" in props ? props.transformStreamPacket : void 0;
|
|
@@ -671,6 +775,7 @@ var AiChatProvider = (props) => {
|
|
|
671
775
|
labels: { ...DEFAULT_AI_CHAT_LABELS, ...labels },
|
|
672
776
|
sendRef,
|
|
673
777
|
retryRef,
|
|
778
|
+
stopRef,
|
|
674
779
|
renderMessageBlock,
|
|
675
780
|
handleQuestionnaireSubmit,
|
|
676
781
|
handleConfirmationSubmit,
|
|
@@ -691,6 +796,7 @@ var AiChatProvider = (props) => {
|
|
|
691
796
|
renderMessageBlock,
|
|
692
797
|
sendRef,
|
|
693
798
|
retryRef,
|
|
799
|
+
stopRef,
|
|
694
800
|
store,
|
|
695
801
|
transport
|
|
696
802
|
]
|
|
@@ -1495,7 +1601,6 @@ import {
|
|
|
1495
1601
|
useState as useState2
|
|
1496
1602
|
} from "react";
|
|
1497
1603
|
import styled4 from "@emotion/styled";
|
|
1498
|
-
import { Input } from "@xinghunm/compass-ui";
|
|
1499
1604
|
|
|
1500
1605
|
// src/components/chat-thread/components/questionnaire-card-helpers.ts
|
|
1501
1606
|
var OTHER_OPTION_VALUE = "__other__";
|
|
@@ -2296,7 +2401,7 @@ var TextInput = styled4.input`
|
|
|
2296
2401
|
color: rgba(255, 255, 255, 0.34);
|
|
2297
2402
|
}
|
|
2298
2403
|
`;
|
|
2299
|
-
var InlineOtherInput = styled4
|
|
2404
|
+
var InlineOtherInput = styled4.input`
|
|
2300
2405
|
width: 100%;
|
|
2301
2406
|
margin-top: 0;
|
|
2302
2407
|
|
|
@@ -3684,19 +3789,20 @@ var ChatThread = () => {
|
|
|
3684
3789
|
if (!activeSessionId)
|
|
3685
3790
|
return;
|
|
3686
3791
|
clearSessionError(activeSessionId);
|
|
3687
|
-
void retryRef.current();
|
|
3792
|
+
void retryRef.current(activeSessionId);
|
|
3688
3793
|
}, [activeSessionId, clearSessionError, retryRef]);
|
|
3689
3794
|
const handleQuestionnaireSubmit = useCallback3(
|
|
3690
3795
|
async (submission) => {
|
|
3796
|
+
const sourceSessionId = activeSessionId;
|
|
3691
3797
|
if (customQuestionnaireSubmit) {
|
|
3692
3798
|
const handled = await customQuestionnaireSubmit(submission, {
|
|
3693
|
-
sessionId:
|
|
3799
|
+
sessionId: sourceSessionId ?? void 0,
|
|
3694
3800
|
mode: activeSessionMode
|
|
3695
3801
|
});
|
|
3696
3802
|
if (handled !== false) {
|
|
3697
|
-
if (
|
|
3803
|
+
if (sourceSessionId && submission.sourceMessageId) {
|
|
3698
3804
|
updateQA(
|
|
3699
|
-
|
|
3805
|
+
sourceSessionId,
|
|
3700
3806
|
submission.sourceMessageId,
|
|
3701
3807
|
submission.questionnaireId,
|
|
3702
3808
|
submission.answers
|
|
@@ -3705,10 +3811,13 @@ var ChatThread = () => {
|
|
|
3705
3811
|
return;
|
|
3706
3812
|
}
|
|
3707
3813
|
}
|
|
3708
|
-
await sendRef.current(submission.content
|
|
3709
|
-
|
|
3814
|
+
await sendRef.current(submission.content, {
|
|
3815
|
+
sessionId: sourceSessionId ?? void 0,
|
|
3816
|
+
includeComposerAttachments: false
|
|
3817
|
+
});
|
|
3818
|
+
if (sourceSessionId && submission.sourceMessageId) {
|
|
3710
3819
|
updateQA(
|
|
3711
|
-
|
|
3820
|
+
sourceSessionId,
|
|
3712
3821
|
submission.sourceMessageId,
|
|
3713
3822
|
submission.questionnaireId,
|
|
3714
3823
|
submission.answers
|
|
@@ -3719,16 +3828,20 @@ var ChatThread = () => {
|
|
|
3719
3828
|
);
|
|
3720
3829
|
const handleConfirmation = useCallback3(
|
|
3721
3830
|
async (submission) => {
|
|
3831
|
+
const sourceSessionId = activeSessionId;
|
|
3722
3832
|
if (customConfirmationSubmit) {
|
|
3723
3833
|
const handled = await customConfirmationSubmit(submission, {
|
|
3724
|
-
sessionId:
|
|
3834
|
+
sessionId: sourceSessionId ?? void 0,
|
|
3725
3835
|
mode: activeSessionMode
|
|
3726
3836
|
});
|
|
3727
3837
|
if (handled !== false) {
|
|
3728
3838
|
return;
|
|
3729
3839
|
}
|
|
3730
3840
|
}
|
|
3731
|
-
await sendRef.current(submission.content
|
|
3841
|
+
await sendRef.current(submission.content, {
|
|
3842
|
+
sessionId: sourceSessionId ?? void 0,
|
|
3843
|
+
includeComposerAttachments: false
|
|
3844
|
+
});
|
|
3732
3845
|
},
|
|
3733
3846
|
[activeSessionId, activeSessionMode, sendRef, customConfirmationSubmit]
|
|
3734
3847
|
);
|
|
@@ -3865,25 +3978,6 @@ import { useEffect as useEffect7, useLayoutEffect as useLayoutEffect3, useRef as
|
|
|
3865
3978
|
import styled14 from "@emotion/styled";
|
|
3866
3979
|
|
|
3867
3980
|
// src/components/chat-composer/lib/chat-composer.ts
|
|
3868
|
-
var DRAFT_CHAT_SESSION_ID_PREFIX = "draft-session-";
|
|
3869
|
-
var createDraftChatSessionId = () => `${DRAFT_CHAT_SESSION_ID_PREFIX}${Date.now()}`;
|
|
3870
|
-
var isDraftChatSessionId = (sessionId) => Boolean(sessionId?.startsWith(DRAFT_CHAT_SESSION_ID_PREFIX));
|
|
3871
|
-
var createDraftChatSession = ({
|
|
3872
|
-
model,
|
|
3873
|
-
mode = DEFAULT_CHAT_AGENT_MODE,
|
|
3874
|
-
nowIso: nowIso2,
|
|
3875
|
-
createSessionId
|
|
3876
|
-
}) => {
|
|
3877
|
-
const iso = nowIso2();
|
|
3878
|
-
return {
|
|
3879
|
-
sessionId: createSessionId(),
|
|
3880
|
-
title: "New Chat",
|
|
3881
|
-
createdAt: iso,
|
|
3882
|
-
updatedAt: iso,
|
|
3883
|
-
model,
|
|
3884
|
-
mode
|
|
3885
|
-
};
|
|
3886
|
-
};
|
|
3887
3981
|
var createUserMessage = ({
|
|
3888
3982
|
sessionId,
|
|
3889
3983
|
content,
|
|
@@ -4044,7 +4138,8 @@ var useComposerAttachments = () => {
|
|
|
4044
4138
|
return [];
|
|
4045
4139
|
}
|
|
4046
4140
|
const nextMessageAttachments = currentAttachments.map(({ file: _file, ...attachment }) => ({
|
|
4047
|
-
...attachment
|
|
4141
|
+
...attachment,
|
|
4142
|
+
file: _file
|
|
4048
4143
|
}));
|
|
4049
4144
|
attachmentsRef.current = [];
|
|
4050
4145
|
setAttachments([]);
|
|
@@ -4083,19 +4178,20 @@ var normalizeChatErrorMessage = (message, labels) => {
|
|
|
4083
4178
|
return trimmedMessage;
|
|
4084
4179
|
};
|
|
4085
4180
|
var useChatComposer = () => {
|
|
4086
|
-
const { transport, enableImageAttachments, labels } = useChatContext();
|
|
4181
|
+
const { transport, enableImageAttachments, labels, store } = useChatContext();
|
|
4087
4182
|
const activeSessionId = useChatStore((s) => s.activeSessionId);
|
|
4088
4183
|
const activeSession = useChatStore(
|
|
4089
4184
|
(s) => s.sessions.find((x) => x.sessionId === s.activeSessionId) ?? null
|
|
4090
4185
|
);
|
|
4091
4186
|
const preferredMode = useChatStore((s) => s.preferredMode);
|
|
4092
4187
|
const streamingSessionId = useChatStore(
|
|
4093
|
-
(s) =>
|
|
4188
|
+
(s) => s.activeSessionId && s.isStreamingBySession[s.activeSessionId] ? s.activeSessionId : null
|
|
4094
4189
|
);
|
|
4095
4190
|
const isStreaming = Boolean(streamingSessionId);
|
|
4096
|
-
const isStopping = useChatStore(
|
|
4097
|
-
|
|
4098
|
-
|
|
4191
|
+
const isStopping = useChatStore((s) => {
|
|
4192
|
+
const currentStreamingSessionId = s.activeSessionId && s.isStreamingBySession[s.activeSessionId] ? s.activeSessionId : null;
|
|
4193
|
+
return currentStreamingSessionId ? s.isStoppingBySession[currentStreamingSessionId] ?? false : false;
|
|
4194
|
+
});
|
|
4099
4195
|
const createSession = useChatStore((s) => s.createSession);
|
|
4100
4196
|
const replaceSessionId = useChatStore((s) => s.replaceSessionId);
|
|
4101
4197
|
const appendMessage = useChatStore((s) => s.appendMessage);
|
|
@@ -4132,9 +4228,9 @@ var useChatComposer = () => {
|
|
|
4132
4228
|
const [selectedMode, setSelectedModeLocal] = useState6(DEFAULT_CHAT_AGENT_MODE);
|
|
4133
4229
|
const [attachmentNotice, setAttachmentNotice] = useState6(null);
|
|
4134
4230
|
const { attachments, appendFiles, removeAttachment, takeMessageAttachments } = useComposerAttachments();
|
|
4135
|
-
const
|
|
4136
|
-
const
|
|
4137
|
-
const
|
|
4231
|
+
const abortControllerBySessionRef = useRef7(/* @__PURE__ */ new Map());
|
|
4232
|
+
const stopRequestBySessionRef = useRef7(/* @__PURE__ */ new Map());
|
|
4233
|
+
const lastRequestBySessionRef = useRef7(/* @__PURE__ */ new Map());
|
|
4138
4234
|
useEffect6(() => {
|
|
4139
4235
|
setSelectedModel(
|
|
4140
4236
|
(current) => resolveSelectedChatModel({ currentModel: current, availableModels, isModelsLoading })
|
|
@@ -4157,33 +4253,47 @@ var useChatComposer = () => {
|
|
|
4157
4253
|
return () => window.clearTimeout(timeoutId);
|
|
4158
4254
|
}, [attachmentNotice]);
|
|
4159
4255
|
const clearStopTimeout = (sessionId) => {
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
if (sessionId && stopRequestRef.current.sessionId !== sessionId)
|
|
4256
|
+
const stopRequest = stopRequestBySessionRef.current.get(sessionId);
|
|
4257
|
+
if (!stopRequest || stopRequest.timeoutId === null) {
|
|
4163
4258
|
return;
|
|
4164
|
-
if (stopRequestRef.current.timeoutId !== null) {
|
|
4165
|
-
window.clearTimeout(stopRequestRef.current.timeoutId);
|
|
4166
|
-
stopRequestRef.current.timeoutId = null;
|
|
4167
4259
|
}
|
|
4260
|
+
window.clearTimeout(stopRequest.timeoutId);
|
|
4261
|
+
stopRequest.timeoutId = null;
|
|
4168
4262
|
};
|
|
4169
4263
|
const clearStopRequest = useCallback4((sessionId) => {
|
|
4170
|
-
if (!stopRequestRef.current)
|
|
4171
|
-
return;
|
|
4172
|
-
if (sessionId && stopRequestRef.current.sessionId !== sessionId)
|
|
4173
|
-
return;
|
|
4174
4264
|
clearStopTimeout(sessionId);
|
|
4175
|
-
|
|
4265
|
+
stopRequestBySessionRef.current.delete(sessionId);
|
|
4176
4266
|
}, []);
|
|
4267
|
+
const moveSessionRuntimeState = useCallback4(
|
|
4268
|
+
(previousSessionId, nextSessionId) => {
|
|
4269
|
+
if (previousSessionId === nextSessionId) {
|
|
4270
|
+
return;
|
|
4271
|
+
}
|
|
4272
|
+
const abortController = abortControllerBySessionRef.current.get(previousSessionId);
|
|
4273
|
+
if (abortController) {
|
|
4274
|
+
abortControllerBySessionRef.current.set(nextSessionId, abortController);
|
|
4275
|
+
abortControllerBySessionRef.current.delete(previousSessionId);
|
|
4276
|
+
}
|
|
4277
|
+
const stopRequest = stopRequestBySessionRef.current.get(previousSessionId);
|
|
4278
|
+
if (stopRequest) {
|
|
4279
|
+
stopRequestBySessionRef.current.set(nextSessionId, stopRequest);
|
|
4280
|
+
stopRequestBySessionRef.current.delete(previousSessionId);
|
|
4281
|
+
}
|
|
4282
|
+
},
|
|
4283
|
+
[]
|
|
4284
|
+
);
|
|
4177
4285
|
const finalizeStop = useCallback4(
|
|
4178
4286
|
(sessionId) => {
|
|
4179
|
-
|
|
4180
|
-
|
|
4287
|
+
const stopRequest = stopRequestBySessionRef.current.get(sessionId);
|
|
4288
|
+
if (stopRequest) {
|
|
4289
|
+
if (stopRequest.finalized) {
|
|
4181
4290
|
return;
|
|
4182
|
-
|
|
4291
|
+
}
|
|
4292
|
+
stopRequest.finalized = true;
|
|
4183
4293
|
}
|
|
4184
4294
|
clearStopTimeout(sessionId);
|
|
4185
|
-
|
|
4186
|
-
|
|
4295
|
+
abortControllerBySessionRef.current.get(sessionId)?.abort();
|
|
4296
|
+
abortControllerBySessionRef.current.delete(sessionId);
|
|
4187
4297
|
finalizeStoppedStreamingMessage(sessionId);
|
|
4188
4298
|
clearStopRequest(sessionId);
|
|
4189
4299
|
},
|
|
@@ -4194,10 +4304,11 @@ var useChatComposer = () => {
|
|
|
4194
4304
|
localSessionId,
|
|
4195
4305
|
sessionId,
|
|
4196
4306
|
content,
|
|
4307
|
+
attachments: attachments2,
|
|
4197
4308
|
model,
|
|
4198
4309
|
mode
|
|
4199
4310
|
}) => {
|
|
4200
|
-
clearStopRequest();
|
|
4311
|
+
clearStopRequest(localSessionId);
|
|
4201
4312
|
let currentSessionId = localSessionId;
|
|
4202
4313
|
clearSessionError(currentSessionId);
|
|
4203
4314
|
const assistantMessage = createAssistantStreamingMessage({
|
|
@@ -4206,29 +4317,44 @@ var useChatComposer = () => {
|
|
|
4206
4317
|
createMessageId: () => `assistant-${Date.now()}`
|
|
4207
4318
|
});
|
|
4208
4319
|
startStreamingMessage(currentSessionId, assistantMessage);
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4320
|
+
abortControllerBySessionRef.current.get(currentSessionId)?.abort();
|
|
4321
|
+
const abortController = new AbortController();
|
|
4322
|
+
abortControllerBySessionRef.current.set(currentSessionId, abortController);
|
|
4323
|
+
lastRequestBySessionRef.current.set(currentSessionId, {
|
|
4324
|
+
localSessionId,
|
|
4325
|
+
sessionId,
|
|
4326
|
+
content,
|
|
4327
|
+
attachments: attachments2,
|
|
4328
|
+
model,
|
|
4329
|
+
mode
|
|
4330
|
+
});
|
|
4212
4331
|
let accumulated = "";
|
|
4332
|
+
let streamSettled = false;
|
|
4213
4333
|
try {
|
|
4214
4334
|
await transport.startStream({
|
|
4215
4335
|
sessionId,
|
|
4216
4336
|
model,
|
|
4217
4337
|
mode,
|
|
4218
4338
|
content,
|
|
4219
|
-
|
|
4339
|
+
attachments: attachments2,
|
|
4340
|
+
signal: abortController.signal,
|
|
4220
4341
|
onSessionId: (nextSessionId) => {
|
|
4221
4342
|
if (!nextSessionId || nextSessionId === currentSessionId)
|
|
4222
4343
|
return;
|
|
4223
|
-
|
|
4344
|
+
const previousSessionId = currentSessionId;
|
|
4345
|
+
replaceSessionId(previousSessionId, nextSessionId);
|
|
4346
|
+
moveSessionRuntimeState(previousSessionId, nextSessionId);
|
|
4224
4347
|
currentSessionId = nextSessionId;
|
|
4225
|
-
|
|
4348
|
+
const nextRequest = {
|
|
4226
4349
|
localSessionId: nextSessionId,
|
|
4227
4350
|
sessionId: nextSessionId,
|
|
4228
4351
|
content,
|
|
4352
|
+
attachments: attachments2,
|
|
4229
4353
|
model,
|
|
4230
4354
|
mode
|
|
4231
4355
|
};
|
|
4356
|
+
lastRequestBySessionRef.current.delete(previousSessionId);
|
|
4357
|
+
lastRequestBySessionRef.current.set(nextSessionId, nextRequest);
|
|
4232
4358
|
},
|
|
4233
4359
|
onUpdate: (update) => {
|
|
4234
4360
|
accumulated = resolveAccumulatedContent(accumulated, update);
|
|
@@ -4238,16 +4364,18 @@ var useChatComposer = () => {
|
|
|
4238
4364
|
});
|
|
4239
4365
|
},
|
|
4240
4366
|
onDone: () => {
|
|
4241
|
-
|
|
4367
|
+
streamSettled = true;
|
|
4368
|
+
if (stopRequestBySessionRef.current.has(currentSessionId)) {
|
|
4242
4369
|
finalizeStop(currentSessionId);
|
|
4243
4370
|
return;
|
|
4244
4371
|
}
|
|
4245
4372
|
completeStreamingMessage(currentSessionId);
|
|
4246
|
-
|
|
4373
|
+
abortControllerBySessionRef.current.delete(currentSessionId);
|
|
4247
4374
|
clearStopRequest(currentSessionId);
|
|
4248
4375
|
},
|
|
4249
4376
|
onError: (streamError) => {
|
|
4250
|
-
|
|
4377
|
+
streamSettled = true;
|
|
4378
|
+
if (stopRequestBySessionRef.current.has(currentSessionId)) {
|
|
4251
4379
|
finalizeStop(currentSessionId);
|
|
4252
4380
|
return;
|
|
4253
4381
|
}
|
|
@@ -4256,12 +4384,24 @@ var useChatComposer = () => {
|
|
|
4256
4384
|
currentSessionId,
|
|
4257
4385
|
normalizeChatErrorMessage(streamError.message, labels)
|
|
4258
4386
|
);
|
|
4259
|
-
|
|
4387
|
+
abortControllerBySessionRef.current.delete(currentSessionId);
|
|
4260
4388
|
clearStopRequest(currentSessionId);
|
|
4261
4389
|
}
|
|
4262
4390
|
});
|
|
4263
|
-
} catch {
|
|
4264
|
-
|
|
4391
|
+
} catch (streamError) {
|
|
4392
|
+
abortControllerBySessionRef.current.delete(currentSessionId);
|
|
4393
|
+
if (streamSettled || abortController.signal.aborted || !store.getState().isStreamingBySession[currentSessionId]) {
|
|
4394
|
+
return;
|
|
4395
|
+
}
|
|
4396
|
+
finalizeStoppedStreamingMessage(currentSessionId);
|
|
4397
|
+
setSessionError(
|
|
4398
|
+
currentSessionId,
|
|
4399
|
+
normalizeChatErrorMessage(
|
|
4400
|
+
streamError instanceof Error ? streamError.message : void 0,
|
|
4401
|
+
labels
|
|
4402
|
+
)
|
|
4403
|
+
);
|
|
4404
|
+
clearStopRequest(currentSessionId);
|
|
4265
4405
|
}
|
|
4266
4406
|
},
|
|
4267
4407
|
[
|
|
@@ -4270,61 +4410,68 @@ var useChatComposer = () => {
|
|
|
4270
4410
|
clearStopRequest,
|
|
4271
4411
|
finalizeStop,
|
|
4272
4412
|
labels,
|
|
4413
|
+
moveSessionRuntimeState,
|
|
4273
4414
|
startStreamingMessage,
|
|
4274
4415
|
replaceSessionId,
|
|
4275
4416
|
patchStreamingMessage,
|
|
4276
4417
|
completeStreamingMessage,
|
|
4277
4418
|
finalizeStoppedStreamingMessage,
|
|
4278
|
-
setSessionError
|
|
4419
|
+
setSessionError,
|
|
4420
|
+
store
|
|
4279
4421
|
]
|
|
4280
4422
|
);
|
|
4281
4423
|
const send = useCallback4(
|
|
4282
|
-
async (contentOverride) => {
|
|
4424
|
+
async (contentOverride, options) => {
|
|
4283
4425
|
const content = (contentOverride ?? value).trim();
|
|
4284
|
-
const
|
|
4285
|
-
const
|
|
4426
|
+
const includeComposerAttachments = options?.includeComposerAttachments ?? true;
|
|
4427
|
+
const composerAttachmentCount = includeComposerAttachments ? attachments.length : 0;
|
|
4286
4428
|
if (!canSendChatMessage({
|
|
4287
4429
|
value: content,
|
|
4288
|
-
attachmentCount:
|
|
4430
|
+
attachmentCount: composerAttachmentCount,
|
|
4289
4431
|
isModelsLoading,
|
|
4290
4432
|
isModelsError,
|
|
4291
4433
|
hasModels
|
|
4292
4434
|
})) {
|
|
4293
4435
|
return;
|
|
4294
4436
|
}
|
|
4295
|
-
|
|
4437
|
+
const storeState = store.getState();
|
|
4438
|
+
const currentActiveSessionId = options?.sessionId ?? storeState.activeSessionId;
|
|
4439
|
+
const currentActiveSession = storeState.sessions.find((session2) => session2.sessionId === currentActiveSessionId) ?? null;
|
|
4440
|
+
const currentMode = currentActiveSession?.mode ?? selectedMode;
|
|
4441
|
+
if (!(selectedModel || currentActiveSession?.model || availableModels[0]?.id)) {
|
|
4296
4442
|
return;
|
|
4297
4443
|
}
|
|
4298
|
-
const resolvedModel = selectedModel ||
|
|
4444
|
+
const resolvedModel = selectedModel || currentActiveSession?.model || availableModels[0]?.id || "local-image";
|
|
4299
4445
|
const { localSessionId, sessionId, session } = resolveSendSession({
|
|
4300
|
-
activeSessionId,
|
|
4446
|
+
activeSessionId: currentActiveSessionId,
|
|
4301
4447
|
selectedModel: resolvedModel,
|
|
4302
|
-
selectedMode,
|
|
4448
|
+
selectedMode: currentMode,
|
|
4303
4449
|
nowIso,
|
|
4304
4450
|
createSessionId: createDraftChatSessionId
|
|
4305
4451
|
});
|
|
4306
4452
|
if (session)
|
|
4307
4453
|
createSession(session);
|
|
4308
|
-
const messageAttachments = takeMessageAttachments();
|
|
4454
|
+
const messageAttachments = includeComposerAttachments ? takeMessageAttachments() : void 0;
|
|
4309
4455
|
const userMessage = createUserMessage({
|
|
4310
4456
|
sessionId: localSessionId,
|
|
4311
4457
|
content,
|
|
4312
4458
|
attachments: messageAttachments,
|
|
4313
|
-
localOnly:
|
|
4459
|
+
localOnly: false,
|
|
4314
4460
|
createdAt: nowIso(),
|
|
4315
4461
|
createMessageId: () => `user-${Date.now()}`
|
|
4316
4462
|
});
|
|
4317
4463
|
appendMessage(localSessionId, userMessage);
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4464
|
+
if (includeComposerAttachments) {
|
|
4465
|
+
setAttachmentNotice(null);
|
|
4466
|
+
setValue("");
|
|
4467
|
+
}
|
|
4322
4468
|
await runStream({
|
|
4323
4469
|
localSessionId,
|
|
4324
4470
|
sessionId,
|
|
4325
4471
|
content,
|
|
4472
|
+
attachments: messageAttachments,
|
|
4326
4473
|
model: resolvedModel,
|
|
4327
|
-
mode:
|
|
4474
|
+
mode: currentMode
|
|
4328
4475
|
});
|
|
4329
4476
|
},
|
|
4330
4477
|
[
|
|
@@ -4334,16 +4481,47 @@ var useChatComposer = () => {
|
|
|
4334
4481
|
isModelsError,
|
|
4335
4482
|
hasModels,
|
|
4336
4483
|
selectedModel,
|
|
4337
|
-
activeSession,
|
|
4338
4484
|
availableModels,
|
|
4339
|
-
activeSessionId,
|
|
4340
4485
|
selectedMode,
|
|
4341
4486
|
createSession,
|
|
4342
4487
|
takeMessageAttachments,
|
|
4343
4488
|
appendMessage,
|
|
4344
|
-
runStream
|
|
4489
|
+
runStream,
|
|
4490
|
+
store
|
|
4345
4491
|
]
|
|
4346
4492
|
);
|
|
4493
|
+
const stopSession = useCallback4(
|
|
4494
|
+
async (sessionId) => {
|
|
4495
|
+
const storeState = store.getState();
|
|
4496
|
+
const isSessionStreaming = storeState.isStreamingBySession[sessionId] ?? false;
|
|
4497
|
+
const isSessionStopping = storeState.isStoppingBySession[sessionId] ?? false;
|
|
4498
|
+
if (!isSessionStreaming || isSessionStopping) {
|
|
4499
|
+
return;
|
|
4500
|
+
}
|
|
4501
|
+
if (isDraftChatSessionId(sessionId)) {
|
|
4502
|
+
finalizeStop(sessionId);
|
|
4503
|
+
return;
|
|
4504
|
+
}
|
|
4505
|
+
requestStopStreaming(sessionId);
|
|
4506
|
+
stopRequestBySessionRef.current.set(sessionId, {
|
|
4507
|
+
timeoutId: window.setTimeout(() => {
|
|
4508
|
+
finalizeStop(sessionId);
|
|
4509
|
+
}, STOP_WAIT_TIMEOUT_MS),
|
|
4510
|
+
finalized: false
|
|
4511
|
+
});
|
|
4512
|
+
try {
|
|
4513
|
+
const result = await transport.terminateStream(sessionId);
|
|
4514
|
+
if (!result.terminated) {
|
|
4515
|
+
console.error("Failed to terminate chat session: server returned not terminated");
|
|
4516
|
+
}
|
|
4517
|
+
finalizeStop(sessionId);
|
|
4518
|
+
} catch (err) {
|
|
4519
|
+
console.error("Failed to terminate chat session", err);
|
|
4520
|
+
finalizeStop(sessionId);
|
|
4521
|
+
}
|
|
4522
|
+
},
|
|
4523
|
+
[finalizeStop, requestStopStreaming, store, transport]
|
|
4524
|
+
);
|
|
4347
4525
|
return {
|
|
4348
4526
|
state: {
|
|
4349
4527
|
value,
|
|
@@ -4383,43 +4561,27 @@ var useChatComposer = () => {
|
|
|
4383
4561
|
setPreferredMode(mode);
|
|
4384
4562
|
if (activeSessionId)
|
|
4385
4563
|
setSessionMode(activeSessionId, mode);
|
|
4386
|
-
if (
|
|
4387
|
-
|
|
4564
|
+
if (activeSessionId) {
|
|
4565
|
+
const previousRequest = lastRequestBySessionRef.current.get(activeSessionId);
|
|
4566
|
+
if (previousRequest) {
|
|
4567
|
+
lastRequestBySessionRef.current.set(activeSessionId, { ...previousRequest, mode });
|
|
4568
|
+
}
|
|
4388
4569
|
}
|
|
4389
4570
|
},
|
|
4390
4571
|
reloadModels: () => void fetchModels(),
|
|
4572
|
+
stopSession,
|
|
4391
4573
|
stop: async () => {
|
|
4392
4574
|
if (!streamingSessionId)
|
|
4393
4575
|
return;
|
|
4394
|
-
|
|
4395
|
-
return;
|
|
4396
|
-
if (isDraftChatSessionId(streamingSessionId)) {
|
|
4397
|
-
finalizeStop(streamingSessionId);
|
|
4398
|
-
return;
|
|
4399
|
-
}
|
|
4400
|
-
requestStopStreaming(streamingSessionId);
|
|
4401
|
-
stopRequestRef.current = {
|
|
4402
|
-
sessionId: streamingSessionId,
|
|
4403
|
-
timeoutId: window.setTimeout(() => {
|
|
4404
|
-
finalizeStop(streamingSessionId);
|
|
4405
|
-
}, STOP_WAIT_TIMEOUT_MS),
|
|
4406
|
-
finalized: false
|
|
4407
|
-
};
|
|
4408
|
-
try {
|
|
4409
|
-
const result = await transport.terminateStream(streamingSessionId);
|
|
4410
|
-
if (!result.terminated) {
|
|
4411
|
-
console.error("Failed to terminate chat session: server returned not terminated");
|
|
4412
|
-
}
|
|
4413
|
-
finalizeStop(streamingSessionId);
|
|
4414
|
-
} catch (err) {
|
|
4415
|
-
console.error("Failed to terminate chat session", err);
|
|
4416
|
-
finalizeStop(streamingSessionId);
|
|
4417
|
-
}
|
|
4576
|
+
await stopSession(streamingSessionId);
|
|
4418
4577
|
},
|
|
4419
|
-
retry: () => {
|
|
4420
|
-
if (!
|
|
4578
|
+
retry: (sessionId) => {
|
|
4579
|
+
if (!sessionId)
|
|
4421
4580
|
return;
|
|
4422
|
-
|
|
4581
|
+
const request = lastRequestBySessionRef.current.get(sessionId);
|
|
4582
|
+
if (!request)
|
|
4583
|
+
return;
|
|
4584
|
+
void runStream(request);
|
|
4423
4585
|
}
|
|
4424
4586
|
}
|
|
4425
4587
|
};
|
|
@@ -5066,7 +5228,7 @@ var ChatComposerView = ({
|
|
|
5066
5228
|
}
|
|
5067
5229
|
) : null,
|
|
5068
5230
|
/* @__PURE__ */ jsx15(
|
|
5069
|
-
|
|
5231
|
+
Input,
|
|
5070
5232
|
{
|
|
5071
5233
|
ref: inputRef,
|
|
5072
5234
|
"data-testid": "chat-composer-input",
|
|
@@ -5127,15 +5289,16 @@ var ChatComposerView = ({
|
|
|
5127
5289
|
] }) });
|
|
5128
5290
|
};
|
|
5129
5291
|
var ChatComposer = () => {
|
|
5130
|
-
const { labels, sendRef, retryRef, enableImageAttachments } = useChatContext();
|
|
5292
|
+
const { labels, sendRef, retryRef, stopRef, enableImageAttachments } = useChatContext();
|
|
5131
5293
|
const { state, actions } = useChatComposer();
|
|
5132
5294
|
const { send, retry } = actions;
|
|
5133
5295
|
useEffect7(() => {
|
|
5134
5296
|
sendRef.current = send;
|
|
5135
|
-
retryRef.current = async () => {
|
|
5136
|
-
retry();
|
|
5297
|
+
retryRef.current = async (sessionId) => {
|
|
5298
|
+
retry(sessionId);
|
|
5137
5299
|
};
|
|
5138
|
-
|
|
5300
|
+
stopRef.current = actions.stopSession;
|
|
5301
|
+
}, [actions.stopSession, retry, retryRef, send, sendRef, stopRef]);
|
|
5139
5302
|
const modeLabels = {
|
|
5140
5303
|
ask: labels.modeLabelAsk,
|
|
5141
5304
|
plan: labels.modeLabelPlan,
|
|
@@ -5210,7 +5373,7 @@ var InputArea = styled14.div`
|
|
|
5210
5373
|
grid-area: input;
|
|
5211
5374
|
position: relative;
|
|
5212
5375
|
`;
|
|
5213
|
-
var
|
|
5376
|
+
var Input = styled14.textarea`
|
|
5214
5377
|
--textarea-line-height: ${CHAT_COMPOSER_LINE_HEIGHT_PX}px;
|
|
5215
5378
|
--textarea-min-rows: ${CHAT_COMPOSER_MIN_ROWS};
|
|
5216
5379
|
--textarea-max-rows: ${CHAT_COMPOSER_MAX_ROWS};
|
|
@@ -5281,9 +5444,9 @@ var ComposerExpandButton = styled14.button`
|
|
|
5281
5444
|
var Footer = styled14.div`
|
|
5282
5445
|
grid-area: footer;
|
|
5283
5446
|
display: grid;
|
|
5284
|
-
grid-template-columns: minmax(0, 1fr)
|
|
5447
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
5285
5448
|
align-items: flex-end;
|
|
5286
|
-
gap:
|
|
5449
|
+
gap: 8px;
|
|
5287
5450
|
padding: 0 14px 14px;
|
|
5288
5451
|
`;
|
|
5289
5452
|
var LeadingActions = styled14.div`
|
|
@@ -5298,6 +5461,9 @@ var TrailingActions = styled14.div`
|
|
|
5298
5461
|
align-items: center;
|
|
5299
5462
|
flex-wrap: wrap;
|
|
5300
5463
|
min-width: 0;
|
|
5464
|
+
width: fit-content;
|
|
5465
|
+
max-width: 100%;
|
|
5466
|
+
justify-self: end;
|
|
5301
5467
|
justify-content: flex-end;
|
|
5302
5468
|
gap: 8px;
|
|
5303
5469
|
`;
|
|
@@ -5384,28 +5550,17 @@ var ChatConversationList = () => {
|
|
|
5384
5550
|
const { labels } = useChatContext();
|
|
5385
5551
|
const sessions = useChatStore((s) => s.sessions);
|
|
5386
5552
|
const activeSessionId = useChatStore((s) => s.activeSessionId);
|
|
5387
|
-
const
|
|
5388
|
-
const createSession = useChatStore((s) => s.createSession);
|
|
5553
|
+
const startNewChat = useChatStore((s) => s.startNewChat);
|
|
5389
5554
|
const setActiveSession = useChatStore((s) => s.setActiveSession);
|
|
5390
5555
|
const modeLabels = {
|
|
5391
5556
|
ask: labels.modeLabelAsk,
|
|
5392
5557
|
plan: labels.modeLabelPlan,
|
|
5393
5558
|
agent: labels.modeLabelAgent
|
|
5394
5559
|
};
|
|
5395
|
-
const handleCreateSession = () => {
|
|
5396
|
-
const session = createDraftChatSession({
|
|
5397
|
-
// Model is intentionally deferred: ChatComposer resolves selectedModel at send time.
|
|
5398
|
-
model: "",
|
|
5399
|
-
mode: preferredMode,
|
|
5400
|
-
nowIso: () => (/* @__PURE__ */ new Date()).toISOString(),
|
|
5401
|
-
createSessionId: createDraftChatSessionId
|
|
5402
|
-
});
|
|
5403
|
-
createSession(session);
|
|
5404
|
-
};
|
|
5405
5560
|
return /* @__PURE__ */ jsxs12(Container3, { children: [
|
|
5406
5561
|
/* @__PURE__ */ jsxs12(Toolbar, { children: [
|
|
5407
5562
|
/* @__PURE__ */ jsx17(Title3, { children: "Sessions" }),
|
|
5408
|
-
/* @__PURE__ */ jsx17(CreateButton, { type: "button", "data-testid": "chat-create-session", onClick:
|
|
5563
|
+
/* @__PURE__ */ jsx17(CreateButton, { type: "button", "data-testid": "chat-create-session", onClick: startNewChat, children: labels.newChat })
|
|
5409
5564
|
] }),
|
|
5410
5565
|
/* @__PURE__ */ jsx17(List2, { "data-testid": "chat-session-list", children: sessions.map((session) => /* @__PURE__ */ jsx17(
|
|
5411
5566
|
ChatSessionItem,
|
|
@@ -5456,8 +5611,70 @@ var List2 = styled16.div`
|
|
|
5456
5611
|
`;
|
|
5457
5612
|
|
|
5458
5613
|
// src/components/ai-chat/index.tsx
|
|
5459
|
-
import { jsx as jsx18, jsxs as jsxs13 } from "@emotion/react/jsx-runtime";
|
|
5460
|
-
var
|
|
5614
|
+
import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs13 } from "@emotion/react/jsx-runtime";
|
|
5615
|
+
var QuickActions = ({ renderNewChatTrigger }) => {
|
|
5616
|
+
const { labels, stopRef, store } = useChatContext();
|
|
5617
|
+
const startNewChat = useChatStore((state) => state.startNewChat);
|
|
5618
|
+
const activeSessionId = useChatStore((state) => state.activeSessionId);
|
|
5619
|
+
const isActiveSessionStreaming = useChatStore(
|
|
5620
|
+
(state) => state.activeSessionId ? state.isStreamingBySession[state.activeSessionId] ?? false : false
|
|
5621
|
+
);
|
|
5622
|
+
const isActiveSessionStopping = useChatStore(
|
|
5623
|
+
(state) => state.activeSessionId ? state.isStoppingBySession[state.activeSessionId] ?? false : false
|
|
5624
|
+
);
|
|
5625
|
+
const createNewSession = () => {
|
|
5626
|
+
startNewChat();
|
|
5627
|
+
};
|
|
5628
|
+
const stopActiveSession = async () => {
|
|
5629
|
+
const currentState = store.getState();
|
|
5630
|
+
const currentSessionId = currentState.activeSessionId;
|
|
5631
|
+
const isCurrentSessionStreaming = currentSessionId ? currentState.isStreamingBySession[currentSessionId] ?? false : false;
|
|
5632
|
+
if (!currentSessionId || !isCurrentSessionStreaming) {
|
|
5633
|
+
return;
|
|
5634
|
+
}
|
|
5635
|
+
await stopRef.current(currentSessionId);
|
|
5636
|
+
};
|
|
5637
|
+
const handleStartNewChat = async () => {
|
|
5638
|
+
const currentState = store.getState();
|
|
5639
|
+
const currentSessionId = currentState.activeSessionId;
|
|
5640
|
+
const isCurrentSessionStreaming = currentSessionId ? currentState.isStreamingBySession[currentSessionId] ?? false : false;
|
|
5641
|
+
if (currentSessionId && isCurrentSessionStreaming) {
|
|
5642
|
+
void stopRef.current(currentSessionId);
|
|
5643
|
+
}
|
|
5644
|
+
createNewSession();
|
|
5645
|
+
};
|
|
5646
|
+
const triggerProps = {
|
|
5647
|
+
activeSessionId,
|
|
5648
|
+
isStreaming: isActiveSessionStreaming,
|
|
5649
|
+
isStopping: isActiveSessionStopping,
|
|
5650
|
+
createNewSession,
|
|
5651
|
+
stopActiveSession,
|
|
5652
|
+
startNewChat: handleStartNewChat
|
|
5653
|
+
};
|
|
5654
|
+
if (renderNewChatTrigger) {
|
|
5655
|
+
return /* @__PURE__ */ jsx18(QuickActionsRow, { children: /* @__PURE__ */ jsx18(NewChatTriggerRenderer, { renderNewChatTrigger, triggerProps }) });
|
|
5656
|
+
}
|
|
5657
|
+
return /* @__PURE__ */ jsx18(QuickActionsRow, { children: /* @__PURE__ */ jsx18(
|
|
5658
|
+
QuickActionButton,
|
|
5659
|
+
{
|
|
5660
|
+
type: "button",
|
|
5661
|
+
"data-testid": "chat-start-new-session",
|
|
5662
|
+
onClick: () => void handleStartNewChat(),
|
|
5663
|
+
disabled: isActiveSessionStopping,
|
|
5664
|
+
children: labels.newChat
|
|
5665
|
+
}
|
|
5666
|
+
) });
|
|
5667
|
+
};
|
|
5668
|
+
var NewChatTriggerRenderer = ({
|
|
5669
|
+
renderNewChatTrigger,
|
|
5670
|
+
triggerProps
|
|
5671
|
+
}) => /* @__PURE__ */ jsx18(Fragment5, { children: renderNewChatTrigger(triggerProps) });
|
|
5672
|
+
var AiChat = ({
|
|
5673
|
+
showConversationList = false,
|
|
5674
|
+
showNewChatButton = false,
|
|
5675
|
+
renderNewChatTrigger,
|
|
5676
|
+
...providerProps
|
|
5677
|
+
}) => /* @__PURE__ */ jsx18(
|
|
5461
5678
|
ConfigProvider,
|
|
5462
5679
|
{
|
|
5463
5680
|
theme: {
|
|
@@ -5495,6 +5712,7 @@ var AiChat = ({ showConversationList = false, ...providerProps }) => /* @__PURE_
|
|
|
5495
5712
|
children: /* @__PURE__ */ jsx18(AiChatProvider, { ...providerProps, children: /* @__PURE__ */ jsxs13(Root, { "data-testid": "ai-chat", children: [
|
|
5496
5713
|
showConversationList ? /* @__PURE__ */ jsx18(ChatConversationList, {}) : null,
|
|
5497
5714
|
/* @__PURE__ */ jsxs13(Workspace, { children: [
|
|
5715
|
+
showNewChatButton && !showConversationList ? /* @__PURE__ */ jsx18(QuickActions, { renderNewChatTrigger }) : null,
|
|
5498
5716
|
/* @__PURE__ */ jsx18(ChatThread, {}),
|
|
5499
5717
|
/* @__PURE__ */ jsx18(ChatComposer, {})
|
|
5500
5718
|
] })
|
|
@@ -5512,9 +5730,28 @@ var Workspace = styled17.section`
|
|
|
5512
5730
|
flex: 1;
|
|
5513
5731
|
display: flex;
|
|
5514
5732
|
flex-direction: column;
|
|
5733
|
+
gap: 12px;
|
|
5515
5734
|
min-height: 0;
|
|
5516
5735
|
overflow: hidden;
|
|
5517
5736
|
`;
|
|
5737
|
+
var QuickActionsRow = styled17.div`
|
|
5738
|
+
display: flex;
|
|
5739
|
+
justify-content: flex-end;
|
|
5740
|
+
padding: 12px 12px 0;
|
|
5741
|
+
`;
|
|
5742
|
+
var QuickActionButton = styled17.button`
|
|
5743
|
+
border: none;
|
|
5744
|
+
border-radius: 12px;
|
|
5745
|
+
padding: 10px 14px;
|
|
5746
|
+
background: rgba(255, 255, 255, 0.08);
|
|
5747
|
+
color: var(--text-primary, #fcfbf8);
|
|
5748
|
+
cursor: pointer;
|
|
5749
|
+
|
|
5750
|
+
&:disabled {
|
|
5751
|
+
opacity: 0.5;
|
|
5752
|
+
cursor: not-allowed;
|
|
5753
|
+
}
|
|
5754
|
+
`;
|
|
5518
5755
|
export {
|
|
5519
5756
|
AiChat,
|
|
5520
5757
|
AiChatProvider,
|