@zeniai/client-epic-state 5.3.18-betaAK2 → 5.3.18

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.
Files changed (38) hide show
  1. package/lib/entity/tenant/epic/fetchAllTenantsEpic.d.ts +4 -2
  2. package/lib/entity/tenant/epic/fetchAllTenantsEpic.js +42 -45
  3. package/lib/entity/tenant/tenantPayload.d.ts +1 -17
  4. package/lib/entity/tenant/tenantReducer.d.ts +2 -7
  5. package/lib/entity/tenant/tenantReducer.js +19 -48
  6. package/lib/entity/tenant/tenantSelector.d.ts +6 -26
  7. package/lib/entity/tenant/tenantSelector.js +96 -119
  8. package/lib/entity/tenant/tenantState.d.ts +0 -10
  9. package/lib/epic.d.ts +1 -2
  10. package/lib/epic.js +0 -2
  11. package/lib/esm/entity/tenant/epic/fetchAllTenantsEpic.js +46 -49
  12. package/lib/esm/entity/tenant/tenantReducer.js +17 -46
  13. package/lib/esm/entity/tenant/tenantSelector.js +95 -115
  14. package/lib/esm/epic.js +0 -2
  15. package/lib/esm/index.js +7 -7
  16. package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +3 -65
  17. package/lib/esm/view/aiCfoView/aiCfoViewSelector.js +0 -25
  18. package/lib/esm/view/dashboard/dashboardEpic.js +4 -0
  19. package/lib/esm/view/dashboard/dashboardSelector.js +3 -2
  20. package/lib/esm/view/financeStatement/financeStatementEpic.js +5 -1
  21. package/lib/esm/view/people/peoplePageEpic.js +4 -0
  22. package/lib/index.d.ts +8 -8
  23. package/lib/index.js +46 -56
  24. package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +0 -20
  25. package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +2 -2
  26. package/lib/view/aiCfoView/aiCfoViewReducer.js +4 -66
  27. package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +1 -8
  28. package/lib/view/aiCfoView/aiCfoViewSelector.js +0 -27
  29. package/lib/view/aiCfoView/aiCfoViewState.d.ts +0 -9
  30. package/lib/view/dashboard/dashboardEpic.js +4 -0
  31. package/lib/view/dashboard/dashboardSelector.d.ts +2 -0
  32. package/lib/view/dashboard/dashboardSelector.js +2 -1
  33. package/lib/view/financeStatement/financeStatementEpic.js +5 -1
  34. package/lib/view/people/peoplePageEpic.js +4 -0
  35. package/package.json +1 -1
  36. package/lib/esm/view/aiCfoView/epics/transcribeAudioEpic.js +0 -60
  37. package/lib/view/aiCfoView/epics/transcribeAudioEpic.d.ts +0 -19
  38. package/lib/view/aiCfoView/epics/transcribeAudioEpic.js +0 -64
@@ -12,26 +12,6 @@ export interface SubmitFeedbackPayload {
12
12
  model?: string;
13
13
  questionText?: string;
14
14
  }
15
- export interface TranscribeAudioPayload {
16
- /** Recorded audio, already in a format the transcription model accepts. */
17
- audio: Blob;
18
- /**
19
- * Session the recording was made in. Epics outlive the component, so without
20
- * this a transcript that lands after the user switches sessions would append
21
- * to whichever composer is open by then.
22
- */
23
- chatSessionId?: ID;
24
- /** BCP-47 dictation language. Omitted means the model auto-detects. */
25
- language?: string;
26
- }
27
- export interface TranscribeAudioSuccessPayload {
28
- transcript: string;
29
- chatSessionId?: ID;
30
- }
31
- /** Shape of the /1.0/transcriptions response body. */
32
- export interface TranscriptionResponseData {
33
- transcript: string;
34
- }
35
15
  export type ContextStatus = 'NONE' | 'NOT_FOUND' | 'PERMISSION_DENIED' | 'SUCCESS';
36
16
  export interface CreateSessionResponseData {
37
17
  chat_session_id: string;
@@ -4,7 +4,7 @@ import { PageToken } from '../../commonStateTypes/viewAndReport/viewAndReport';
4
4
  import { ChatSessionPayload } from '../../entity/aiCfo/aiCfoPayload';
5
5
  import { AiCfoAnswerResponseType } from '../../entity/aiCfo/aiCfoState';
6
6
  import { ZeniAPIStatus } from '../../responsePayload';
7
- import { ContextStatus, FeedbackType, SubmitFeedbackPayload, TranscribeAudioPayload, TranscribeAudioSuccessPayload } from './aiCfoViewPayload';
7
+ import { ContextStatus, FeedbackType, SubmitFeedbackPayload } from './aiCfoViewPayload';
8
8
  import { AiCfoViewState, Routine, RoutineDraft, RoutineRun, Skill, SkillDetail, SkillDraft, SkillVersion, SkillVisibility } from './aiCfoViewState';
9
9
  export declare const initialAiCfoViewState: AiCfoViewState;
10
10
  export declare const acceptMasterTOS: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[userRoleId: string], {
@@ -220,7 +220,7 @@ export declare const acceptMasterTOS: import("@reduxjs/toolkit").ActionCreatorWi
220
220
  }, "aiCfoView/submitQuestion", never, never>, submitQuestionFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
221
221
  error: ZeniAPIStatus;
222
222
  sessionId: ID;
223
- }, "aiCfoView/submitQuestionFailure">, submitQuestionSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<string, "aiCfoView/submitQuestionSuccess">, transcribeAudio: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[audio: Blob, language?: string | undefined, chatSessionId?: string | undefined], TranscribeAudioPayload, "aiCfoView/transcribeAudio", never, never>, transcribeAudioFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "aiCfoView/transcribeAudioFailure">, transcribeAudioSuccess: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transcript: string, chatSessionId?: string | undefined], TranscribeAudioSuccessPayload, "aiCfoView/transcribeAudioSuccess", never, never>, updateAiCfoViewScrollPosition: import("@reduxjs/toolkit").ActionCreatorWithPayload<number, "aiCfoView/updateAiCfoViewScrollPosition">, updateCotCollapsedState: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
223
+ }, "aiCfoView/submitQuestionFailure">, submitQuestionSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<string, "aiCfoView/submitQuestionSuccess">, updateAiCfoViewScrollPosition: import("@reduxjs/toolkit").ActionCreatorWithPayload<number, "aiCfoView/updateAiCfoViewScrollPosition">, updateCotCollapsedState: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
224
224
  isCollapsed: boolean;
225
225
  questionAnswerId: ID;
226
226
  }, "aiCfoView/updateCotCollapsedState">, updateCurrentInput: import("@reduxjs/toolkit").ActionCreatorWithPayload<string, "aiCfoView/updateCurrentInput">, updateResponseState: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
@@ -2,7 +2,7 @@
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.fetchSkillVersionBodySuccess = exports.fetchSkillVersionBodyFailure = exports.fetchSkillVersionBody = exports.fetchSkillsSuccess = exports.fetchSkillsFailure = exports.fetchSkills = exports.fetchSkillDetailSuccess = exports.fetchSkillDetailFailure = exports.fetchSkillDetail = exports.fetchRoutinesSuccess = exports.fetchRoutinesFailure = exports.fetchRoutines = exports.fetchRoutineRunsSuccess = exports.fetchRoutineRunsFailure = exports.fetchRoutineRuns = exports.fetchChatSessionsForUserSuccess = exports.fetchChatSessionsForUserFailure = exports.fetchChatSessionsForUser = exports.fetchChatHistorySuccess = exports.fetchChatHistoryFailure = exports.fetchChatHistory = exports.deleteSkillSuccess = exports.deleteSkillFailure = exports.deleteSkill = exports.deleteRoutineSuccess = exports.deleteRoutineFailure = exports.deleteRoutine = exports.deleteChatSessionSuccess = exports.deleteChatSessionFailure = exports.deleteChatSession = exports.createSessionSuccess = exports.createSessionFailure = exports.createSessionAndSubmitSuccess = exports.createSessionAndSubmitFailure = exports.createSessionAndSubmit = exports.createSession = exports.closeSkillsBrowser = exports.closeRoutinesBrowser = exports.closeRoutineRuns = exports.clearSkillMutation = exports.clearSkillDetail = exports.clearLastContextMessage = exports.clearDeleteChatSessionStatus = exports.clearCurrentSessionId = exports.clearAiCfoSidePanelHostPageContext = exports.applyAiCfoSidePanelHostPageTransition = exports.acceptMasterTOSSuccess = exports.acceptMasterTOSFailure = exports.acceptMasterTOS = exports.initialAiCfoViewState = void 0;
5
- exports.updateResponseState = exports.updateCurrentInput = exports.updateCotCollapsedState = exports.updateAiCfoViewScrollPosition = exports.transcribeAudioSuccess = exports.transcribeAudioFailure = exports.transcribeAudio = exports.submitQuestionSuccess = exports.submitQuestionFailure = exports.submitQuestion = exports.submitFeedbackSuccess = exports.submitFeedbackFailure = exports.submitFeedback = exports.stopSubmitSuccess = exports.stopSubmitQuestionSuccess = exports.stopSubmitQuestionFailure = exports.stopSubmitQuestion = exports.stopSubmitFailure = exports.stopSubmit = exports.setSkillVisibilitySuccess = exports.setSkillVisibilityFailure = exports.setSkillVisibility = exports.setSession = exports.setRoutineEnabled = exports.saveSkillSuccess = exports.saveSkillFailure = exports.saveSkill = exports.saveRoutineSuccess = exports.saveRoutineFailure = exports.saveRoutine = exports.runRoutineSuccess = exports.runRoutineFailure = exports.runRoutine = exports.openSkillsBrowser = exports.openRoutinesBrowser = exports.initializeNewSessionState = exports.fetchSuggestedQuestionsSuccess = exports.fetchSuggestedQuestionsFailure = exports.fetchSuggestedQuestions = exports.fetchSkillVersionsSuccess = exports.fetchSkillVersionsFailure = exports.fetchSkillVersions = void 0;
5
+ exports.updateResponseState = exports.updateCurrentInput = exports.updateCotCollapsedState = exports.updateAiCfoViewScrollPosition = exports.submitQuestionSuccess = exports.submitQuestionFailure = exports.submitQuestion = exports.submitFeedbackSuccess = exports.submitFeedbackFailure = exports.submitFeedback = exports.stopSubmitSuccess = exports.stopSubmitQuestionSuccess = exports.stopSubmitQuestionFailure = exports.stopSubmitQuestion = exports.stopSubmitFailure = exports.stopSubmit = exports.setSkillVisibilitySuccess = exports.setSkillVisibilityFailure = exports.setSkillVisibility = exports.setSession = exports.setRoutineEnabled = exports.saveSkillSuccess = exports.saveSkillFailure = exports.saveSkill = exports.saveRoutineSuccess = exports.saveRoutineFailure = exports.saveRoutine = exports.runRoutineSuccess = exports.runRoutineFailure = exports.runRoutine = exports.openSkillsBrowser = exports.openRoutinesBrowser = exports.initializeNewSessionState = exports.fetchSuggestedQuestionsSuccess = exports.fetchSuggestedQuestionsFailure = exports.fetchSuggestedQuestions = exports.fetchSkillVersionsSuccess = exports.fetchSkillVersionsFailure = exports.fetchSkillVersions = void 0;
6
6
  const toolkit_1 = require("@reduxjs/toolkit");
7
7
  const rootActions_1 = require("../../rootActions");
8
8
  function removeSessionIdFromPageKeyMap(draft, sessionId) {
@@ -52,8 +52,6 @@ exports.initialAiCfoViewState = {
52
52
  fetchChatSessionHistoryByChatSessionId: {},
53
53
  responseStateByChatSessionId: {},
54
54
  stopSubmitStateByChatSessionId: {},
55
- transcriptionState: { fetchState: 'Not-Started', error: undefined },
56
- transcribingChatSessionId: undefined,
57
55
  suggestedQuestionsByPageContext: {},
58
56
  skillDetail: {
59
57
  fetchState: 'Not-Started',
@@ -154,19 +152,6 @@ function closeSkillsBrowserState(draft) {
154
152
  draft.uiState.isSkillsBrowserOpen = false;
155
153
  clearOpenSkillState(draft);
156
154
  }
157
- /**
158
- * Clear a finished dictation attempt when the conversation moves on, so a failed one
159
- * stops showing "Could not transcribe that recording" in every later chat. A running
160
- * take keeps its state — the composer is showing a live "Transcribing…" for it.
161
- */
162
- function resetFinishedTranscription(draft) {
163
- if (draft.transcriptionState.fetchState === 'In-Progress') {
164
- return;
165
- }
166
- draft.transcriptionState.fetchState = 'Not-Started';
167
- draft.transcriptionState.error = undefined;
168
- draft.transcribingChatSessionId = undefined;
169
- }
170
155
  const aiCfoView = (0, toolkit_1.createSlice)({
171
156
  name: 'aiCfoView',
172
157
  initialState: exports.initialAiCfoViewState,
@@ -174,7 +159,6 @@ const aiCfoView = (0, toolkit_1.createSlice)({
174
159
  submitQuestion: {
175
160
  reducer(draft, action) {
176
161
  const { sessionId } = action.payload;
177
- resetFinishedTranscription(draft);
178
162
  // A turn is being sent, so the chat body has to be what the user sees. Doing this
179
163
  // here rather than at each call site is deliberate: the composer, the sample
180
164
  // chips, Run, and the `/` menu all submit, and every one of them was a separate
@@ -320,7 +304,6 @@ const aiCfoView = (0, toolkit_1.createSlice)({
320
304
  setSession(draft, action) {
321
305
  draft.uiState.currentChatSessionId = action.payload.sessionId;
322
306
  draft.uiState.agentId = action.payload.agentId;
323
- resetFinishedTranscription(draft);
324
307
  // Picking a session means wanting to see that chat, so the browser cannot stay over
325
308
  // it. In the reducer because there are six dispatch sites across three separate
326
309
  // rails, and covering them one at a time missed half of them.
@@ -373,7 +356,6 @@ const aiCfoView = (0, toolkit_1.createSlice)({
373
356
  createSessionAndSubmit: {
374
357
  reducer(draft, action) {
375
358
  draft.uiState.agentId = action.payload.agentId;
376
- resetFinishedTranscription(draft);
377
359
  draft.createSessionAndSubmitState.fetchState = 'In-Progress';
378
360
  draft.createSessionAndSubmitState.error = undefined;
379
361
  },
@@ -574,49 +556,7 @@ const aiCfoView = (0, toolkit_1.createSlice)({
574
556
  return { payload: { chatMessageId, error } };
575
557
  },
576
558
  },
577
- transcribeAudio: {
578
- reducer(draft, action) {
579
- draft.transcriptionState.fetchState = 'In-Progress';
580
- draft.transcriptionState.error = undefined;
581
- draft.transcribingChatSessionId = action.payload.chatSessionId;
582
- },
583
- prepare(audio, language, chatSessionId) {
584
- return { payload: { audio, chatSessionId, language } };
585
- },
586
- },
587
- transcribeAudioSuccess: {
588
- reducer(draft, action) {
589
- draft.transcriptionState.fetchState = 'Completed';
590
- draft.transcriptionState.error = undefined;
591
- // The user moved to another session while this was in flight — dropping it
592
- // is the only safe option, since appending would put their words in a
593
- // conversation they did not dictate into.
594
- if (action.payload.chatSessionId !== draft.uiState.currentChatSessionId) {
595
- return;
596
- }
597
- const transcript = action.payload.transcript.trim();
598
- if (transcript === '') {
599
- // Silence, not a failure: leave the composer untouched so the user can
600
- // simply speak again rather than hunting for what went wrong.
601
- return;
602
- }
603
- // Append to whatever is in the box now rather than to a snapshot taken when
604
- // recording began — a take produces exactly one result, so there is nothing
605
- // to reconcile, and anything typed while transcribing survives.
606
- const existing = draft.uiState.currentInput.trim();
607
- draft.uiState.currentInput =
608
- existing === '' ? transcript : `${existing} ${transcript}`;
609
- },
610
- prepare(transcript, chatSessionId) {
611
- return { payload: { chatSessionId, transcript } };
612
- },
613
- },
614
- transcribeAudioFailure(draft, action) {
615
- draft.transcriptionState.fetchState = 'Error';
616
- draft.transcriptionState.error = action.payload;
617
- },
618
559
  clearCurrentSessionId(draft) {
619
- resetFinishedTranscription(draft);
620
560
  // New Chat: the empty composer is the point, so the browser cannot stay over it.
621
561
  if (draft.uiState.isSkillsBrowserOpen === true) {
622
562
  closeSkillsBrowserState(draft);
@@ -900,8 +840,7 @@ const aiCfoView = (0, toolkit_1.createSlice)({
900
840
  // The server has it. Nothing it sends from here on will contain this row,
901
841
  // so the tombstone has done its job and holding it any longer is what
902
842
  // makes a routine recreated under the same id invisible forever.
903
- draft.routines.deletedScheduleIds =
904
- draft.routines.deletedScheduleIds.filter((id) => id !== action.payload.scheduleId);
843
+ draft.routines.deletedScheduleIds = draft.routines.deletedScheduleIds.filter((id) => id !== action.payload.scheduleId);
905
844
  draft.routineMutation = {
906
845
  fetchState: 'Completed',
907
846
  error: undefined,
@@ -913,8 +852,7 @@ const aiCfoView = (0, toolkit_1.createSlice)({
913
852
  // is what lets the refetch put the row back — leaving it hidden would
914
853
  // tell the user they had stopped something they had not, which is the
915
854
  // worst outcome this list can produce.
916
- draft.routines.deletedScheduleIds =
917
- draft.routines.deletedScheduleIds.filter((id) => id !== action.payload.scheduleId);
855
+ draft.routines.deletedScheduleIds = draft.routines.deletedScheduleIds.filter((id) => id !== action.payload.scheduleId);
918
856
  // Its own slice: the refetch that puts the row back would otherwise wipe
919
857
  // this error, leaving the row silently reappearing with no explanation.
920
858
  draft.routineMutation = {
@@ -1250,5 +1188,5 @@ const aiCfoView = (0, toolkit_1.createSlice)({
1250
1188
  });
1251
1189
  },
1252
1190
  });
1253
- _a = aiCfoView.actions, exports.acceptMasterTOS = _a.acceptMasterTOS, exports.acceptMasterTOSFailure = _a.acceptMasterTOSFailure, exports.acceptMasterTOSSuccess = _a.acceptMasterTOSSuccess, exports.applyAiCfoSidePanelHostPageTransition = _a.applyAiCfoSidePanelHostPageTransition, exports.clearAiCfoSidePanelHostPageContext = _a.clearAiCfoSidePanelHostPageContext, exports.clearCurrentSessionId = _a.clearCurrentSessionId, exports.clearDeleteChatSessionStatus = _a.clearDeleteChatSessionStatus, exports.clearLastContextMessage = _a.clearLastContextMessage, exports.clearSkillDetail = _a.clearSkillDetail, exports.clearSkillMutation = _a.clearSkillMutation, exports.closeRoutineRuns = _a.closeRoutineRuns, exports.closeRoutinesBrowser = _a.closeRoutinesBrowser, exports.closeSkillsBrowser = _a.closeSkillsBrowser, exports.createSession = _a.createSession, exports.createSessionAndSubmit = _a.createSessionAndSubmit, exports.createSessionAndSubmitFailure = _a.createSessionAndSubmitFailure, exports.createSessionAndSubmitSuccess = _a.createSessionAndSubmitSuccess, exports.createSessionFailure = _a.createSessionFailure, exports.createSessionSuccess = _a.createSessionSuccess, exports.deleteChatSession = _a.deleteChatSession, exports.deleteChatSessionFailure = _a.deleteChatSessionFailure, exports.deleteChatSessionSuccess = _a.deleteChatSessionSuccess, exports.deleteRoutine = _a.deleteRoutine, exports.deleteRoutineFailure = _a.deleteRoutineFailure, exports.deleteRoutineSuccess = _a.deleteRoutineSuccess, exports.deleteSkill = _a.deleteSkill, exports.deleteSkillFailure = _a.deleteSkillFailure, exports.deleteSkillSuccess = _a.deleteSkillSuccess, exports.fetchChatHistory = _a.fetchChatHistory, exports.fetchChatHistoryFailure = _a.fetchChatHistoryFailure, exports.fetchChatHistorySuccess = _a.fetchChatHistorySuccess, exports.fetchChatSessionsForUser = _a.fetchChatSessionsForUser, exports.fetchChatSessionsForUserFailure = _a.fetchChatSessionsForUserFailure, exports.fetchChatSessionsForUserSuccess = _a.fetchChatSessionsForUserSuccess, exports.fetchRoutineRuns = _a.fetchRoutineRuns, exports.fetchRoutineRunsFailure = _a.fetchRoutineRunsFailure, exports.fetchRoutineRunsSuccess = _a.fetchRoutineRunsSuccess, exports.fetchRoutines = _a.fetchRoutines, exports.fetchRoutinesFailure = _a.fetchRoutinesFailure, exports.fetchRoutinesSuccess = _a.fetchRoutinesSuccess, exports.fetchSkillDetail = _a.fetchSkillDetail, exports.fetchSkillDetailFailure = _a.fetchSkillDetailFailure, exports.fetchSkillDetailSuccess = _a.fetchSkillDetailSuccess, exports.fetchSkills = _a.fetchSkills, exports.fetchSkillsFailure = _a.fetchSkillsFailure, exports.fetchSkillsSuccess = _a.fetchSkillsSuccess, exports.fetchSkillVersionBody = _a.fetchSkillVersionBody, exports.fetchSkillVersionBodyFailure = _a.fetchSkillVersionBodyFailure, exports.fetchSkillVersionBodySuccess = _a.fetchSkillVersionBodySuccess, exports.fetchSkillVersions = _a.fetchSkillVersions, exports.fetchSkillVersionsFailure = _a.fetchSkillVersionsFailure, exports.fetchSkillVersionsSuccess = _a.fetchSkillVersionsSuccess, exports.fetchSuggestedQuestions = _a.fetchSuggestedQuestions, exports.fetchSuggestedQuestionsFailure = _a.fetchSuggestedQuestionsFailure, exports.fetchSuggestedQuestionsSuccess = _a.fetchSuggestedQuestionsSuccess, exports.initializeNewSessionState = _a.initializeNewSessionState, exports.openRoutinesBrowser = _a.openRoutinesBrowser, exports.openSkillsBrowser = _a.openSkillsBrowser, exports.runRoutine = _a.runRoutine, exports.runRoutineFailure = _a.runRoutineFailure, exports.runRoutineSuccess = _a.runRoutineSuccess, exports.saveRoutine = _a.saveRoutine, exports.saveRoutineFailure = _a.saveRoutineFailure, exports.saveRoutineSuccess = _a.saveRoutineSuccess, exports.saveSkill = _a.saveSkill, exports.saveSkillFailure = _a.saveSkillFailure, exports.saveSkillSuccess = _a.saveSkillSuccess, exports.setRoutineEnabled = _a.setRoutineEnabled, exports.setSession = _a.setSession, exports.setSkillVisibility = _a.setSkillVisibility, exports.setSkillVisibilityFailure = _a.setSkillVisibilityFailure, exports.setSkillVisibilitySuccess = _a.setSkillVisibilitySuccess, exports.stopSubmit = _a.stopSubmit, exports.stopSubmitFailure = _a.stopSubmitFailure, exports.stopSubmitQuestion = _a.stopSubmitQuestion, exports.stopSubmitQuestionFailure = _a.stopSubmitQuestionFailure, exports.stopSubmitQuestionSuccess = _a.stopSubmitQuestionSuccess, exports.stopSubmitSuccess = _a.stopSubmitSuccess, exports.submitFeedback = _a.submitFeedback, exports.submitFeedbackFailure = _a.submitFeedbackFailure, exports.submitFeedbackSuccess = _a.submitFeedbackSuccess, exports.submitQuestion = _a.submitQuestion, exports.submitQuestionFailure = _a.submitQuestionFailure, exports.submitQuestionSuccess = _a.submitQuestionSuccess, exports.transcribeAudio = _a.transcribeAudio, exports.transcribeAudioFailure = _a.transcribeAudioFailure, exports.transcribeAudioSuccess = _a.transcribeAudioSuccess, exports.updateAiCfoViewScrollPosition = _a.updateAiCfoViewScrollPosition, exports.updateCotCollapsedState = _a.updateCotCollapsedState, exports.updateCurrentInput = _a.updateCurrentInput, exports.updateResponseState = _a.updateResponseState;
1191
+ _a = aiCfoView.actions, exports.acceptMasterTOS = _a.acceptMasterTOS, exports.acceptMasterTOSFailure = _a.acceptMasterTOSFailure, exports.acceptMasterTOSSuccess = _a.acceptMasterTOSSuccess, exports.applyAiCfoSidePanelHostPageTransition = _a.applyAiCfoSidePanelHostPageTransition, exports.clearAiCfoSidePanelHostPageContext = _a.clearAiCfoSidePanelHostPageContext, exports.clearCurrentSessionId = _a.clearCurrentSessionId, exports.clearDeleteChatSessionStatus = _a.clearDeleteChatSessionStatus, exports.clearLastContextMessage = _a.clearLastContextMessage, exports.clearSkillDetail = _a.clearSkillDetail, exports.clearSkillMutation = _a.clearSkillMutation, exports.closeRoutineRuns = _a.closeRoutineRuns, exports.closeRoutinesBrowser = _a.closeRoutinesBrowser, exports.closeSkillsBrowser = _a.closeSkillsBrowser, exports.createSession = _a.createSession, exports.createSessionAndSubmit = _a.createSessionAndSubmit, exports.createSessionAndSubmitFailure = _a.createSessionAndSubmitFailure, exports.createSessionAndSubmitSuccess = _a.createSessionAndSubmitSuccess, exports.createSessionFailure = _a.createSessionFailure, exports.createSessionSuccess = _a.createSessionSuccess, exports.deleteChatSession = _a.deleteChatSession, exports.deleteChatSessionFailure = _a.deleteChatSessionFailure, exports.deleteChatSessionSuccess = _a.deleteChatSessionSuccess, exports.deleteRoutine = _a.deleteRoutine, exports.deleteRoutineFailure = _a.deleteRoutineFailure, exports.deleteRoutineSuccess = _a.deleteRoutineSuccess, exports.deleteSkill = _a.deleteSkill, exports.deleteSkillFailure = _a.deleteSkillFailure, exports.deleteSkillSuccess = _a.deleteSkillSuccess, exports.fetchChatHistory = _a.fetchChatHistory, exports.fetchChatHistoryFailure = _a.fetchChatHistoryFailure, exports.fetchChatHistorySuccess = _a.fetchChatHistorySuccess, exports.fetchChatSessionsForUser = _a.fetchChatSessionsForUser, exports.fetchChatSessionsForUserFailure = _a.fetchChatSessionsForUserFailure, exports.fetchChatSessionsForUserSuccess = _a.fetchChatSessionsForUserSuccess, exports.fetchRoutineRuns = _a.fetchRoutineRuns, exports.fetchRoutineRunsFailure = _a.fetchRoutineRunsFailure, exports.fetchRoutineRunsSuccess = _a.fetchRoutineRunsSuccess, exports.fetchRoutines = _a.fetchRoutines, exports.fetchRoutinesFailure = _a.fetchRoutinesFailure, exports.fetchRoutinesSuccess = _a.fetchRoutinesSuccess, exports.fetchSkillDetail = _a.fetchSkillDetail, exports.fetchSkillDetailFailure = _a.fetchSkillDetailFailure, exports.fetchSkillDetailSuccess = _a.fetchSkillDetailSuccess, exports.fetchSkills = _a.fetchSkills, exports.fetchSkillsFailure = _a.fetchSkillsFailure, exports.fetchSkillsSuccess = _a.fetchSkillsSuccess, exports.fetchSkillVersionBody = _a.fetchSkillVersionBody, exports.fetchSkillVersionBodyFailure = _a.fetchSkillVersionBodyFailure, exports.fetchSkillVersionBodySuccess = _a.fetchSkillVersionBodySuccess, exports.fetchSkillVersions = _a.fetchSkillVersions, exports.fetchSkillVersionsFailure = _a.fetchSkillVersionsFailure, exports.fetchSkillVersionsSuccess = _a.fetchSkillVersionsSuccess, exports.fetchSuggestedQuestions = _a.fetchSuggestedQuestions, exports.fetchSuggestedQuestionsFailure = _a.fetchSuggestedQuestionsFailure, exports.fetchSuggestedQuestionsSuccess = _a.fetchSuggestedQuestionsSuccess, exports.initializeNewSessionState = _a.initializeNewSessionState, exports.openRoutinesBrowser = _a.openRoutinesBrowser, exports.openSkillsBrowser = _a.openSkillsBrowser, exports.runRoutine = _a.runRoutine, exports.runRoutineFailure = _a.runRoutineFailure, exports.runRoutineSuccess = _a.runRoutineSuccess, exports.saveRoutine = _a.saveRoutine, exports.saveRoutineFailure = _a.saveRoutineFailure, exports.saveRoutineSuccess = _a.saveRoutineSuccess, exports.saveSkill = _a.saveSkill, exports.saveSkillFailure = _a.saveSkillFailure, exports.saveSkillSuccess = _a.saveSkillSuccess, exports.setRoutineEnabled = _a.setRoutineEnabled, exports.setSession = _a.setSession, exports.setSkillVisibility = _a.setSkillVisibility, exports.setSkillVisibilityFailure = _a.setSkillVisibilityFailure, exports.setSkillVisibilitySuccess = _a.setSkillVisibilitySuccess, exports.stopSubmit = _a.stopSubmit, exports.stopSubmitFailure = _a.stopSubmitFailure, exports.stopSubmitQuestion = _a.stopSubmitQuestion, exports.stopSubmitQuestionFailure = _a.stopSubmitQuestionFailure, exports.stopSubmitQuestionSuccess = _a.stopSubmitQuestionSuccess, exports.stopSubmitSuccess = _a.stopSubmitSuccess, exports.submitFeedback = _a.submitFeedback, exports.submitFeedbackFailure = _a.submitFeedbackFailure, exports.submitFeedbackSuccess = _a.submitFeedbackSuccess, exports.submitQuestion = _a.submitQuestion, exports.submitQuestionFailure = _a.submitQuestionFailure, exports.submitQuestionSuccess = _a.submitQuestionSuccess, exports.updateAiCfoViewScrollPosition = _a.updateAiCfoViewScrollPosition, exports.updateCotCollapsedState = _a.updateCotCollapsedState, exports.updateCurrentInput = _a.updateCurrentInput, exports.updateResponseState = _a.updateResponseState;
1254
1192
  exports.default = aiCfoView.reducer;
@@ -4,7 +4,7 @@ import { FetchStateAndError } from '../../commonStateTypes/common';
4
4
  import { SelectorView } from '../../commonStateTypes/viewAndReport/viewAndReport';
5
5
  import { AiCfoSelectorView } from '../../entity/aiCfo/aiCfoSelector';
6
6
  import { RootState } from '../../rootStateTypes';
7
- import { AiCfoViewUIState, RoutineMutationState, RoutineRunsState, RoutinesState, SkillDetailState, SkillMutationState, SkillVersionBodyState, SkillVersionsState, SkillsState, SuggestedQuestionsForPageContext } from './aiCfoViewState';
7
+ import { AiCfoViewUIState, SkillDetailState, SkillMutationState, SkillVersionBodyState, SkillVersionsState, RoutineMutationState, RoutineRunsState, RoutinesState, SkillsState, SuggestedQuestionsForPageContext } from './aiCfoViewState';
8
8
  export interface AiCfoViewSelector extends SelectorView, AiCfoSelectorView {
9
9
  createSessionAndSubmitState: FetchStateAndError;
10
10
  createSessionState: FetchStateAndError;
@@ -42,10 +42,3 @@ export declare function getSkillVersionBody(state: RootState): SkillVersionBodyS
42
42
  export declare function getSkillMutation(state: RootState): SkillMutationState;
43
43
  /** True only when the server says the feature is on for this tenant. */
44
44
  export declare function getSkillsEnabled(state: RootState): boolean;
45
- export declare function getIsTranscribing(state: RootState): boolean;
46
- /**
47
- * Set when a transcription request failed. Without surfacing this the composer
48
- * would just drop the "Transcribing…" label and sit there silently, leaving the
49
- * user with no sign their recording went nowhere.
50
- */
51
- export declare function getTranscriptionFailed(state: RootState): boolean;
@@ -13,8 +13,6 @@ exports.getSkillVersions = getSkillVersions;
13
13
  exports.getSkillVersionBody = getSkillVersionBody;
14
14
  exports.getSkillMutation = getSkillMutation;
15
15
  exports.getSkillsEnabled = getSkillsEnabled;
16
- exports.getIsTranscribing = getIsTranscribing;
17
- exports.getTranscriptionFailed = getTranscriptionFailed;
18
16
  const aiCfoReducer_1 = require("../../entity/aiCfo/aiCfoReducer");
19
17
  const aiCfoSelector_1 = require("../../entity/aiCfo/aiCfoSelector");
20
18
  const aiCfoViewReducer_1 = require("./aiCfoViewReducer");
@@ -151,28 +149,3 @@ function getSkillMutation(state) {
151
149
  function getSkillsEnabled(state) {
152
150
  return getSkills(state).skillsEnabled;
153
151
  }
154
- /** True while a finished voice recording is being transcribed server-side. */
155
- /**
156
- * A take belongs to the chat it was dictated into. A new chat has no session id yet on
157
- * either side, which is a match rather than a mismatch.
158
- */
159
- function isTranscribingCurrentSession(state) {
160
- if (state.aiCfoViewState == null) {
161
- return false;
162
- }
163
- return (state.aiCfoViewState.transcribingChatSessionId ===
164
- state.aiCfoViewState.uiState.currentChatSessionId);
165
- }
166
- function getIsTranscribing(state) {
167
- return (state.aiCfoViewState?.transcriptionState?.fetchState === 'In-Progress' &&
168
- isTranscribingCurrentSession(state));
169
- }
170
- /**
171
- * Set when a transcription request failed. Without surfacing this the composer
172
- * would just drop the "Transcribing…" label and sit there silently, leaving the
173
- * user with no sign their recording went nowhere.
174
- */
175
- function getTranscriptionFailed(state) {
176
- return (state.aiCfoViewState?.transcriptionState?.fetchState === 'Error' &&
177
- isTranscribingCurrentSession(state));
178
- }
@@ -378,14 +378,5 @@ export interface AiCfoViewState extends FetchStateAndError {
378
378
  stopSubmitStateByChatSessionId: Record<ID, FetchStateAndError>;
379
379
  /** Keyed by `page_context` query value (e.g. balance_sheet). */
380
380
  suggestedQuestionsByPageContext: Partial<Record<AiCfoSuggestedQuestionsPageContext, SuggestedQuestionsForPageContext>>;
381
- /** Voice dictation: in-flight while a recording is being transcribed. */
382
- transcriptionState: FetchStateAndError;
383
381
  uiState: AiCfoViewUIState;
384
- /**
385
- * Conversation the take in `transcriptionState` was dictated into. The spinner and
386
- * the failure message belong to that chat alone — an epic outlives the component, so
387
- * without this a take started in one session locks the composer, or shows its error,
388
- * in whichever session the user has moved to.
389
- */
390
- transcribingChatSessionId?: ID;
391
382
  }
@@ -91,6 +91,10 @@ const fetchDashboardEpic = (actions$, state$) => actions$.pipe((0, operators_1.f
91
91
  const revenueState = (0, revenueSelector_1.getRevenueReportFetchState)(state.revenueState.uiState.selectedForecast?.id, state.revenueState);
92
92
  const opExState = (0, opExSelector_1.getOperatingExpensesReportFetchState)(state.opExState.uiState.selectedForecast?.id, state.opExState);
93
93
  const netBurnOrIncomeReportFetchState = (0, netBurnOrIncomeSelector_1.getNetBurnOrIncomeReportFetchState)(state.netBurnOrIncomeState.uiState.selectedForecast?.id, state.netBurnOrIncomeState);
94
+ if (state.tenantState.fetchState !== 'In-Progress' &&
95
+ !state.tenantState.hasValidState()) {
96
+ fetchActions.push((0, tenantReducer_1.fetchAllTenants)(userId));
97
+ }
94
98
  if (state.cardBalanceState.fetchState !== 'In-Progress' &&
95
99
  !state.cardBalanceState.hasValidState()) {
96
100
  fetchActions.push((0, cardBalanceReducer_1.fetchCardBalance)());
@@ -1,4 +1,5 @@
1
1
  import { ReportID, SelectorReport, SelectorView } from '../../commonStateTypes/viewAndReport/viewAndReport';
2
+ import { TenantsOrdered } from '../../entity/tenant/tenantSelector';
2
3
  import { Tenant } from '../../entity/tenant/tenantState';
3
4
  import { RootState } from '../../rootStateTypes';
4
5
  import { CardType } from './dashboardState';
@@ -6,6 +7,7 @@ export interface DashboardReport extends SelectorReport {
6
7
  cardsForDashboardUI: CardType[];
7
8
  cardsOrdered: CardType[];
8
9
  reportsInOrder: (SelectorReport | SelectorView)[];
10
+ tenantsOrdered: TenantsOrdered;
9
11
  currentTenant?: Tenant;
10
12
  }
11
13
  export declare const getDashboard: (state: RootState, additionalExcludedReports: ReportID[]) => DashboardReport;
@@ -37,7 +37,8 @@ const getCashInCashOutLast4Periods = (state) => (0, cashInCashOutSelector_1.getC
37
37
  const getNetBurnOrIncomeStoryCard = (state) => (0, netBurnOrIncomeStoryCardSelector_1.getNetBurnOrIncomeStoryCardReport)(state);
38
38
  const apAgingSelector = (state) => (0, apAgingSelector_1.getApAgingReport)(state);
39
39
  const arAgingSelector = (state) => (0, arAgingSelector_1.getArAgingReport)(state);
40
- const tenantSelector = (0, toolkit_1.createSelector)(tenantSelector_1.getCurrentTenant, (currentTenant) => ({
40
+ const tenantSelector = (0, toolkit_1.createSelector)(tenantSelector_1.getTenantsByCheckInDateSelector, tenantSelector_1.getCurrentTenant, (tenantsOrdered, currentTenant) => ({
41
+ tenantsOrdered,
41
42
  currentTenant,
42
43
  }));
43
44
  exports.getDashboard = (0, toolkit_1.createSelector)(tenantSelector, cardBalanceSelector_1.getCardBalance, cashBalanceSelector_1.getCashBalance, getOperatingExpensesForLast5Periods, getRevenueForLast4Periods, topExSelector_1.getTop6Expenses, getNetBurnOrIncomeForLast4Periods, getNetBurnOrIncomeStoryCard, getCashPositionLast5Periods, getCashInCashOutLast4Periods, insightsCardSelector_1.getInsights, companyPassportViewSelector_1.getCompanyPassportView, tasksCardSelector_1.getTasksCardReport, billPayCardSelector_1.getBillPayCardReport, reimbursementCardSelector_1.getReimbursementCardReport, apAgingSelector, arAgingSelector, referralSelector_1.getRewardsPlanCard, dashboardLayoutSelector_1.getDashboardCardsOrdered, (state) => {
@@ -18,8 +18,12 @@ const fetchFinanceStatementEpic = (actions$, state$) => actions$.pipe((0, operat
18
18
  return (0, rxjs_1.of)((0, tenantReducer_1.fetchAllTenants)(userId), (0, profitAndLossReducer_1.fetchProfitAndLoss)(), (0, balanceSheetReducer_1.fetchBalanceSheet)(), (0, cashFlowReducer_1.fetchCashFlow)());
19
19
  }
20
20
  else {
21
- const { financeStatementState } = state;
21
+ const { tenantState, financeStatementState } = state;
22
22
  const fetchActions = [];
23
+ if (tenantState.fetchState !== 'In-Progress' &&
24
+ !tenantState.hasValidState()) {
25
+ fetchActions.push((0, tenantReducer_1.fetchAllTenants)(userId));
26
+ }
23
27
  const pandLFetchState = (0, profitAndLossSelector_1.getPandLReportFetchState)(undefined, state.profitAndLossState);
24
28
  const balanceSheetFetchState = (0, balanceSheetSelector_1.getBalanceSheetFetchState)(state.balanceSheetState);
25
29
  const cashFlowFetchState = (0, cashFlowSelector_1.getCashFlowReportFetchState)(state.cashFlowState);
@@ -13,6 +13,10 @@ const fetchPeoplePageEpic = (actions$, state$) => actions$.pipe((0, operators_1.
13
13
  else {
14
14
  const state = state$.value;
15
15
  const fetchActions = [];
16
+ if (state.tenantState.fetchState !== 'In-Progress' &&
17
+ !state.tenantState.hasValidState()) {
18
+ fetchActions.push((0, tenantReducer_1.fetchAllTenants)(userId));
19
+ }
16
20
  if (state.peopleState.fetchState != 'In-Progress' &&
17
21
  !state.peopleState.hasValidState()) {
18
22
  fetchActions.push((0, peopleReducer_1.fetchPeople)());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "5.3.18-betaAK2",
3
+ "version": "5.3.18",
4
4
  "description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/esm/index.js",
@@ -1,60 +0,0 @@
1
- import { of } from 'rxjs';
2
- import { catchError, filter, finalize, map, switchMap, takeUntil, timeout, } from 'rxjs/operators';
3
- import { createZeniAPIStatus, isSuccessResponse, } from '../../../responsePayload';
4
- import { clearAll } from '../../../rootActions';
5
- import { transcribeAudio, transcribeAudioFailure, transcribeAudioSuccess, } from '../aiCfoViewReducer';
6
- const AUDIO_FIELD = 'audio';
7
- const LANGUAGE_FIELD = 'language';
8
- /** Extension only has to match the recorded format; the server reads the part's MIME type. */
9
- const AUDIO_FILE_NAME = 'dictation.wav';
10
- /**
11
- * A hung request would otherwise pin `isTranscribing` true forever, and the composer
12
- * gates both submit and the mic on it — leaving the user unable to send even typed
13
- * text until something else resolved it.
14
- */
15
- const TRANSCRIPTION_TIMEOUT_MS = 30000;
16
- /**
17
- * Voice dictation for the AI CFO composer. Dispatch `transcribeAudio(blob, language)` with a
18
- * finished recording to POST it to the AI CFO micro-service `/1.0/transcriptions` endpoint;
19
- * on success the transcript is appended to the composer input for the user to edit and send.
20
- *
21
- * `switchMap` (not `mergeMap`): a newer recording supersedes an older in-flight one, so a
22
- * slow response can never append a stale transcript after a fresh one has already landed.
23
- * The AbortController makes that cancellation real — `fetch` wrapped in a promise ignores
24
- * an RxJS unsubscribe, so without the signal the superseded request would run to completion
25
- * and still bill a transcription call whose result nothing wants.
26
- */
27
- export const transcribeAudioEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(transcribeAudio.match), switchMap((action) => {
28
- const { audio, chatSessionId, language } = action.payload;
29
- const abortController = new AbortController();
30
- const formData = new FormData();
31
- formData.append(AUDIO_FIELD, audio, AUDIO_FILE_NAME);
32
- if (language != null && language !== '') {
33
- formData.append(LANGUAGE_FIELD, language);
34
- }
35
- return zeniAPI
36
- .postFormData(`${zeniAPI.apiEndPoints.aiCfoMicroServiceBaseUrl}/1.0/transcriptions`, formData, abortController.signal)
37
- .pipe(timeout(TRANSCRIPTION_TIMEOUT_MS),
38
- // A tenant switch clears the store; a transcript still in flight must not
39
- // land in the next tenant's composer (both sessions can be `undefined`, so
40
- // the reducer's session guard would let it through).
41
- takeUntil(actions$.pipe(filter(clearAll.match))), map((response) => {
42
- if (!isSuccessResponse(response)) {
43
- return transcribeAudioFailure(response.status);
44
- }
45
- // An EMPTY transcript is a success (the mic caught silence) and the
46
- // reducer leaves the composer alone. A MISSING one breaks the response
47
- // contract, so it surfaces as an error rather than being coerced to
48
- // silence the user cannot distinguish from a quiet room.
49
- if (response.data?.transcript == null) {
50
- return transcribeAudioFailure(createZeniAPIStatus('Transcription succeeded but the response carried no transcript', 'Unexpected Error'));
51
- }
52
- // The session id rides along so a transcript that lands after the user
53
- // switched sessions is dropped rather than misfiled.
54
- return transcribeAudioSuccess(response.data.transcript, chatSessionId);
55
- }), finalize(() => abortController.abort()), catchError((error) => of(transcribeAudioFailure(createZeniAPIStatus(
56
- // message (detailed) first, then the short title — per createZeniAPIStatus(message, title).
57
- // JSON.stringify(Error) drops the (non-enumerable) message — extract it explicitly.
58
- 'Transcription REST API call errored out: ' +
59
- (error instanceof Error ? error.message : String(error)), 'Unexpected Error')))));
60
- }));
@@ -1,19 +0,0 @@
1
- import { ActionsObservable, StateObservable } from 'redux-observable';
2
- import { Observable } from 'rxjs';
3
- import { clearAll } from '../../../rootActions';
4
- import { RootState } from '../../../rootStateTypes';
5
- import { ZeniAPI } from '../../../zeniAPI';
6
- import { transcribeAudio, transcribeAudioFailure, transcribeAudioSuccess } from '../aiCfoViewReducer';
7
- export type ActionType = ReturnType<typeof clearAll> | ReturnType<typeof transcribeAudio> | ReturnType<typeof transcribeAudioSuccess> | ReturnType<typeof transcribeAudioFailure>;
8
- /**
9
- * Voice dictation for the AI CFO composer. Dispatch `transcribeAudio(blob, language)` with a
10
- * finished recording to POST it to the AI CFO micro-service `/1.0/transcriptions` endpoint;
11
- * on success the transcript is appended to the composer input for the user to edit and send.
12
- *
13
- * `switchMap` (not `mergeMap`): a newer recording supersedes an older in-flight one, so a
14
- * slow response can never append a stale transcript after a fresh one has already landed.
15
- * The AbortController makes that cancellation real — `fetch` wrapped in a promise ignores
16
- * an RxJS unsubscribe, so without the signal the superseded request would run to completion
17
- * and still bill a transcription call whose result nothing wants.
18
- */
19
- export declare const transcribeAudioEpic: (actions$: ActionsObservable<ActionType>, _state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
@@ -1,64 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.transcribeAudioEpic = void 0;
4
- const rxjs_1 = require("rxjs");
5
- const operators_1 = require("rxjs/operators");
6
- const responsePayload_1 = require("../../../responsePayload");
7
- const rootActions_1 = require("../../../rootActions");
8
- const aiCfoViewReducer_1 = require("../aiCfoViewReducer");
9
- const AUDIO_FIELD = 'audio';
10
- const LANGUAGE_FIELD = 'language';
11
- /** Extension only has to match the recorded format; the server reads the part's MIME type. */
12
- const AUDIO_FILE_NAME = 'dictation.wav';
13
- /**
14
- * A hung request would otherwise pin `isTranscribing` true forever, and the composer
15
- * gates both submit and the mic on it — leaving the user unable to send even typed
16
- * text until something else resolved it.
17
- */
18
- const TRANSCRIPTION_TIMEOUT_MS = 30000;
19
- /**
20
- * Voice dictation for the AI CFO composer. Dispatch `transcribeAudio(blob, language)` with a
21
- * finished recording to POST it to the AI CFO micro-service `/1.0/transcriptions` endpoint;
22
- * on success the transcript is appended to the composer input for the user to edit and send.
23
- *
24
- * `switchMap` (not `mergeMap`): a newer recording supersedes an older in-flight one, so a
25
- * slow response can never append a stale transcript after a fresh one has already landed.
26
- * The AbortController makes that cancellation real — `fetch` wrapped in a promise ignores
27
- * an RxJS unsubscribe, so without the signal the superseded request would run to completion
28
- * and still bill a transcription call whose result nothing wants.
29
- */
30
- const transcribeAudioEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(aiCfoViewReducer_1.transcribeAudio.match), (0, operators_1.switchMap)((action) => {
31
- const { audio, chatSessionId, language } = action.payload;
32
- const abortController = new AbortController();
33
- const formData = new FormData();
34
- formData.append(AUDIO_FIELD, audio, AUDIO_FILE_NAME);
35
- if (language != null && language !== '') {
36
- formData.append(LANGUAGE_FIELD, language);
37
- }
38
- return zeniAPI
39
- .postFormData(`${zeniAPI.apiEndPoints.aiCfoMicroServiceBaseUrl}/1.0/transcriptions`, formData, abortController.signal)
40
- .pipe((0, operators_1.timeout)(TRANSCRIPTION_TIMEOUT_MS),
41
- // A tenant switch clears the store; a transcript still in flight must not
42
- // land in the next tenant's composer (both sessions can be `undefined`, so
43
- // the reducer's session guard would let it through).
44
- (0, operators_1.takeUntil)(actions$.pipe((0, operators_1.filter)(rootActions_1.clearAll.match))), (0, operators_1.map)((response) => {
45
- if (!(0, responsePayload_1.isSuccessResponse)(response)) {
46
- return (0, aiCfoViewReducer_1.transcribeAudioFailure)(response.status);
47
- }
48
- // An EMPTY transcript is a success (the mic caught silence) and the
49
- // reducer leaves the composer alone. A MISSING one breaks the response
50
- // contract, so it surfaces as an error rather than being coerced to
51
- // silence the user cannot distinguish from a quiet room.
52
- if (response.data?.transcript == null) {
53
- return (0, aiCfoViewReducer_1.transcribeAudioFailure)((0, responsePayload_1.createZeniAPIStatus)('Transcription succeeded but the response carried no transcript', 'Unexpected Error'));
54
- }
55
- // The session id rides along so a transcript that lands after the user
56
- // switched sessions is dropped rather than misfiled.
57
- return (0, aiCfoViewReducer_1.transcribeAudioSuccess)(response.data.transcript, chatSessionId);
58
- }), (0, operators_1.finalize)(() => abortController.abort()), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, aiCfoViewReducer_1.transcribeAudioFailure)((0, responsePayload_1.createZeniAPIStatus)(
59
- // message (detailed) first, then the short title — per createZeniAPIStatus(message, title).
60
- // JSON.stringify(Error) drops the (non-enumerable) message — extract it explicitly.
61
- 'Transcription REST API call errored out: ' +
62
- (error instanceof Error ? error.message : String(error)), 'Unexpected Error')))));
63
- }));
64
- exports.transcribeAudioEpic = transcribeAudioEpic;