@marimo-team/frontend 0.19.3-dev13 → 0.19.3-dev17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.html CHANGED
@@ -66,7 +66,7 @@
66
66
  <marimo-server-token data-token="{{ server_token }}" hidden></marimo-server-token>
67
67
  <!-- /TODO -->
68
68
  <title>{{ title }}</title>
69
- <script type="module" crossorigin src="./assets/index-qglXvdF9.js"></script>
69
+ <script type="module" crossorigin src="./assets/index-ImpEfS6x.js"></script>
70
70
  <link rel="modulepreload" crossorigin href="./assets/preload-helper-BW0IMuFq.js">
71
71
  <link rel="modulepreload" crossorigin href="./assets/hotkeys-uKX61F1_.js">
72
72
  <link rel="modulepreload" crossorigin href="./assets/defaultLocale-BLUna9fQ.js">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/frontend",
3
- "version": "0.19.3-dev13",
3
+ "version": "0.19.3-dev17",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -173,7 +173,7 @@
173
173
  "thememirror": "^2.0.1",
174
174
  "timestring": "^7.0.0",
175
175
  "typescript-memoize": "^1.1.1",
176
- "use-acp": "0.2.5",
176
+ "use-acp": "0.2.6",
177
177
  "use-resize-observer": "^9.1.0",
178
178
  "vega-lite": "6.3.1",
179
179
  "vega-loader": "^5.1.0",
@@ -677,7 +677,7 @@ const AgentPanel: React.FC = () => {
677
677
  ? getAgentWebSocketUrl(selectedTab.agentId)
678
678
  : NO_WS_SET;
679
679
  const { sendUpdateFile, sendFileDetails } = useRequestClient();
680
- const isCreatingNewSession = useRef(false);
680
+ const creatingOrResumingSession = useRef(false);
681
681
 
682
682
  const acpClient = useAcpClient({
683
683
  wsUrl,
@@ -716,6 +716,7 @@ const AgentPanel: React.FC = () => {
716
716
  sessionMode,
717
717
  activeSessionId,
718
718
  agent,
719
+ clearNotifications,
719
720
  } = acpClient;
720
721
 
721
722
  useEffect(() => {
@@ -757,40 +758,42 @@ const AgentPanel: React.FC = () => {
757
758
  return;
758
759
  }
759
760
 
760
- // If there is an active session, we should stop it
761
- if (activeSessionId) {
762
- setActiveSessionId(null);
763
- await agent.cancel({ sessionId: activeSessionId }).catch((error) => {
764
- logger.error("Failed to cancel active session", { error });
765
- });
766
- }
761
+ creatingOrResumingSession.current = true;
762
+
763
+ try {
764
+ // If there is an active session, we should stop it
765
+ if (activeSessionId) {
766
+ await agent.cancel({ sessionId: activeSessionId }).catch((error) => {
767
+ logger.error("Failed to cancel active session", { error });
768
+ });
769
+ clearNotifications(activeSessionId);
770
+ setActiveSessionId(null);
771
+ }
767
772
 
768
- // Get the selected model from the current session state
769
- const currentModel = selectedTab?.selectedModel ?? null;
770
- logger.debug("Creating new agent session", { model: currentModel });
771
- isCreatingNewSession.current = true;
772
- const newSession = await agent
773
- .newSession({
773
+ // Get the selected model from the current session state
774
+ const currentModel = selectedTab?.selectedModel ?? null;
775
+ logger.debug("Creating new agent session", { model: currentModel });
776
+ const newSession = await agent.newSession({
774
777
  cwd: getCwd(),
775
778
  mcpServers: [],
776
779
  _meta: currentModel ? { model: currentModel } : undefined,
777
- })
778
- .finally(() => {
779
- isCreatingNewSession.current = false;
780
780
  });
781
781
 
782
- // Capture models from the response
783
- if (newSession.models) {
784
- logger.debug("Session models received", { models: newSession.models });
785
- setSessionModels(newSession.models);
786
- }
782
+ // Capture models from the response
783
+ if (newSession.models) {
784
+ logger.debug("Session models received", { models: newSession.models });
785
+ setSessionModels(newSession.models);
786
+ }
787
787
 
788
- setSessionState((prev) =>
789
- updateSessionExternalAgentSessionId(
790
- prev,
791
- newSession.sessionId as ExternalAgentSessionId,
792
- ),
793
- );
788
+ setSessionState((prev) =>
789
+ updateSessionExternalAgentSessionId(
790
+ prev,
791
+ newSession.sessionId as ExternalAgentSessionId,
792
+ ),
793
+ );
794
+ } finally {
795
+ creatingOrResumingSession.current = false;
796
+ }
794
797
  });
795
798
 
796
799
  const handleResumeSession = useEvent(
@@ -804,23 +807,28 @@ const AgentPanel: React.FC = () => {
804
807
  if (!agent.loadSession) {
805
808
  throw new Error("Agent does not support loading sessions");
806
809
  }
807
- const loadedSession = await agent.loadSession({
808
- sessionId: previousSessionId,
809
- cwd: getCwd(),
810
- mcpServers: [],
811
- });
812
-
813
- // Capture models from the response if available
814
- if (loadedSession?.models) {
815
- logger.debug("Session models received", {
816
- models: loadedSession.models,
810
+ creatingOrResumingSession.current = true;
811
+ try {
812
+ const loadedSession = await agent.loadSession({
813
+ sessionId: previousSessionId,
814
+ cwd: getCwd(),
815
+ mcpServers: [],
817
816
  });
818
- setSessionModels(loadedSession.models);
819
- }
820
817
 
821
- setSessionState((prev) =>
822
- updateSessionExternalAgentSessionId(prev, previousSessionId),
823
- );
818
+ // Capture models from the response if available
819
+ if (loadedSession?.models) {
820
+ logger.debug("Session models received", {
821
+ models: loadedSession.models,
822
+ });
823
+ setSessionModels(loadedSession.models);
824
+ }
825
+
826
+ setSessionState((prev) =>
827
+ updateSessionExternalAgentSessionId(prev, previousSessionId),
828
+ );
829
+ } finally {
830
+ creatingOrResumingSession.current = false;
831
+ }
824
832
  },
825
833
  );
826
834
 
@@ -838,6 +846,11 @@ const AgentPanel: React.FC = () => {
838
846
  return;
839
847
  }
840
848
 
849
+ // Prevent race conditions
850
+ if (creatingOrResumingSession.current) {
851
+ return;
852
+ }
853
+
841
854
  // If there is an available session, resume it, otherwise create a new one
842
855
  const createOrResumeSession = async () => {
843
856
  const availableSession = tabLastActiveSessionId ?? activeSessionId;
@@ -75,12 +75,26 @@ interface Props extends PluginFunctions {
75
75
  export const Chatbot: React.FC<Props> = (props) => {
76
76
  const [input, setInput] = useState("");
77
77
  const [config, setConfig] = useState<ChatConfig>(props.config);
78
+ const [prevPropsConfig, setPrevPropsConfig] = useState<ChatConfig>(
79
+ props.config,
80
+ );
78
81
  const [files, setFiles] = useState<File[] | undefined>(undefined);
79
82
  const fileInputRef = useRef<HTMLInputElement>(null);
80
83
  const formRef = useRef<HTMLFormElement>(null);
81
84
  const codeMirrorInputRef = useRef<ReactCodeMirrorRef>(null);
82
85
  const scrollContainerRef = useRef<HTMLDivElement>(null);
83
86
 
87
+ const configChanged = Object.keys(props.config).some(
88
+ (key) =>
89
+ props.config[key as keyof ChatConfig] !==
90
+ prevPropsConfig[key as keyof ChatConfig],
91
+ );
92
+
93
+ if (configChanged) {
94
+ setConfig(props.config);
95
+ setPrevPropsConfig(props.config);
96
+ }
97
+
84
98
  // Use a ref to avoid stale closure in the fetch callback
85
99
  const configRef = useRef<ChatConfig>(config);
86
100
  configRef.current = config;
@@ -739,7 +753,6 @@ const ConfigPopup: React.FC<{
739
753
  config: ChatConfig;
740
754
  onChange: (newConfig: ChatConfig) => void;
741
755
  }> = ({ config, onChange }) => {
742
- const [localConfig, setLocalConfig] = useState<ChatConfig>(config);
743
756
  const [open, setOpen] = useState(false);
744
757
 
745
758
  const handleChange = (key: keyof ChatConfig, value: number | null) => {
@@ -754,8 +767,7 @@ const ConfigPopup: React.FC<{
754
767
  finalValue = clampedValue;
755
768
  }
756
769
 
757
- const newConfig = { ...localConfig, [key]: finalValue };
758
- setLocalConfig(newConfig);
770
+ const newConfig = { ...config, [key]: finalValue };
759
771
  onChange(newConfig);
760
772
  };
761
773
 
@@ -782,7 +794,7 @@ const ConfigPopup: React.FC<{
782
794
  <PopoverContent className="w-70 border">
783
795
  <div className="grid gap-3">
784
796
  <h4 className="font-bold leading-none">Configuration</h4>
785
- {Objects.entries(localConfig).map(([key, value]) => (
797
+ {Objects.entries(config).map(([key, value]) => (
786
798
  <div key={key} className="grid grid-cols-3 items-center gap-1">
787
799
  <Label
788
800
  htmlFor={key}