@zeniai/client-epic-state 5.2.32 → 5.2.34

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 (57) hide show
  1. package/lib/commonPayloadTypes/classesView/reportByClassPayloadV2.d.ts +13 -1
  2. package/lib/entity/sectionClassesViewV2/sectionClassesViewEpic.js +10 -7
  3. package/lib/entity/sectionClassesViewV2/sectionClassesViewReducer.d.ts +3 -3
  4. package/lib/entity/sectionProjectView/sectionProjectViewEpic.js +6 -2
  5. package/lib/entity/sectionProjectView/sectionProjectViewReducer.d.ts +3 -3
  6. package/lib/entity/sectionProjectView/sectionProjectViewReducer.js +4 -3
  7. package/lib/epic.js +12 -0
  8. package/lib/esm/entity/class/classReducer.js +1 -1
  9. package/lib/esm/entity/sectionClassesViewV2/sectionClassesViewEpic.js +10 -7
  10. package/lib/esm/entity/sectionProjectView/sectionProjectViewEpic.js +6 -2
  11. package/lib/esm/entity/sectionProjectView/sectionProjectViewReducer.js +5 -4
  12. package/lib/esm/epic.js +12 -0
  13. package/lib/esm/index.js +2 -2
  14. package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +266 -1
  15. package/lib/esm/view/aiCfoView/aiCfoViewSelector.js +50 -0
  16. package/lib/esm/view/aiCfoView/epics/deleteRoutineEpic.js +35 -0
  17. package/lib/esm/view/aiCfoView/epics/fetchRoutineRunsEpic.js +35 -0
  18. package/lib/esm/view/aiCfoView/epics/fetchRoutinesEpic.js +37 -0
  19. package/lib/esm/view/aiCfoView/epics/runRoutineEpic.js +34 -0
  20. package/lib/esm/view/aiCfoView/epics/saveRoutineEpic.js +65 -0
  21. package/lib/esm/view/aiCfoView/epics/setRoutineEnabledEpic.js +28 -0
  22. package/lib/esm/view/aiCfoView/epics/toRoutine.js +64 -0
  23. package/lib/esm/view/aiCfoView/epics/toRoutineRun.js +42 -0
  24. package/lib/esm/view/expenseAutomationView/selectors/fluxAnalysisViewSelector.js +12 -10
  25. package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -11
  26. package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +10 -11
  27. package/lib/index.d.ts +3 -3
  28. package/lib/index.js +55 -40
  29. package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +90 -0
  30. package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +164 -123
  31. package/lib/view/aiCfoView/aiCfoViewReducer.js +268 -3
  32. package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +13 -1
  33. package/lib/view/aiCfoView/aiCfoViewSelector.js +55 -0
  34. package/lib/view/aiCfoView/aiCfoViewState.d.ts +157 -0
  35. package/lib/view/aiCfoView/epics/deleteRoutineEpic.d.ts +18 -0
  36. package/lib/view/aiCfoView/epics/deleteRoutineEpic.js +39 -0
  37. package/lib/view/aiCfoView/epics/fetchRoutineRunsEpic.d.ts +13 -0
  38. package/lib/view/aiCfoView/epics/fetchRoutineRunsEpic.js +39 -0
  39. package/lib/view/aiCfoView/epics/fetchRoutinesEpic.d.ts +7 -0
  40. package/lib/view/aiCfoView/epics/fetchRoutinesEpic.js +41 -0
  41. package/lib/view/aiCfoView/epics/runRoutineEpic.d.ts +14 -0
  42. package/lib/view/aiCfoView/epics/runRoutineEpic.js +38 -0
  43. package/lib/view/aiCfoView/epics/saveRoutineEpic.d.ts +13 -0
  44. package/lib/view/aiCfoView/epics/saveRoutineEpic.js +69 -0
  45. package/lib/view/aiCfoView/epics/setRoutineEnabledEpic.d.ts +15 -0
  46. package/lib/view/aiCfoView/epics/setRoutineEnabledEpic.js +32 -0
  47. package/lib/view/aiCfoView/epics/toRoutine.d.ts +17 -0
  48. package/lib/view/aiCfoView/epics/toRoutine.js +69 -0
  49. package/lib/view/aiCfoView/epics/toRoutineRun.d.ts +12 -0
  50. package/lib/view/aiCfoView/epics/toRoutineRun.js +47 -0
  51. package/lib/view/cashFlowClassesView/cashFlowClassesViewPayload.d.ts +4 -4
  52. package/lib/view/cashFlowProjectView/cashFlowProjectViewPayload.d.ts +4 -4
  53. package/lib/view/expenseAutomationView/selectors/fluxAnalysisViewSelector.js +12 -10
  54. package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -11
  55. package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +10 -11
  56. package/lib/view/profitAndLossProjectView/profitAndLossProjectViewPayload.d.ts +12 -0
  57. package/package.json +1 -1
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.clearSkillDetail = exports.fetchSkillDetailFailure = exports.fetchSkillDetailSuccess = exports.fetchSkillDetail = exports.fetchSkillsFailure = exports.fetchSkillsSuccess = exports.fetchSkills = exports.fetchSuggestedQuestionsFailure = exports.fetchSuggestedQuestionsSuccess = exports.fetchSuggestedQuestions = exports.updateCotCollapsedState = exports.clearDeleteChatSessionStatus = exports.deleteChatSessionFailure = exports.deleteChatSessionSuccess = exports.deleteChatSession = exports.acceptMasterTOSFailure = exports.acceptMasterTOSSuccess = exports.acceptMasterTOS = exports.stopSubmitQuestionFailure = exports.stopSubmitQuestionSuccess = exports.stopSubmitQuestion = exports.stopSubmitFailure = exports.stopSubmitSuccess = exports.stopSubmit = exports.clearLastContextMessage = exports.clearCurrentSessionId = exports.fetchChatHistoryFailure = exports.fetchChatHistorySuccess = exports.fetchChatHistory = exports.fetchChatSessionsForUserFailure = exports.fetchChatSessionsForUserSuccess = exports.fetchChatSessionsForUser = exports.createSessionAndSubmitFailure = exports.createSessionAndSubmitSuccess = exports.initializeNewSessionState = exports.createSessionAndSubmit = exports.createSessionFailure = exports.createSessionSuccess = exports.createSession = exports.setSession = exports.submitFeedbackFailure = exports.submitFeedbackSuccess = exports.submitFeedback = exports.updateCurrentInput = exports.updateAiCfoViewScrollPosition = exports.updateResponseState = exports.submitQuestionFailure = exports.submitQuestionSuccess = exports.submitQuestion = exports.initialAiCfoViewState = void 0;
5
- exports.clearAiCfoSidePanelHostPageContext = exports.applyAiCfoSidePanelHostPageTransition = exports.closeSkillsBrowser = exports.openSkillsBrowser = exports.setSkillVisibilityFailure = exports.setSkillVisibilitySuccess = exports.setSkillVisibility = exports.saveSkillFailure = exports.saveSkillSuccess = exports.saveSkill = exports.fetchSkillVersionsFailure = exports.fetchSkillVersionsSuccess = exports.fetchSkillVersions = exports.fetchSkillVersionBodyFailure = exports.fetchSkillVersionBodySuccess = exports.fetchSkillVersionBody = exports.deleteSkillFailure = exports.deleteSkillSuccess = exports.deleteSkill = exports.clearSkillMutation = void 0;
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.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) {
@@ -86,6 +86,29 @@ exports.initialAiCfoViewState = {
86
86
  skillsEnabled: false,
87
87
  canPublish: false,
88
88
  },
89
+ routines: {
90
+ fetchState: 'Not-Started',
91
+ error: undefined,
92
+ deletedScheduleIds: [],
93
+ routines: [],
94
+ routinesEnabled: false,
95
+ // 0 until the server says otherwise. The form reads this to decide whether
96
+ // "New routine" is available, and a guessed cap would either block a user
97
+ // who is under it or invite one who is over it to fill in a doomed form.
98
+ maxRoutines: 0,
99
+ },
100
+ routineMutation: {
101
+ fetchState: 'Not-Started',
102
+ error: undefined,
103
+ kind: undefined,
104
+ },
105
+ routineRuns: {
106
+ fetchState: 'Not-Started',
107
+ error: undefined,
108
+ runs: [],
109
+ scheduleId: null,
110
+ sessionId: null,
111
+ },
89
112
  };
90
113
  /**
91
114
  * Forget the skill that was open — prompt AND history together.
@@ -268,6 +291,15 @@ const aiCfoView = (0, toolkit_1.createSlice)({
268
291
  fetchState: 'Error',
269
292
  error,
270
293
  };
294
+ // A page that failed is not a promise of another one. Leaving `hasMore`
295
+ // at its default meant the screen kept asking: the fetch condition is
296
+ // "not in flight and there is more", and Error satisfies the first half,
297
+ // so a session whose history 404s was requested in a tight loop forever
298
+ // while the view sat on its loading skeletons.
299
+ draft.uiState.chatHistoryNextPageToken[chatSessionId] = {
300
+ nextPageToken: null,
301
+ hasMore: false,
302
+ };
271
303
  },
272
304
  setSession(draft, action) {
273
305
  draft.uiState.currentChatSessionId = action.payload.sessionId;
@@ -606,6 +638,229 @@ const aiCfoView = (0, toolkit_1.createSlice)({
606
638
  error,
607
639
  };
608
640
  },
641
+ fetchRoutines(draft) {
642
+ draft.routines = {
643
+ fetchState: 'In-Progress',
644
+ error: undefined,
645
+ routines: draft.routines.routines,
646
+ maxRoutines: draft.routines.maxRoutines,
647
+ // Carried for the same reason as maxRoutines: a refetch in flight is not
648
+ // a reason to hide the entry the user is currently looking at.
649
+ routinesEnabled: draft.routines.routinesEnabled,
650
+ // Carried, not cleared: the response about to arrive may still contain a
651
+ // routine deleted moments ago, which is the whole reason the list exists.
652
+ deletedScheduleIds: draft.routines.deletedScheduleIds,
653
+ };
654
+ },
655
+ fetchRoutinesSuccess(draft, action) {
656
+ draft.routines = {
657
+ fetchState: 'Completed',
658
+ error: undefined,
659
+ // A list response can predate a delete — a save refetches, and a delete
660
+ // can land while that is outstanding — so replacing wholesale would put
661
+ // the deleted row back and read as the delete having failed.
662
+ routines: action.payload.routines.filter((routine) => !draft.routines.deletedScheduleIds.includes(routine.scheduleId)),
663
+ maxRoutines: action.payload.maxRoutines,
664
+ routinesEnabled: action.payload.routinesEnabled,
665
+ // Carried, NOT cleared here.
666
+ //
667
+ // The skills slice clears its tombstone on a list response, which fixed
668
+ // one bug and introduced the mirror of it: two list responses can both
669
+ // land before the DELETE is processed, and the second one — arriving
670
+ // with an empty tombstone — puts the deleted row back. The window is
671
+ // small and entirely real, since a save refetches.
672
+ //
673
+ // The tombstone's true lifetime is the delete request, so it is dropped
674
+ // in deleteRoutineSuccess / deleteRoutineFailure instead. That bounds it
675
+ // just as tightly (a delete always resolves) without this race.
676
+ deletedScheduleIds: draft.routines.deletedScheduleIds,
677
+ };
678
+ },
679
+ fetchRoutinesFailure(draft, action) {
680
+ draft.routines = {
681
+ fetchState: 'Error',
682
+ error: action.payload,
683
+ routines: draft.routines.routines,
684
+ // Kept: a failed refresh is not evidence the cap changed, and zeroing it
685
+ // would disable "New routine" on any transient error.
686
+ maxRoutines: draft.routines.maxRoutines,
687
+ // Same again: a transient error must not make the entry vanish.
688
+ routinesEnabled: draft.routines.routinesEnabled,
689
+ deletedScheduleIds: draft.routines.deletedScheduleIds,
690
+ };
691
+ },
692
+ setRoutineEnabled: {
693
+ prepare: (payload) => ({
694
+ payload,
695
+ }),
696
+ reducer(draft, action) {
697
+ // Pause and resume without a full draft. A routine whose cadence this
698
+ // client does not recognise has `recurrence: null`, so it cannot build
699
+ // a RoutineDraft at all — and that is exactly the routine a user most
700
+ // needs to be able to stop. Flipped locally too, so the switch responds
701
+ // immediately; the refetch confirms it.
702
+ const routine = draft.routines.routines.find((candidate) => candidate.scheduleId === action.payload.scheduleId);
703
+ if (routine) {
704
+ routine.enabled = action.payload.enabled;
705
+ }
706
+ draft.routineMutation = {
707
+ fetchState: 'In-Progress',
708
+ error: undefined,
709
+ kind: 'save',
710
+ };
711
+ },
712
+ },
713
+ fetchRoutineRuns: {
714
+ prepare: (payload) => ({ payload }),
715
+ reducer(draft, action) {
716
+ // Only a different routine's rows are wrong to show. This list polls
717
+ // itself while a run is in flight, and clearing on every fetch blanked
718
+ // the history and its summary a few times a minute — the rows were
719
+ // being replaced by "Loading runs…" and then re-rendered, which reads
720
+ // as the page breaking rather than refreshing.
721
+ const sameRoutine = draft.routineRuns.scheduleId === action.payload.scheduleId;
722
+ draft.routineRuns = {
723
+ fetchState: 'In-Progress',
724
+ error: undefined,
725
+ // Showing one routine's runs under another's name is the one thing a
726
+ // history must never do, so a change of routine still clears.
727
+ runs: sameRoutine ? draft.routineRuns.runs : [],
728
+ scheduleId: action.payload.scheduleId,
729
+ sessionId: sameRoutine ? draft.routineRuns.sessionId : null,
730
+ };
731
+ },
732
+ },
733
+ fetchRoutineRunsSuccess: {
734
+ prepare: (payload) => ({ payload }),
735
+ reducer(draft, action) {
736
+ // A response for a routine the user has since collapsed or swapped away
737
+ // from is dropped. switchMap makes this rare, not impossible.
738
+ if (draft.routineRuns.scheduleId !== action.payload.scheduleId) {
739
+ return;
740
+ }
741
+ draft.routineRuns = {
742
+ fetchState: 'Completed',
743
+ error: undefined,
744
+ runs: action.payload.runs,
745
+ scheduleId: action.payload.scheduleId,
746
+ sessionId: action.payload.sessionId,
747
+ };
748
+ },
749
+ },
750
+ fetchRoutineRunsFailure(draft, action) {
751
+ draft.routineRuns.fetchState = 'Error';
752
+ draft.routineRuns.error = action.payload;
753
+ },
754
+ closeRoutineRuns(draft) {
755
+ draft.routineRuns = {
756
+ fetchState: 'Not-Started',
757
+ error: undefined,
758
+ runs: [],
759
+ scheduleId: null,
760
+ sessionId: null,
761
+ };
762
+ },
763
+ runRoutine: {
764
+ prepare: (payload) => ({ payload }),
765
+ reducer(draft, action) {
766
+ draft.routineMutation = {
767
+ fetchState: 'In-Progress',
768
+ error: undefined,
769
+ kind: 'run',
770
+ runningScheduleId: action.payload.scheduleId,
771
+ };
772
+ },
773
+ },
774
+ runRoutineSuccess(draft) {
775
+ draft.routineMutation = {
776
+ fetchState: 'Completed',
777
+ error: undefined,
778
+ kind: 'run',
779
+ // Cleared: the request is done. The RUN is not — the answer arrives by
780
+ // email a minute or two later, and the row reports that through
781
+ // last_run_at on the next fetch, not through this flag.
782
+ runningScheduleId: undefined,
783
+ };
784
+ },
785
+ runRoutineFailure(draft, action) {
786
+ draft.routineMutation = {
787
+ fetchState: 'Error',
788
+ error: action.payload,
789
+ kind: 'run',
790
+ runningScheduleId: undefined,
791
+ };
792
+ },
793
+ saveRoutine: {
794
+ prepare: (payload) => ({
795
+ payload,
796
+ }),
797
+ reducer(draft) {
798
+ draft.routineMutation = {
799
+ fetchState: 'In-Progress',
800
+ error: undefined,
801
+ kind: 'save',
802
+ };
803
+ },
804
+ },
805
+ saveRoutineSuccess(draft) {
806
+ draft.routineMutation = {
807
+ fetchState: 'Completed',
808
+ error: undefined,
809
+ kind: 'save',
810
+ };
811
+ },
812
+ saveRoutineFailure(draft, action) {
813
+ // On its OWN slice, so the `fetchRoutines` this write triggers cannot
814
+ // clear the error in the same tick and report a failed save as nothing.
815
+ draft.routineMutation = {
816
+ fetchState: 'Error',
817
+ error: action.payload,
818
+ kind: 'save',
819
+ };
820
+ },
821
+ deleteRoutine: {
822
+ prepare: (payload) => ({ payload }),
823
+ reducer(draft, action) {
824
+ draft.routineMutation = {
825
+ fetchState: 'In-Progress',
826
+ error: undefined,
827
+ kind: 'delete',
828
+ };
829
+ // Removed immediately AND tombstoned. The row must leave the list now —
830
+ // waiting for the refetch makes the click feel ignored — and the
831
+ // tombstone is what stops an in-flight list response restoring it.
832
+ draft.routines.routines = draft.routines.routines.filter((routine) => routine.scheduleId !== action.payload.scheduleId);
833
+ draft.routines.deletedScheduleIds = [
834
+ ...draft.routines.deletedScheduleIds,
835
+ action.payload.scheduleId,
836
+ ];
837
+ },
838
+ },
839
+ deleteRoutineSuccess(draft, action) {
840
+ // The server has it. Nothing it sends from here on will contain this row,
841
+ // so the tombstone has done its job and holding it any longer is what
842
+ // makes a routine recreated under the same id invisible forever.
843
+ draft.routines.deletedScheduleIds = draft.routines.deletedScheduleIds.filter((id) => id !== action.payload.scheduleId);
844
+ draft.routineMutation = {
845
+ fetchState: 'Completed',
846
+ error: undefined,
847
+ kind: 'delete',
848
+ };
849
+ },
850
+ deleteRoutineFailure(draft, action) {
851
+ // The routine still exists and is still emailing. Dropping the tombstone
852
+ // is what lets the refetch put the row back — leaving it hidden would
853
+ // tell the user they had stopped something they had not, which is the
854
+ // worst outcome this list can produce.
855
+ draft.routines.deletedScheduleIds = draft.routines.deletedScheduleIds.filter((id) => id !== action.payload.scheduleId);
856
+ // Its own slice: the refetch that puts the row back would otherwise wipe
857
+ // this error, leaving the row silently reappearing with no explanation.
858
+ draft.routineMutation = {
859
+ fetchState: 'Error',
860
+ error: action.payload.status,
861
+ kind: 'delete',
862
+ };
863
+ },
609
864
  fetchSkills(draft) {
610
865
  // Read straight off `draft.skills` — no optional chain. This store is never
611
866
  // persisted or rehydrated (no redux-persist anywhere in the repo, and no
@@ -903,8 +1158,18 @@ const aiCfoView = (0, toolkit_1.createSlice)({
903
1158
  kind: undefined,
904
1159
  };
905
1160
  },
1161
+ openRoutinesBrowser(draft) {
1162
+ draft.uiState.isRoutinesBrowserOpen = true;
1163
+ // The two browsers share the page body, so opening one closes the other.
1164
+ // Leaving both true renders whichever the screen happens to check first.
1165
+ draft.uiState.isSkillsBrowserOpen = false;
1166
+ },
1167
+ closeRoutinesBrowser(draft) {
1168
+ draft.uiState.isRoutinesBrowserOpen = false;
1169
+ },
906
1170
  openSkillsBrowser(draft) {
907
1171
  draft.uiState.isSkillsBrowserOpen = true;
1172
+ draft.uiState.isRoutinesBrowserOpen = false;
908
1173
  },
909
1174
  closeSkillsBrowser(draft) {
910
1175
  // Unguarded, unlike the implicit closes: an explicit close should clear a lingering
@@ -923,5 +1188,5 @@ const aiCfoView = (0, toolkit_1.createSlice)({
923
1188
  });
924
1189
  },
925
1190
  });
926
- _a = aiCfoView.actions, exports.submitQuestion = _a.submitQuestion, exports.submitQuestionSuccess = _a.submitQuestionSuccess, exports.submitQuestionFailure = _a.submitQuestionFailure, exports.updateResponseState = _a.updateResponseState, exports.updateAiCfoViewScrollPosition = _a.updateAiCfoViewScrollPosition, exports.updateCurrentInput = _a.updateCurrentInput, exports.submitFeedback = _a.submitFeedback, exports.submitFeedbackSuccess = _a.submitFeedbackSuccess, exports.submitFeedbackFailure = _a.submitFeedbackFailure, exports.setSession = _a.setSession, exports.createSession = _a.createSession, exports.createSessionSuccess = _a.createSessionSuccess, exports.createSessionFailure = _a.createSessionFailure, exports.createSessionAndSubmit = _a.createSessionAndSubmit, exports.initializeNewSessionState = _a.initializeNewSessionState, exports.createSessionAndSubmitSuccess = _a.createSessionAndSubmitSuccess, exports.createSessionAndSubmitFailure = _a.createSessionAndSubmitFailure, exports.fetchChatSessionsForUser = _a.fetchChatSessionsForUser, exports.fetchChatSessionsForUserSuccess = _a.fetchChatSessionsForUserSuccess, exports.fetchChatSessionsForUserFailure = _a.fetchChatSessionsForUserFailure, exports.fetchChatHistory = _a.fetchChatHistory, exports.fetchChatHistorySuccess = _a.fetchChatHistorySuccess, exports.fetchChatHistoryFailure = _a.fetchChatHistoryFailure, exports.clearCurrentSessionId = _a.clearCurrentSessionId, exports.clearLastContextMessage = _a.clearLastContextMessage, exports.stopSubmit = _a.stopSubmit, exports.stopSubmitSuccess = _a.stopSubmitSuccess, exports.stopSubmitFailure = _a.stopSubmitFailure, exports.stopSubmitQuestion = _a.stopSubmitQuestion, exports.stopSubmitQuestionSuccess = _a.stopSubmitQuestionSuccess, exports.stopSubmitQuestionFailure = _a.stopSubmitQuestionFailure, exports.acceptMasterTOS = _a.acceptMasterTOS, exports.acceptMasterTOSSuccess = _a.acceptMasterTOSSuccess, exports.acceptMasterTOSFailure = _a.acceptMasterTOSFailure, exports.deleteChatSession = _a.deleteChatSession, exports.deleteChatSessionSuccess = _a.deleteChatSessionSuccess, exports.deleteChatSessionFailure = _a.deleteChatSessionFailure, exports.clearDeleteChatSessionStatus = _a.clearDeleteChatSessionStatus, exports.updateCotCollapsedState = _a.updateCotCollapsedState, exports.fetchSuggestedQuestions = _a.fetchSuggestedQuestions, exports.fetchSuggestedQuestionsSuccess = _a.fetchSuggestedQuestionsSuccess, exports.fetchSuggestedQuestionsFailure = _a.fetchSuggestedQuestionsFailure, exports.fetchSkills = _a.fetchSkills, exports.fetchSkillsSuccess = _a.fetchSkillsSuccess, exports.fetchSkillsFailure = _a.fetchSkillsFailure, exports.fetchSkillDetail = _a.fetchSkillDetail, exports.fetchSkillDetailSuccess = _a.fetchSkillDetailSuccess, exports.fetchSkillDetailFailure = _a.fetchSkillDetailFailure, exports.clearSkillDetail = _a.clearSkillDetail, exports.clearSkillMutation = _a.clearSkillMutation, exports.deleteSkill = _a.deleteSkill, exports.deleteSkillSuccess = _a.deleteSkillSuccess, exports.deleteSkillFailure = _a.deleteSkillFailure, exports.fetchSkillVersionBody = _a.fetchSkillVersionBody, exports.fetchSkillVersionBodySuccess = _a.fetchSkillVersionBodySuccess, exports.fetchSkillVersionBodyFailure = _a.fetchSkillVersionBodyFailure, exports.fetchSkillVersions = _a.fetchSkillVersions, exports.fetchSkillVersionsSuccess = _a.fetchSkillVersionsSuccess, exports.fetchSkillVersionsFailure = _a.fetchSkillVersionsFailure, exports.saveSkill = _a.saveSkill, exports.saveSkillSuccess = _a.saveSkillSuccess, exports.saveSkillFailure = _a.saveSkillFailure, exports.setSkillVisibility = _a.setSkillVisibility, exports.setSkillVisibilitySuccess = _a.setSkillVisibilitySuccess, exports.setSkillVisibilityFailure = _a.setSkillVisibilityFailure, exports.openSkillsBrowser = _a.openSkillsBrowser, exports.closeSkillsBrowser = _a.closeSkillsBrowser, exports.applyAiCfoSidePanelHostPageTransition = _a.applyAiCfoSidePanelHostPageTransition, exports.clearAiCfoSidePanelHostPageContext = _a.clearAiCfoSidePanelHostPageContext;
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;
927
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, 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;
@@ -23,6 +23,18 @@ export interface AiCfoViewSelector extends SelectorView, AiCfoSelectorView {
23
23
  }
24
24
  export declare const getAiCfoView: (state: RootState) => AiCfoViewSelector;
25
25
  export declare function getSuggestedQuestionsForPageContext(state: RootState, pageContext: AiCfoSuggestedQuestionsPageContext): SuggestedQuestionsForPageContext | undefined;
26
+ export declare function getRoutineMutation(state: RootState): RoutineMutationState;
27
+ export declare function getRoutineRuns(state: RootState): RoutineRunsState;
28
+ export declare function getRoutines(state: RootState): RoutinesState;
29
+ /**
30
+ * Whether another routine may be created.
31
+ *
32
+ * False while the cap is still unknown: offering the control and failing on
33
+ * save is worse than withholding it for the moment the list takes to load.
34
+ */
35
+ export declare function canCreateRoutine(state: RootState): boolean;
36
+ /** True only when the server says Routines is on for this tenant. */
37
+ export declare function getRoutinesEnabled(state: RootState): boolean;
26
38
  export declare function getSkills(state: RootState): SkillsState;
27
39
  export declare function getSkillDetail(state: RootState): SkillDetailState;
28
40
  export declare function getSkillVersions(state: RootState): SkillVersionsState;
@@ -2,6 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getAiCfoView = void 0;
4
4
  exports.getSuggestedQuestionsForPageContext = getSuggestedQuestionsForPageContext;
5
+ exports.getRoutineMutation = getRoutineMutation;
6
+ exports.getRoutineRuns = getRoutineRuns;
7
+ exports.getRoutines = getRoutines;
8
+ exports.canCreateRoutine = canCreateRoutine;
9
+ exports.getRoutinesEnabled = getRoutinesEnabled;
5
10
  exports.getSkills = getSkills;
6
11
  exports.getSkillDetail = getSkillDetail;
7
12
  exports.getSkillVersions = getSkillVersions;
@@ -75,6 +80,56 @@ const EMPTY_SKILL_MUTATION_STATE = {
75
80
  savedMacroId: undefined,
76
81
  kind: undefined,
77
82
  };
83
+ // Stable fallback, same reasoning as EMPTY_SKILLS_STATE: a fresh literal each
84
+ // call defeats useSelector identity checks and re-renders the list for nothing.
85
+ const EMPTY_ROUTINES_STATE = {
86
+ fetchState: 'Not-Started',
87
+ error: undefined,
88
+ routines: [],
89
+ // 0 withholds "New routine" until the server states the cap. Guessing a number
90
+ // either blocks a user who is under it or invites one who is over it into a
91
+ // form that cannot save.
92
+ maxRoutines: 0,
93
+ // false, so the Routines entry stays hidden until the server confirms the
94
+ // feature is on. Defaulting true would flash an entry at tenants without it.
95
+ routinesEnabled: false,
96
+ deletedScheduleIds: [],
97
+ };
98
+ const EMPTY_ROUTINE_MUTATION_STATE = {
99
+ fetchState: 'Not-Started',
100
+ error: undefined,
101
+ kind: undefined,
102
+ };
103
+ function getRoutineMutation(state) {
104
+ return state.aiCfoViewState?.routineMutation ?? EMPTY_ROUTINE_MUTATION_STATE;
105
+ }
106
+ const EMPTY_ROUTINE_RUNS_STATE = {
107
+ fetchState: 'Not-Started',
108
+ error: undefined,
109
+ runs: [],
110
+ scheduleId: null,
111
+ sessionId: null,
112
+ };
113
+ function getRoutineRuns(state) {
114
+ return state.aiCfoViewState?.routineRuns ?? EMPTY_ROUTINE_RUNS_STATE;
115
+ }
116
+ function getRoutines(state) {
117
+ return state.aiCfoViewState?.routines ?? EMPTY_ROUTINES_STATE;
118
+ }
119
+ /**
120
+ * Whether another routine may be created.
121
+ *
122
+ * False while the cap is still unknown: offering the control and failing on
123
+ * save is worse than withholding it for the moment the list takes to load.
124
+ */
125
+ function canCreateRoutine(state) {
126
+ const { maxRoutines, routines } = getRoutines(state);
127
+ return maxRoutines > 0 && routines.length < maxRoutines;
128
+ }
129
+ /** True only when the server says Routines is on for this tenant. */
130
+ function getRoutinesEnabled(state) {
131
+ return getRoutines(state).routinesEnabled;
132
+ }
78
133
  function getSkills(state) {
79
134
  return state.aiCfoViewState?.skills ?? EMPTY_SKILLS_STATE;
80
135
  }
@@ -37,6 +37,14 @@ export interface AiCfoViewUIState {
37
37
  * the sidebar drawer on mobile) while the browser renders in `AiCfoPage` — sibling
38
38
  * subtrees with no common owner below the store.
39
39
  */
40
+ /**
41
+ * Whether the AI CFO page body shows the Routines list instead of the chat.
42
+ *
43
+ * Lives here, not in component state, for the same reason as the Skills flag:
44
+ * the entries that open it are in the app drawer and the mobile sidebar,
45
+ * neither of which is an ancestor of the screen that renders it.
46
+ */
47
+ isRoutinesBrowserOpen?: boolean;
40
48
  isSkillsBrowserOpen?: boolean;
41
49
  lastContextMessage?: string;
42
50
  lastContextStatus?: ContextStatus;
@@ -90,6 +98,150 @@ export interface SkillDetail {
90
98
  instructionsCharCount: number;
91
99
  skill: Skill;
92
100
  }
101
+ /** How often a routine runs. `once` exists server-side but is not offered. */
102
+ export type RoutineRecurrence = 'daily' | 'weekly' | 'monthly';
103
+ /** The outcome of a routine's last run, as the list badges it. */
104
+ export type RoutineStatus = 'succeeded' | 'failed' | 'timeout';
105
+ /**
106
+ * A scheduled recurring run, from GET /1.0/routines.
107
+ *
108
+ * A routine is a schedule pointing at a skill — which is why `macroId` is always
109
+ * present even for one the user wrote as a bare prompt. In that case `isAdHoc`
110
+ * is true and the skill exists only behind this routine: it is not in the `/`
111
+ * menu, and the list offers "save as a skill" rather than "open the skill".
112
+ */
113
+ export interface Routine {
114
+ consecutiveFailures: number;
115
+ dayOfMonth: number | null;
116
+ /** False when paused by the user, or auto-paused after repeated failures. */
117
+ enabled: boolean;
118
+ hour: number;
119
+ isAdHoc: boolean;
120
+ lastRunAt: string | null;
121
+ lastStatus: RoutineStatus | null;
122
+ macroId: ID;
123
+ minute: number;
124
+ name: string;
125
+ nextRunAt: string | null;
126
+ /**
127
+ * The skill version this routine actually runs.
128
+ *
129
+ * Pinned deliberately: editing a skill must never silently change what goes
130
+ * out unattended, so moving a routine forward is an explicit act. Null only
131
+ * for a routine that predates pinning.
132
+ */
133
+ pinnedVersion: number | null;
134
+ /** Null when this client does not recognise the server's cadence. */
135
+ recurrence: RoutineRecurrence | null;
136
+ scheduleId: ID;
137
+ /** The one conversation this routine appends to, run after run. */
138
+ sessionId: string | null;
139
+ /** Null only if the server omitted it, which means something is wrong. */
140
+ tzName: string | null;
141
+ /** Runs whose answer has not been opened. Drives the "N new" badge. */
142
+ unreadRuns: number;
143
+ weekday: number | null;
144
+ }
145
+ /**
146
+ * What the routine form submits.
147
+ *
148
+ * Exactly one of `macroId` and `prompt`: scheduling an existing skill, or a
149
+ * one-off the user typed. Both, or neither, is refused by the server.
150
+ */
151
+ export interface RoutineDraft {
152
+ hour: number;
153
+ name: string;
154
+ recurrence: RoutineRecurrence;
155
+ tzName: string;
156
+ dayOfMonth?: number;
157
+ enabled?: boolean;
158
+ macroId?: ID;
159
+ minute?: number;
160
+ prompt?: string;
161
+ weekday?: number;
162
+ }
163
+ /**
164
+ * In-flight state for a routine WRITE, kept apart from the list.
165
+ *
166
+ * The list and the mutations shared one `fetchState`/`error` pair, and every
167
+ * write refetches — so a failed save or delete had its error erased by its own
168
+ * refresh, in the same tick. For a feature that emails financial reports on a
169
+ * schedule, "we told you it saved and it did not" is the worst thing this can
170
+ * do. The skills slice keeps `skillMutation` separate for exactly this reason.
171
+ */
172
+ export interface RoutineMutationState extends FetchStateAndError {
173
+ /** WHICH write this is reporting, so a delete cannot drive a save's button. */
174
+ kind: 'save' | 'delete' | 'run' | undefined;
175
+ /**
176
+ * The routine a Run-now was requested for.
177
+ *
178
+ * Held because the list shows the feedback on that ROW, and `kind` alone
179
+ * cannot say which one — unlike save and delete, which drive a single form or
180
+ * a single confirm.
181
+ */
182
+ runningScheduleId?: ID;
183
+ }
184
+ /** The outcome of one run, as the history badges it. */
185
+ export type RoutineRunStatus = 'claimed' | 'running' | 'succeeded' | 'failed' | 'timeout';
186
+ export interface RoutineRun {
187
+ attempt: number;
188
+ /** Why it failed. The only place a failed run explains itself. */
189
+ error: string | null;
190
+ finishedAt: string | null;
191
+ /** Started by someone pressing Run, rather than by the schedule. */
192
+ isManual: boolean;
193
+ /**
194
+ * The message this run produced, inside the routine's one conversation.
195
+ *
196
+ * Null when the agent's response did not name one — the run then opens the
197
+ * thread rather than a message that may not exist.
198
+ */
199
+ questionAnswerId: ID | null;
200
+ runId: ID;
201
+ scheduledFor: string | null;
202
+ /** This run's own conversation. Null on runs from before runs had one. */
203
+ sessionId: ID | null;
204
+ startedAt: string | null;
205
+ /** Null when this client does not recognise the server's status. */
206
+ status: RoutineRunStatus | null;
207
+ }
208
+ /**
209
+ * The run history for ONE routine — whichever the user has expanded.
210
+ *
211
+ * A single slot rather than a map keyed by routine: only one history is open at
212
+ * a time, so a map would be state to invalidate for no behaviour anyone can
213
+ * see.
214
+ */
215
+ export interface RoutineRunsState extends FetchStateAndError {
216
+ runs: RoutineRun[];
217
+ /** Which routine these belong to, so a stale response cannot fill the wrong list. */
218
+ scheduleId: ID | null;
219
+ /** The conversation every run of this routine appends to. */
220
+ sessionId: ID | null;
221
+ }
222
+ export interface RoutinesState extends FetchStateAndError {
223
+ /**
224
+ * Routines deleted locally, so a list response already in flight cannot put
225
+ * them back. Same race, and the same reasoning, as `deletedMacroIds` on the
226
+ * skills slice: a save refetches, and a delete can land while that is
227
+ * outstanding.
228
+ */
229
+ deletedScheduleIds: ID[];
230
+ /**
231
+ * The server's per-user cap, so the client can disable "New routine" with a
232
+ * reason rather than letting the user fill in a form and fail on save.
233
+ */
234
+ maxRoutines: number;
235
+ routines: Routine[];
236
+ /**
237
+ * Whether the feature is on for this tenant, from the server.
238
+ *
239
+ * Starts false so the Routines entry stays hidden until the server says
240
+ * otherwise — an empty `routines` list is not evidence either way, and a
241
+ * tenant without the feature would otherwise see a dead entry.
242
+ */
243
+ routinesEnabled: boolean;
244
+ }
93
245
  export interface SkillsState extends FetchStateAndError {
94
246
  /**
95
247
  * Whether the signed-in user may publish a skill tenant-wide. From the server, which
@@ -208,6 +360,11 @@ export interface AiCfoViewState extends FetchStateAndError {
208
360
  reasoning: FetchStateAndError;
209
361
  thought: FetchStateAndError;
210
362
  }>;
363
+ /** The outcome of the last routine write, safe from list refreshes. */
364
+ routineMutation: RoutineMutationState;
365
+ routineRuns: RoutineRunsState;
366
+ /** Scheduled recurring runs — the Routines tab. */
367
+ routines: RoutinesState;
211
368
  /** The skill whose prompt is open in the Skills browser. */
212
369
  skillDetail: SkillDetailState;
213
370
  /** Create / save-new-version / delete, while one is in flight. */
@@ -0,0 +1,18 @@
1
+ import { ActionsObservable } from 'redux-observable';
2
+ import { Observable } from 'rxjs';
3
+ import { ZeniAPI } from '../../../zeniAPI';
4
+ import { deleteRoutine, deleteRoutineFailure, deleteRoutineSuccess, fetchRoutines } from '../aiCfoViewReducer';
5
+ export type ActionType = ReturnType<typeof deleteRoutine> | ReturnType<typeof deleteRoutineSuccess> | ReturnType<typeof deleteRoutineFailure> | ReturnType<typeof fetchRoutines>;
6
+ /**
7
+ * DELETE /1.0/routines/{scheduleId}.
8
+ *
9
+ * The row has already left the list by the time this runs — the reducer removes
10
+ * it optimistically so the click does not feel ignored.
11
+ *
12
+ * A failure therefore has to put it BACK, not merely report. The routine still
13
+ * exists and is still emailing the user their financials on a schedule; leaving
14
+ * it hidden would tell them they had stopped something they had not. So a
15
+ * failure drops the tombstone and refetches, and the error explains why the row
16
+ * returned.
17
+ */
18
+ export declare const deleteRoutineEpic: (actions$: ActionsObservable<ActionType>, _state$: unknown, zeniAPI: ZeniAPI) => Observable<ActionType>;