@copilotz/chat-ui 0.1.34 → 0.1.35
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.cjs +130 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +130 -46
- package/dist/index.js.map +1 -1
- package/dist/styles.css +7 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -96,6 +96,8 @@ var defaultChatConfig = {
|
|
|
96
96
|
voiceFinishing: "Finishing capture...",
|
|
97
97
|
voiceReview: "Ready to send",
|
|
98
98
|
voiceSending: "Sending...",
|
|
99
|
+
voiceReviewArmedHint: "Still listening. Speak to add more before it sends.",
|
|
100
|
+
voiceReviewPausedHint: "Tap the mic to keep adding to this message.",
|
|
99
101
|
voiceStart: "Start recording",
|
|
100
102
|
voiceStop: "Stop recording",
|
|
101
103
|
voiceSendNow: "Send now",
|
|
@@ -171,6 +173,7 @@ var defaultChatConfig = {
|
|
|
171
173
|
voiceCompose: {
|
|
172
174
|
enabled: false,
|
|
173
175
|
defaultMode: "text",
|
|
176
|
+
reviewMode: "manual",
|
|
174
177
|
autoSendDelayMs: 5e3,
|
|
175
178
|
persistComposer: true,
|
|
176
179
|
showTranscriptPreview: true,
|
|
@@ -3256,11 +3259,13 @@ var VoiceComposer = ({
|
|
|
3256
3259
|
countdownMs,
|
|
3257
3260
|
autoSendDelayMs,
|
|
3258
3261
|
isAutoSendActive,
|
|
3262
|
+
reviewMode,
|
|
3259
3263
|
errorMessage,
|
|
3260
3264
|
disabled = false,
|
|
3261
3265
|
labels,
|
|
3262
3266
|
onStart,
|
|
3263
3267
|
onStop,
|
|
3268
|
+
onPauseReview,
|
|
3264
3269
|
onCancelAutoSend,
|
|
3265
3270
|
onDiscard,
|
|
3266
3271
|
onRecordAgain,
|
|
@@ -3272,9 +3277,26 @@ var VoiceComposer = ({
|
|
|
3272
3277
|
const countdownValue = autoSendDelayMs > 0 ? Math.min(100, Math.max(0, (autoSendDelayMs - countdownMs) / autoSendDelayMs * 100)) : 100;
|
|
3273
3278
|
const isBusy = state === "preparing" || state === "finishing" || state === "sending";
|
|
3274
3279
|
const isCapturing = state === "waiting_for_speech" || state === "listening";
|
|
3275
|
-
const
|
|
3280
|
+
const hasDraft = Boolean(attachment);
|
|
3281
|
+
const isDraftLayout = hasDraft;
|
|
3282
|
+
const isArmedDraft = isDraftLayout && reviewMode === "armed" && (state === "waiting_for_speech" || state === "listening");
|
|
3276
3283
|
const levelValue = isCapturing || state === "preparing" || state === "finishing" ? Math.max(8, Math.round(audioLevel * 100)) : 0;
|
|
3277
|
-
const headerLabel = state === "error" ? labels?.voiceCaptureError || "Unable to capture audio." : resolveStateLabel(state, labels, errorMessage);
|
|
3284
|
+
const headerLabel = hasDraft && state !== "sending" && state !== "error" ? labels?.voiceReview || "Ready to send" : state === "error" ? labels?.voiceCaptureError || "Unable to capture audio." : resolveStateLabel(state, labels, errorMessage);
|
|
3285
|
+
const reviewHelperText = isArmedDraft ? labels?.voiceReviewArmedHint || "Speak to add more before it sends." : labels?.voiceReviewPausedHint || labels?.voiceRecordAgain || "Tap the mic to continue this message.";
|
|
3286
|
+
const orbIsListening = state === "listening";
|
|
3287
|
+
const orbCanStop = !isDraftLayout && (state === "waiting_for_speech" || state === "listening");
|
|
3288
|
+
const orbIsReviewBusy = state === "preparing" || state === "finishing" || state === "sending";
|
|
3289
|
+
const handleReviewOrbClick = () => {
|
|
3290
|
+
if (state === "listening") {
|
|
3291
|
+
onStop();
|
|
3292
|
+
return;
|
|
3293
|
+
}
|
|
3294
|
+
if (isArmedDraft) {
|
|
3295
|
+
onPauseReview();
|
|
3296
|
+
return;
|
|
3297
|
+
}
|
|
3298
|
+
onRecordAgain();
|
|
3299
|
+
};
|
|
3278
3300
|
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "w-full max-w-3xl rounded-xl border bg-background p-3 shadow-sm sm:p-4 md:min-w-3xl", children: [
|
|
3279
3301
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center justify-between gap-2 sm:gap-3", children: [
|
|
3280
3302
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
@@ -3297,7 +3319,7 @@ var VoiceComposer = ({
|
|
|
3297
3319
|
}
|
|
3298
3320
|
)
|
|
3299
3321
|
] }),
|
|
3300
|
-
!
|
|
3322
|
+
!isDraftLayout ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mt-3 rounded-xl border border-dashed border-primary/30 bg-primary/5 px-3 py-3 text-center sm:px-4 sm:py-4", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "mx-auto flex w-full max-w-sm flex-col items-center gap-3", children: [
|
|
3301
3323
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3302
3324
|
Button,
|
|
3303
3325
|
{
|
|
@@ -3339,6 +3361,27 @@ var VoiceComposer = ({
|
|
|
3339
3361
|
}
|
|
3340
3362
|
)
|
|
3341
3363
|
] }),
|
|
3364
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "mt-4 flex flex-col items-center gap-3 text-center", children: [
|
|
3365
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3366
|
+
Button,
|
|
3367
|
+
{
|
|
3368
|
+
type: "button",
|
|
3369
|
+
size: "icon",
|
|
3370
|
+
variant: orbCanStop ? "destructive" : "outline",
|
|
3371
|
+
className: `h-16 w-16 rounded-full sm:h-20 sm:w-20 ${orbIsListening ? "border-red-500 bg-red-500 text-white hover:bg-red-600" : isArmedDraft ? "border-red-200 bg-red-50 text-red-600 shadow-[0_0_0_10px_rgba(239,68,68,0.08)] hover:bg-red-100 hover:text-red-700" : "border-red-200 bg-red-50 text-red-600 hover:bg-red-100 hover:text-red-700"}`,
|
|
3372
|
+
onClick: handleReviewOrbClick,
|
|
3373
|
+
disabled: disabled || orbIsReviewBusy,
|
|
3374
|
+
children: orbIsReviewBusy ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Loader2, { className: "h-7 w-7 animate-spin" }) : orbIsListening ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Square, { className: "h-7 w-7" }) : isArmedDraft ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Mic, { className: "h-7 w-7 animate-pulse" }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Mic, { className: "h-7 w-7" })
|
|
3375
|
+
}
|
|
3376
|
+
),
|
|
3377
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "w-full max-w-sm space-y-2", children: [
|
|
3378
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Progress, { value: levelValue, className: "h-2" }),
|
|
3379
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [
|
|
3380
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: formatDuration(durationMs) }),
|
|
3381
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "max-w-[15rem] text-right", children: reviewHelperText })
|
|
3382
|
+
] })
|
|
3383
|
+
] })
|
|
3384
|
+
] }),
|
|
3342
3385
|
attachment && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mt-3 rounded-lg bg-background p-2", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("audio", { controls: true, preload: "metadata", className: "w-full", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("source", { src: attachment.dataUrl, type: attachment.mimeType }) }) }),
|
|
3343
3386
|
showTranscriptPreview && transcriptMode !== "none" && transcriptText && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mt-3 rounded-lg border bg-background px-3 py-2 text-left text-sm", children: transcriptText }),
|
|
3344
3387
|
isAutoSendActive && autoSendDelayMs > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "mt-3 space-y-2", children: [
|
|
@@ -3350,19 +3393,6 @@ var VoiceComposer = ({
|
|
|
3350
3393
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.X, { className: "h-4 w-4" }),
|
|
3351
3394
|
labels?.voiceCancel || "Cancel"
|
|
3352
3395
|
] }),
|
|
3353
|
-
!isAutoSendActive && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3354
|
-
Button,
|
|
3355
|
-
{
|
|
3356
|
-
type: "button",
|
|
3357
|
-
variant: "outline",
|
|
3358
|
-
size: "icon",
|
|
3359
|
-
onClick: onRecordAgain,
|
|
3360
|
-
disabled,
|
|
3361
|
-
"aria-label": labels?.voiceRecordAgain || "Record again",
|
|
3362
|
-
title: labels?.voiceRecordAgain || "Record again",
|
|
3363
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Mic, { className: "h-4 w-4" })
|
|
3364
|
-
}
|
|
3365
|
-
),
|
|
3366
3396
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Button, { type: "button", size: "sm", onClick: onSendNow, disabled, children: [
|
|
3367
3397
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Send, { className: "h-4 w-4" }),
|
|
3368
3398
|
labels?.voiceSendNow || "Send now"
|
|
@@ -3640,6 +3670,7 @@ var ChatInput = (0, import_react5.memo)(function ChatInput2({
|
|
|
3640
3670
|
}) {
|
|
3641
3671
|
const voiceComposeEnabled = config?.voiceCompose?.enabled === true;
|
|
3642
3672
|
const voiceDefaultMode = config?.voiceCompose?.defaultMode ?? "text";
|
|
3673
|
+
const voiceReviewMode = config?.voiceCompose?.reviewMode ?? "manual";
|
|
3643
3674
|
const voiceAutoSendDelayMs = config?.voiceCompose?.autoSendDelayMs ?? 5e3;
|
|
3644
3675
|
const voicePersistComposer = config?.voiceCompose?.persistComposer ?? true;
|
|
3645
3676
|
const voiceShowTranscriptPreview = config?.voiceCompose?.showTranscriptPreview ?? true;
|
|
@@ -3874,13 +3905,30 @@ var ChatInput = (0, import_react5.memo)(function ChatInput2({
|
|
|
3874
3905
|
setIsVoiceAutoSendActive(false);
|
|
3875
3906
|
setVoiceError(null);
|
|
3876
3907
|
}, []);
|
|
3908
|
+
const armVoiceDraftForAppend = (0, import_react5.useCallback)((segment) => {
|
|
3909
|
+
voiceAppendBaseRef.current = segment;
|
|
3910
|
+
voiceAppendBaseDurationRef.current = segment ? resolveVoiceSegmentDuration(segment) : 0;
|
|
3911
|
+
}, []);
|
|
3912
|
+
const handleVoiceProviderStateChange = (0, import_react5.useCallback)((nextState) => {
|
|
3913
|
+
if (voiceReviewMode === "armed" && (nextState === "waiting_for_speech" || nextState === "listening")) {
|
|
3914
|
+
const currentDraft = voiceDraftRef.current;
|
|
3915
|
+
if (currentDraft) {
|
|
3916
|
+
armVoiceDraftForAppend(currentDraft);
|
|
3917
|
+
}
|
|
3918
|
+
}
|
|
3919
|
+
if (voiceReviewMode === "armed" && nextState === "listening" && voiceDraftRef.current) {
|
|
3920
|
+
setVoiceCountdownMs(voiceAutoSendDelayMs);
|
|
3921
|
+
setIsVoiceAutoSendActive(false);
|
|
3922
|
+
}
|
|
3923
|
+
setVoiceState(nextState);
|
|
3924
|
+
}, [armVoiceDraftForAppend, voiceAutoSendDelayMs, voiceReviewMode]);
|
|
3877
3925
|
const ensureVoiceProvider = (0, import_react5.useCallback)(async () => {
|
|
3878
3926
|
if (voiceProviderRef.current) {
|
|
3879
3927
|
return voiceProviderRef.current;
|
|
3880
3928
|
}
|
|
3881
3929
|
const createProvider = resolveVoiceProviderFactory(config?.voiceCompose?.createProvider);
|
|
3882
3930
|
const provider = await createProvider({
|
|
3883
|
-
onStateChange:
|
|
3931
|
+
onStateChange: handleVoiceProviderStateChange,
|
|
3884
3932
|
onAudioLevelChange: setVoiceAudioLevel,
|
|
3885
3933
|
onDurationChange: (durationMs) => {
|
|
3886
3934
|
setVoiceDurationMs(voiceAppendBaseDurationRef.current + durationMs);
|
|
@@ -3896,8 +3944,6 @@ var ChatInput = (0, import_react5.memo)(function ChatInput2({
|
|
|
3896
3944
|
const previousSegment = voiceAppendBaseRef.current;
|
|
3897
3945
|
try {
|
|
3898
3946
|
const nextSegment = previousSegment ? await appendVoiceSegments(previousSegment, segment) : segment;
|
|
3899
|
-
voiceAppendBaseRef.current = null;
|
|
3900
|
-
voiceAppendBaseDurationRef.current = 0;
|
|
3901
3947
|
voiceDraftRef.current = nextSegment;
|
|
3902
3948
|
setVoiceDraft(nextSegment);
|
|
3903
3949
|
setVoiceTranscript(nextSegment.transcript ?? clearVoiceTranscript());
|
|
@@ -3906,11 +3952,15 @@ var ChatInput = (0, import_react5.memo)(function ChatInput2({
|
|
|
3906
3952
|
setVoiceCountdownMs(voiceAutoSendDelayMs);
|
|
3907
3953
|
setIsVoiceAutoSendActive(voiceAutoSendDelayMs > 0);
|
|
3908
3954
|
setVoiceError(null);
|
|
3909
|
-
|
|
3955
|
+
if (voiceReviewMode === "armed") {
|
|
3956
|
+
armVoiceDraftForAppend(nextSegment);
|
|
3957
|
+
} else {
|
|
3958
|
+
armVoiceDraftForAppend(null);
|
|
3959
|
+
}
|
|
3960
|
+
setVoiceState((currentState) => voiceReviewMode === "armed" && (currentState === "waiting_for_speech" || currentState === "listening") ? currentState : "review");
|
|
3910
3961
|
} catch (error) {
|
|
3911
3962
|
const resolvedError = resolveVoiceErrorMessage(error, config);
|
|
3912
|
-
|
|
3913
|
-
voiceAppendBaseDurationRef.current = 0;
|
|
3963
|
+
armVoiceDraftForAppend(null);
|
|
3914
3964
|
setVoiceAudioLevel(0);
|
|
3915
3965
|
setVoiceCountdownMs(0);
|
|
3916
3966
|
setIsVoiceAutoSendActive(false);
|
|
@@ -3934,8 +3984,7 @@ var ChatInput = (0, import_react5.memo)(function ChatInput2({
|
|
|
3934
3984
|
},
|
|
3935
3985
|
onError: (error) => {
|
|
3936
3986
|
const previousSegment = voiceAppendBaseRef.current;
|
|
3937
|
-
|
|
3938
|
-
voiceAppendBaseDurationRef.current = 0;
|
|
3987
|
+
armVoiceDraftForAppend(null);
|
|
3939
3988
|
setVoiceError(resolveVoiceErrorMessage(error, config));
|
|
3940
3989
|
setVoiceAudioLevel(0);
|
|
3941
3990
|
setVoiceCountdownMs(0);
|
|
@@ -3959,7 +4008,7 @@ var ChatInput = (0, import_react5.memo)(function ChatInput2({
|
|
|
3959
4008
|
});
|
|
3960
4009
|
voiceProviderRef.current = provider;
|
|
3961
4010
|
return provider;
|
|
3962
|
-
}, [config, voiceAutoSendDelayMs, voiceMaxRecordingMs]);
|
|
4011
|
+
}, [armVoiceDraftForAppend, config, handleVoiceProviderStateChange, voiceAutoSendDelayMs, voiceMaxRecordingMs, voiceReviewMode]);
|
|
3963
4012
|
const closeVoiceComposer = (0, import_react5.useCallback)(async () => {
|
|
3964
4013
|
voiceAppendBaseRef.current = null;
|
|
3965
4014
|
voiceAppendBaseDurationRef.current = 0;
|
|
@@ -4051,16 +4100,21 @@ var ChatInput = (0, import_react5.memo)(function ChatInput2({
|
|
|
4051
4100
|
void closeVoiceComposer();
|
|
4052
4101
|
}, [voicePersistComposer, resetVoiceComposerState, closeVoiceComposer]);
|
|
4053
4102
|
const sendVoiceDraft = (0, import_react5.useCallback)(() => {
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4103
|
+
void (async () => {
|
|
4104
|
+
if (!voiceDraft || disabled || isGenerating) {
|
|
4105
|
+
return;
|
|
4106
|
+
}
|
|
4107
|
+
setVoiceState("sending");
|
|
4108
|
+
setVoiceCountdownMs(0);
|
|
4109
|
+
setIsVoiceAutoSendActive(false);
|
|
4110
|
+
if (voiceProviderRef.current) {
|
|
4111
|
+
await voiceProviderRef.current.cancel();
|
|
4112
|
+
}
|
|
4113
|
+
onSubmit("", [...attachments, voiceDraft.attachment]);
|
|
4114
|
+
onChange("");
|
|
4115
|
+
onAttachmentsChange([]);
|
|
4116
|
+
finalizeVoiceComposerAfterSend();
|
|
4117
|
+
})();
|
|
4064
4118
|
}, [
|
|
4065
4119
|
voiceDraft,
|
|
4066
4120
|
disabled,
|
|
@@ -4072,25 +4126,51 @@ var ChatInput = (0, import_react5.memo)(function ChatInput2({
|
|
|
4072
4126
|
finalizeVoiceComposerAfterSend
|
|
4073
4127
|
]);
|
|
4074
4128
|
const cancelVoiceAutoSend = (0, import_react5.useCallback)(() => {
|
|
4129
|
+
void (async () => {
|
|
4130
|
+
if (voiceReviewMode === "armed" && voiceProviderRef.current) {
|
|
4131
|
+
await voiceProviderRef.current.cancel();
|
|
4132
|
+
}
|
|
4133
|
+
armVoiceDraftForAppend(null);
|
|
4134
|
+
setVoiceAudioLevel(0);
|
|
4135
|
+
setVoiceState("review");
|
|
4136
|
+
})();
|
|
4075
4137
|
setVoiceCountdownMs(0);
|
|
4076
4138
|
setIsVoiceAutoSendActive(false);
|
|
4077
|
-
}, []);
|
|
4139
|
+
}, [armVoiceDraftForAppend, voiceReviewMode]);
|
|
4140
|
+
const pauseVoiceReview = (0, import_react5.useCallback)(async () => {
|
|
4141
|
+
if (voiceState === "listening") {
|
|
4142
|
+
await stopVoiceCapture();
|
|
4143
|
+
return;
|
|
4144
|
+
}
|
|
4145
|
+
if (voiceReviewMode === "armed" && voiceProviderRef.current) {
|
|
4146
|
+
await voiceProviderRef.current.cancel();
|
|
4147
|
+
}
|
|
4148
|
+
armVoiceDraftForAppend(null);
|
|
4149
|
+
setVoiceAudioLevel(0);
|
|
4150
|
+
setVoiceState("review");
|
|
4151
|
+
}, [armVoiceDraftForAppend, stopVoiceCapture, voiceReviewMode, voiceState]);
|
|
4078
4152
|
(0, import_react5.useEffect)(() => {
|
|
4079
|
-
if (
|
|
4153
|
+
if (!voiceDraft || voiceAutoSendDelayMs <= 0 || !isVoiceAutoSendActive) {
|
|
4154
|
+
return;
|
|
4155
|
+
}
|
|
4156
|
+
const canContinueCounting = voiceState === "review" || voiceReviewMode === "armed" && voiceState === "waiting_for_speech";
|
|
4157
|
+
if (!canContinueCounting) {
|
|
4080
4158
|
return;
|
|
4081
4159
|
}
|
|
4082
|
-
const startedAt = Date.now();
|
|
4083
|
-
setVoiceCountdownMs(voiceAutoSendDelayMs);
|
|
4084
4160
|
const timer = setInterval(() => {
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4161
|
+
setVoiceCountdownMs((previous) => {
|
|
4162
|
+
const remaining = Math.max(0, previous - 100);
|
|
4163
|
+
if (remaining <= 0) {
|
|
4164
|
+
clearInterval(timer);
|
|
4165
|
+
queueMicrotask(() => {
|
|
4166
|
+
sendVoiceDraft();
|
|
4167
|
+
});
|
|
4168
|
+
}
|
|
4169
|
+
return remaining;
|
|
4170
|
+
});
|
|
4091
4171
|
}, 100);
|
|
4092
4172
|
return () => clearInterval(timer);
|
|
4093
|
-
}, [voiceState, voiceDraft, voiceAutoSendDelayMs, isVoiceAutoSendActive, sendVoiceDraft]);
|
|
4173
|
+
}, [voiceState, voiceDraft, voiceReviewMode, voiceAutoSendDelayMs, isVoiceAutoSendActive, sendVoiceDraft]);
|
|
4094
4174
|
const removeAttachment = (index) => {
|
|
4095
4175
|
const newAttachments = attachments.filter((_, i) => i !== index);
|
|
4096
4176
|
onAttachmentsChange(newAttachments);
|
|
@@ -4145,6 +4225,7 @@ var ChatInput = (0, import_react5.memo)(function ChatInput2({
|
|
|
4145
4225
|
countdownMs: voiceCountdownMs,
|
|
4146
4226
|
autoSendDelayMs: voiceAutoSendDelayMs,
|
|
4147
4227
|
isAutoSendActive: isVoiceAutoSendActive,
|
|
4228
|
+
reviewMode: voiceReviewMode,
|
|
4148
4229
|
errorMessage: voiceError,
|
|
4149
4230
|
disabled: disabled || isGenerating,
|
|
4150
4231
|
labels: config?.labels,
|
|
@@ -4154,6 +4235,9 @@ var ChatInput = (0, import_react5.memo)(function ChatInput2({
|
|
|
4154
4235
|
onStop: () => {
|
|
4155
4236
|
void stopVoiceCapture();
|
|
4156
4237
|
},
|
|
4238
|
+
onPauseReview: () => {
|
|
4239
|
+
void pauseVoiceReview();
|
|
4240
|
+
},
|
|
4157
4241
|
onCancelAutoSend: () => {
|
|
4158
4242
|
cancelVoiceAutoSend();
|
|
4159
4243
|
},
|