AgentControlBar.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import { Tooltip } from "@nextui-org/react";
  2. import React, { useEffect } from "react";
  3. import { useSelector } from "react-redux";
  4. import ArrowIcon from "#/assets/arrow";
  5. import PauseIcon from "#/assets/pause";
  6. import PlayIcon from "#/assets/play";
  7. import { changeTaskState } from "#/services/agentStateService";
  8. import { clearMsgs } from "#/services/session";
  9. import { clearMessages } from "#/state/chatSlice";
  10. import store, { RootState } from "#/store";
  11. import AgentTaskAction from "#/types/AgentTaskAction";
  12. import AgentTaskState from "#/types/AgentTaskState";
  13. const TaskStateActionMap = {
  14. [AgentTaskAction.START]: AgentTaskState.RUNNING,
  15. [AgentTaskAction.PAUSE]: AgentTaskState.PAUSED,
  16. [AgentTaskAction.RESUME]: AgentTaskState.RUNNING,
  17. [AgentTaskAction.STOP]: AgentTaskState.STOPPED,
  18. };
  19. const IgnoreTaskStateMap: { [k: string]: AgentTaskState[] } = {
  20. [AgentTaskAction.PAUSE]: [
  21. AgentTaskState.INIT,
  22. AgentTaskState.PAUSED,
  23. AgentTaskState.STOPPED,
  24. AgentTaskState.FINISHED,
  25. ],
  26. [AgentTaskAction.RESUME]: [
  27. AgentTaskState.INIT,
  28. AgentTaskState.RUNNING,
  29. AgentTaskState.STOPPED,
  30. AgentTaskState.FINISHED,
  31. ],
  32. [AgentTaskAction.STOP]: [
  33. AgentTaskState.INIT,
  34. AgentTaskState.STOPPED,
  35. AgentTaskState.FINISHED,
  36. ],
  37. };
  38. interface ButtonProps {
  39. isDisabled: boolean;
  40. content: string;
  41. action: AgentTaskAction;
  42. handleAction: (action: AgentTaskAction) => void;
  43. large?: boolean;
  44. }
  45. function ActionButton({
  46. isDisabled = false,
  47. content,
  48. action,
  49. handleAction,
  50. children,
  51. large,
  52. }: React.PropsWithChildren<ButtonProps>): React.ReactNode {
  53. return (
  54. <Tooltip content={content} closeDelay={100}>
  55. <button
  56. onClick={() => handleAction(action)}
  57. disabled={isDisabled}
  58. className={`${large ? "rounded-full bg-neutral-800 p-3" : ""} hover:opacity-80 transition-all`}
  59. type="button"
  60. >
  61. {children}
  62. </button>
  63. </Tooltip>
  64. );
  65. }
  66. ActionButton.defaultProps = {
  67. large: false,
  68. };
  69. function AgentControlBar() {
  70. const { curTaskState } = useSelector((state: RootState) => state.agent);
  71. const [desiredState, setDesiredState] = React.useState(AgentTaskState.INIT);
  72. const [isLoading, setIsLoading] = React.useState(false);
  73. const handleAction = (action: AgentTaskAction) => {
  74. if (IgnoreTaskStateMap[action].includes(curTaskState)) {
  75. return;
  76. }
  77. let act = action;
  78. if (act === AgentTaskAction.STOP) {
  79. act = AgentTaskAction.STOP;
  80. clearMsgs().then().catch();
  81. store.dispatch(clearMessages());
  82. } else {
  83. setIsLoading(true);
  84. }
  85. setDesiredState(TaskStateActionMap[act]);
  86. changeTaskState(act);
  87. };
  88. useEffect(() => {
  89. if (curTaskState === desiredState) {
  90. if (curTaskState === AgentTaskState.STOPPED) {
  91. clearMsgs().then().catch();
  92. store.dispatch(clearMessages());
  93. }
  94. setIsLoading(false);
  95. } else if (curTaskState === AgentTaskState.RUNNING) {
  96. setDesiredState(AgentTaskState.RUNNING);
  97. }
  98. // We only want to run this effect when curTaskState changes
  99. // eslint-disable-next-line react-hooks/exhaustive-deps
  100. }, [curTaskState]);
  101. return (
  102. <div className="flex items-center gap-3">
  103. {curTaskState === AgentTaskState.PAUSED ? (
  104. <ActionButton
  105. isDisabled={
  106. isLoading ||
  107. IgnoreTaskStateMap[AgentTaskAction.RESUME].includes(curTaskState)
  108. }
  109. content="Resume the agent task"
  110. action={AgentTaskAction.RESUME}
  111. handleAction={handleAction}
  112. large
  113. >
  114. <PlayIcon />
  115. </ActionButton>
  116. ) : (
  117. <ActionButton
  118. isDisabled={
  119. isLoading ||
  120. IgnoreTaskStateMap[AgentTaskAction.PAUSE].includes(curTaskState)
  121. }
  122. content="Pause the agent task"
  123. action={AgentTaskAction.PAUSE}
  124. handleAction={handleAction}
  125. large
  126. >
  127. <PauseIcon />
  128. </ActionButton>
  129. )}
  130. <ActionButton
  131. isDisabled={isLoading}
  132. content="Restart a new agent task"
  133. action={AgentTaskAction.STOP}
  134. handleAction={handleAction}
  135. >
  136. <ArrowIcon />
  137. </ActionButton>
  138. </div>
  139. );
  140. }
  141. export default AgentControlBar;