From 7ff649c6582b7e00dcf2d7fe607699f850310ba0 Mon Sep 17 00:00:00 2001
From: "A.J. Shulman" <Shulman.aj@gmail.com>
Date: Thu, 30 May 2024 13:58:40 -0400
Subject: fixing chatbox features

still messages appear weird when using code interpreter and now doesn't detect file links
---
 .../views/collections/CollectionNoteTakingViewColumn.tsx     | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

(limited to 'src/client/views/collections/CollectionNoteTakingViewColumn.tsx')

diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
index 44ab1968d..2c6257cf2 100644
--- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
+++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
@@ -1,6 +1,6 @@
 /* eslint-disable jsx-a11y/control-has-associated-label */
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, makeObservable, observable } from 'mobx';
+import { action, computed, makeObservable, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { lightOrDark, returnEmptyString } from '../../../ClientUtils';
@@ -88,12 +88,16 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV
     };
 
     componentDidMount(): void {
-        this._ele && this.props.refList.push(this._ele);
+        runInAction(() => {
+            this._ele && this.props.refList.push(this._ele);
+        });
     }
 
     componentWillUnmount() {
-        this._ele && this.props.refList.splice(this._props.refList.indexOf(this._ele), 1);
-        this._ele = null;
+        runInAction(() => {
+            this._ele && this.props.refList.splice(this._props.refList.indexOf(this._ele), 1);
+            this._ele = null;
+        });
     }
 
     @undoBatch
-- 
cgit v1.2.3-70-g09d2


From 139a3cb0b3b081c270187e9b4ca281d04ca923bf Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 30 Sep 2024 12:19:22 -0400
Subject: upate AJ assistant from master and fix some lint errors

---
 eslint.config.mjs                                  |   2 +-
 src/client/documents/Documents.ts                  |   9 --
 src/client/util/CurrentUserUtils.ts                |   8 +-
 src/client/util/Scripting.ts                       |  13 +-
 src/client/views/MainView.tsx                      |   7 +-
 .../collections/CollectionNoteTakingViewColumn.tsx |   5 +-
 src/client/views/nodes/PDFBox.tsx                  |  21 ++-
 .../views/nodes/RecordingBox/ProgressBar.tsx       |   2 -
 .../views/nodes/chatbot/agentsystem/Agent.ts       |  33 ++--
 .../nodes/chatbot/chatboxcomponents/ChatBox.tsx    |  61 +++----
 .../nodes/chatbot/response_parsers/AnswerParser.ts |   9 +-
 .../response_parsers/StreamedAnswerParser.ts       |   2 -
 src/client/views/nodes/chatbot/tools/BaseTool.ts   |   8 +-
 .../views/nodes/chatbot/tools/CalculateTool.ts     |   2 +-
 .../views/nodes/chatbot/tools/CreateCSVTool.ts     |   2 +-
 .../nodes/chatbot/tools/CreateCollectionTool.ts    |   2 +-
 .../views/nodes/chatbot/tools/DataAnalysisTool.ts  |   2 +-
 .../views/nodes/chatbot/tools/GetDocsTool.ts       |   2 +-
 src/client/views/nodes/chatbot/tools/NoTool.ts     |   5 +-
 src/client/views/nodes/chatbot/tools/RAGTool.ts    |  13 +-
 src/client/views/nodes/chatbot/tools/SearchTool.ts |   5 +-
 .../nodes/chatbot/tools/WebsiteInfoScraperTool.ts  |   5 +-
 .../views/nodes/chatbot/tools/WikipediaTool.ts     |   7 +-
 src/client/views/nodes/chatbot/types/types.ts      |  25 ++-
 .../views/nodes/chatbot/vectorstore/Vectorstore.ts |  13 +-
 src/client/views/pdf/PDFViewer.tsx                 |  46 ++----
 src/server/ApiManagers/AssistantManager.ts         | 178 ++++++++++-----------
 27 files changed, 215 insertions(+), 272 deletions(-)

(limited to 'src/client/views/collections/CollectionNoteTakingViewColumn.tsx')

diff --git a/eslint.config.mjs b/eslint.config.mjs
index aebdc20d0..f7063caa5 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -48,7 +48,7 @@ export default [
             'no-return-assign': 'error',
             'no-await-in-loop': 'error',
             'no-loop-func': 'error',
-            '@typescript-eslint/no-cond-assign': 'error',
+            'no-cond-assign': 'error',
             'no-use-before-define': 'error',
             '@typescript-eslint/no-explicit-any': 'error',
             'no-restricted-globals': ['error', 'event'],
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index e0a9918f4..d77f76b81 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,5 +1,3 @@
-/* eslint-disable prefer-destructuring */
-/* eslint-disable default-param-last */
 /* eslint-disable no-use-before-define */
 import { reaction } from 'mobx';
 import { basename } from 'path';
@@ -671,7 +669,6 @@ export namespace Docs {
          * only when creating a DockDocument from the current user's already existing
          * main document.
          */
-        // eslint-disable-next-line default-param-last
         function InstanceFromProto(proto: Doc, data: FieldType | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = 'data', protoId?: string, placeholderDocIn?: Doc, noView?: boolean) {
             const placeholderDoc = placeholderDocIn;
             const viewKeys = ['x', 'y', 'isSystem']; // keys that should be addded to the view document even though they don't begin with an "_"
@@ -732,7 +729,6 @@ export namespace Docs {
             return dataDoc;
         }
 
-        // eslint-disable-next-line default-param-last
         export function ImageDocument(url: string | ImageField, options: DocumentOptions = {}, overwriteDoc?: Doc) {
             const imgField = url instanceof ImageField ? url : url ? new ImageField(url) : undefined;
             return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: basename(imgField?.url.href ?? '-no image-'), ...options }, undefined, undefined, undefined, overwriteDoc);
@@ -751,7 +747,6 @@ export namespace Docs {
          * @param fieldKey the field that the compiled script is written into.
          * @returns the Scripting Doc
          */
-        // eslint-disable-next-line default-param-last
         export function ScriptingDocument(script: Opt<ScriptField> | null, options: DocumentOptions = {}, fieldKey?: string) {
             return InstanceFromProto(Prototypes.get(DocumentType.SCRIPTING), script || undefined, { ...options, layout: fieldKey ? `<ScriptingBox {...props} fieldKey={'${fieldKey}'}/>` /* ScriptingBox.LayoutString(fieldKey) */ : undefined });
         }
@@ -759,7 +754,6 @@ export namespace Docs {
         export function ChatDocument(options?: DocumentOptions) {
             return InstanceFromProto(Prototypes.get(DocumentType.CHAT), undefined, { ...(options || {}) });
         }
-        // eslint-disable-next-line default-param-last
         export function VideoDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) {
             return InstanceFromProto(Prototypes.get(DocumentType.VID), new VideoField(url), options, undefined, undefined, undefined, overwriteDoc);
         }
@@ -779,7 +773,6 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.DIAGRAM), undefined, options);
         }
 
-        // eslint-disable-next-line default-param-last
         export function AudioDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) {
             return InstanceFromProto(Prototypes.get(DocumentType.AUDIO), new AudioField(url), options, undefined, undefined, undefined, overwriteDoc);
         }
@@ -839,7 +832,6 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.RTF), field, options, undefined, fieldKey);
         }
 
-        // eslint-disable-next-line default-param-last
         export function LinkDocument(source: Doc, target: Doc, options: DocumentOptions = {}, id?: string) {
             const linkDoc = InstanceFromProto(
                 Prototypes.get(DocumentType.LINK),
@@ -883,7 +875,6 @@ export namespace Docs {
             return ink;
         }
 
-        // eslint-disable-next-line default-param-last
         export function PdfDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) {
             const width = options._width || undefined;
             const height = options._height || undefined;
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 96b30c429..09adf70f5 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -2,7 +2,7 @@
 import { reaction, runInAction } from "mobx";
 import * as rp from 'request-promise';
 import { ClientUtils, OmitKeys } from "../../ClientUtils";
-import { Doc, DocListCast, DocListCastAsync, FieldType, Opt, StrListCast } from "../../fields/Doc";
+import { Doc, DocListCast, DocListCastAsync, FieldType, Opt } from "../../fields/Doc";
 import { DocData } from "../../fields/DocSymbols";
 import { InkTool } from "../../fields/InkField";
 import { List } from "../../fields/List";
@@ -366,11 +366,11 @@ pie title Minerals in my tap water
             {key: "Button",     creator: Docs.Create.ButtonDocument,                        opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, title_custom: true,  waitForDoubleClickToClick: 'never'}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}},
             {key: "Script",     creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }},
             {key: "DataViz",    creator: opts => Docs.Create.DataVizDocument("/users/rz/Downloads/addresses.csv", opts),   opts: { _width: 300, _height: 300 }},
-            {key: "Chat",       creator: Docs.Create.ChatDocument,          opts: { _width: 500, _height: 500, }},
+            {key: "Chat",       creator: Docs.Create.ChatDocument,                          opts: { _width: 500, _height: 500, }},
             {key: "Header",     creator: headerTemplate,                                    opts: { _width: 300, _height: 120, _header_pointerEvents: "all", _header_height: 50, _header_fontSize: 9,_layout_autoHeightMargins: 50, _layout_autoHeight: true, treeView_HideUnrendered: true}},
             {key: "ViewSlide",  creator: slideView,                                         opts: { _width: 400, _height: 300, _xMargin: 3, _yMargin: 3,}},
             {key: "Trail",      creator: Docs.Create.PresDocument,                          opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, _layout_dontCenter:'xy', dropAction: dropActionType.embed, treeView_HideTitle: true, _layout_fitWidth:true, layout_boxShadow: "0 0" }},
-            {key: "Tab",        creator: opts => Docs.Create.FreeformDocument([], opts),    opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }},
+        {key: "Tab",        creator: opts => Docs.Create.FreeformDocument([], opts),    opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }},
             {key: "Slide",      creator: opts => Docs.Create.TreeDocument([], opts),        opts: { _width: 300, _height: 200, _type_collection: CollectionViewType.Tree, 
                                                                                                 treeView_HasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true, 
                                                                                                 dropAction:dropActionType.move, treeView_Type: TreeViewType.outline, 
@@ -801,7 +801,7 @@ pie title Minerals in my tap water
             { title: "Num",     icon:"", toolTip: "Frame # (click to toggle edit mode)",btnType: ButtonType.TextButton,          expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}},
             { title: "Fwd",     icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton,         expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, width: 30,  scripts: { onClick: 'nextKeyFrame(_readOnly_)'}},
             
-            { title: "Filter",  icon: "=",      toolTip: "Filter cards by tags", subMenu: CurrentUserUtils.tagGroupTools(),ignoreClick:true, toolType:DocumentType.COL,            funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, btnType: ButtonType.MultiToggleButton, width: 30, backgroundColor: doc.userVariantColor},
+            { title: "Filter",  icon: "=",      toolTip: "Filter cards by tags", subMenu: CurrentUserUtils.tagGroupTools(),ignoreClick:true, toolType:DocumentType.COL,            funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, btnType: ButtonType.MultiToggleButton, width: 30, backgroundColor: doc.userVariantColor as string},
             { title: "Text",    icon: "Text",   toolTip: "Text functions",       subMenu: CurrentUserUtils.textTools(),   expertMode: false, toolType:DocumentType.RTF,            funcs: {                                                                             linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
             { title: "Ink",     icon: "Ink",    toolTip: "Ink functions",        subMenu: CurrentUserUtils.inkTools(),    expertMode: false, toolType:DocumentType.INK,            funcs: {hidden: `IsExploreMode()`,                                                   linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
             { title: "Doc",     icon: "Doc",    toolTip: "Freeform Doc tools",   subMenu: CurrentUserUtils.freeTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode, true)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index 3e7a2df02..c7b86815a 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -1,7 +1,7 @@
 // export const ts = (window as any).ts;
 // import * as typescriptlib from '!!raw-loader!../../../node_modules/typescript/lib/lib.d.ts'
 // import * as typescriptes5 from '!!raw-loader!../../../node_modules/typescript/lib/lib.es5.d.ts'
-// import typescriptlib from 'type_decls.d';
+import typescriptlib from 'type_decls.d';
 import * as ts from 'typescript';
 import { Doc, FieldType } from '../../fields/Doc';
 import { RefField } from '../../fields/RefField';
@@ -29,7 +29,7 @@ export interface CompiledScript {
     readonly compiled: true;
     readonly originalScript: string;
     // eslint-disable-next-line no-use-before-define
-    readonly options: Readonly;
+    readonly options: Readonly<ScriptOptions>;
     run(args?: { [name: string]: unknown }, onError?: (res: string) => void, errorVal?: unknown): ScriptResult;
 }
 
@@ -60,7 +60,6 @@ function Run(script: string | undefined, customParams: string[], diagnostics: ts
     // let params: any[] = [Docs, ...fieldTypes];
     const compiledFunction = (() => {
         try {
-            // eslint-disable-next-line no-new-func
             return new Function(...paramNames, `return ${script}`);
         } catch (e) {
             console.log(e);
@@ -69,10 +68,8 @@ function Run(script: string | undefined, customParams: string[], diagnostics: ts
     })();
     if (!compiledFunction) return { compiled: false, errors };
     const { capturedVariables = {} } = options;
-    // eslint-disable-next-line default-param-last
     const run = (args: { [name: string]: unknown } = {}, onError?: (e: string) => void, errorVal?: ts.Diagnostic): ScriptResult => {
         const argsArray: unknown[] = [];
-        // eslint-disable-next-line no-restricted-syntax
         for (const name of customParams) {
             if (name !== 'this') {
                 argsArray.push(name in args ? args[name] : capturedVariables[name]);
@@ -154,7 +151,7 @@ class ScriptingCompilerHost {
 export type Traverser = (node: ts.Node, indentation: string) => boolean | void;
 export type TraverserParam = Traverser | { onEnter: Traverser; onLeave: Traverser };
 export type Transformer = {
-    transformer: ts.TransformerFactory;
+    transformer: ts.TransformerFactory<ts.Node>;
     getVars?: () => { [name: string]: FieldType };
 };
 export interface ScriptOptions {
@@ -224,7 +221,6 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp
     if ('this' in params || 'this' in capturedVariables) {
         paramNames.push('this');
     }
-    // eslint-disable-next-line no-restricted-syntax
     for (const key in params) {
         if (key !== 'this') {
             paramNames.push(key);
@@ -234,7 +230,6 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp
         const val = params[key];
         return `${key}: ${val}`;
     });
-    // eslint-disable-next-line no-restricted-syntax
     for (const key in capturedVariables) {
         if (key !== 'this') {
             const val = capturedVariables[key];
@@ -248,7 +243,7 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp
     const funcScript = `(function(${paramString})${reqTypes} { ${body} })`;
     host.writeFile('file.ts', funcScript);
 
-    // if (typecheck) host.writeFile('node_modules/typescript/lib/lib.d.ts', typescriptlib);
+    if (typecheck) host.writeFile('node_modules/typescript/lib/lib.d.ts', typescriptlib);
     const program = ts.createProgram(['file.ts'], {}, host);
     const testResult = program.emit();
     const outputText = host.readFile('file.js');
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 8b8f85dfb..abe154de4 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -75,7 +75,7 @@ import { AnchorMenu } from './pdf/AnchorMenu';
 import { GPTPopup } from './pdf/GPTPopup/GPTPopup';
 import { TopBar } from './topbar/TopBar';
 
-// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
+// eslint-disable-next-line @typescript-eslint/no-require-imports
 const { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } = require('./global/globalCssVariables.module.scss'); // prettier-ignore
 
 @observer
@@ -1059,10 +1059,7 @@ export class MainView extends ObservableReactComponent<object> {
                         docView={DocButtonState.Instance.LinkEditorDocView}
                     />
                 ) : null}
-                {LinkInfo.Instance?.LinkInfo ? (
-                    // eslint-disable-next-line react/jsx-props-no-spreading
-                    <LinkDocPreview {...LinkInfo.Instance.LinkInfo} />
-                ) : null}
+                {LinkInfo.Instance?.LinkInfo ? <LinkDocPreview {...LinkInfo.Instance.LinkInfo} /> : null}
                 {((page: string) => {
                     // prettier-ignore
                     switch (page) {
diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
index fc5f5cb71..226d06f37 100644
--- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
+++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
@@ -252,10 +252,7 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV
                                     <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} textCallback={this.addTextNote} placeholder={"Type ':' for commands"} contents="+ Node" menuCallback={this.menuCallback} />
                                 </div>
                                 <div className="collectionNoteTakingView-addDocumentButton" style={{ color: lightOrDark(this._props.backgroundColor?.()) }}>
-                                    {
-                                        // eslint-disable-next-line react/jsx-props-no-spreading
-                                        <EditableView {...this._props.editableViewProps()} />
-                                    }
+                                    <EditableView {...this._props.editableViewProps()} />
                                 </div>
                             </div>
                         ) : null}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 4616ec057..596975062 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -10,7 +10,7 @@ import { DocData } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { ComputedField } from '../../../fields/ScriptField';
-import { Cast, FieldValue, ImageCast, NumCast, StrCast, toList } from '../../../fields/Types';
+import { Cast, FieldValue, NumCast, StrCast, toList } from '../../../fields/Types';
 import { ImageField, PdfField } from '../../../fields/URLField';
 import { TraceMobx } from '../../../fields/util';
 import { emptyFunction } from '../../../Utils';
@@ -43,14 +43,14 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     public static openSidebarWidth = 250;
     public static sidebarResizerWidth = 5;
     private _searchString: string = '';
-    private _initialScrollTarget: Opt;
+    private _initialScrollTarget: Opt<Doc>;
     private _pdfViewer: PDFViewer | undefined;
     private _searchRef = React.createRef<HTMLInputElement>();
     private _disposers: { [name: string]: IReactionDisposer } = {};
     private _sidebarRef = React.createRef<SidebarAnnos>();
 
     @observable private _searching: boolean = false;
-    @observable private _pdf: Opt = undefined;
+    @observable private _pdf: Opt<Pdfjs.PDFDocumentProxy> = undefined;
     @observable private _pageControls = false;
 
     @computed get pdfUrl() {
@@ -242,13 +242,13 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             options.didMove = true;
             this.toggleSidebar(false);
         }
-        return new Promise<Opt>(res => {
+        return new Promise<Opt<DocumentView>>(res => {
             DocumentView.addViewRenderedCb(doc, dv => res(dv));
         });
     };
 
     getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
-        let ele: Opt;
+        let ele: Opt<HTMLDivElement>;
         if (this._pdfViewer?.selectionContent()) {
             ele = document.createElement('div');
             ele.append(this._pdfViewer.selectionContent()!);
@@ -327,7 +327,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             this._initialScrollTarget = undefined;
         }
     };
-    searchStringChanged = (e: React.ChangeEvent) => {
+    searchStringChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
         this._searchString = e.currentTarget.value;
     };
 
@@ -365,8 +365,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             }
         );
     };
-    @observable _previewNativeWidth: Opt = undefined;
-    @observable _previewWidth: Opt = undefined;
+    @observable _previewNativeWidth: Opt<number> = undefined;
+    @observable _previewWidth: Opt<number> = undefined;
     toggleSidebar = action((preview: boolean = false) => {
         const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']);
         const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth;
@@ -540,7 +540,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             return ComponentTag === CollectionStackingView ? (
                 <SidebarAnnos
                     ref={this._sidebarRef}
-                    // eslint-disable-next-line react/jsx-props-no-spreading
                     {...this._props}
                     Document={this.Document}
                     layoutDoc={this.layoutDoc}
@@ -556,7 +555,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             ) : (
                 <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this._props.select(false), true)}>
                     <ComponentTag
-                        // eslint-disable-next-line react/jsx-props-no-spreading
                         {...this._props}
                         setContentViewBox={emptyFunction} // override setContentView to do nothing
                         NativeWidth={this.sidebarNativeWidthFunc}
@@ -610,7 +608,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         top: 0,
                     }}>
                     <PDFViewer
-                        // eslint-disable-next-line react/jsx-props-no-spreading
                         {...this._props}
                         pdfBox={this}
                         sidebarAddDoc={this.sidebarAddDocument}
@@ -637,7 +634,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     }
 
     static pdfcache = new Map<string, Pdfjs.PDFDocumentProxy>();
-    static pdfpromise = new Map<string, Promise>();
+    static pdfpromise = new Map<string, Promise<Pdfjs.PDFDocumentProxy>>();
     render() {
         TraceMobx();
         const pdfView = !this._pdf ? null : this.renderPdfView;
diff --git a/src/client/views/nodes/RecordingBox/ProgressBar.tsx b/src/client/views/nodes/RecordingBox/ProgressBar.tsx
index 62798bc2f..7e91df7ab 100644
--- a/src/client/views/nodes/RecordingBox/ProgressBar.tsx
+++ b/src/client/views/nodes/RecordingBox/ProgressBar.tsx
@@ -1,5 +1,3 @@
-/* eslint-disable react/no-array-index-key */
-/* eslint-disable react/require-default-props */
 import * as React from 'react';
 import { useEffect, useState, useRef } from 'react';
 import './ProgressBar.scss';
diff --git a/src/client/views/nodes/chatbot/agentsystem/Agent.ts b/src/client/views/nodes/chatbot/agentsystem/Agent.ts
index 180d05cf3..ccf9caf15 100644
--- a/src/client/views/nodes/chatbot/agentsystem/Agent.ts
+++ b/src/client/views/nodes/chatbot/agentsystem/Agent.ts
@@ -1,20 +1,19 @@
+import dotenv from 'dotenv';
+import { XMLBuilder, XMLParser } from 'fast-xml-parser';
 import OpenAI from 'openai';
-import { Tool, AgentMessage, AssistantMessage, TEXT_TYPE, CHUNK_TYPE, ASSISTANT_ROLE, ProcessingInfo, PROCESSING_TYPE } from '../types/types';
-import { getReactPrompt } from './prompts';
-import { XMLParser, XMLBuilder } from 'fast-xml-parser';
-import { Vectorstore } from '../vectorstore/Vectorstore';
 import { ChatCompletionMessageParam } from 'openai/resources';
-import dotenv from 'dotenv';
-import { CalculateTool } from '../tools/CalculateTool';
-import { RAGTool } from '../tools/RAGTool';
-import { DataAnalysisTool } from '../tools/DataAnalysisTool';
-import { WebsiteInfoScraperTool } from '../tools/WebsiteInfoScraperTool';
-import { SearchTool } from '../tools/SearchTool';
-import { NoTool } from '../tools/NoTool';
-import { v4 as uuidv4 } from 'uuid';
 import { AnswerParser } from '../response_parsers/AnswerParser';
 import { StreamedAnswerParser } from '../response_parsers/StreamedAnswerParser';
+import { CalculateTool } from '../tools/CalculateTool';
 import { CreateCSVTool } from '../tools/CreateCSVTool';
+import { DataAnalysisTool } from '../tools/DataAnalysisTool';
+import { NoTool } from '../tools/NoTool';
+import { RAGTool } from '../tools/RAGTool';
+import { SearchTool } from '../tools/SearchTool';
+import { WebsiteInfoScraperTool } from '../tools/WebsiteInfoScraperTool';
+import { AgentMessage, AssistantMessage, PROCESSING_TYPE, ProcessingInfo, Tool } from '../types/types';
+import { Vectorstore } from '../vectorstore/Vectorstore';
+import { getReactPrompt } from './prompts';
 
 dotenv.config();
 
@@ -25,7 +24,7 @@ dotenv.config();
 export class Agent {
     // Private properties
     private client: OpenAI;
-    private tools: Record<string, Tool<any>>;
+    private tools: Record<string, Tool<any>>; // bcz: need a real type here
     private messages: AgentMessage[] = [];
     private interMessages: AgentMessage[] = [];
     private vectorstore: Vectorstore;
@@ -102,7 +101,7 @@ export class Agent {
             ignoreAttributes: false,
             attributeNamePrefix: '@_',
             textNodeName: '_text',
-            isArray: (name, jpath, isLeafNode, isAttribute) => ['query', 'url'].indexOf(name) !== -1,
+            isArray: (name /* , jpath, isLeafNode, isAttribute */) => ['query', 'url'].indexOf(name) !== -1,
         });
         const builder = new XMLBuilder({ ignoreAttributes: false, attributeNamePrefix: '@_' });
 
@@ -167,7 +166,7 @@ export class Agent {
                     if (currentAction) {
                         try {
                             // Process the action with its input
-                            const observation = await this.processAction(currentAction, actionInput.inputs);
+                            const observation = (await this.processAction(currentAction, actionInput.inputs)) as any; // bcz: really need a type here
                             const nextPrompt = [{ type: 'text', text: `<stage number="${i + 1}" role="user"> <observation>` }, ...observation, { type: 'text', text: '</observation></stage>' }];
                             console.log(observation);
                             this.interMessages.push({ role: 'user', content: nextPrompt });
@@ -214,7 +213,7 @@ export class Agent {
 
         // Process each chunk of the streamed response
         for await (const chunk of stream) {
-            let content = chunk.choices[0]?.delta?.content || '';
+            const content = chunk.choices[0]?.delta?.content || '';
             fullResponse += content;
 
             // Parse the streamed content character by character
@@ -267,7 +266,7 @@ export class Agent {
      * @param actionInput The inputs for the action.
      * @returns The result of the action.
      */
-    private async processAction(action: string, actionInput: any): Promise<any> {
+    private async processAction(action: string, actionInput: unknown): Promise<unknown> {
         if (!(action in this.tools)) {
             throw new Error(`Unknown action: ${action}`);
         }
diff --git a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx
index d4deff78b..613cb7078 100644
--- a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx
+++ b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx
@@ -1,30 +1,29 @@
-import { action, computed, makeObservable, observable, observe, reaction, runInAction, ObservableSet } from 'mobx';
+import dotenv from 'dotenv';
+import { ObservableSet, action, computed, makeObservable, observable, observe, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import OpenAI, { ClientOptions } from 'openai';
 import * as React from 'react';
+import { v4 as uuidv4 } from 'uuid';
+import { ClientUtils } from '../../../../../ClientUtils';
 import { Doc, DocListCast } from '../../../../../fields/Doc';
+import { DocData, DocViews } from '../../../../../fields/DocSymbols';
 import { CsvCast, DocCast, PDFCast, RTFCast, StrCast } from '../../../../../fields/Types';
+import { Networking } from '../../../../Network';
+import { DocUtils } from '../../../../documents/DocUtils';
 import { DocumentType } from '../../../../documents/DocumentTypes';
 import { Docs } from '../../../../documents/Documents';
+import { DocumentManager } from '../../../../util/DocumentManager';
 import { LinkManager } from '../../../../util/LinkManager';
 import { ViewBoxAnnotatableComponent } from '../../../DocComponent';
+import { DocumentView } from '../../DocumentView';
 import { FieldView, FieldViewProps } from '../../FieldView';
+import { PDFBox } from '../../PDFBox';
+import { Agent } from '../agentsystem/Agent';
+import { ASSISTANT_ROLE, AssistantMessage, CHUNK_TYPE, Citation, ProcessingInfo, SimplifiedChunk, TEXT_TYPE } from '../types/types';
+import { Vectorstore } from '../vectorstore/Vectorstore';
 import './ChatBox.scss';
 import MessageComponentBox from './MessageComponent';
-import { ASSISTANT_ROLE, AssistantMessage, Citation, CHUNK_TYPE, TEXT_TYPE, SimplifiedChunk, ProcessingInfo } from '../types/types';
-import { Vectorstore } from '../vectorstore/Vectorstore';
-import { Agent } from '../agentsystem/Agent';
-import dotenv from 'dotenv';
-import { DocData, DocViews } from '../../../../../fields/DocSymbols';
-import { DocumentManager } from '../../../../util/DocumentManager';
-import { v4 as uuidv4 } from 'uuid';
-import { DocUtils } from '../../../../documents/DocUtils';
-import { ClientUtils } from '../../../../../ClientUtils';
 import { ProgressBar } from './ProgressBar';
-import { DocumentView } from '../../DocumentView';
-import { Networking } from '../../../../Network';
-import { PDFViewer } from '../../../pdf/PDFViewer';
-import { PDFBox } from '../../PDFBox';
 
 dotenv.config();
 
@@ -247,7 +246,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
      * @param event The form submission event.
      */
     @action
-    askGPT = async (event: React.FormEvent): Promise<any> => {
+    askGPT = async (event: React.FormEvent): Promise<void> => {
         event.preventDefault();
         this.inputValue = '';
 
@@ -413,7 +412,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         const chunkId = citation.chunk_id;
 
         // Loop through the linked documents to find the matching chunk and handle its display
-        for (let doc of currentLinkedDocs) {
+        for (const doc of currentLinkedDocs) {
             if (doc.chunk_simpl) {
                 const docChunkSimpl = JSON.parse(StrCast(doc.chunk_simpl)) as { chunks: SimplifiedChunk[] };
                 const foundChunk = docChunkSimpl.chunks.find(chunk => chunk.chunkId === chunkId);
@@ -422,24 +421,26 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                     switch (foundChunk.chunkType) {
                         case CHUNK_TYPE.IMAGE:
                         case CHUNK_TYPE.TABLE:
-                            const values = foundChunk.location?.replace(/[\[\]]/g, '').split(',');
+                            {
+                                const values = foundChunk.location?.replace(/[[\]]/g, '').split(',');
 
-                            if (values?.length !== 4) {
-                                console.error('Location string must contain exactly 4 numbers');
-                                return;
-                            }
+                                if (values?.length !== 4) {
+                                    console.error('Location string must contain exactly 4 numbers');
+                                    return;
+                                }
 
-                            const x1 = parseFloat(values[0]) * Doc.NativeWidth(doc);
-                            const y1 = parseFloat(values[1]) * Doc.NativeHeight(doc) + foundChunk.startPage * Doc.NativeHeight(doc);
-                            const x2 = parseFloat(values[2]) * Doc.NativeWidth(doc);
-                            const y2 = parseFloat(values[3]) * Doc.NativeHeight(doc) + foundChunk.startPage * Doc.NativeHeight(doc);
+                                const x1 = parseFloat(values[0]) * Doc.NativeWidth(doc);
+                                const y1 = parseFloat(values[1]) * Doc.NativeHeight(doc) + foundChunk.startPage * Doc.NativeHeight(doc);
+                                const x2 = parseFloat(values[2]) * Doc.NativeWidth(doc);
+                                const y2 = parseFloat(values[3]) * Doc.NativeHeight(doc) + foundChunk.startPage * Doc.NativeHeight(doc);
 
-                            const annotationKey = Doc.LayoutFieldKey(doc) + '_annotations';
+                                const annotationKey = Doc.LayoutFieldKey(doc) + '_annotations';
 
-                            const existingDoc = DocListCast(doc[DocData][annotationKey]).find(d => d.citation_id === citation.citation_id);
-                            const highlightDoc = existingDoc ?? this.createImageCitationHighlight(x1, y1, x2, y2, citation, annotationKey, doc);
+                                const existingDoc = DocListCast(doc[DocData][annotationKey]).find(d => d.citation_id === citation.citation_id);
+                                const highlightDoc = existingDoc ?? this.createImageCitationHighlight(x1, y1, x2, y2, citation, annotationKey, doc);
 
-                            DocumentManager.Instance.showDocument(highlightDoc, { willZoomCentered: true }, () => {});
+                                DocumentManager.Instance.showDocument(highlightDoc, { willZoomCentered: true }, () => {});
+                            }
                             break;
                         case CHUNK_TYPE.TEXT:
                             this.citationPopup = { text: citation.direct_text ?? 'No text available', visible: true };
@@ -695,7 +696,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                     </div>
                 )}
                 <div className="chat-header">
-                    <h2>{this.userName()}'s AI Assistant</h2>
+                    <h2>{this.userName()}&apos;s AI Assistant</h2>
                 </div>
                 <div className="chat-messages" ref={this.messagesRef}>
                     {this.history.map((message, index) => (
diff --git a/src/client/views/nodes/chatbot/response_parsers/AnswerParser.ts b/src/client/views/nodes/chatbot/response_parsers/AnswerParser.ts
index 3b4fdb6f5..1ac753790 100644
--- a/src/client/views/nodes/chatbot/response_parsers/AnswerParser.ts
+++ b/src/client/views/nodes/chatbot/response_parsers/AnswerParser.ts
@@ -1,5 +1,5 @@
-import { ASSISTANT_ROLE, AssistantMessage, Citation, CHUNK_TYPE, TEXT_TYPE, getChunkType, ProcessingInfo } from '../types/types';
 import { v4 as uuid } from 'uuid';
+import { ASSISTANT_ROLE, AssistantMessage, Citation, ProcessingInfo, TEXT_TYPE, getChunkType } from '../types/types';
 
 export class AnswerParser {
     static parse(xml: string, processingInfo: ProcessingInfo[]): AssistantMessage {
@@ -22,8 +22,8 @@ export class AnswerParser {
         }
 
         let rawTextContent = answerMatch[1].trim();
-        let content: AssistantMessage['content'] = [];
-        let citations: Citation[] = [];
+        const content: AssistantMessage['content'] = [];
+        const citations: Citation[] = [];
         let contentIndex = 0;
 
         // Remove citations and follow-up questions from rawTextContent
@@ -43,6 +43,7 @@ export class AnswerParser {
         if (citationsMatch) {
             const citationsContent = citationsMatch[1];
             while ((citationMatch = citationRegex.exec(citationsContent)) !== null) {
+                // eslint-disable-next-line @typescript-eslint/no-unused-vars
                 const [_, index, chunk_id, type, direct_text] = citationMatch;
                 const citation_id = uuid();
                 citationMap.set(index, citation_id);
@@ -102,7 +103,7 @@ export class AnswerParser {
             }
         }
 
-        let followUpQuestions: string[] = [];
+        const followUpQuestions: string[] = [];
         if (followUpQuestionsMatch) {
             const questionsText = followUpQuestionsMatch[1];
             let questionMatch;
diff --git a/src/client/views/nodes/chatbot/response_parsers/StreamedAnswerParser.ts b/src/client/views/nodes/chatbot/response_parsers/StreamedAnswerParser.ts
index 3585cab4a..4149f3da9 100644
--- a/src/client/views/nodes/chatbot/response_parsers/StreamedAnswerParser.ts
+++ b/src/client/views/nodes/chatbot/response_parsers/StreamedAnswerParser.ts
@@ -1,5 +1,3 @@
-import { threadId } from 'worker_threads';
-
 enum ParserState {
     Outside,
     InGroundedText,
diff --git a/src/client/views/nodes/chatbot/tools/BaseTool.ts b/src/client/views/nodes/chatbot/tools/BaseTool.ts
index b57f1c8e4..10780617b 100644
--- a/src/client/views/nodes/chatbot/tools/BaseTool.ts
+++ b/src/client/views/nodes/chatbot/tools/BaseTool.ts
@@ -1,17 +1,17 @@
 import { Tool } from '../types/types';
 
-export abstract class BaseTool<T extends Record<string, any> = Record<string, any>> implements Tool<T> {
+export abstract class BaseTool<T extends Record<string, unknown> = Record<string, unknown>> implements Tool<T> {
     constructor(
         public name: string,
         public description: string,
-        public parameters: Record<string, any>,
+        public parameters: Record<string, unknown>,
         public citationRules: string,
         public briefSummary: string
     ) {}
 
-    abstract execute(args: T): Promise<any>;
+    abstract execute(args: T): Promise<unknown>;
 
-    getActionRule(): Record<string, any> {
+    getActionRule(): Record<string, unknown> {
         return {
             [this.name]: {
                 name: this.name,
diff --git a/src/client/views/nodes/chatbot/tools/CalculateTool.ts b/src/client/views/nodes/chatbot/tools/CalculateTool.ts
index 74b7ca27b..77ab1b39b 100644
--- a/src/client/views/nodes/chatbot/tools/CalculateTool.ts
+++ b/src/client/views/nodes/chatbot/tools/CalculateTool.ts
@@ -18,7 +18,7 @@ export class CalculateTool extends BaseTool<{ expression: string }> {
         );
     }
 
-    async execute(args: { expression: string }): Promise<any> {
+    async execute(args: { expression: string }): Promise<unknown> {
         // Note: Using eval() can be dangerous. Consider using a safer alternative.
         const result = eval(args.expression);
         return [{ type: 'text', text: result.toString() }];
diff --git a/src/client/views/nodes/chatbot/tools/CreateCSVTool.ts b/src/client/views/nodes/chatbot/tools/CreateCSVTool.ts
index 55015846b..d3ded0de0 100644
--- a/src/client/views/nodes/chatbot/tools/CreateCSVTool.ts
+++ b/src/client/views/nodes/chatbot/tools/CreateCSVTool.ts
@@ -28,7 +28,7 @@ export class CreateCSVTool extends BaseTool<{ csvData: string; filename: string
         this._handleCSVResult = handleCSVResult;
     }
 
-    async execute(args: { csvData: string; filename: string }): Promise<any> {
+    async execute(args: { csvData: string; filename: string }): Promise<unknown> {
         try {
             console.log('Creating CSV file:', args.filename, ' with data:', args.csvData);
             // Post the raw CSV data to the createCSV endpoint on the server
diff --git a/src/client/views/nodes/chatbot/tools/CreateCollectionTool.ts b/src/client/views/nodes/chatbot/tools/CreateCollectionTool.ts
index 573428179..1e479a62c 100644
--- a/src/client/views/nodes/chatbot/tools/CreateCollectionTool.ts
+++ b/src/client/views/nodes/chatbot/tools/CreateCollectionTool.ts
@@ -25,7 +25,7 @@ export class GetDocsContentTool extends BaseTool<{ title: string; document_ids:
         this._docView = docView;
     }
 
-    async execute(args: { title: string; document_ids: string[] }): Promise<any> {
+    async execute(args: { title: string; document_ids: string[] }): Promise<unknown> {
         // Note: Using eval() can be dangerous. Consider using a safer alternative.
         const docs = args.document_ids.map(doc_id => DocCast(DocServer.GetCachedRefField(doc_id)));
         const collection = Docs.Create.FreeformDocument(docs, { title: args.title });
diff --git a/src/client/views/nodes/chatbot/tools/DataAnalysisTool.ts b/src/client/views/nodes/chatbot/tools/DataAnalysisTool.ts
index a12ee46e5..2e663fed1 100644
--- a/src/client/views/nodes/chatbot/tools/DataAnalysisTool.ts
+++ b/src/client/views/nodes/chatbot/tools/DataAnalysisTool.ts
@@ -33,7 +33,7 @@ export class DataAnalysisTool extends BaseTool<{ csv_file_name: string | string[
         return file?.id;
     }
 
-    async execute(args: { csv_file_name: string | string[] }): Promise<any> {
+    async execute(args: { csv_file_name: string | string[] }): Promise<unknown> {
         const filenames = Array.isArray(args.csv_file_name) ? args.csv_file_name : [args.csv_file_name];
         const results = [];
 
diff --git a/src/client/views/nodes/chatbot/tools/GetDocsTool.ts b/src/client/views/nodes/chatbot/tools/GetDocsTool.ts
index f970ca8ee..903f3f69c 100644
--- a/src/client/views/nodes/chatbot/tools/GetDocsTool.ts
+++ b/src/client/views/nodes/chatbot/tools/GetDocsTool.ts
@@ -18,7 +18,7 @@ export class GetDocsTool extends BaseTool<{ title: string; document_ids: string[
         this._docView = docView;
     }
 
-    async execute(args: { title: string; document_ids: string[] }): Promise<any> {
+    async execute(args: { title: string; document_ids: string[] }): Promise<unknown> {
         // Note: Using eval() can be dangerous. Consider using a safer alternative.
         const docs = args.document_ids.map(doc_id => DocCast(DocServer.GetCachedRefField(doc_id)));
         const collection = Docs.Create.FreeformDocument(docs, { title: args.title });
diff --git a/src/client/views/nodes/chatbot/tools/NoTool.ts b/src/client/views/nodes/chatbot/tools/NoTool.ts
index 1f0830a77..edd3160ec 100644
--- a/src/client/views/nodes/chatbot/tools/NoTool.ts
+++ b/src/client/views/nodes/chatbot/tools/NoTool.ts
@@ -1,7 +1,7 @@
 // tools/NoTool.ts
 import { BaseTool } from './BaseTool';
 
-export class NoTool extends BaseTool<{}> {
+export class NoTool extends BaseTool<Record<string, unknown>> {
     constructor() {
         super(
             'no_tool',
@@ -12,7 +12,8 @@ export class NoTool extends BaseTool<{}> {
         );
     }
 
-    async execute(args: {}): Promise<any> {
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    async execute(args: object): Promise<unknown> {
         return [{ type: 'text', text: 'No tool used. Proceed with answering the question.' }];
     }
 }
diff --git a/src/client/views/nodes/chatbot/tools/RAGTool.ts b/src/client/views/nodes/chatbot/tools/RAGTool.ts
index f4b7b42ea..4cc2f26ff 100644
--- a/src/client/views/nodes/chatbot/tools/RAGTool.ts
+++ b/src/client/views/nodes/chatbot/tools/RAGTool.ts
@@ -1,10 +1,7 @@
-import { BaseTool } from './BaseTool';
-import { Vectorstore } from '../vectorstore/Vectorstore';
-import { RAGChunk } from '../types/types';
-import * as fs from 'fs';
 import { Networking } from '../../../../Network';
-import { file } from 'jszip';
-import { ChatCompletion, ChatCompletionContentPart, ChatCompletionMessageParam } from 'openai/resources';
+import { RAGChunk } from '../types/types';
+import { Vectorstore } from '../vectorstore/Vectorstore';
+import { BaseTool } from './BaseTool';
 
 export class RAGTool extends BaseTool {
     constructor(private vectorstore: Vectorstore) {
@@ -59,13 +56,13 @@ export class RAGTool extends BaseTool {
         );
     }
 
-    async execute(args: { hypothetical_document_chunk: string }): Promise<any> {
+    async execute(args: { hypothetical_document_chunk: string }): Promise<unknown> {
         const relevantChunks = await this.vectorstore.retrieve(args.hypothetical_document_chunk);
         const formatted_chunks = await this.getFormattedChunks(relevantChunks);
         return formatted_chunks;
     }
 
-    async getFormattedChunks(relevantChunks: RAGChunk[]): Promise<any> {
+    async getFormattedChunks(relevantChunks: RAGChunk[]): Promise<unknown> {
         try {
             const { formattedChunks } = await Networking.PostToServer('/formatChunks', { relevantChunks });
 
diff --git a/src/client/views/nodes/chatbot/tools/SearchTool.ts b/src/client/views/nodes/chatbot/tools/SearchTool.ts
index b926cbadc..3a4668422 100644
--- a/src/client/views/nodes/chatbot/tools/SearchTool.ts
+++ b/src/client/views/nodes/chatbot/tools/SearchTool.ts
@@ -1,7 +1,6 @@
-import { max } from 'lodash';
+import { v4 as uuidv4 } from 'uuid';
 import { Networking } from '../../../../Network';
 import { BaseTool } from './BaseTool';
-import { v4 as uuidv4 } from 'uuid';
 
 export class SearchTool extends BaseTool<{ query: string | string[] }> {
     private _addLinkedUrlDoc: (url: string, id: string) => void;
@@ -25,7 +24,7 @@ export class SearchTool extends BaseTool<{ query: string | string[] }> {
         this._max_results = max_results;
     }
 
-    async execute(args: { query: string | string[] }): Promise<any> {
+    async execute(args: { query: string | string[] }): Promise<unknown> {
         const queries = Array.isArray(args.query) ? args.query : [args.query];
         const allResults = [];
 
diff --git a/src/client/views/nodes/chatbot/tools/WebsiteInfoScraperTool.ts b/src/client/views/nodes/chatbot/tools/WebsiteInfoScraperTool.ts
index 2118218f6..1efb389b8 100644
--- a/src/client/views/nodes/chatbot/tools/WebsiteInfoScraperTool.ts
+++ b/src/client/views/nodes/chatbot/tools/WebsiteInfoScraperTool.ts
@@ -1,6 +1,6 @@
+import { v4 as uuidv4 } from 'uuid';
 import { Networking } from '../../../../Network';
 import { BaseTool } from './BaseTool';
-import { v4 as uuidv4 } from 'uuid';
 
 export class WebsiteInfoScraperTool extends BaseTool<{ url: string | string[] }> {
     private _addLinkedUrlDoc: (url: string, id: string) => void;
@@ -63,7 +63,7 @@ export class WebsiteInfoScraperTool extends BaseTool<{ url: string | string[] }>
         this._addLinkedUrlDoc = addLinkedUrlDoc;
     }
 
-    async execute(args: { url: string | string[] }): Promise<any> {
+    async execute(args: { url: string | string[] }): Promise<unknown> {
         const urls = Array.isArray(args.url) ? args.url : [args.url];
         const results = [];
 
@@ -74,6 +74,7 @@ export class WebsiteInfoScraperTool extends BaseTool<{ url: string | string[] }>
                 this._addLinkedUrlDoc(url, id);
                 results.push({ type: 'text', text: `<chunk chunk_id=${id} chunk_type=url>\n${website_plain_text}\n</chunk>\n` });
             } catch (error) {
+                console.log(error);
                 results.push({ type: 'text', text: `An error occurred while scraping the website: ${url}` });
             }
         }
diff --git a/src/client/views/nodes/chatbot/tools/WikipediaTool.ts b/src/client/views/nodes/chatbot/tools/WikipediaTool.ts
index 143d91d80..692dff749 100644
--- a/src/client/views/nodes/chatbot/tools/WikipediaTool.ts
+++ b/src/client/views/nodes/chatbot/tools/WikipediaTool.ts
@@ -1,8 +1,6 @@
-import { title } from 'process';
+import { v4 as uuidv4 } from 'uuid';
 import { Networking } from '../../../../Network';
 import { BaseTool } from './BaseTool';
-import axios from 'axios';
-import { v4 as uuidv4 } from 'uuid';
 
 export class WikipediaTool extends BaseTool<{ title: string }> {
     private _addLinkedUrlDoc: (url: string, id: string) => void;
@@ -23,7 +21,7 @@ export class WikipediaTool extends BaseTool<{ title: string }> {
         this._addLinkedUrlDoc = addLinkedUrlDoc;
     }
 
-    async execute(args: { title: string }): Promise<any> {
+    async execute(args: { title: string }): Promise<unknown> {
         try {
             const { text } = await Networking.PostToServer('/getWikipediaSummary', { title: args.title });
             const id = uuidv4();
@@ -31,6 +29,7 @@ export class WikipediaTool extends BaseTool<{ title: string }> {
             this._addLinkedUrlDoc(url, id);
             return [{ type: 'text', text: `<chunk chunk_id=${id} chunk_type=csv}> ${text} </chunk>` }];
         } catch (error) {
+            console.log(error);
             return [{ type: 'text', text: 'An error occurred while fetching the article.' }];
         }
     }
diff --git a/src/client/views/nodes/chatbot/types/types.ts b/src/client/views/nodes/chatbot/types/types.ts
index f5d14ad6a..2bc7f4952 100644
--- a/src/client/views/nodes/chatbot/types/types.ts
+++ b/src/client/views/nodes/chatbot/types/types.ts
@@ -52,15 +52,6 @@ export interface ProcessingInfo {
     content: string;
 }
 
-export interface AssistantMessage {
-    role: ASSISTANT_ROLE;
-    content: MessageContent[];
-    follow_up_questions?: string[];
-    citations?: Citation[];
-    processing_info: ProcessingInfo[];
-    loop_summary?: string;
-}
-
 export interface MessageContent {
     index: number;
     type: TEXT_TYPE;
@@ -75,6 +66,14 @@ export interface Citation {
     citation_id: string;
     url?: string;
 }
+export interface AssistantMessage {
+    role: ASSISTANT_ROLE;
+    content: MessageContent[];
+    follow_up_questions?: string[];
+    citations?: Citation[];
+    processing_info: ProcessingInfo[];
+    loop_summary?: string;
+}
 
 export interface RAGChunk {
     id: string;
@@ -113,14 +112,14 @@ export interface AI_Document {
     type: string;
 }
 
-export interface Tool<T extends Record<string, any> = Record<string, any>> {
+export interface Tool<T extends Record<string, unknown> = Record<string, unknown>> {
     name: string;
     description: string;
-    parameters: Record<string, any>;
+    parameters: Record<string, unknown>;
     citationRules: string;
     briefSummary: string;
-    execute: (args: T) => Promise<any>;
-    getActionRule: () => Record<string, any>;
+    execute: (args: T) => Promise<unknown>;
+    getActionRule: () => Record<string, unknown>;
 }
 
 export interface AgentMessage {
diff --git a/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts b/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts
index 07a2b73bc..9575277f7 100644
--- a/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts
+++ b/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts
@@ -1,11 +1,11 @@
-import { Pinecone, Index, IndexList, PineconeRecord, RecordMetadata, QueryResponse } from '@pinecone-database/pinecone';
+import { Index, IndexList, Pinecone, PineconeRecord, QueryResponse, RecordMetadata } from '@pinecone-database/pinecone';
 import { CohereClient } from 'cohere-ai';
 import { EmbedResponse } from 'cohere-ai/api';
 import dotenv from 'dotenv';
-import { RAGChunk, AI_Document, CHUNK_TYPE } from '../types/types';
 import { Doc } from '../../../../../fields/Doc';
 import { CsvCast, PDFCast, StrCast } from '../../../../../fields/Types';
 import { Networking } from '../../../../Network';
+import { AI_Document, CHUNK_TYPE, RAGChunk } from '../types/types';
 
 dotenv.config();
 
@@ -103,8 +103,8 @@ export class Vectorstore {
                 const { jobId } = await Networking.PostToServer('/createDocument', { file_path: local_file_path });
 
                 // Poll the server for progress updates.
-                let inProgress: boolean = true;
-                let result: any = null;
+                const inProgress = true;
+                let result: (AI_Document & { doc_id: string }) | null = null; // bcz: is this the correct type??
                 while (inProgress) {
                     // Polling interval for status updates.
                     await new Promise(resolve => setTimeout(resolve, 2000));
@@ -127,6 +127,9 @@ export class Vectorstore {
                         progressCallback(progress, step);
                     }
                 }
+                if (!result) {
+                    throw new Error('no result received...'); // bcz: is this an Error?
+                }
 
                 // Once completed, process the document and add it to the vectorstore.
                 console.log('Document JSON:', result);
@@ -175,7 +178,7 @@ export class Vectorstore {
      * Indexes the processed document by uploading the document's vector chunks to the Pinecone index.
      * @param document The processed document containing its chunks and metadata.
      */
-    private async indexDocument(document: any) {
+    private async indexDocument(document: AI_Document) {
         console.log('Uploading vectors to content namespace...');
 
         // Prepare Pinecone records for each chunk in the document.
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 7543b3fb1..b5c69bff0 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -51,7 +51,7 @@ interface IViewerProps extends FieldViewProps {
  * Handles rendering and virtualization of the pdf
  */
 @observer
-export class PDFViewer extends ObservableReactComponent {
+export class PDFViewer extends ObservableReactComponent<IViewerProps> {
     static _annotationStyle = addStyleSheet();
 
     constructor(props: IViewerProps) {
@@ -68,12 +68,12 @@ export class PDFViewer extends ObservableReactComponent {
     private _pdfViewer!: PDFJSViewer.PDFViewer;
     private _styleRule: number | undefined; // stylesheet rule for making hyperlinks clickable
     private _retries = 0; // number of times tried to create the PDF viewer
-    private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt) => void);
+    private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void);
     private _marqueeref = React.createRef<MarqueeAnnotator>();
-    private _annotationLayer: React.RefObject = React.createRef();
+    private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
     private _disposers: { [name: string]: IReactionDisposer } = {};
-    private _viewer: React.RefObject = React.createRef();
-    _mainCont: React.RefObject = React.createRef();
+    private _viewer: React.RefObject<HTMLDivElement> = React.createRef();
+    _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
     private _selectionText: string = '';
     private _selectionContent: DocumentFragment | undefined;
     private _downX: number = 0;
@@ -81,9 +81,9 @@ export class PDFViewer extends ObservableReactComponent {
     private _lastSearch = false;
     private _viewerIsSetup = false;
     private _ignoreScroll = false;
-    private _initialScroll: { loc: Opt; easeFunc: 'linear' | 'ease' | undefined } | undefined;
+    private _initialScroll: { loc: Opt<number>; easeFunc: 'linear' | 'ease' | undefined } | undefined;
     private _forcedScroll = true;
-    _getAnchor: (savedAnnotations: Opt, addAsAnnotation: boolean) => Opt = () => undefined;
+    _getAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined;
 
     selectionText = () => this._selectionText;
     selectionContent = () => this._selectionContent;
@@ -179,7 +179,7 @@ export class PDFViewer extends ObservableReactComponent {
     // otherwise it will scroll smoothly.
     scrollFocus = (doc: Doc, scrollTop: number, options: FocusViewOptions) => {
         const mainCont = this._mainCont.current;
-        let focusSpeed: Opt;
+        let focusSpeed: Opt<number>;
         if (doc !== this._props.Document && mainCont) {
             const windowHeight = this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1);
             const scrollTo = ClientUtils.scrollIntoView(scrollTop, doc[Height](), NumCast(this._props.layoutDoc._layout_scrollTop), windowHeight, windowHeight * 0.1, this._scrollHeight);
@@ -394,30 +394,6 @@ export class PDFViewer extends ObservableReactComponent {
         }
     };
 
-    // @action
-    // createMarquee = (coords: [x1: number, x2: number, y1: number, y2: number]): void => {
-    //     // const hit = document.elementFromPoint(e.clientX, e.clientY);
-    //     // bcz: Change. drag selecting requires that preventDefault is NOT called.  This used to happen in DocumentView,
-    //     //      but that's changed, so this shouldn't be needed.
-    //     // if (hit && hit.localName === "span" && this.annotationsActive(true)) {  // drag selecting text stops propagation
-    //     //     e.button === 0 && e.stopPropagation();
-    //     // }
-    //     // if alt+left click, drag and annotate
-    //     this._downX = coords[0];
-    //     this._downY = coords[2];
-
-    //     if ((this._props.Document._freeform_scale || 1) !== 1) return;
-    //     this._props.select(false);
-    //     MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
-    //     this.isAnnotating = true;
-    //     this._textSelecting = false;
-    //     // if textLayer is hit, then we select text instead of using a marquee so clear out the marquee.
-    //     this._styleRule = addStyleSheetRule(PDFViewer._annotationStyle, 'htmlAnnotation', { 'pointer-events': 'none' });
-
-    //     this._marqueeref.current?.onInitiateSelection([coords[0], coords[2]]);
-    //     this._marqueeref.current?.onTerminateSelection();
-    // };
-
     @action
     finishMarquee = (/* x?: number, y?: number */) => {
         this._getAnchor = AnchorMenu.Instance?.GetAnchor;
@@ -495,7 +471,7 @@ export class PDFViewer extends ObservableReactComponent {
         // e.stopPropagation();  // bcz: not sure why this was here.  We need to allow the DocumentView to get clicks to process doubleClicks
     };
 
-    setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean, doc: Opt) => void) => {
+    setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void) => {
         this._setPreviewCursor = func;
     };
 
@@ -520,7 +496,6 @@ export class PDFViewer extends ObservableReactComponent {
         return (
             <div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this._props.Document), transform: `scale(${NumCast(this._props.layoutDoc._freeform_scale, 1)})` }} ref={this._annotationLayer}>
                 {inlineAnnos.map(anno => (
-                    // eslint-disable-next-line react/jsx-props-no-spreading
                     <Annotation {...this._props} fieldKey={this._props.fieldKey + '_annotations'} pointerEvents={this.pointerEvents} containerDataDoc={this._props.dataDoc} annoDoc={anno} key={`${anno[Id]}-annotation`} />
                 ))}
             </div>
@@ -534,7 +509,7 @@ export class PDFViewer extends ObservableReactComponent {
     panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1);
     transparentFilter = () => [...this._props.childFilters(), ClientUtils.TransparentBackgroundFilter];
     opaqueFilter = () => [...this._props.childFilters(), ClientUtils.noDragDocsFilter, ...(SnappingManager.CanEmbed && this._props.isContentActive() ? [] : [ClientUtils.OpaqueBackgroundFilter])];
-    childStyleProvider = (doc: Doc | undefined, props: Opt, property: string) => {
+    childStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => {
         if (doc instanceof Doc && property === StyleProp.PointerEvents) {
             if (this.inlineTextAnnotations.includes(doc) || this._props.isContentActive() === false) return 'none';
             const isInk = doc.layout_isSvg && !props?.LayoutTemplateString;
@@ -554,7 +529,6 @@ export class PDFViewer extends ObservableReactComponent {
                 pointerEvents: Doc.ActiveTool !== InkTool.None ? 'all' : undefined,
             }}>
             <CollectionFreeFormView
-                // eslint-disable-next-line react/jsx-props-no-spreading
                 {...this._props}
                 NativeWidth={returnZero}
                 NativeHeight={returnZero}
diff --git a/src/server/ApiManagers/AssistantManager.ts b/src/server/ApiManagers/AssistantManager.ts
index e940fb121..b4ebb1eae 100644
--- a/src/server/ApiManagers/AssistantManager.ts
+++ b/src/server/ApiManagers/AssistantManager.ts
@@ -1,23 +1,19 @@
+import { Readability } from '@mozilla/readability';
+import axios from 'axios';
+import { spawn } from 'child_process';
 import * as fs from 'fs';
-import { createReadStream, writeFile } from 'fs';
+import { writeFile } from 'fs';
+import { google } from 'googleapis';
+import { JSDOM } from 'jsdom';
 import OpenAI from 'openai';
 import * as path from 'path';
+import * as puppeteer from 'puppeteer';
 import { promisify } from 'util';
 import * as uuid from 'uuid';
-import { filesDirectory, publicDirectory } from '../SocketData';
+import { AI_Document } from '../../client/views/nodes/chatbot/types/types';
 import { Method } from '../RouteManager';
+import { filesDirectory, publicDirectory } from '../SocketData';
 import ApiManager, { Registration } from './ApiManager';
-import axios from 'axios';
-import { RAGChunk } from '../../client/views/nodes/chatbot/types/types';
-import { UnstructuredClient } from 'unstructured-client';
-import { PartitionResponse } from 'unstructured-client/sdk/models/operations';
-import { ChunkingStrategy, Strategy } from 'unstructured-client/sdk/models/shared';
-import * as cheerio from 'cheerio';
-import { google } from 'googleapis';
-import * as puppeteer from 'puppeteer';
-import { JSDOM } from 'jsdom';
-import { Readability } from '@mozilla/readability';
-import { spawn } from 'child_process';
 
 // Enumeration of directories where different file types are stored
 export enum Directory {
@@ -34,8 +30,8 @@ export enum Directory {
 }
 
 // In-memory job tracking
-let jobResults: { [key: string]: any } = {};
-let jobProgress: { [key: string]: any } = {};
+const jobResults: { [key: string]: unknown } = {};
+const jobProgress: { [key: string]: unknown } = {};
 
 /**
  * Constructs a normalized path to a file in the server's file system.
@@ -81,10 +77,10 @@ export default class AssistantManager extends ApiManager {
      */
     protected initialize(register: Registration): void {
         // Initialize OpenAI API with client key
-        const openai = new OpenAI({
+        const openai = new OpenAI({ // bcz: is this needed?  variable is never used...
             apiKey: process.env._CLIENT_OPENAI_KEY,
             dangerouslyAllowBrowser: true,
-        });
+        }); // prettier-ignore
 
         // Initialize Google Custom Search API
         const customsearch = google.customsearch('v1');
@@ -107,11 +103,11 @@ export default class AssistantManager extends ApiManager {
                     });
                     const summary = response.data.query.search[0]?.snippet || 'No article found with that title.';
                     res.send({ text: summary });
-                } catch (error: any) {
+                } catch (error) {
                     console.error('Error retrieving Wikipedia summary:', error);
                     res.status(500).send({
                         error: 'Error retrieving article summary from Wikipedia.',
-                        details: error.message,
+                        details: (error as { message: string }).message ?? error, // bcz: don't know what the error type contains...
                     });
                 }
             },
@@ -134,17 +130,17 @@ export default class AssistantManager extends ApiManager {
                     });
 
                     const results =
-                        response.data.items?.map((item: any) => ({
+                        response.data.items?.map(item => ({
                             url: item.link,
                             snippet: item.snippet,
                         })) || [];
 
                     res.send({ results });
-                } catch (error: any) {
+                } catch (error) {
                     console.error('Error performing web search:', error);
                     res.status(500).send({
                         error: 'Failed to perform web search',
-                        details: error.message,
+                        details: (error as { message: string }).message ?? error, // bcz: don't know wha tthe error type contains...
                     });
                 }
             },
@@ -170,16 +166,16 @@ export default class AssistantManager extends ApiManager {
          * @param retries The number of retry attempts.
          * @param backoff Initial backoff time in milliseconds.
          */
-        const fetchWithRetry = async (url: string, retries = 3, backoff = 300) => {
+        const fetchWithRetry = async (url: string, retries = 3, backoff = 300): Promise<unknown> => {
             try {
                 const response = await axiosInstance.get(url);
                 return response.data;
-            } catch (error: any) {
-                if (retries > 0 && error.response?.status === 429) {
+            } catch (error) {
+                if (retries > 0 && (error as { response: { status: number } }).response?.status === 429) {   // bcz: don't know the error type
                     console.log(`Rate limited. Retrying in ${backoff}ms...`);
                     await delay(backoff);
                     return fetchWithRetry(url, retries - 1, backoff * 2);
-                }
+                } // prettier-ignore
                 throw error;
             }
         };
@@ -199,11 +195,11 @@ export default class AssistantManager extends ApiManager {
                 try {
                     const data = await fetchWithRetry(url);
                     res.send({ data });
-                } catch (error: any) {
+                } catch (error) {
                     console.error('Error fetching the URL:', error);
                     res.status(500).send({
                         error: 'Failed to fetch the URL',
-                        details: error.message,
+                        details: (error as { message: string }).message ?? error, // bcz: don't know wha tthe error type contains...
                     });
                 }
             },
@@ -241,11 +237,11 @@ export default class AssistantManager extends ApiManager {
                     } else {
                         res.status(500).send({ error: 'Failed to extract readable content' });
                     }
-                } catch (error: any) {
+                } catch (error) {
                     console.error('Error scraping website:', error);
                     res.status(500).send({
                         error: 'Failed to scrape website',
-                        details: error.message,
+                        details: (error as { message: string }).message ?? error, // bcz: don't know wha tthe error type contains...
                     });
                 }
             },
@@ -267,15 +263,16 @@ export default class AssistantManager extends ApiManager {
                     const jobId = uuid.v4();
 
                     // Spawn the Python process and track its progress/output
+                    // eslint-disable-next-line no-use-before-define
                     spawnPythonProcess(jobId, file_name, file_data);
 
                     // Send the job ID back to the client for tracking
                     res.send({ jobId });
-                } catch (error: any) {
+                } catch (error) {
                     console.error('Error initiating document creation:', error);
                     res.status(500).send({
                         error: 'Failed to initiate document creation',
-                        details: error.message,
+                        details: (error as { message: string }).message ?? error, // bcz: don't know wha tthe error type contains...
                     });
                 }
             },
@@ -307,13 +304,13 @@ export default class AssistantManager extends ApiManager {
                 const { jobId } = req.params; // Get the job ID from the URL parameters
                 // Check if the job result is available
                 if (jobResults[jobId]) {
-                    const result = jobResults[jobId];
+                    const result = jobResults[jobId] as AI_Document & { status: string };
 
                     // If the result contains image or table chunks, save the base64 data as image files
                     if (result.chunks && Array.isArray(result.chunks)) {
                         for (const chunk of result.chunks) {
                             if (chunk.metadata && (chunk.metadata.type === 'image' || chunk.metadata.type === 'table')) {
-                                let files_directory = '/files/chunk_images/';
+                                const files_directory = '/files/chunk_images/';
                                 const directory = path.join(publicDirectory, files_directory);
 
                                 // Ensure the directory exists or create it
@@ -338,7 +335,7 @@ export default class AssistantManager extends ApiManager {
                                 }
                             }
                         }
-                        result['status'] = 'completed';
+                        result.status = 'completed';
                     } else {
                         result.status = 'pending';
                     }
@@ -429,11 +426,11 @@ export default class AssistantManager extends ApiManager {
 
                     // Send the file URL and UUID back to the client
                     res.send({ fileUrl, id: uuidv4 });
-                } catch (error: any) {
+                } catch (error) {
                     console.error('Error creating CSV file:', error);
                     res.status(500).send({
                         error: 'Failed to create CSV file.',
-                        details: error.message,
+                        details: (error as { message: string }).message ?? error, // bcz: don't know what the error type contains...
                     });
                 }
             },
@@ -446,59 +443,6 @@ function spawnPythonProcess(jobId: string, file_name: string, file_data: string)
     const requirementsPath = path.join(__dirname, '../chunker/requirements.txt');
     const pythonScriptPath = path.join(__dirname, '../chunker/pdf_chunker.py');
 
-    // Check if venv exists
-    if (!fs.existsSync(venvPath)) {
-        console.log('Virtual environment not found. Creating and setting up...');
-
-        // Create venv
-        const createVenvProcess = spawn('python', ['-m', 'venv', venvPath]);
-
-        createVenvProcess.on('close', code => {
-            if (code !== 0) {
-                console.error(`Failed to create virtual environment. Exit code: ${code}`);
-                return;
-            }
-
-            console.log('Virtual environment created. Installing requirements...');
-
-            // Determine the pip path based on the OS
-            const pipPath = process.platform === 'win32' ? path.join(venvPath, 'Scripts', 'pip.exe') : path.join(venvPath, 'bin', 'pip3'); // Try 'pip3' for Unix-like systems
-
-            if (!fs.existsSync(pipPath)) {
-                console.error(`pip executable not found at ${pipPath}`);
-                return;
-            }
-
-            // Install requirements
-            const installRequirementsProcess = spawn(pipPath, ['install', '-r', requirementsPath]);
-
-            installRequirementsProcess.stdout.on('data', data => {
-                console.log(`pip stdout: ${data}`);
-            });
-
-            installRequirementsProcess.stderr.on('data', data => {
-                console.error(`pip stderr: ${data}`);
-            });
-
-            installRequirementsProcess.on('error', error => {
-                console.error(`Error starting pip process: ${error}`);
-            });
-
-            installRequirementsProcess.on('close', code => {
-                if (code !== 0) {
-                    console.error(`Failed to install requirements. Exit code: ${code}`);
-                    return;
-                }
-
-                console.log('Requirements installed. Running Python script...');
-                runPythonScript();
-            });
-        });
-    } else {
-        console.log('Virtual environment found. Running Python script...');
-        runPythonScript();
-    }
-
     function runPythonScript() {
         const pythonPath = process.platform === 'win32' ? path.join(venvPath, 'Scripts', 'python') : path.join(venvPath, 'bin', 'python3');
 
@@ -530,7 +474,7 @@ function spawnPythonProcess(jobId: string, file_name: string, file_data: string)
                             };
                         }
                     } catch (err) {
-                        console.error('Progress log from Python:', line);
+                        console.error('Progress log from Python:', line, err);
                     }
                 }
             });
@@ -551,4 +495,56 @@ function spawnPythonProcess(jobId: string, file_name: string, file_data: string)
             }
         });
     }
+    // Check if venv exists
+    if (!fs.existsSync(venvPath)) {
+        console.log('Virtual environment not found. Creating and setting up...');
+
+        // Create venv
+        const createVenvProcess = spawn('python', ['-m', 'venv', venvPath]);
+
+        createVenvProcess.on('close', code => {
+            if (code !== 0) {
+                console.error(`Failed to create virtual environment. Exit code: ${code}`);
+                return;
+            }
+
+            console.log('Virtual environment created. Installing requirements...');
+
+            // Determine the pip path based on the OS
+            const pipPath = process.platform === 'win32' ? path.join(venvPath, 'Scripts', 'pip.exe') : path.join(venvPath, 'bin', 'pip3'); // Try 'pip3' for Unix-like systems
+
+            if (!fs.existsSync(pipPath)) {
+                console.error(`pip executable not found at ${pipPath}`);
+                return;
+            }
+
+            // Install requirements
+            const installRequirementsProcess = spawn(pipPath, ['install', '-r', requirementsPath]);
+
+            installRequirementsProcess.stdout.on('data', data => {
+                console.log(`pip stdout: ${data}`);
+            });
+
+            installRequirementsProcess.stderr.on('data', data => {
+                console.error(`pip stderr: ${data}`);
+            });
+
+            installRequirementsProcess.on('error', error => {
+                console.error(`Error starting pip process: ${error}`);
+            });
+
+            installRequirementsProcess.on('close', closecode => {
+                if (closecode !== 0) {
+                    console.error(`Failed to install requirements. Exit code: ${closecode}`);
+                    return;
+                }
+
+                console.log('Requirements installed. Running Python script...');
+                runPythonScript();
+            });
+        });
+    } else {
+        console.log('Virtual environment found. Running Python script...');
+        runPythonScript();
+    }
 }
-- 
cgit v1.2.3-70-g09d2

