@opengeni/react 0.45.0 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -12
- package/dist/{chunk-U3CSCMWA.js → chunk-FK6VG4LL.js} +9 -13
- package/dist/chunk-FK6VG4LL.js.map +1 -0
- package/dist/{chunk-HFO4ERGQ.js → chunk-FWXGSNXT.js} +2 -2
- package/dist/{chunk-SRFUT2ZU.js → chunk-I4MPFDRP.js} +119 -63
- package/dist/chunk-I4MPFDRP.js.map +1 -0
- package/dist/{chunk-EB67J347.js → chunk-KZ73RL76.js} +111 -31
- package/dist/chunk-KZ73RL76.js.map +1 -0
- package/dist/{chunk-LWR4MXSS.js → chunk-LHLYWG5R.js} +10 -1
- package/dist/chunk-LHLYWG5R.js.map +1 -0
- package/dist/{chunk-L3EWO3UK.js → chunk-NJ7M2B6Z.js} +445 -84
- package/dist/chunk-NJ7M2B6Z.js.map +1 -0
- package/dist/{chunk-VCBFUSUZ.js → chunk-O4VXOBGF.js} +3 -3
- package/dist/{chunk-VCBFUSUZ.js.map → chunk-O4VXOBGF.js.map} +1 -1
- package/dist/{chunk-6EDV6YFE.js → chunk-OL6QVXGF.js} +121 -29
- package/dist/chunk-OL6QVXGF.js.map +1 -0
- package/dist/chunk-VZTQ73XT.js +86 -0
- package/dist/chunk-VZTQ73XT.js.map +1 -0
- package/dist/{chunk-EHSYZ4KP.js → chunk-WYA65Y3F.js} +16 -16
- package/dist/chunk-WYA65Y3F.js.map +1 -0
- package/dist/{chunk-FD72GJMK.js → chunk-XCNTXWBB.js} +274 -125
- package/dist/chunk-XCNTXWBB.js.map +1 -0
- package/dist/client.d.ts +1 -1
- package/dist/components/chat-composer.d.ts +7 -2
- package/dist/components/composer-transcription-control.d.ts +2 -0
- package/dist/components/composer.d.ts +14 -0
- package/dist/components/machines/machine-detail.d.ts +3 -1
- package/dist/components/machines-dashboard.d.ts +3 -3
- package/dist/components/message-timeline.d.ts +12 -2
- package/dist/components/sandbox-files.d.ts +2 -2
- package/dist/components/sandbox-terminal.d.ts +29 -0
- package/dist/components/sandbox-workspace.d.ts +5 -1
- package/dist/components/workspace-dock.d.ts +3 -1
- package/dist/composer.d.ts +2 -2
- package/dist/composer.js +6 -6
- package/dist/hooks/internal.d.ts +6 -0
- package/dist/hooks/use-codex-accounts.d.ts +1 -1
- package/dist/hooks/use-environments.d.ts +10 -4
- package/dist/hooks/use-machines.d.ts +7 -0
- package/dist/hooks/use-sandbox-files.d.ts +19 -0
- package/dist/hooks/use-sandbox-git.d.ts +7 -0
- package/dist/hooks/use-transcription.d.ts +2 -2
- package/dist/hooks/use-voice-input.d.ts +13 -4
- package/dist/index.d.ts +6 -5
- package/dist/index.js +904 -538
- package/dist/index.js.map +1 -1
- package/dist/lib/composer-responsive-context.d.ts +9 -0
- package/dist/lib/use-portal-token-style.d.ts +14 -3
- package/dist/machines.js +2 -2
- package/dist/{queue-surface-implementation-J4XJFKRW.js → queue-surface-implementation-U5JFG7HT.js} +19 -18
- package/dist/queue-surface-implementation-U5JFG7HT.js.map +1 -0
- package/dist/realtime/realtime-control.d.ts +9 -0
- package/dist/realtime.js +29 -32
- package/dist/realtime.js.map +1 -1
- package/dist/session-ui.js +5 -5
- package/dist/session.js +4 -4
- package/dist/timeline/activity-rail.d.ts +3 -2
- package/dist/timeline/index.d.ts +2 -2
- package/dist/timeline/parsers.d.ts +3 -3
- package/dist/timeline/registry.d.ts +3 -0
- package/dist/timeline/screenshot-lightbox.d.ts +1 -1
- package/dist/timeline/types.d.ts +4 -0
- package/dist/voice-recording-store.d.ts +8 -2
- package/package.json +20 -4
- package/src/client.ts +3 -0
- package/src/components/chat-composer.tsx +12 -2
- package/src/components/code-editor.tsx +1 -1
- package/src/components/command-palette.tsx +1 -1
- package/src/components/composer-transcription-control.tsx +41 -16
- package/src/components/composer.tsx +52 -26
- package/src/components/copy-button.tsx +2 -2
- package/src/components/desktop-viewer.tsx +2 -2
- package/src/components/file-browser.tsx +39 -17
- package/src/components/human-input-form.tsx +2 -2
- package/src/components/machine-card.tsx +1 -1
- package/src/components/machines/machine-detail.tsx +39 -15
- package/src/components/machines-dashboard.tsx +7 -6
- package/src/components/message-timeline.tsx +44 -11
- package/src/components/model-picker.tsx +2 -2
- package/src/components/model-policy-picker.tsx +16 -15
- package/src/components/queue-surface-implementation.tsx +20 -16
- package/src/components/queue-surface-state.tsx +2 -2
- package/src/components/sandbox-files.tsx +140 -60
- package/src/components/sandbox-terminal.tsx +24 -5
- package/src/components/sandbox-workspace.tsx +180 -142
- package/src/components/session-chrome.tsx +14 -14
- package/src/components/tooltip.tsx +13 -16
- package/src/components/user-message-body.tsx +1 -1
- package/src/components/workbench-changes.tsx +4 -4
- package/src/components/workspace-dock.tsx +13 -5
- package/src/composer.ts +3 -0
- package/src/hooks/internal.ts +132 -38
- package/src/hooks/use-codex-accounts.ts +4 -4
- package/src/hooks/use-environments.ts +24 -5
- package/src/hooks/use-file-attachments.ts +70 -32
- package/src/hooks/use-goal.ts +17 -5
- package/src/hooks/use-machines.ts +47 -1
- package/src/hooks/use-sandbox-files.ts +310 -59
- package/src/hooks/use-sandbox-git.ts +148 -41
- package/src/hooks/use-session-capabilities.ts +35 -24
- package/src/hooks/use-session-events.ts +18 -4
- package/src/hooks/use-transcription.ts +4 -14
- package/src/hooks/use-turn-queue.ts +17 -5
- package/src/hooks/use-voice-input.ts +481 -36
- package/src/hooks/use-windowed-sections.ts +9 -7
- package/src/index.ts +11 -6
- package/src/lib/composer-responsive-context.ts +15 -0
- package/src/lib/use-portal-token-style.ts +60 -15
- package/src/provider.tsx +52 -7
- package/src/realtime/dropdown-menu.tsx +15 -19
- package/src/realtime/realtime-control.tsx +18 -7
- package/src/timeline/activity-rail.tsx +15 -6
- package/src/timeline/index.ts +1 -1
- package/src/timeline/parsers.ts +33 -20
- package/src/timeline/projection.ts +23 -0
- package/src/timeline/registry.ts +7 -0
- package/src/timeline/screenshot-lightbox.tsx +15 -4
- package/src/timeline/shared.tsx +8 -8
- package/src/timeline/tool-renderers.tsx +166 -22
- package/src/timeline/turn-summary.tsx +6 -6
- package/src/timeline/types.ts +4 -0
- package/src/voice-recording-store.ts +15 -0
- package/styles/compiled.css +5065 -0
- package/styles/compiled.d.ts +2 -0
- package/styles/effective-tokens.css +27 -0
- package/styles/index.css +3 -0
- package/styles/responsive.css +196 -0
- package/styles/responsive.d.ts +2 -0
- package/styles/tokens.css +50 -17
- package/dist/chunk-6EDV6YFE.js.map +0 -1
- package/dist/chunk-EB67J347.js.map +0 -1
- package/dist/chunk-EHSYZ4KP.js.map +0 -1
- package/dist/chunk-FD72GJMK.js.map +0 -1
- package/dist/chunk-JB5725BI.js +0 -48
- package/dist/chunk-JB5725BI.js.map +0 -1
- package/dist/chunk-L3EWO3UK.js.map +0 -1
- package/dist/chunk-LWR4MXSS.js.map +0 -1
- package/dist/chunk-SRFUT2ZU.js.map +0 -1
- package/dist/chunk-U3CSCMWA.js.map +0 -1
- package/dist/queue-surface-implementation-J4XJFKRW.js.map +0 -1
- /package/dist/{chunk-HFO4ERGQ.js.map → chunk-FWXGSNXT.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
shouldSteerOnKey,
|
|
3
3
|
shouldSubmitOnKey
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-FWXGSNXT.js";
|
|
5
5
|
import {
|
|
6
6
|
groupPickerRowsByBillingClass
|
|
7
7
|
} from "./chunk-23EJ676W.js";
|
|
@@ -10,12 +10,15 @@ import {
|
|
|
10
10
|
TooltipContent,
|
|
11
11
|
TooltipProvider,
|
|
12
12
|
TooltipTrigger
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-FK6VG4LL.js";
|
|
14
14
|
import {
|
|
15
15
|
composerSubmissionErrorMessage,
|
|
16
16
|
formatBytes,
|
|
17
17
|
formatRelativeTime
|
|
18
18
|
} from "./chunk-LAKLF4PA.js";
|
|
19
|
+
import {
|
|
20
|
+
ComposerResponsiveContext
|
|
21
|
+
} from "./chunk-VZTQ73XT.js";
|
|
19
22
|
import {
|
|
20
23
|
cn
|
|
21
24
|
} from "./chunk-22KP6LR5.js";
|
|
@@ -69,6 +72,8 @@ function createVoiceRecordingManifest(input) {
|
|
|
69
72
|
uploadState: "pending",
|
|
70
73
|
transcriptionState: "pending",
|
|
71
74
|
finalizationState: "pending",
|
|
75
|
+
recoveryMode: "automatic",
|
|
76
|
+
handoffMode: "append",
|
|
72
77
|
ownerId: input.ownerId ?? null,
|
|
73
78
|
ownerHeartbeatAt: input.ownerId ? input.createdAt : null,
|
|
74
79
|
transcriptText: null,
|
|
@@ -184,6 +189,7 @@ var IndexedDbVoiceRecordingStore = class {
|
|
|
184
189
|
const updated = {
|
|
185
190
|
...manifest,
|
|
186
191
|
captureState: manifest.captureState === "capturing" ? "stopped" : manifest.captureState,
|
|
192
|
+
handoffMode: "explicit",
|
|
187
193
|
ownerId,
|
|
188
194
|
ownerHeartbeatAt: claimedAt,
|
|
189
195
|
updatedAt: claimedAt
|
|
@@ -300,7 +306,9 @@ function normalizeManifest(manifest) {
|
|
|
300
306
|
...manifest,
|
|
301
307
|
ownerId: manifest.ownerId ?? null,
|
|
302
308
|
ownerHeartbeatAt: manifest.ownerHeartbeatAt ?? null,
|
|
303
|
-
transcriptText: manifest.transcriptText ?? null
|
|
309
|
+
transcriptText: manifest.transcriptText ?? null,
|
|
310
|
+
recoveryMode: manifest.recoveryMode ?? "manual",
|
|
311
|
+
handoffMode: manifest.handoffMode ?? "explicit"
|
|
304
312
|
};
|
|
305
313
|
}
|
|
306
314
|
function manifestAvailableToOwner(manifest, ownership) {
|
|
@@ -546,7 +554,7 @@ function useTranscription({
|
|
|
546
554
|
(diagnostic) => {
|
|
547
555
|
if (!onDiagnostic) return;
|
|
548
556
|
try {
|
|
549
|
-
onDiagnostic(
|
|
557
|
+
onDiagnostic(normalizeTranscriptionDiagnostic(diagnostic));
|
|
550
558
|
} catch {
|
|
551
559
|
}
|
|
552
560
|
},
|
|
@@ -840,18 +848,14 @@ function normalizeTranscriptionErrorCode(code) {
|
|
|
840
848
|
return "unknown";
|
|
841
849
|
}
|
|
842
850
|
}
|
|
843
|
-
function
|
|
851
|
+
function normalizeTranscriptionDiagnostic(diagnostic) {
|
|
844
852
|
const source = isRecord(diagnostic) ? diagnostic : {};
|
|
845
853
|
const operation = source.operation === "start" || source.operation === "session" || source.operation === "cancel" || source.operation === "close" ? source.operation : "session";
|
|
846
854
|
const rawDetail = typeof source.detail === "string" ? source.detail : "No diagnostic detail.";
|
|
847
|
-
const detail = rawDetail.replace(/[\u0000-\u001f\u007f]+/gu, " ").replace(/\bBearer\s+[A-Za-z0-9._~+/=-]+/giu, "Bearer [REDACTED]").replace(/\bsk-[A-Za-z0-9_-]{4,}\b/gu, "[REDACTED]").replace(
|
|
848
|
-
/\b(api[-_ ]?key|authorization|access[-_ ]?token|refresh[-_ ]?token|token|secret)\b\s*[:=]\s*[^\s,;]+/giu,
|
|
849
|
-
"$1=[REDACTED]"
|
|
850
|
-
).trim().slice(0, 512);
|
|
851
855
|
return {
|
|
852
856
|
operation,
|
|
853
857
|
code: normalizeTranscriptionErrorCode(source.code),
|
|
854
|
-
detail:
|
|
858
|
+
detail: rawDetail
|
|
855
859
|
};
|
|
856
860
|
}
|
|
857
861
|
function detachSessionCleanup(session, options) {
|
|
@@ -929,6 +933,7 @@ function transcriptionPolicyRevision(policy, selection) {
|
|
|
929
933
|
}
|
|
930
934
|
|
|
931
935
|
// src/hooks/use-voice-input.ts
|
|
936
|
+
import { OpenGeniApiError } from "@opengeni/sdk";
|
|
932
937
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
933
938
|
|
|
934
939
|
// src/voice-recording-owner.ts
|
|
@@ -1113,9 +1118,31 @@ var VOICE_RECORDING_TIMESLICE_MILLISECONDS = 5e3;
|
|
|
1113
1118
|
var VOICE_RECORDING_OWNER_HEARTBEAT_MILLISECONDS = 5e3;
|
|
1114
1119
|
var VOICE_RECORDING_OWNER_STALE_MILLISECONDS = 3e4;
|
|
1115
1120
|
var VOICE_RECORDING_CLIENT_MAX_DURATION_SECONDS = 600;
|
|
1121
|
+
var VOICE_RECORDING_RESUMABLE_CLIENT_MAX_DURATION_SECONDS = 8 * 60 * 60;
|
|
1122
|
+
var VOICE_RECORDING_RECOVERY_STATUS_POLL_MILLISECONDS = 2e3;
|
|
1123
|
+
var VOICE_RECORDING_RECOVERY_MAX_MUTATION_DELAY_MILLISECONDS = 3e4;
|
|
1124
|
+
var TRANSCRIPTION_RECORDING_RECOVERY_RETRY_AFTER_MILLISECONDS = 5e3;
|
|
1116
1125
|
var MIME_PREFERENCES = ["audio/webm;codecs=opus", "audio/mp4", "audio/ogg;codecs=opus"];
|
|
1117
1126
|
var createDefaultVoiceRecordingId = () => crypto.randomUUID();
|
|
1118
1127
|
var currentDate = () => /* @__PURE__ */ new Date();
|
|
1128
|
+
function transcriptionRecoveryMutationDelayMilliseconds(retryAfterMilliseconds, attempt, random = Math.random) {
|
|
1129
|
+
const hint = typeof retryAfterMilliseconds === "number" && Number.isInteger(retryAfterMilliseconds) && retryAfterMilliseconds > 0 ? retryAfterMilliseconds : TRANSCRIPTION_RECORDING_RECOVERY_RETRY_AFTER_MILLISECONDS;
|
|
1130
|
+
const boundedHint = Math.max(
|
|
1131
|
+
500,
|
|
1132
|
+
Math.min(hint, VOICE_RECORDING_RECOVERY_MAX_MUTATION_DELAY_MILLISECONDS)
|
|
1133
|
+
);
|
|
1134
|
+
const exponent = Math.max(0, Math.min(Math.floor(attempt), 6));
|
|
1135
|
+
const exponential = Math.min(
|
|
1136
|
+
VOICE_RECORDING_RECOVERY_MAX_MUTATION_DELAY_MILLISECONDS,
|
|
1137
|
+
boundedHint * 2 ** exponent
|
|
1138
|
+
);
|
|
1139
|
+
const sampledJitter = random();
|
|
1140
|
+
const jitterRatio = Number.isFinite(sampledJitter) ? Math.max(0, Math.min(1, sampledJitter)) : 0;
|
|
1141
|
+
return Math.min(
|
|
1142
|
+
VOICE_RECORDING_RECOVERY_MAX_MUTATION_DELAY_MILLISECONDS,
|
|
1143
|
+
Math.ceil(exponential * (1 + jitterRatio * 0.2))
|
|
1144
|
+
);
|
|
1145
|
+
}
|
|
1119
1146
|
function useVoiceInput({
|
|
1120
1147
|
client,
|
|
1121
1148
|
workspaceId,
|
|
@@ -1128,7 +1155,8 @@ function useVoiceInput({
|
|
|
1128
1155
|
createRecordingStore,
|
|
1129
1156
|
createRecordingId = createDefaultVoiceRecordingId,
|
|
1130
1157
|
createOwnerId,
|
|
1131
|
-
now = currentDate
|
|
1158
|
+
now = currentDate,
|
|
1159
|
+
automaticRetryDelayMilliseconds
|
|
1132
1160
|
}) {
|
|
1133
1161
|
const [status, setStatus] = useState2("idle");
|
|
1134
1162
|
const [error, setError] = useState2(null);
|
|
@@ -1153,6 +1181,8 @@ function useVoiceInput({
|
|
|
1153
1181
|
const recorderRef = useRef2(null);
|
|
1154
1182
|
const streamRef = useRef2(null);
|
|
1155
1183
|
const timerRef = useRef2(null);
|
|
1184
|
+
const automaticRetryTimerRef = useRef2(null);
|
|
1185
|
+
const automaticRetryAttemptRef = useRef2(0);
|
|
1156
1186
|
const ownerHeartbeatTimerRef = useRef2(null);
|
|
1157
1187
|
const controllerRef = useRef2(null);
|
|
1158
1188
|
const valueRef = useRef2(value);
|
|
@@ -1204,6 +1234,7 @@ function useVoiceInput({
|
|
|
1204
1234
|
setRecordingId(null);
|
|
1205
1235
|
setDurationSeconds(0);
|
|
1206
1236
|
setLocallySaved(false);
|
|
1237
|
+
automaticRetryAttemptRef.current = 0;
|
|
1207
1238
|
}, [stopOwnerHeartbeat]);
|
|
1208
1239
|
const ensureStore = useCallback2(async () => {
|
|
1209
1240
|
if (storeRef.current) return storeRef.current;
|
|
@@ -1318,7 +1349,7 @@ function useVoiceInput({
|
|
|
1318
1349
|
rememberManifest(claimed);
|
|
1319
1350
|
beginOwnerHeartbeat(claimed);
|
|
1320
1351
|
setStatus(
|
|
1321
|
-
claimed.finalizationState === "transcript-ready" && claimed.transcriptText !== null ? "transcript-ready" : "recovered"
|
|
1352
|
+
claimed.finalizationState === "transcript-ready" && claimed.transcriptText !== null ? "transcript-ready" : claimed.recoveryMode === "automatic" ? "retrying" : "recovered"
|
|
1322
1353
|
);
|
|
1323
1354
|
setError(null);
|
|
1324
1355
|
return;
|
|
@@ -1337,8 +1368,10 @@ function useVoiceInput({
|
|
|
1337
1368
|
const finalizePersistedRecording = useCallback2(
|
|
1338
1369
|
async (generation) => {
|
|
1339
1370
|
const manifest = manifestRef.current;
|
|
1340
|
-
const
|
|
1341
|
-
|
|
1371
|
+
const resumable = capability?.resumable && isResumableVoiceInputClient(client) ? capability.resumable : null;
|
|
1372
|
+
const maxSizeBytes = resumable?.maxSizeBytes ?? capability?.maxSizeBytes;
|
|
1373
|
+
if (!manifest || !client || !capability || !maxSizeBytes || manifest.workspaceId !== workspaceId)
|
|
1374
|
+
return;
|
|
1342
1375
|
const controller = new AbortController();
|
|
1343
1376
|
controllerRef.current?.abort();
|
|
1344
1377
|
controllerRef.current = controller;
|
|
@@ -1370,7 +1403,12 @@ function useVoiceInput({
|
|
|
1370
1403
|
if (chunks.length === 0) {
|
|
1371
1404
|
const retained = await store.updateManifest(
|
|
1372
1405
|
transcribing.recordingId,
|
|
1373
|
-
{
|
|
1406
|
+
{
|
|
1407
|
+
uploadState: "retrying",
|
|
1408
|
+
transcriptionState: "retrying",
|
|
1409
|
+
recoveryMode: "manual",
|
|
1410
|
+
handoffMode: "explicit"
|
|
1411
|
+
},
|
|
1374
1412
|
readNow().toISOString(),
|
|
1375
1413
|
ownerIdRef.current ?? void 0
|
|
1376
1414
|
);
|
|
@@ -1378,16 +1416,12 @@ function useVoiceInput({
|
|
|
1378
1416
|
await preserveForRetry(retained, "invalid_audio", generation);
|
|
1379
1417
|
return;
|
|
1380
1418
|
}
|
|
1381
|
-
const
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
const response = await client.transcribeAudio(workspaceId, {
|
|
1388
|
-
audio,
|
|
1389
|
-
mimeType: audio.type,
|
|
1390
|
-
durationSeconds: transcribing.totalDurationMilliseconds / 1e3,
|
|
1419
|
+
const response = await transcribePersistedRecording({
|
|
1420
|
+
client,
|
|
1421
|
+
workspaceId,
|
|
1422
|
+
capability,
|
|
1423
|
+
manifest: transcribing,
|
|
1424
|
+
chunks,
|
|
1391
1425
|
signal: controller.signal
|
|
1392
1426
|
});
|
|
1393
1427
|
if (!active()) return;
|
|
@@ -1405,6 +1439,13 @@ function useVoiceInput({
|
|
|
1405
1439
|
);
|
|
1406
1440
|
if (!active()) return;
|
|
1407
1441
|
rememberManifest(ready);
|
|
1442
|
+
automaticRetryAttemptRef.current = 0;
|
|
1443
|
+
if (ready.handoffMode === "explicit") {
|
|
1444
|
+
setStatus("transcript-ready");
|
|
1445
|
+
setError("handoff_uncertain");
|
|
1446
|
+
focusInput();
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1408
1449
|
const next = appendFinalTranscript(valueRef.current, response.text);
|
|
1409
1450
|
if (next !== valueRef.current) {
|
|
1410
1451
|
valueRef.current = next;
|
|
@@ -1428,6 +1469,12 @@ function useVoiceInput({
|
|
|
1428
1469
|
}
|
|
1429
1470
|
if (!active()) return;
|
|
1430
1471
|
rememberManifest(handedOff);
|
|
1472
|
+
if (resumable && isResumableVoiceInputClient(client)) {
|
|
1473
|
+
await client.discardTranscriptionRecording(workspaceId, handedOff.recordingId, {
|
|
1474
|
+
signal: controller.signal
|
|
1475
|
+
}).catch(() => void 0);
|
|
1476
|
+
}
|
|
1477
|
+
if (!active()) return;
|
|
1431
1478
|
await store.discard(handedOff.recordingId, ownerIdRef.current ?? void 0).catch(() => void 0);
|
|
1432
1479
|
if (!active()) return;
|
|
1433
1480
|
clearVisibleRecording();
|
|
@@ -1437,22 +1484,28 @@ function useVoiceInput({
|
|
|
1437
1484
|
await loadNextRecoverable(generation);
|
|
1438
1485
|
} catch (reason) {
|
|
1439
1486
|
if (!active()) return;
|
|
1487
|
+
const code = controller.signal.aborted ? null : errorCode(reason);
|
|
1488
|
+
const retryable = !controller.signal.aborted && isRetryableVoiceInputError(reason);
|
|
1440
1489
|
const retained = await updateManifestBestEffort(transcribing, {
|
|
1441
1490
|
uploadState: "retrying",
|
|
1442
|
-
transcriptionState: "retrying"
|
|
1491
|
+
transcriptionState: "retrying",
|
|
1492
|
+
recoveryMode: retryable ? "automatic" : "manual",
|
|
1493
|
+
handoffMode: "explicit"
|
|
1443
1494
|
});
|
|
1444
1495
|
if (!active()) return;
|
|
1445
|
-
|
|
1446
|
-
retained
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1496
|
+
if (retryable) {
|
|
1497
|
+
rememberManifest(retained);
|
|
1498
|
+
setStatus("retrying");
|
|
1499
|
+
setError(code);
|
|
1500
|
+
} else {
|
|
1501
|
+
await preserveForRetry(retained, code, generation);
|
|
1502
|
+
}
|
|
1450
1503
|
} finally {
|
|
1451
1504
|
if (controllerRef.current === controller) controllerRef.current = null;
|
|
1452
1505
|
}
|
|
1453
1506
|
},
|
|
1454
1507
|
[
|
|
1455
|
-
capability
|
|
1508
|
+
capability,
|
|
1456
1509
|
clearVisibleRecording,
|
|
1457
1510
|
client,
|
|
1458
1511
|
ensureStore,
|
|
@@ -1466,6 +1519,44 @@ function useVoiceInput({
|
|
|
1466
1519
|
workspaceId
|
|
1467
1520
|
]
|
|
1468
1521
|
);
|
|
1522
|
+
const finalizePersistedRecordingRef = useRef2(finalizePersistedRecording);
|
|
1523
|
+
finalizePersistedRecordingRef.current = finalizePersistedRecording;
|
|
1524
|
+
const clientAvailable = client !== null && client !== void 0;
|
|
1525
|
+
useEffect2(() => {
|
|
1526
|
+
if (status !== "retrying" || !manifestRef.current || manifestRef.current.recoveryMode !== "automatic" || manifestRef.current.workspaceId !== workspaceId || !clientAvailable || disabled || !enabled) {
|
|
1527
|
+
return;
|
|
1528
|
+
}
|
|
1529
|
+
const generation = generationRef.current;
|
|
1530
|
+
let started = false;
|
|
1531
|
+
const run = () => {
|
|
1532
|
+
if (started || generation !== generationRef.current || statusRef.current !== "retrying" || workspaceIdRef.current !== workspaceId) {
|
|
1533
|
+
return;
|
|
1534
|
+
}
|
|
1535
|
+
started = true;
|
|
1536
|
+
if (automaticRetryTimerRef.current) clearTimeout(automaticRetryTimerRef.current);
|
|
1537
|
+
automaticRetryTimerRef.current = null;
|
|
1538
|
+
automaticRetryAttemptRef.current += 1;
|
|
1539
|
+
void finalizePersistedRecordingRef.current(generation);
|
|
1540
|
+
};
|
|
1541
|
+
const onOnline = () => run();
|
|
1542
|
+
globalThis.addEventListener?.("online", onOnline);
|
|
1543
|
+
if (typeof navigator !== "undefined" && navigator.onLine === false) {
|
|
1544
|
+
return () => globalThis.removeEventListener?.("online", onOnline);
|
|
1545
|
+
}
|
|
1546
|
+
const delay2 = Math.max(
|
|
1547
|
+
0,
|
|
1548
|
+
automaticRetryDelayMilliseconds ?? transcriptionRecoveryMutationDelayMilliseconds(
|
|
1549
|
+
TRANSCRIPTION_RECORDING_RECOVERY_RETRY_AFTER_MILLISECONDS,
|
|
1550
|
+
automaticRetryAttemptRef.current
|
|
1551
|
+
)
|
|
1552
|
+
);
|
|
1553
|
+
automaticRetryTimerRef.current = setTimeout(run, delay2);
|
|
1554
|
+
return () => {
|
|
1555
|
+
globalThis.removeEventListener?.("online", onOnline);
|
|
1556
|
+
if (automaticRetryTimerRef.current) clearTimeout(automaticRetryTimerRef.current);
|
|
1557
|
+
automaticRetryTimerRef.current = null;
|
|
1558
|
+
};
|
|
1559
|
+
}, [automaticRetryDelayMilliseconds, clientAvailable, disabled, enabled, status, workspaceId]);
|
|
1469
1560
|
const stop = useCallback2(() => {
|
|
1470
1561
|
const recorder = recorderRef.current;
|
|
1471
1562
|
if (!recorder || recorder.state === "inactive") return;
|
|
@@ -1475,7 +1566,7 @@ function useVoiceInput({
|
|
|
1475
1566
|
recorder.stop();
|
|
1476
1567
|
}, []);
|
|
1477
1568
|
const start = useCallback2(async () => {
|
|
1478
|
-
if (disabled || !client || !enabled || !capability?.available || manifestRef.current !== null || status === "requesting-permission" || status === "recording" || status === "saving" || status === "transcribing" || !navigator.mediaDevices?.getUserMedia || typeof MediaRecorder === "undefined") {
|
|
1569
|
+
if (disabled || !client || !enabled || !capability?.available || manifestRef.current !== null || status === "requesting-permission" || status === "recording" || status === "saving" || status === "transcribing" || status === "retrying" || !navigator.mediaDevices?.getUserMedia || typeof MediaRecorder === "undefined") {
|
|
1479
1570
|
return false;
|
|
1480
1571
|
}
|
|
1481
1572
|
const prerequisiteGeneration = generationRef.current;
|
|
@@ -1568,7 +1659,8 @@ function useVoiceInput({
|
|
|
1568
1659
|
});
|
|
1569
1660
|
if (!startAttemptIsCurrent()) return;
|
|
1570
1661
|
rememberManifest(result.manifest);
|
|
1571
|
-
|
|
1662
|
+
const maxSizeBytes = capability.resumable && isResumableVoiceInputClient(client) ? capability.resumable.maxSizeBytes : capability.maxSizeBytes;
|
|
1663
|
+
if (result.manifest.totalBytes > maxSizeBytes) {
|
|
1572
1664
|
attemptCaptureLimitError = "too_large";
|
|
1573
1665
|
if (attemptOwnsSharedCapture()) captureLimitErrorRef.current = "too_large";
|
|
1574
1666
|
if (recorder.state !== "inactive") recorder.stop();
|
|
@@ -1607,11 +1699,19 @@ function useVoiceInput({
|
|
|
1607
1699
|
}
|
|
1608
1700
|
rememberManifest(stopped);
|
|
1609
1701
|
if (attemptPersistenceError) {
|
|
1610
|
-
await
|
|
1702
|
+
const retained = await updateManifestBestEffort(stopped, {
|
|
1703
|
+
recoveryMode: "manual",
|
|
1704
|
+
handoffMode: "explicit"
|
|
1705
|
+
});
|
|
1706
|
+
await preserveForRetry(retained, "storage_unavailable", generation);
|
|
1611
1707
|
return;
|
|
1612
1708
|
}
|
|
1613
1709
|
if (attemptCaptureLimitError) {
|
|
1614
|
-
await
|
|
1710
|
+
const retained = await updateManifestBestEffort(stopped, {
|
|
1711
|
+
recoveryMode: "manual",
|
|
1712
|
+
handoffMode: "explicit"
|
|
1713
|
+
});
|
|
1714
|
+
await preserveForRetry(retained, attemptCaptureLimitError, generation);
|
|
1615
1715
|
return;
|
|
1616
1716
|
}
|
|
1617
1717
|
await finalizePersistedRecording(generation);
|
|
@@ -1627,7 +1727,10 @@ function useVoiceInput({
|
|
|
1627
1727
|
setStatus("recording");
|
|
1628
1728
|
timerRef.current = setTimeout(
|
|
1629
1729
|
stop,
|
|
1630
|
-
Math.min(
|
|
1730
|
+
Math.min(
|
|
1731
|
+
capability.resumable && isResumableVoiceInputClient(client) ? capability.resumable.maxDurationSeconds : capability.maxDurationSeconds,
|
|
1732
|
+
capability.resumable && isResumableVoiceInputClient(client) ? VOICE_RECORDING_RESUMABLE_CLIENT_MAX_DURATION_SECONDS : VOICE_RECORDING_CLIENT_MAX_DURATION_SECONDS
|
|
1733
|
+
) * 1e3
|
|
1631
1734
|
);
|
|
1632
1735
|
return true;
|
|
1633
1736
|
} catch (reason) {
|
|
@@ -1693,9 +1796,29 @@ function useVoiceInput({
|
|
|
1693
1796
|
}
|
|
1694
1797
|
const generation = ++generationRef.current;
|
|
1695
1798
|
controllerRef.current?.abort();
|
|
1799
|
+
if (automaticRetryTimerRef.current) clearTimeout(automaticRetryTimerRef.current);
|
|
1800
|
+
automaticRetryTimerRef.current = null;
|
|
1801
|
+
automaticRetryAttemptRef.current = 0;
|
|
1696
1802
|
setError(null);
|
|
1697
|
-
|
|
1698
|
-
|
|
1803
|
+
const manifest = manifestRef.current;
|
|
1804
|
+
void updateManifestBestEffort(manifest, {
|
|
1805
|
+
recoveryMode: "automatic",
|
|
1806
|
+
handoffMode: "append"
|
|
1807
|
+
}).then((retained) => {
|
|
1808
|
+
if (generation !== generationRef.current) return;
|
|
1809
|
+
rememberManifest(retained);
|
|
1810
|
+
void finalizePersistedRecording(generation);
|
|
1811
|
+
});
|
|
1812
|
+
}, [
|
|
1813
|
+
client,
|
|
1814
|
+
disabled,
|
|
1815
|
+
enabled,
|
|
1816
|
+
finalizePersistedRecording,
|
|
1817
|
+
rememberManifest,
|
|
1818
|
+
status,
|
|
1819
|
+
updateManifestBestEffort,
|
|
1820
|
+
workspaceId
|
|
1821
|
+
]);
|
|
1699
1822
|
const insertSavedTranscript = useCallback2(async () => {
|
|
1700
1823
|
const manifest = manifestRef.current;
|
|
1701
1824
|
if (!manifest || manifest.workspaceId !== workspaceId || manifest.finalizationState !== "transcript-ready" || manifest.transcriptText === null) {
|
|
@@ -1728,6 +1851,10 @@ function useVoiceInput({
|
|
|
1728
1851
|
return;
|
|
1729
1852
|
}
|
|
1730
1853
|
if (generation !== generationRef.current) return;
|
|
1854
|
+
if (capability?.resumable && isResumableVoiceInputClient(client)) {
|
|
1855
|
+
await client.discardTranscriptionRecording(workspaceId, handedOff.recordingId).catch(() => void 0);
|
|
1856
|
+
}
|
|
1857
|
+
if (generation !== generationRef.current) return;
|
|
1731
1858
|
await store.discard(handedOff.recordingId, ownerIdRef.current ?? void 0).catch(() => void 0);
|
|
1732
1859
|
if (generation !== generationRef.current) return;
|
|
1733
1860
|
clearVisibleRecording();
|
|
@@ -1737,6 +1864,8 @@ function useVoiceInput({
|
|
|
1737
1864
|
await loadNextRecoverable(generation);
|
|
1738
1865
|
}, [
|
|
1739
1866
|
clearVisibleRecording,
|
|
1867
|
+
capability?.resumable,
|
|
1868
|
+
client,
|
|
1740
1869
|
ensureStore,
|
|
1741
1870
|
focusInput,
|
|
1742
1871
|
loadNextRecoverable,
|
|
@@ -1760,6 +1889,10 @@ function useVoiceInput({
|
|
|
1760
1889
|
await captureSettled.catch(() => void 0);
|
|
1761
1890
|
if (generation !== generationRef.current) return;
|
|
1762
1891
|
if (manifest) {
|
|
1892
|
+
if (capability?.resumable && isResumableVoiceInputClient(client)) {
|
|
1893
|
+
await client.discardTranscriptionRecording(workspaceId, manifest.recordingId).catch(() => void 0);
|
|
1894
|
+
}
|
|
1895
|
+
if (generation !== generationRef.current) return;
|
|
1763
1896
|
try {
|
|
1764
1897
|
await (await ensureStore()).discard(manifest.recordingId, ownerIdRef.current ?? void 0);
|
|
1765
1898
|
} catch {
|
|
@@ -1781,20 +1914,25 @@ function useVoiceInput({
|
|
|
1781
1914
|
}, [
|
|
1782
1915
|
clearCaptureRuntime,
|
|
1783
1916
|
clearVisibleRecording,
|
|
1917
|
+
capability?.resumable,
|
|
1918
|
+
client,
|
|
1784
1919
|
ensureStore,
|
|
1785
1920
|
focusInput,
|
|
1786
1921
|
loadNextRecoverable,
|
|
1787
|
-
rememberManifest
|
|
1922
|
+
rememberManifest,
|
|
1923
|
+
workspaceId
|
|
1788
1924
|
]);
|
|
1789
1925
|
const cancel = useCallback2(() => {
|
|
1790
1926
|
if (status === "recording" || status === "requesting-permission") {
|
|
1791
1927
|
void discard();
|
|
1792
1928
|
return;
|
|
1793
1929
|
}
|
|
1794
|
-
if (status === "saving" || status === "transcribing") {
|
|
1930
|
+
if (status === "saving" || status === "transcribing" || status === "retrying") {
|
|
1795
1931
|
const generation = ++generationRef.current;
|
|
1796
1932
|
controllerRef.current?.abort();
|
|
1797
1933
|
controllerRef.current = null;
|
|
1934
|
+
if (automaticRetryTimerRef.current) clearTimeout(automaticRetryTimerRef.current);
|
|
1935
|
+
automaticRetryTimerRef.current = null;
|
|
1798
1936
|
const captureSettled = status === "saving" ? captureSettledRef.current : Promise.resolve();
|
|
1799
1937
|
void captureSettled.then(async () => {
|
|
1800
1938
|
const manifest = manifestRef.current;
|
|
@@ -1802,7 +1940,9 @@ function useVoiceInput({
|
|
|
1802
1940
|
const retained = await updateManifestBestEffort(manifest, {
|
|
1803
1941
|
captureState: "stopped",
|
|
1804
1942
|
uploadState: "retrying",
|
|
1805
|
-
transcriptionState: "retrying"
|
|
1943
|
+
transcriptionState: "retrying",
|
|
1944
|
+
recoveryMode: "manual",
|
|
1945
|
+
handoffMode: "explicit"
|
|
1806
1946
|
});
|
|
1807
1947
|
await preserveForRetry(retained, null, generation);
|
|
1808
1948
|
});
|
|
@@ -1831,7 +1971,12 @@ function useVoiceInput({
|
|
|
1831
1971
|
current.recordingId,
|
|
1832
1972
|
{
|
|
1833
1973
|
...current.captureState === "capturing" ? { captureState: "stopped" } : {},
|
|
1834
|
-
...wasProcessing ? {
|
|
1974
|
+
...wasProcessing ? {
|
|
1975
|
+
uploadState: "retrying",
|
|
1976
|
+
transcriptionState: "retrying",
|
|
1977
|
+
recoveryMode: "automatic",
|
|
1978
|
+
handoffMode: "explicit"
|
|
1979
|
+
} : {},
|
|
1835
1980
|
ownerId: null,
|
|
1836
1981
|
ownerHeartbeatAt: null
|
|
1837
1982
|
},
|
|
@@ -1855,7 +2000,7 @@ function useVoiceInput({
|
|
|
1855
2000
|
]);
|
|
1856
2001
|
useEffect2(() => {
|
|
1857
2002
|
const onKeyDown = (event) => {
|
|
1858
|
-
if (event.key === "Escape" && (status === "requesting-permission" || status === "recording" || status === "saving" || status === "transcribing")) {
|
|
2003
|
+
if (event.key === "Escape" && (status === "requesting-permission" || status === "recording" || status === "saving" || status === "transcribing" || status === "retrying")) {
|
|
1859
2004
|
event.preventDefault();
|
|
1860
2005
|
cancel();
|
|
1861
2006
|
}
|
|
@@ -1868,6 +2013,8 @@ function useVoiceInput({
|
|
|
1868
2013
|
generationRef.current += 1;
|
|
1869
2014
|
controllerRef.current?.abort();
|
|
1870
2015
|
controllerRef.current = null;
|
|
2016
|
+
if (automaticRetryTimerRef.current) clearTimeout(automaticRetryTimerRef.current);
|
|
2017
|
+
automaticRetryTimerRef.current = null;
|
|
1871
2018
|
const manifest = manifestRef.current;
|
|
1872
2019
|
const ownerReady = ownerIdPromiseRef.current;
|
|
1873
2020
|
stopOwnerHeartbeat();
|
|
@@ -1882,14 +2029,16 @@ function useVoiceInput({
|
|
|
1882
2029
|
const ownerId = ownerIdRef.current ?? (ownerReady ? await ownerReady.catch(() => null) : null);
|
|
1883
2030
|
const store = storeRef.current;
|
|
1884
2031
|
if (store && manifest && ownerId) {
|
|
1885
|
-
const wasProcessing = statusRef.current === "saving" || statusRef.current === "transcribing";
|
|
2032
|
+
const wasProcessing = statusRef.current === "saving" || statusRef.current === "transcribing" || statusRef.current === "retrying";
|
|
1886
2033
|
await store.updateManifest(
|
|
1887
2034
|
manifest.recordingId,
|
|
1888
2035
|
{
|
|
1889
2036
|
...manifest.captureState === "capturing" ? { captureState: "stopped" } : {},
|
|
1890
2037
|
...wasProcessing ? {
|
|
1891
2038
|
uploadState: "retrying",
|
|
1892
|
-
transcriptionState: "retrying"
|
|
2039
|
+
transcriptionState: "retrying",
|
|
2040
|
+
recoveryMode: "automatic",
|
|
2041
|
+
handoffMode: "explicit"
|
|
1893
2042
|
} : {},
|
|
1894
2043
|
ownerId: null,
|
|
1895
2044
|
ownerHeartbeatAt: null
|
|
@@ -1924,6 +2073,187 @@ function useVoiceInput({
|
|
|
1924
2073
|
discard
|
|
1925
2074
|
};
|
|
1926
2075
|
}
|
|
2076
|
+
async function transcribePersistedRecording(input) {
|
|
2077
|
+
const client = input.client;
|
|
2078
|
+
const resumable = input.capability.resumable;
|
|
2079
|
+
const ordered = [...input.chunks].sort((left, right) => left.chunkNumber - right.chunkNumber);
|
|
2080
|
+
if (!resumable || !isResumableVoiceInputClient(client)) {
|
|
2081
|
+
const audio = new Blob(
|
|
2082
|
+
ordered.map((chunk) => chunk.audio),
|
|
2083
|
+
{ type: input.manifest.mimeType }
|
|
2084
|
+
);
|
|
2085
|
+
if (audio.size > input.capability.maxSizeBytes) throw { code: "too_large" };
|
|
2086
|
+
return await client.transcribeAudio(input.workspaceId, {
|
|
2087
|
+
audio,
|
|
2088
|
+
mimeType: audio.type,
|
|
2089
|
+
durationSeconds: input.manifest.totalDurationMilliseconds / 1e3,
|
|
2090
|
+
signal: input.signal
|
|
2091
|
+
});
|
|
2092
|
+
}
|
|
2093
|
+
if (input.manifest.totalBytes > resumable.maxSizeBytes || input.manifest.totalDurationMilliseconds > resumable.maxDurationSeconds * 1e3) {
|
|
2094
|
+
throw { code: "too_large" };
|
|
2095
|
+
}
|
|
2096
|
+
if (ordered.some((chunk, index) => chunk.chunkNumber !== index) || ordered.length !== input.manifest.chunkCount) {
|
|
2097
|
+
throw { code: "invalid_audio" };
|
|
2098
|
+
}
|
|
2099
|
+
const finalizeInput = {
|
|
2100
|
+
chunkCount: input.manifest.chunkCount,
|
|
2101
|
+
totalBytes: input.manifest.totalBytes,
|
|
2102
|
+
totalDurationMilliseconds: input.manifest.totalDurationMilliseconds,
|
|
2103
|
+
signal: input.signal
|
|
2104
|
+
};
|
|
2105
|
+
let remote = await client.createTranscriptionRecording(input.workspaceId, {
|
|
2106
|
+
recordingId: input.manifest.recordingId,
|
|
2107
|
+
mimeType: input.manifest.mimeType,
|
|
2108
|
+
signal: input.signal
|
|
2109
|
+
});
|
|
2110
|
+
for (const chunk of ordered) {
|
|
2111
|
+
if (chunk.chunkNumber < remote.recording.nextChunkNumber) continue;
|
|
2112
|
+
if (chunk.chunkNumber !== remote.recording.nextChunkNumber) {
|
|
2113
|
+
throw { code: "invalid_audio" };
|
|
2114
|
+
}
|
|
2115
|
+
if (chunk.byteLength > resumable.maxChunkSizeBytes) throw { code: "too_large" };
|
|
2116
|
+
const uploaded = await client.uploadTranscriptionRecordingChunk(
|
|
2117
|
+
input.workspaceId,
|
|
2118
|
+
input.manifest.recordingId,
|
|
2119
|
+
chunk.chunkNumber,
|
|
2120
|
+
{
|
|
2121
|
+
audio: chunk.audio,
|
|
2122
|
+
mimeType: input.manifest.mimeType,
|
|
2123
|
+
sha256: chunk.sha256,
|
|
2124
|
+
startMilliseconds: chunk.startMilliseconds,
|
|
2125
|
+
durationMilliseconds: chunk.durationMilliseconds,
|
|
2126
|
+
signal: input.signal
|
|
2127
|
+
}
|
|
2128
|
+
);
|
|
2129
|
+
remote = { recording: uploaded.recording, segments: remote.segments };
|
|
2130
|
+
}
|
|
2131
|
+
if (remote.recording.nextChunkNumber !== ordered.length) {
|
|
2132
|
+
throw { code: "invalid_audio" };
|
|
2133
|
+
}
|
|
2134
|
+
remote = await client.finalizeTranscriptionRecording(
|
|
2135
|
+
input.workspaceId,
|
|
2136
|
+
input.manifest.recordingId,
|
|
2137
|
+
finalizeInput
|
|
2138
|
+
);
|
|
2139
|
+
let recoveryMutationAttempt = 0;
|
|
2140
|
+
let recoveryMutationDueAt = 0;
|
|
2141
|
+
const scheduleRecoveryMutation = (response) => {
|
|
2142
|
+
if (response.recording.state !== "segmenting" && response.recording.state !== "transcribing") {
|
|
2143
|
+
return;
|
|
2144
|
+
}
|
|
2145
|
+
recoveryMutationDueAt = Date.now() + transcriptionRecoveryMutationDelayMilliseconds(
|
|
2146
|
+
response.retryAfterMilliseconds,
|
|
2147
|
+
recoveryMutationAttempt
|
|
2148
|
+
);
|
|
2149
|
+
recoveryMutationAttempt += 1;
|
|
2150
|
+
};
|
|
2151
|
+
scheduleRecoveryMutation(remote);
|
|
2152
|
+
for (; ; ) {
|
|
2153
|
+
if (input.signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
2154
|
+
switch (remote.recording.state) {
|
|
2155
|
+
case "complete":
|
|
2156
|
+
if (remote.recording.transcriptText === null) throw { code: "invalid_audio" };
|
|
2157
|
+
return {
|
|
2158
|
+
text: remote.recording.transcriptText,
|
|
2159
|
+
languages: remote.recording.languages
|
|
2160
|
+
};
|
|
2161
|
+
case "ready":
|
|
2162
|
+
remote = await client.processNextTranscriptionRecordingSegment(
|
|
2163
|
+
input.workspaceId,
|
|
2164
|
+
input.manifest.recordingId,
|
|
2165
|
+
{ signal: input.signal }
|
|
2166
|
+
);
|
|
2167
|
+
scheduleRecoveryMutation(remote);
|
|
2168
|
+
break;
|
|
2169
|
+
case "failed": {
|
|
2170
|
+
if (!remote.recording.retryable) {
|
|
2171
|
+
throw { code: remote.recording.errorCode ?? "unknown", retryable: false };
|
|
2172
|
+
}
|
|
2173
|
+
const retried = remote.recording.segmentCount === 0 ? await client.finalizeTranscriptionRecording(
|
|
2174
|
+
input.workspaceId,
|
|
2175
|
+
input.manifest.recordingId,
|
|
2176
|
+
finalizeInput
|
|
2177
|
+
) : await client.processNextTranscriptionRecordingSegment(
|
|
2178
|
+
input.workspaceId,
|
|
2179
|
+
input.manifest.recordingId,
|
|
2180
|
+
{ signal: input.signal }
|
|
2181
|
+
);
|
|
2182
|
+
if (retried.recording.state === "failed") {
|
|
2183
|
+
throw {
|
|
2184
|
+
code: retried.recording.errorCode ?? "unknown",
|
|
2185
|
+
retryable: retried.recording.retryable
|
|
2186
|
+
};
|
|
2187
|
+
}
|
|
2188
|
+
remote = retried;
|
|
2189
|
+
scheduleRecoveryMutation(remote);
|
|
2190
|
+
break;
|
|
2191
|
+
}
|
|
2192
|
+
case "discarded":
|
|
2193
|
+
throw { code: "invalid_audio" };
|
|
2194
|
+
case "uploading":
|
|
2195
|
+
remote = await client.finalizeTranscriptionRecording(
|
|
2196
|
+
input.workspaceId,
|
|
2197
|
+
input.manifest.recordingId,
|
|
2198
|
+
finalizeInput
|
|
2199
|
+
);
|
|
2200
|
+
scheduleRecoveryMutation(remote);
|
|
2201
|
+
break;
|
|
2202
|
+
case "segmenting":
|
|
2203
|
+
case "transcribing":
|
|
2204
|
+
if (Date.now() < recoveryMutationDueAt) {
|
|
2205
|
+
await abortableDelay(
|
|
2206
|
+
Math.min(
|
|
2207
|
+
recoveryMutationDueAt - Date.now(),
|
|
2208
|
+
VOICE_RECORDING_RECOVERY_STATUS_POLL_MILLISECONDS
|
|
2209
|
+
),
|
|
2210
|
+
input.signal
|
|
2211
|
+
);
|
|
2212
|
+
remote = await client.getTranscriptionRecording(
|
|
2213
|
+
input.workspaceId,
|
|
2214
|
+
input.manifest.recordingId,
|
|
2215
|
+
{ signal: input.signal }
|
|
2216
|
+
);
|
|
2217
|
+
break;
|
|
2218
|
+
}
|
|
2219
|
+
if (remote.recording.state === "segmenting") {
|
|
2220
|
+
remote = await client.finalizeTranscriptionRecording(
|
|
2221
|
+
input.workspaceId,
|
|
2222
|
+
input.manifest.recordingId,
|
|
2223
|
+
finalizeInput
|
|
2224
|
+
);
|
|
2225
|
+
} else {
|
|
2226
|
+
remote = await client.processNextTranscriptionRecordingSegment(
|
|
2227
|
+
input.workspaceId,
|
|
2228
|
+
input.manifest.recordingId,
|
|
2229
|
+
{ signal: input.signal }
|
|
2230
|
+
);
|
|
2231
|
+
}
|
|
2232
|
+
scheduleRecoveryMutation(remote);
|
|
2233
|
+
break;
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
function isResumableVoiceInputClient(client) {
|
|
2238
|
+
return Boolean(
|
|
2239
|
+
client && client.createTranscriptionRecording && client.getTranscriptionRecording && client.uploadTranscriptionRecordingChunk && client.finalizeTranscriptionRecording && client.processNextTranscriptionRecordingSegment && client.discardTranscriptionRecording
|
|
2240
|
+
);
|
|
2241
|
+
}
|
|
2242
|
+
async function abortableDelay(milliseconds, signal) {
|
|
2243
|
+
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
2244
|
+
await new Promise((resolve, reject) => {
|
|
2245
|
+
const timer = setTimeout(() => {
|
|
2246
|
+
signal.removeEventListener("abort", onAbort);
|
|
2247
|
+
resolve();
|
|
2248
|
+
}, milliseconds);
|
|
2249
|
+
const onAbort = () => {
|
|
2250
|
+
clearTimeout(timer);
|
|
2251
|
+
signal.removeEventListener("abort", onAbort);
|
|
2252
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
2253
|
+
};
|
|
2254
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
2255
|
+
});
|
|
2256
|
+
}
|
|
1927
2257
|
function chooseMimeType(accepted) {
|
|
1928
2258
|
const normalized = accepted.map((value) => value.trim().toLowerCase());
|
|
1929
2259
|
return MIME_PREFERENCES.find((mimeType) => {
|
|
@@ -1933,6 +2263,9 @@ function chooseMimeType(accepted) {
|
|
|
1933
2263
|
});
|
|
1934
2264
|
}
|
|
1935
2265
|
function errorCode(error) {
|
|
2266
|
+
if (error instanceof OpenGeniApiError && typeof error.details?.transcriptionCode === "string") {
|
|
2267
|
+
return error.details.transcriptionCode;
|
|
2268
|
+
}
|
|
1936
2269
|
if (error && typeof error === "object" && "code" in error && typeof error.code === "string") {
|
|
1937
2270
|
return error.code;
|
|
1938
2271
|
}
|
|
@@ -1940,6 +2273,16 @@ function errorCode(error) {
|
|
|
1940
2273
|
if (error instanceof DOMException && error.name === "NotSupportedError") return "not_supported";
|
|
1941
2274
|
return "unknown";
|
|
1942
2275
|
}
|
|
2276
|
+
function isRetryableVoiceInputError(error) {
|
|
2277
|
+
if (error instanceof OpenGeniApiError) {
|
|
2278
|
+
return error.retryable && error.status !== 409;
|
|
2279
|
+
}
|
|
2280
|
+
if (error instanceof TypeError) return true;
|
|
2281
|
+
if (error && typeof error === "object" && "retryable" in error) {
|
|
2282
|
+
return error.retryable === true;
|
|
2283
|
+
}
|
|
2284
|
+
return false;
|
|
2285
|
+
}
|
|
1943
2286
|
|
|
1944
2287
|
// src/workstream-control-event.ts
|
|
1945
2288
|
var OPEN_WORKSTREAM_CONTROL_EVENT = "opengeni:open-workstream-control";
|
|
@@ -2412,7 +2755,7 @@ function CommandPalette({
|
|
|
2412
2755
|
] }),
|
|
2413
2756
|
/* @__PURE__ */ jsxs("span", { className: "ml-auto flex items-center gap-1.5", children: [
|
|
2414
2757
|
command.danger ? /* @__PURE__ */ jsx("span", { className: "rounded-og-xs bg-og-status-failed/15 px-1 text-[10px] uppercase tracking-wide text-og-status-failed", children: dangerLabel }) : null,
|
|
2415
|
-
/* @__PURE__ */ jsx("span", { className: "truncate text-[12px] text-og-fg-subtle max-sm:hidden", children: command.description })
|
|
2758
|
+
/* @__PURE__ */ jsx("span", { className: "og-command-description truncate text-[12px] text-og-fg-subtle max-sm:hidden", children: command.description })
|
|
2416
2759
|
] })
|
|
2417
2760
|
]
|
|
2418
2761
|
},
|
|
@@ -2499,10 +2842,10 @@ function ModelPicker({
|
|
|
2499
2842
|
disabled: disabled === true,
|
|
2500
2843
|
"aria-label": label,
|
|
2501
2844
|
className: cn(
|
|
2502
|
-
"h-8 max-w-[180px] cursor-pointer appearance-none truncate rounded-og-md bg-transparent",
|
|
2845
|
+
"og-model-picker-native h-8 max-w-[180px] cursor-pointer appearance-none truncate rounded-og-md bg-transparent pointer-coarse:h-11",
|
|
2503
2846
|
"py-0 pl-2 pr-6 text-[13px] text-og-fg-muted",
|
|
2504
2847
|
"transition-colors duration-150 hover:bg-og-surface-2 hover:text-og-fg",
|
|
2505
|
-
"focus:outline-
|
|
2848
|
+
"focus:outline-hidden focus-visible:outline-hidden",
|
|
2506
2849
|
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
2507
2850
|
),
|
|
2508
2851
|
children: useBillingGroups ? billingGroups.map((group) => /* @__PURE__ */ jsx2("optgroup", { label: group.label, children: group.rows.map((row) => /* @__PURE__ */ jsx2("option", { value: row.id, disabled: !row.selectable, children: row.unavailableReason ? `${row.label} (${row.unavailableReason})` : row.label }, row.id)) }, group.billingClass)) : providerGroupList.map((group) => /* @__PURE__ */ jsx2("optgroup", { label: group.label, children: group.models.map((model) => /* @__PURE__ */ jsx2("option", { value: model.id, disabled: model.optionDisabled, children: model.label }, model.id)) }, group.label))
|
|
@@ -3003,21 +3346,27 @@ function useChatComposer() {
|
|
|
3003
3346
|
function isRecord2(value) {
|
|
3004
3347
|
return typeof value === "object" && value !== null;
|
|
3005
3348
|
}
|
|
3006
|
-
var Root = forwardRef(function ComposerRoot({ controller, children, className, style, ...props }, forwardedRef) {
|
|
3007
|
-
|
|
3349
|
+
var Root = forwardRef(function ComposerRoot({ controller, children, className, style, responsiveBasis = "viewport", ...props }, forwardedRef) {
|
|
3350
|
+
const responsiveRootRef = useRef4(null);
|
|
3351
|
+
const responsiveContext = useMemo4(
|
|
3352
|
+
() => ({ responsiveBasis, rootRef: responsiveRootRef }),
|
|
3353
|
+
[responsiveBasis]
|
|
3354
|
+
);
|
|
3355
|
+
return /* @__PURE__ */ jsx3(ComposerContext.Provider, { value: controller, children: /* @__PURE__ */ jsx3(ComposerResponsiveContext.Provider, { value: responsiveContext, children: /* @__PURE__ */ jsx3(TooltipProvider, { delayDuration: 300, children: /* @__PURE__ */ jsxs3(
|
|
3008
3356
|
"div",
|
|
3009
3357
|
{
|
|
3010
3358
|
...props,
|
|
3011
|
-
ref: mergeRefs(controller.rootRef, forwardedRef),
|
|
3359
|
+
ref: mergeRefs(controller.rootRef, responsiveRootRef, forwardedRef),
|
|
3012
3360
|
"data-og-composer-id": controller.id,
|
|
3013
|
-
|
|
3361
|
+
"data-og-responsive-basis": responsiveBasis,
|
|
3362
|
+
className: cn("og-root og-composer", className),
|
|
3014
3363
|
style: { paddingBottom: "env(safe-area-inset-bottom)", ...style },
|
|
3015
3364
|
children: [
|
|
3016
3365
|
children,
|
|
3017
3366
|
/* @__PURE__ */ jsx3(ComposerAnnouncements, {})
|
|
3018
3367
|
]
|
|
3019
3368
|
}
|
|
3020
|
-
) }) });
|
|
3369
|
+
) }) }) });
|
|
3021
3370
|
});
|
|
3022
3371
|
var Frame = forwardRef(function ComposerFrame({ className, ...props }, ref) {
|
|
3023
3372
|
return /* @__PURE__ */ jsx3("div", { ...props, ref, className: cn("relative", className) });
|
|
@@ -3163,8 +3512,8 @@ var Input = forwardRef(function ComposerInput({ rows = 1, placeholder, className
|
|
|
3163
3512
|
"aria-controls": paletteOpen ? controller.listboxId : void 0,
|
|
3164
3513
|
"aria-activedescendant": paletteOpen ? `${controller.listboxId}-option-${controller.palette.highlight}` : void 0,
|
|
3165
3514
|
className: cn(
|
|
3166
|
-
"block w-full resize-none bg-transparent px-3.5 pt-3 pb-1 text-og-composer md:px-4 md:text-og-composer-wide",
|
|
3167
|
-
"text-og-fg placeholder:text-og-fg-subtle focus:outline-
|
|
3515
|
+
"og-composer-input block w-full resize-none bg-transparent px-3.5 pt-3 pb-1 text-og-composer md:px-4 md:text-og-composer-wide pointer-coarse:min-h-11",
|
|
3516
|
+
"text-og-fg placeholder:text-og-fg-subtle focus:outline-hidden focus-visible:outline-hidden",
|
|
3168
3517
|
"disabled:cursor-not-allowed disabled:opacity-60",
|
|
3169
3518
|
className
|
|
3170
3519
|
)
|
|
@@ -3193,7 +3542,7 @@ var Footer = forwardRef(function ComposerFooter({ className, ...props }, ref) {
|
|
|
3193
3542
|
...props,
|
|
3194
3543
|
ref,
|
|
3195
3544
|
className: cn(
|
|
3196
|
-
"flex items-end gap-1.5 px-2 pb-2 pt-0.5 sm:px-2.5 sm:pb-2.5",
|
|
3545
|
+
"og-composer-footer flex items-end gap-1.5 px-2 pb-2 pt-0.5 sm:px-2.5 sm:pb-2.5",
|
|
3197
3546
|
// Mobile: one control row — never wrap into a second toolbar line.
|
|
3198
3547
|
"max-sm:flex-nowrap max-sm:items-center max-sm:gap-1",
|
|
3199
3548
|
className
|
|
@@ -3209,7 +3558,7 @@ var Controls = forwardRef(
|
|
|
3209
3558
|
...props,
|
|
3210
3559
|
ref,
|
|
3211
3560
|
className: cn(
|
|
3212
|
-
"flex min-w-0 flex-1 flex-wrap items-center gap-1.5",
|
|
3561
|
+
"og-composer-controls flex min-w-0 flex-1 flex-wrap items-center gap-1.5",
|
|
3213
3562
|
"max-sm:flex-nowrap max-sm:gap-1",
|
|
3214
3563
|
className
|
|
3215
3564
|
)
|
|
@@ -3224,7 +3573,10 @@ var Hint = forwardRef(function ComposerHint({ className, children, ...props }, r
|
|
|
3224
3573
|
{
|
|
3225
3574
|
...props,
|
|
3226
3575
|
ref,
|
|
3227
|
-
className: cn(
|
|
3576
|
+
className: cn(
|
|
3577
|
+
"og-composer-hint min-w-0 flex-1 px-1.5 text-og-xs text-og-fg-subtle max-sm:hidden",
|
|
3578
|
+
className
|
|
3579
|
+
),
|
|
3228
3580
|
children: children ?? controller.messages.keyboardHint
|
|
3229
3581
|
}
|
|
3230
3582
|
);
|
|
@@ -3236,7 +3588,7 @@ var Actions = forwardRef(function ComposerActions({ className, ...props }, ref)
|
|
|
3236
3588
|
...props,
|
|
3237
3589
|
ref,
|
|
3238
3590
|
className: cn(
|
|
3239
|
-
"ml-auto flex shrink-0 items-center gap-1.5",
|
|
3591
|
+
"og-composer-actions ml-auto flex shrink-0 items-center gap-1.5",
|
|
3240
3592
|
"max-sm:flex-nowrap max-sm:gap-1",
|
|
3241
3593
|
className
|
|
3242
3594
|
)
|
|
@@ -3273,7 +3625,7 @@ var AttachButton = forwardRef(
|
|
|
3273
3625
|
className: cn(
|
|
3274
3626
|
"inline-flex size-8 items-center justify-center rounded-og-md",
|
|
3275
3627
|
"text-og-fg-muted transition-colors duration-150 hover:bg-og-surface-2 hover:text-og-fg",
|
|
3276
|
-
"disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:size-
|
|
3628
|
+
"disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:size-11",
|
|
3277
3629
|
className
|
|
3278
3630
|
),
|
|
3279
3631
|
children: children ?? /* @__PURE__ */ jsx3(PaperclipIcon, { className: "size-4" })
|
|
@@ -3322,7 +3674,7 @@ var PauseButton = forwardRef(
|
|
|
3322
3674
|
disabled: busy,
|
|
3323
3675
|
"aria-label": ariaLabel ?? controller.messages.pauseAriaLabel,
|
|
3324
3676
|
className: cn(
|
|
3325
|
-
"inline-flex size-8 items-center justify-center rounded-og-md border border-og-border pointer-coarse:size-
|
|
3677
|
+
"inline-flex size-8 items-center justify-center rounded-og-md border border-og-border pointer-coarse:size-11",
|
|
3326
3678
|
"bg-og-surface-2 text-og-fg-muted transition-colors duration-150",
|
|
3327
3679
|
"hover:border-og-status-waiting/50 hover:text-og-status-waiting",
|
|
3328
3680
|
"disabled:opacity-50",
|
|
@@ -3348,7 +3700,7 @@ var SendButton = forwardRef(
|
|
|
3348
3700
|
"data-og-tip": tip,
|
|
3349
3701
|
"aria-label": ariaLabel ?? (controller.paused ? controller.messages.sendAndResumeAriaLabel : controller.messages.sendMessageAriaLabel),
|
|
3350
3702
|
className: cn(
|
|
3351
|
-
"inline-flex size-8 items-center justify-center rounded-og-md pointer-coarse:size-
|
|
3703
|
+
"inline-flex size-8 items-center justify-center rounded-og-md pointer-coarse:size-11",
|
|
3352
3704
|
"bg-og-accent text-og-accent-fg shadow-og-sm",
|
|
3353
3705
|
"transition-[background-color,transform,opacity] duration-150 ease-og-spring",
|
|
3354
3706
|
"hover:bg-og-accent-strong active:scale-95",
|
|
@@ -3470,8 +3822,8 @@ function WorkstreamPausedStrip({
|
|
|
3470
3822
|
onClick: onResume,
|
|
3471
3823
|
children: [
|
|
3472
3824
|
busy ? /* @__PURE__ */ jsx3(LoaderCircleIcon, { className: "size-3.5 animate-og-spin" }) : /* @__PURE__ */ jsx3(PlayIcon, { className: "size-3.5 fill-current" }),
|
|
3473
|
-
/* @__PURE__ */ jsx3("span", { className: "hidden min-[400px]:inline", children: messages.resumeThisWorkstream }),
|
|
3474
|
-
/* @__PURE__ */ jsx3("span", { className: "min-[400px]:hidden", children: messages.resumeShort })
|
|
3825
|
+
/* @__PURE__ */ jsx3("span", { className: "og-composer-resume-label-long hidden min-[400px]:inline", children: messages.resumeThisWorkstream }),
|
|
3826
|
+
/* @__PURE__ */ jsx3("span", { className: "og-composer-resume-label-short min-[400px]:hidden", children: messages.resumeShort })
|
|
3475
3827
|
]
|
|
3476
3828
|
}
|
|
3477
3829
|
),
|
|
@@ -3497,7 +3849,7 @@ function WorkstreamPausedStrip({
|
|
|
3497
3849
|
"a",
|
|
3498
3850
|
{
|
|
3499
3851
|
href: blockerHref(entry, controlLinks),
|
|
3500
|
-
className: "font-medium text-og-fg underline decoration-og-border-strong underline-offset-2 hover:text-og-accent focus-visible:outline-
|
|
3852
|
+
className: "font-medium text-og-fg underline decoration-og-border-strong underline-offset-2 hover:text-og-accent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-ring/40",
|
|
3501
3853
|
children: entry.displayName
|
|
3502
3854
|
}
|
|
3503
3855
|
) : /* @__PURE__ */ jsx3("span", { className: "font-medium text-og-fg", children: entry.displayName }),
|
|
@@ -3643,7 +3995,7 @@ function AttachmentChips({
|
|
|
3643
3995
|
onRemove,
|
|
3644
3996
|
onRetry
|
|
3645
3997
|
}) {
|
|
3646
|
-
return /* @__PURE__ */ jsx3("div", { className: "flex flex-wrap gap-2
|
|
3998
|
+
return /* @__PURE__ */ jsx3("div", { className: "flex flex-wrap gap-2 px-3 py-2", children: attachments.map((attachment) => {
|
|
3647
3999
|
const failed = attachment.status === "failed";
|
|
3648
4000
|
const statusText = attachment.status === "uploading" ? messages.uploading : failed ? attachment.error || messages.uploadFailed : messages.formatBytes(attachment.sizeBytes);
|
|
3649
4001
|
return /* @__PURE__ */ jsxs3(
|
|
@@ -3759,10 +4111,12 @@ var defaultMessages = {
|
|
|
3759
4111
|
stop: "Stop and transcribe",
|
|
3760
4112
|
cancel: "Cancel recording",
|
|
3761
4113
|
retry: "Retry voice input",
|
|
4114
|
+
pauseRetrying: "Pause automatic retry",
|
|
3762
4115
|
requestingPermission: "Requesting microphone\u2026",
|
|
3763
4116
|
recording: "Recording. Press Escape to cancel.",
|
|
3764
4117
|
saving: "Saving audio locally\u2026",
|
|
3765
4118
|
transcribing: "Transcribing\u2026",
|
|
4119
|
+
retrying: "Recording saved. Retrying automatically\u2026",
|
|
3766
4120
|
recovered: "Recording recovered and saved locally.",
|
|
3767
4121
|
recoveredTranscript: "Transcript saved locally. Check your draft before inserting.",
|
|
3768
4122
|
insertRecoveredTranscript: "Insert saved transcript",
|
|
@@ -3810,6 +4164,7 @@ function ComposerTranscriptionControl({
|
|
|
3810
4164
|
createOwnerId
|
|
3811
4165
|
});
|
|
3812
4166
|
const { status } = transcription;
|
|
4167
|
+
const retrying = status === "retrying";
|
|
3813
4168
|
const cancelTranscription = transcription.cancel;
|
|
3814
4169
|
useEffect4(() => {
|
|
3815
4170
|
if (!suppressed) return;
|
|
@@ -3818,12 +4173,12 @@ function ComposerTranscriptionControl({
|
|
|
3818
4173
|
}
|
|
3819
4174
|
}, [cancelTranscription, status, suppressed]);
|
|
3820
4175
|
const active = status === "requesting-permission" || status === "recording" || status === "saving" || status === "transcribing";
|
|
3821
|
-
const recoverable = transcription.hasRecoverableRecording && (status === "recovered" || status === "transcript-ready" || status === "error");
|
|
4176
|
+
const recoverable = transcription.hasRecoverableRecording && (retrying || status === "recovered" || status === "transcript-ready" || status === "error");
|
|
3822
4177
|
const savedTranscript = status === "transcript-ready" && transcription.savedTranscript !== null;
|
|
3823
4178
|
const unavailableMessage = composer.disabled ? messages.unavailableDisabled : !capability?.available || !workspaceEnabled ? messages.unavailable : !transcription.available ? messages.errorStorageUnavailable : null;
|
|
3824
4179
|
const idleLabel = unavailableMessage ?? (status === "error" ? messages.retry : messages.start);
|
|
3825
4180
|
const errorMessage3 = transcription.error ? transcriptionErrorMessage(transcription.error, messages) : null;
|
|
3826
|
-
const announcement = status === "requesting-permission" ? messages.requestingPermission : status === "recording" ? messages.recording : status === "saving" ? messages.saving : status === "transcribing" ? messages.transcribing : status === "recovered" ? messages.recovered : status === "transcript-ready" ? messages.recoveredTranscript : status === "error" ? errorMessage3 ?? messages.errorUnknown : unavailableMessage;
|
|
4181
|
+
const announcement = status === "requesting-permission" ? messages.requestingPermission : status === "recording" ? messages.recording : status === "saving" ? messages.saving : status === "transcribing" ? messages.transcribing : retrying ? messages.retrying : status === "recovered" ? messages.recovered : status === "transcript-ready" ? messages.recoveredTranscript : status === "error" ? errorMessage3 ?? messages.errorUnknown : unavailableMessage;
|
|
3827
4182
|
function start(event) {
|
|
3828
4183
|
if (unavailableMessage) {
|
|
3829
4184
|
event.preventDefault();
|
|
@@ -3853,21 +4208,27 @@ function ComposerTranscriptionControl({
|
|
|
3853
4208
|
"bg-og-surface-2/70 pl-2 pr-1 pointer-coarse:h-11"
|
|
3854
4209
|
),
|
|
3855
4210
|
children: [
|
|
3856
|
-
/* @__PURE__ */ jsx4("span", { className: "max-w-44 truncate text-og-xs text-og-fg-muted max-sm:max-w-28", children: savedTranscript ? errorMessage3 ?? messages.recoveredTranscript : status === "error" ? errorMessage3 ?? messages.errorRetryable : messages.recovered }),
|
|
3857
|
-
/* @__PURE__ */ jsx4(
|
|
3858
|
-
|
|
4211
|
+
/* @__PURE__ */ jsx4("span", { className: "og-transcription-recovered-label max-w-44 truncate text-og-xs text-og-fg-muted max-sm:max-w-28", children: savedTranscript ? errorMessage3 ?? messages.recoveredTranscript : retrying ? messages.retrying : status === "error" ? errorMessage3 ?? messages.errorRetryable : messages.recovered }),
|
|
4212
|
+
/* @__PURE__ */ jsx4(
|
|
4213
|
+
Tip,
|
|
3859
4214
|
{
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
4215
|
+
tip: savedTranscript ? messages.insertRecoveredTranscript : retrying ? messages.pauseRetrying : messages.retry,
|
|
4216
|
+
children: /* @__PURE__ */ jsx4(
|
|
4217
|
+
"button",
|
|
4218
|
+
{
|
|
4219
|
+
type: "button",
|
|
4220
|
+
onClick: () => savedTranscript ? void transcription.insertSavedTranscript() : retrying ? transcription.cancel() : transcription.retry(),
|
|
4221
|
+
"aria-label": savedTranscript ? messages.insertRecoveredTranscript : retrying ? messages.pauseRetrying : messages.retry,
|
|
4222
|
+
className: cn(
|
|
4223
|
+
"inline-flex size-7 shrink-0 items-center justify-center rounded-og-sm",
|
|
4224
|
+
"bg-og-fg text-og-bg transition-colors duration-150 motion-reduce:transition-none",
|
|
4225
|
+
"hover:bg-og-fg-muted pointer-coarse:size-11"
|
|
4226
|
+
),
|
|
4227
|
+
children: savedTranscript ? /* @__PURE__ */ jsx4(ClipboardPasteIcon, { className: "size-3.5" }) : retrying ? /* @__PURE__ */ jsx4(SquareIcon, { className: "size-3.5" }) : /* @__PURE__ */ jsx4(RefreshCwIcon, { className: "size-3.5" })
|
|
4228
|
+
}
|
|
4229
|
+
)
|
|
3869
4230
|
}
|
|
3870
|
-
)
|
|
4231
|
+
),
|
|
3871
4232
|
/* @__PURE__ */ jsx4(Tip, { tip: messages.discardRecovered, children: /* @__PURE__ */ jsx4(
|
|
3872
4233
|
"button",
|
|
3873
4234
|
{
|
|
@@ -3978,7 +4339,7 @@ function ComposerTranscriptionControl({
|
|
|
3978
4339
|
"span",
|
|
3979
4340
|
{
|
|
3980
4341
|
"aria-hidden": "true",
|
|
3981
|
-
className: "max-w-40 truncate text-og-xs text-og-status-failed max-sm:max-w-24",
|
|
4342
|
+
className: "og-transcription-error-label max-w-40 truncate text-og-xs text-og-status-failed max-sm:max-w-24",
|
|
3982
4343
|
children: errorMessage3
|
|
3983
4344
|
}
|
|
3984
4345
|
) }) : null,
|
|
@@ -4162,4 +4523,4 @@ export {
|
|
|
4162
4523
|
Status,
|
|
4163
4524
|
ComposerTranscriptionControl
|
|
4164
4525
|
};
|
|
4165
|
-
//# sourceMappingURL=chunk-
|
|
4526
|
+
//# sourceMappingURL=chunk-NJ7M2B6Z.js.map
|