pygpt-net 2.6.16__py3-none-any.whl → 2.6.17__py3-none-any.whl

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.
pygpt_net/CHANGELOG.txt CHANGED
@@ -1,3 +1,9 @@
1
+ 2.6.17 (2025-08-21)
2
+
3
+ - Optimized profile switching.
4
+ - Fixed: setting initial splitter size on first launch.
5
+ - Added smoother view reload.
6
+
1
7
  2.6.16 (2025-08-20)
2
8
 
3
9
  - Fixed: Attachment string joining.
pygpt_net/__init__.py CHANGED
@@ -6,15 +6,15 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.20 00:00:00 #
9
+ # Updated Date: 2025.08.21 00:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  __author__ = "Marcin Szczygliński"
13
13
  __copyright__ = "Copyright 2025, Marcin Szczygliński"
14
14
  __credits__ = ["Marcin Szczygliński"]
15
15
  __license__ = "MIT"
16
- __version__ = "2.6.16"
17
- __build__ = "2025-08-20"
16
+ __version__ = "2.6.17"
17
+ __build__ = "2025-08-21"
18
18
  __maintainer__ = "Marcin Szczygliński"
19
19
  __github__ = "https://github.com/szczyglis-dev/py-gpt"
20
20
  __report__ = "https://github.com/szczyglis-dev/py-gpt/issues"
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.12.09 23:00:00 #
9
+ # Updated Date: 2025.08.20 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from pygpt_net.controller.access import Access
@@ -147,8 +147,12 @@ class Controller:
147
147
  """Reload components"""
148
148
  self.reloading = True # lock
149
149
 
150
+ print("Reloading components... please wait...")
151
+
150
152
  mem_clean() # try to clean memory
151
153
 
154
+ prev_theme = self.window.core.config.get("theme")
155
+
152
156
  self.window.core.reload() # db, config, patch, etc.
153
157
  self.ui.tabs.reload()
154
158
  self.ctx.reload()
@@ -175,6 +179,8 @@ class Controller:
175
179
  self.ctx.reload_after()
176
180
  self.ui.tabs.restore_data() # restore opened tabs data
177
181
  self.kernel.restart()
178
- self.theme.reload_all()
182
+ self.theme.reload_all(prev_theme=prev_theme) # do not reload theme if no change
179
183
 
180
184
  self.reloading = False # unlock
185
+
186
+ print("[OK] Components reloaded successfully.")
@@ -22,7 +22,7 @@ from .summarizer import Summarizer
22
22
  from .extra import Extra
23
23
 
24
24
  from pygpt_net.utils import trans
25
- from ...core.types import MODE_ASSISTANT
25
+ from pygpt_net.core.types import MODE_ASSISTANT
26
26
 
27
27
 
28
28
  class Ctx:
@@ -79,7 +79,7 @@ class Ctx:
79
79
  self.select_by_current(focus=True) # scroll to current ctx
80
80
 
81
81
  # focus input after loading
82
- QTimer.singleShot(10, self.window.controller.chat.common.focus_input)
82
+ QTimer.singleShot(2000, self.window.controller.chat.common.focus_input)
83
83
 
84
84
  def update_mode_in_current(self):
85
85
  """Update current ctx mode"""
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.15 03:00:00 #
9
+ # Updated Date: 2025.08.20 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from pygpt_net.core.events import Event, AppEvent
@@ -98,7 +98,8 @@ class Mode:
98
98
  c.model.select_current()
99
99
 
100
100
  # set status: ready
101
- w.update_status(trans('status.started'))
101
+ if not c.reloading:
102
+ w.update_status(trans('status.started'))
102
103
 
103
104
  # if assistant mode then update ctx label
104
105
  if mode == "assistant":
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.16 00:00:00 #
9
+ # Updated Date: 2025.08.20 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -16,6 +16,7 @@ from typing import Optional, Dict, Any
16
16
  from PySide6.QtCore import Slot, QTimer
17
17
  from PySide6.QtGui import QAction
18
18
 
19
+ from pygpt_net.core.types import MODE_CHAT
19
20
  from pygpt_net.utils import trans
20
21
 
21
22
 
@@ -52,7 +53,8 @@ class Profile:
52
53
  self,
53
54
  uuid: str,
54
55
  force: bool = False,
55
- save_current: bool = True
56
+ save_current: bool = True,
57
+ on_finish: Optional[callable] = None
56
58
  ):
57
59
  """
58
60
  Switch profile
@@ -60,6 +62,7 @@ class Profile:
60
62
  :param uuid: Profile UUID
61
63
  :param force: Force switch
62
64
  :param save_current: Save current profile
65
+ :param on_finish: Callback function to call after switch
63
66
  """
64
67
  current = self.window.core.config.profile.get_current()
65
68
  if uuid == current and not force:
@@ -103,6 +106,7 @@ class Profile:
103
106
  self.update_list()
104
107
  self.window.ui.update_title()
105
108
  self.window.update_status(trans("dialog.profile.status.changed") + ": " + name)
109
+ self.window.ui.dialogs.close('profile.item')
106
110
  self.select_current_on_list()
107
111
 
108
112
  def select_current_on_list(self):
@@ -291,10 +295,19 @@ class Profile:
291
295
 
292
296
  :param uuid: profile UUID
293
297
  """
294
- self.switch(uuid, force=True)
298
+ self.switch(uuid, force=True, on_finish=self.after_create_finish)
299
+
300
+ def after_create_finish(self, uuid: str):
301
+ """
302
+ After profile creation
303
+
304
+ :param uuid: profile UUID
305
+ """
295
306
  self.window.ui.dialogs.close('profile.item')
296
307
  self.update_menu()
297
308
  self.update_list()
309
+ self.window.ui.update_title()
310
+ self.window.controller.mode.select(MODE_CHAT)
298
311
 
299
312
  def dismiss_update(self):
300
313
  """Dismiss update dialog"""
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.11 14:00:00 #
9
+ # Updated Date: 2025.08.20 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -16,6 +16,7 @@ from typing import Optional
16
16
  from uuid import uuid4
17
17
 
18
18
  from PySide6.QtCore import QObject, QRunnable, Signal, Slot
19
+ from PySide6.QtWidgets import QApplication
19
20
 
20
21
  from pygpt_net.utils import trans
21
22
 
@@ -32,7 +33,7 @@ class WorkerSignals(QObject):
32
33
  updateStatus = Signal(str) # update status in dialog
33
34
  updateGlobalStatus = Signal(str) # update global status
34
35
  alert = Signal(object) # dialog alert
35
- reload = Signal() # on reload components (e.g. after workdir change)
36
+ after_migrate = Signal(bool, str, str, str) # result, profile_name, current_path, new_path
36
37
  confirm = Signal(str, str, str) # confirm dialog (action, path, message)
37
38
  restored = Signal(str) # after restoring workdir
38
39
  updated = Signal(str) # after updating workdir
@@ -68,12 +69,8 @@ class WorkdirWorker(QRunnable):
68
69
  @Slot()
69
70
  def run(self):
70
71
  try:
71
- if self.action == "update":
72
- self.worker_update()
73
- elif self.action == "migrate":
72
+ if self.action == "migrate":
74
73
  self.worker_migrate()
75
- elif self.action == "restore":
76
- self.worker_restore()
77
74
  elif self.action == "delete":
78
75
  self.worker_delete_files()
79
76
  elif self.action == "duplicate":
@@ -116,7 +113,7 @@ class WorkdirWorker(QRunnable):
116
113
  if not os.path.exists(path) or not os.path.isdir(path):
117
114
  self.signals.alert.emit(trans("dialog.profile.alert.path.not_exists"))
118
115
  return
119
- print("Clearing workdir: ", path)
116
+ print(f"Clearing workdir: {path}")
120
117
  self.window.core.filesystem.clear_workdir(
121
118
  path,
122
119
  remove_db=remove_db,
@@ -149,7 +146,7 @@ class WorkdirWorker(QRunnable):
149
146
  # copy files from workdir
150
147
  path_from = profile['workdir'].replace("%HOME%", str(Path.home()))
151
148
  path_to = new_path
152
- print("Copying all files from {} to: {}".format(path_from, path_to))
149
+ print(f"Copying all files from {path_from} to: {path_to}")
153
150
  self.signals.updateGlobalStatus.emit("Copying files...")
154
151
  result = self.window.core.filesystem.copy_workdir(
155
152
  path_from,
@@ -175,7 +172,7 @@ class WorkdirWorker(QRunnable):
175
172
  profile = profiles[uuid]
176
173
  path = profile['workdir'].replace("%HOME%", str(Path.home()))
177
174
  if not os.path.exists(path) or not os.path.isdir(path):
178
- self.signals.alert.emit("Directory not exists!")
175
+ self.signals.alert.emit(f"Directory not exists: {path}")
179
176
  return
180
177
  print("Clearing workdir: ", path)
181
178
  self.window.core.db.close()
@@ -186,53 +183,7 @@ class WorkdirWorker(QRunnable):
186
183
  )
187
184
  if uuid == current:
188
185
  self.signals.switch.emit(uuid) # switch to profile
189
- self.signals.updateGlobalStatus.emit("Profile cleared: " + profile['name'])
190
-
191
- def worker_update(self):
192
- """Switch working directory to the existing one"""
193
- print("\n====================")
194
- print("Changing workdir to: ", self.path)
195
- print("====================\n")
196
- current_path = self.window.core.config.get_user_path()
197
- default_path = self.window.core.config.get_base_workdir()
198
-
199
- if self.force:
200
- self.signals.updateStatus.emit(trans("dialog.workdir.result.wait"))
201
-
202
- lock_file = os.path.join(default_path, 'path.cfg') # put "path.cfg"
203
- lock_path = self.path.replace(str(Path.home()), "%HOME%")
204
- if self.path == default_path:
205
- lock_path = "" # set empty if default dir
206
- with open(lock_file, 'w', encoding='utf-8') as f:
207
- f.write(lock_path)
208
-
209
- # update path in current profile
210
- self.window.core.config.profile.update_current_workdir(self.path)
211
-
212
- # reload config
213
- self.window.core.config.set_workdir(self.path, reload=True)
214
- self.window.core.config.set('license.accepted', True) # accept license to prevent show dialog again
215
-
216
- # reload components
217
- if self.force:
218
- try:
219
- self.signals.reload.emit()
220
- success_msg = trans("dialog.workdir.result.success").format(path=self.path)
221
- self.signals.updateStatus.emit(success_msg)
222
- self.signals.alert.emit(success_msg)
223
- except Exception as e:
224
- self.window.core.debug.log(e)
225
- self.signals.alert.emit(str(e))
226
- print("Error reloading components: ", e)
227
- self.worker_restore(custom_current=current_path)
228
- self.window.controller.reloading = False # unlock
229
- else:
230
- # always reload
231
- self.signals.reload.emit()
232
-
233
- # update profile after workdir change
234
- if self.profile_name:
235
- self.signals.updated.emit(self.profile_name)
186
+ self.signals.updateGlobalStatus.emit(f"Profile cleared: {profile['name']}")
236
187
 
237
188
  def worker_migrate(self):
238
189
  """Migrate working directory"""
@@ -267,7 +218,7 @@ class WorkdirWorker(QRunnable):
267
218
 
268
219
  self.signals.hideStatus.emit()
269
220
  self.window.controller.settings.workdir.busy = True
270
- print("Migrating workdir from: ", current, " to: ", self.path)
221
+ print(f"Migrating workdir from: {current} to: {self.path}...")
271
222
 
272
223
  # check if path exists
273
224
  if not os.path.exists(self.path) or not os.path.isdir(self.path):
@@ -289,6 +240,8 @@ class WorkdirWorker(QRunnable):
289
240
  return
290
241
 
291
242
  # copy workdir
243
+ self.signals.updateGlobalStatus.emit(trans("dialog.workdir.result.wait"))
244
+ QApplication.processEvents() # process events to update UI
292
245
  try:
293
246
  result = self.window.core.filesystem.copy_workdir(current, self.path)
294
247
  except Exception as e:
@@ -297,46 +250,28 @@ class WorkdirWorker(QRunnable):
297
250
  print("Error migrating workdir: ", e)
298
251
  result = False
299
252
 
300
- if result:
301
- try:
302
- # remove old workdir
303
- self.window.core.debug.info("Clearing old workdir: {}".format(current))
304
- try:
305
- # allow errors here
306
- self.window.core.filesystem.clear_workdir(current)
307
- except Exception as e:
308
- self.window.core.debug.log(e)
309
- print("Error clearing old workdir: ", e)
253
+ # reload UI, config, etc.
254
+ self.signals.after_migrate.emit(result, self.profile_name, current, self.path)
310
255
 
311
- # update workdir to new path
312
- self.worker_update()
313
- success_msg = trans("dialog.workdir.result.success").format(path=self.path)
314
- print(success_msg)
315
- self.signals.updateStatus.emit(success_msg)
316
- self.signals.alert.emit(success_msg)
317
- except Exception as e:
318
- self.window.core.debug.log(e)
319
- self.signals.alert.emit(str(e))
320
- print("Error migrating workdir: ", e)
321
- self.worker_restore(custom_current=current)
322
- self.window.controller.reloading = False
323
- else:
324
- self.signals.updateStatus.emit(trans("dialog.workdir.result.failed"))
325
- self.signals.alert.emit(trans("dialog.workdir.result.failed"))
326
- self.worker_restore(custom_current=current)
327
- self.window.controller.reloading = False
328
256
 
329
- self.window.controller.settings.workdir.busy = False
330
- self.window.core.debug.info("Finished migrating workdir from: {} to: {}".format(current, self.path))
257
+ class Workdir:
258
+ def __init__(self, window=None):
259
+ """
260
+ Workdir controller
331
261
 
332
- def worker_restore(self, custom_current: str = None):
262
+ :param window: window instance
333
263
  """
334
- Restore default working directory
264
+ self.window = window
265
+ self.is_dialog = False
266
+ self.busy = False
267
+
268
+ def rollback(self, current: str = None):
269
+ """
270
+ Rollback to the previous working directory
335
271
 
336
- :param custom_current: custom current working directory (optional)
272
+ :param current: current working directory (optional)
337
273
  """
338
- current = custom_current if custom_current is not None else self.current
339
- print("Reverting workdir to: ", current)
274
+ print(f"Reverting workdir to: {current}...")
340
275
  self.window.core.config.set_workdir(current, reload=True)
341
276
  default_path = self.window.core.config.get_base_workdir()
342
277
  lock_file = os.path.join(default_path, 'path.cfg')
@@ -345,23 +280,151 @@ class WorkdirWorker(QRunnable):
345
280
  lock_path = ""
346
281
  with open(lock_file, 'w', encoding='utf-8') as f:
347
282
  f.write(lock_path)
348
- self.signals.restored.emit(current)
349
- self.signals.updateStatus.emit("Failed. Reverted to current workdir: {}".format(current))
350
- self.signals.reload.emit()
283
+ self.window.ui.dialogs.workdir.set_path(current)
284
+ self.window.ui.dialogs.workdir.show_status(f"Failed. Reverted to previous workdir: {current}.")
285
+ self.window.controller.reload()
351
286
  self.window.core.config.profile.update_current_workdir(current)
352
287
 
288
+ def update_workdir(
289
+ self,
290
+ force: bool = False,
291
+ path: str = None
292
+ ):
293
+ """
294
+ Update working directory
353
295
 
354
- class Workdir:
355
- def __init__(self, window=None):
296
+ :param force: boolean indicating if update should be forced (confirm)
297
+ :param path: new working directory to set
356
298
  """
357
- Workdir controller
299
+ print("\n====================")
300
+ print(f"Changing workdir to: {path}")
301
+ print("====================\n")
302
+ default_path = self.window.core.config.get_base_workdir()
303
+ if force:
304
+ self.window.ui.dialogs.workdir.show_status(trans("dialog.workdir.result.wait"))
358
305
 
359
- :param window: window instance
306
+ lock_file = os.path.join(default_path, 'path.cfg') # put "path.cfg"
307
+ lock_path = path.replace(str(Path.home()), "%HOME%")
308
+ if path == default_path:
309
+ lock_path = "" # set empty if default dir
310
+ with open(lock_file, 'w', encoding='utf-8') as f:
311
+ f.write(lock_path)
312
+
313
+ # update path in current profile
314
+ self.window.core.config.profile.update_current_workdir(path)
315
+
316
+ # reload config
317
+ self.window.core.config.set_workdir(path, reload=True)
318
+ self.window.core.config.set('license.accepted', True) # accept license to prevent show dialog again
319
+
320
+ @Slot(bool, str, str, str)
321
+ def do_update(
322
+ self,
323
+ force: bool,
324
+ profile_name: str,
325
+ current_path: str,
326
+ new_path: str
327
+ ) -> bool:
360
328
  """
361
- self.window = window
362
- self.is_dialog = False
363
- self.busy = False
364
- self.worker = None
329
+ Update working directory
330
+
331
+ :param force: boolean indicating if update should be forced (confirm)
332
+ :param profile_name: profile name to update after workdir change
333
+ :param current_path: current working directory before update
334
+ :param new_path: new working directory to set
335
+ :return: boolean indicating if update was successful
336
+ """
337
+ self.update_workdir(
338
+ force=force,
339
+ path=new_path,
340
+ )
341
+ rollback = False
342
+ success = False
343
+ if force:
344
+ try:
345
+ self.window.ui.dialogs.workdir.show_status(trans("dialog.workdir.result.wait"))
346
+ self.window.controller.reload()
347
+ self.window.ui.dialogs.workdir.show_status(trans("dialog.workdir.result.wait"))
348
+ msg = trans("dialog.workdir.result.success").format(path=new_path)
349
+ self.window.ui.dialogs.workdir.show_status(msg)
350
+ self.window.ui.dialogs.alert(msg)
351
+ success = True
352
+ except Exception as e:
353
+ rollback = True
354
+ self.window.core.debug.log(e)
355
+ self.window.ui.dialogs.alert(str(e))
356
+ print("Error reloading components: ", e)
357
+ self.window.controller.reloading = False # unlock
358
+ else:
359
+ self.window.controller.reload() # reload only
360
+
361
+ if rollback: # if failed
362
+ self.rollback(current=current_path) # revert to previous workdir
363
+ else:
364
+ # update profile after workdir change
365
+ if profile_name:
366
+ self.window.controller.settings.profile.after_update(profile_name)
367
+ return success
368
+
369
+ @Slot(bool, str, str, str)
370
+ def do_migrate(
371
+ self,
372
+ result: bool,
373
+ profile_name: str,
374
+ current_path: str,
375
+ new_path: str
376
+ ) -> bool:
377
+ """
378
+ Handle migration result
379
+
380
+ :param result: boolean indicating if migration was successful
381
+ :param profile_name: profile name to update after migration
382
+ :param current_path: current working directory before migration
383
+ :param new_path: new working directory after migration
384
+ :return: boolean indicating if migration was successful
385
+ """
386
+ success = False
387
+ if result:
388
+ try:
389
+ # update workdir to new path
390
+ success = self.do_update(
391
+ force=True,
392
+ profile_name=profile_name,
393
+ current_path=current_path,
394
+ new_path=new_path,
395
+ ) # with rollback if failed
396
+
397
+ if not success:
398
+ raise Exception("Migration failed, workdir not updated.")
399
+
400
+ msg = trans("dialog.workdir.result.success").format(path=new_path)
401
+ self.window.ui.dialogs.workdir.show_status(msg)
402
+ self.window.ui.dialogs.alert(msg)
403
+
404
+ # remove old workdir only if success
405
+ self.window.core.debug.info(f"Clearing old workdir: {current_path}...")
406
+ try:
407
+ self.window.core.filesystem.clear_workdir(current_path) # allow errors here
408
+ self.window.core.debug.info(f"Old workdir cleared: {current_path}.")
409
+ except Exception as e:
410
+ self.window.core.debug.log(e)
411
+ print("Error clearing old workdir: ", e)
412
+
413
+ except Exception as e:
414
+ self.window.core.debug.log(e)
415
+ self.window.ui.dialogs.alert(str(e))
416
+ print("Error migrating workdir: ", e)
417
+ self.window.controller.reloading = False
418
+ else:
419
+ # if migration failed
420
+ self.window.ui.dialogs.workdir.show_status(trans("dialog.workdir.result.failed"))
421
+ self.window.ui.dialogs.alert(trans("dialog.workdir.result.failed"))
422
+ self.window.controller.reloading = False
423
+
424
+ self.window.controller.settings.workdir.busy = False
425
+ if success:
426
+ self.window.core.debug.info(f"Finished migrating workdir from: {current_path} to: {new_path}.")
427
+ return success
365
428
 
366
429
  def change(self):
367
430
  """Change working directory (open dialog)"""
@@ -402,7 +465,7 @@ class Workdir:
402
465
  :param profile_new_name: new profile name (optional, for duplicate action)
403
466
  :param profile_new_path: new profile path (optional, for duplicate action)
404
467
  """
405
- self.worker = WorkdirWorker(
468
+ worker = WorkdirWorker(
406
469
  window=self.window,
407
470
  action=action,
408
471
  path=path,
@@ -415,21 +478,21 @@ class Workdir:
415
478
  )
416
479
 
417
480
  # connect signals
418
- self.worker.signals.updateGlobalStatus.connect(self.window.update_status)
419
- self.worker.signals.updateStatus.connect(self.window.ui.dialogs.workdir.show_status)
420
- self.worker.signals.hideStatus.connect(self.window.ui.dialogs.workdir.hide_status)
421
- self.worker.signals.alert.connect(self.window.ui.dialogs.alert)
422
- self.worker.signals.reload.connect(self.window.controller.reload)
423
- self.worker.signals.error.connect(lambda err: self.window.core.debug.log(f"Worker error: {err}"))
424
- self.worker.signals.confirm.connect(self.window.ui.dialogs.confirm)
425
- self.worker.signals.restored.connect(lambda current: self.window.ui.dialogs.workdir.set_path(current))
426
- self.worker.signals.updated.connect(self.window.controller.settings.profile.after_update)
427
- self.worker.signals.deleted.connect(self.window.controller.settings.profile.after_delete)
428
- self.worker.signals.duplicated.connect(self.window.controller.settings.profile.after_duplicate)
429
- self.worker.signals.switch.connect(self.window.controller.settings.profile.switch_current)
481
+ worker.signals.updateGlobalStatus.connect(self.window.update_status)
482
+ worker.signals.updateStatus.connect(self.window.ui.dialogs.workdir.show_status)
483
+ worker.signals.hideStatus.connect(self.window.ui.dialogs.workdir.hide_status)
484
+ worker.signals.alert.connect(self.window.ui.dialogs.alert)
485
+ worker.signals.error.connect(lambda err: self.window.core.debug.log(f"Worker error: {err}"))
486
+ worker.signals.confirm.connect(self.window.ui.dialogs.confirm)
487
+ worker.signals.restored.connect(lambda current: self.window.ui.dialogs.workdir.set_path(current))
488
+ worker.signals.updated.connect(self.window.controller.settings.profile.after_update)
489
+ worker.signals.deleted.connect(self.window.controller.settings.profile.after_delete)
490
+ worker.signals.duplicated.connect(self.window.controller.settings.profile.after_duplicate)
491
+ worker.signals.switch.connect(self.window.controller.settings.profile.switch_current)
492
+ worker.signals.after_migrate.connect(self.do_migrate)
430
493
 
431
494
  # start worker in thread pool
432
- self.window.threadpool.start(self.worker)
495
+ self.window.threadpool.start(worker)
433
496
 
434
497
  def update(
435
498
  self,
@@ -444,11 +507,11 @@ class Workdir:
444
507
  :param force: force update (confirm)
445
508
  :param profile_name: profile name (optional, for future use)
446
509
  """
447
- self.run_action(
448
- action="update",
449
- path=path,
510
+ self.do_update(
450
511
  force=force,
451
512
  profile_name=profile_name,
513
+ current_path=self.window.core.config.get_user_path(),
514
+ new_path=path,
452
515
  )
453
516
 
454
517
  def migrate(
@@ -477,10 +540,7 @@ class Workdir:
477
540
 
478
541
  :param current: current working directory
479
542
  """
480
- self.run_action(
481
- action="restore",
482
- current=current,
483
- )
543
+ self.rollback(current=current)
484
544
 
485
545
  def delete_files(
486
546
  self,
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.15 03:00:00 #
9
+ # Updated Date: 2025.08.20 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -248,8 +248,14 @@ class Theme:
248
248
  """
249
249
  return self.common.get_style(element)
250
250
 
251
- def reload_all(self):
252
- """Reload all"""
253
- self.setup()
254
- self.update_style()
251
+ def reload_all(self, prev_theme: Optional[str] = None):
252
+ """
253
+ Reload all
254
+
255
+ :param prev_theme: previous theme name
256
+ """
257
+ current_theme = self.window.core.config.get('theme')
258
+ if not prev_theme or prev_theme != current_theme:
259
+ self.setup()
260
+ self.update_style()
255
261
  self.update_syntax()
@@ -240,8 +240,6 @@ class LlamaWorkflow(BaseRunner):
240
240
  item_ctx.output = "" # empty to prevent render
241
241
  item_ctx.stream = "" # for stream
242
242
 
243
- print("RUN AGENT!!!!!!!!!!!!!!!!!!!!")
244
-
245
243
  async for event in handler.stream_events():
246
244
  if self.is_stopped():
247
245
  # persist current output on stop