pygpt-net 2.6.15__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.
Files changed (57) hide show
  1. pygpt_net/CHANGELOG.txt +12 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/controller/__init__.py +8 -2
  4. pygpt_net/controller/chat/command.py +18 -6
  5. pygpt_net/controller/ctx/ctx.py +2 -2
  6. pygpt_net/controller/mode/mode.py +3 -2
  7. pygpt_net/controller/plugins/plugins.py +31 -15
  8. pygpt_net/controller/presets/editor.py +11 -32
  9. pygpt_net/controller/settings/profile.py +16 -3
  10. pygpt_net/controller/settings/workdir.py +184 -124
  11. pygpt_net/controller/theme/theme.py +11 -5
  12. pygpt_net/core/agents/observer/evaluation.py +3 -14
  13. pygpt_net/core/agents/runners/llama_workflow.py +7 -6
  14. pygpt_net/core/command/command.py +5 -3
  15. pygpt_net/core/experts/experts.py +58 -13
  16. pygpt_net/core/plugins/plugins.py +12 -1
  17. pygpt_net/core/render/plain/body.py +10 -19
  18. pygpt_net/core/render/plain/renderer.py +27 -27
  19. pygpt_net/data/config/config.json +6 -6
  20. pygpt_net/data/config/models.json +3 -3
  21. pygpt_net/data/locale/locale.en.ini +2 -2
  22. pygpt_net/data/locale/plugin.openai_dalle.de.ini +1 -1
  23. pygpt_net/data/locale/plugin.openai_dalle.en.ini +1 -1
  24. pygpt_net/data/locale/plugin.openai_dalle.es.ini +1 -1
  25. pygpt_net/data/locale/plugin.openai_dalle.fr.ini +1 -1
  26. pygpt_net/data/locale/plugin.openai_dalle.it.ini +1 -1
  27. pygpt_net/data/locale/plugin.openai_dalle.pl.ini +1 -1
  28. pygpt_net/data/locale/plugin.openai_dalle.uk.ini +1 -1
  29. pygpt_net/data/locale/plugin.openai_dalle.zh.ini +1 -1
  30. pygpt_net/data/locale/plugin.openai_vision.de.ini +1 -1
  31. pygpt_net/data/locale/plugin.openai_vision.en.ini +1 -1
  32. pygpt_net/data/locale/plugin.openai_vision.es.ini +1 -1
  33. pygpt_net/data/locale/plugin.openai_vision.fr.ini +1 -1
  34. pygpt_net/data/locale/plugin.openai_vision.it.ini +1 -1
  35. pygpt_net/data/locale/plugin.openai_vision.pl.ini +1 -1
  36. pygpt_net/data/locale/plugin.openai_vision.uk.ini +1 -1
  37. pygpt_net/data/locale/plugin.openai_vision.zh.ini +1 -1
  38. pygpt_net/item/ctx.py +5 -4
  39. pygpt_net/plugin/idx_llama_index/plugin.py +9 -5
  40. pygpt_net/plugin/idx_llama_index/worker.py +5 -2
  41. pygpt_net/plugin/openai_dalle/plugin.py +1 -1
  42. pygpt_net/tools/translator/ui/dialogs.py +1 -0
  43. pygpt_net/tools/translator/ui/widgets.py +1 -2
  44. pygpt_net/ui/__init__.py +12 -10
  45. pygpt_net/ui/base/config_dialog.py +15 -10
  46. pygpt_net/ui/dialog/about.py +26 -18
  47. pygpt_net/ui/dialog/plugins.py +6 -4
  48. pygpt_net/ui/dialog/settings.py +75 -87
  49. pygpt_net/ui/dialog/workdir.py +7 -2
  50. pygpt_net/ui/main.py +5 -1
  51. pygpt_net/ui/widget/textarea/editor.py +1 -2
  52. pygpt_net/ui/widget/textarea/web.py +22 -16
  53. {pygpt_net-2.6.15.dist-info → pygpt_net-2.6.17.dist-info}/METADATA +26 -14
  54. {pygpt_net-2.6.15.dist-info → pygpt_net-2.6.17.dist-info}/RECORD +57 -57
  55. {pygpt_net-2.6.15.dist-info → pygpt_net-2.6.17.dist-info}/LICENSE +0 -0
  56. {pygpt_net-2.6.15.dist-info → pygpt_net-2.6.17.dist-info}/WHEEL +0 -0
  57. {pygpt_net-2.6.15.dist-info → pygpt_net-2.6.17.dist-info}/entry_points.txt +0 -0
pygpt_net/CHANGELOG.txt CHANGED
@@ -1,3 +1,15 @@
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
+
7
+ 2.6.16 (2025-08-20)
8
+
9
+ - Fixed: Attachment string joining.
10
+ - Improved expert function calls.
11
+ - Added sorting to the plugin list.
12
+
1
13
  2.6.15 (2025-08-20)
2
14
 
3
15
  - Added: do not change the context menu font size in text editing.
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.15"
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.")
@@ -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.18 01:00:00 #
9
+ # Updated Date: 2025.08.20 09:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -88,6 +88,10 @@ class Command:
88
88
  else:
89
89
  reply.type = ReplyContext.CMD_EXECUTE_INLINE
90
90
 
91
+ # force call (experts, internal, etc.)
92
+ if internal and ctx.force_call:
93
+ reply.type = ReplyContext.CMD_EXECUTE
94
+
91
95
  data = {
92
96
  "meta": ctx.meta,
93
97
  }
@@ -101,10 +105,19 @@ class Command:
101
105
  if internal:
102
106
  ctx.agent_call = True
103
107
  if reply.type == ReplyContext.CMD_EXECUTE:
104
- self.window.controller.plugins.apply_cmds(
105
- reply.ctx,
106
- reply.cmds,
107
- )
108
+ if ctx.force_call:
109
+ # force call, execute all commands
110
+ self.window.controller.plugins.apply_cmds(
111
+ reply.ctx,
112
+ reply.cmds,
113
+ all=True,
114
+ execute_only=True,
115
+ )
116
+ else:
117
+ self.window.controller.plugins.apply_cmds(
118
+ reply.ctx,
119
+ reply.cmds,
120
+ )
108
121
  elif reply.type == ReplyContext.CMD_EXECUTE_INLINE:
109
122
  self.window.controller.plugins.apply_cmds_inline(
110
123
  reply.ctx,
@@ -114,7 +127,6 @@ class Command:
114
127
  else:
115
128
  # force call
116
129
  if ctx.force_call:
117
- #ctx.agent_call = True
118
130
  self.window.controller.plugins.apply_cmds(
119
131
  reply.ctx,
120
132
  reply.cmds,
@@ -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":
@@ -9,7 +9,7 @@
9
9
  # Updated Date: 2025.08.15 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
- from typing import List, Dict, Any
12
+ from typing import List, Dict, Any, Optional
13
13
 
14
14
  from PySide6.QtGui import QAction
15
15
 
@@ -37,9 +37,11 @@ class Plugins:
37
37
  self._suspend_updates = 0
38
38
 
39
39
  def _begin_batch(self):
40
+ """Begin batch updates"""
40
41
  self._suspend_updates += 1
41
42
 
42
43
  def _end_batch(self):
44
+ """End batch updates"""
43
45
  if self._suspend_updates > 0:
44
46
  self._suspend_updates -= 1
45
47
  if self._suspend_updates == 0:
@@ -85,7 +87,7 @@ class Plugins:
85
87
  pm = self.window.core.plugins
86
88
  ui_menu = self.window.ui.menu
87
89
  menu_plugins = ui_menu['plugins']
88
- for pid in pm.get_ids():
90
+ for pid in pm.get_ids(sort=True):
89
91
  if pid in menu_plugins:
90
92
  continue
91
93
  name = pm.get_name(pid)
@@ -185,7 +187,6 @@ class Plugins:
185
187
 
186
188
  :param id: plugin id
187
189
  :return: True if enabled
188
- :rtype: bool
189
190
  """
190
191
  return self.window.core.plugins.is_registered(id) and self.enabled.get(id, False)
191
192
 
@@ -213,7 +214,7 @@ class Plugins:
213
214
  """
214
215
  pm = self.window.core.plugins
215
216
  plugin_idx = 0
216
- for pid in pm.get_ids():
217
+ for pid in pm.get_ids(sort=True):
217
218
  if pm.has_options(pid):
218
219
  if plugin_idx == idx:
219
220
  self.settings.current_plugin = pid
@@ -222,15 +223,15 @@ class Plugins:
222
223
  current = self.window.ui.models['plugin.list'].index(idx, 0)
223
224
  self.window.ui.nodes['plugin.list'].setCurrentIndex(current)
224
225
 
225
- def get_tab_idx(self, plugin_id: str) -> int:
226
+ def get_tab_idx(self, plugin_id: str) -> Optional[int]:
226
227
  """
227
228
  Get plugin tab index
228
229
 
229
230
  :param plugin_id: plugin id
230
- :return: tab index
231
+ :return: tab index or None if not found
231
232
  """
232
233
  pm = self.window.core.plugins
233
- for i, pid in enumerate(pm.get_ids()):
234
+ for i, pid in enumerate(pm.get_ids(sort=True)):
234
235
  if pid == plugin_id:
235
236
  return i
236
237
  return None
@@ -262,6 +263,7 @@ class Plugins:
262
263
  def has_type(self, id: str, type: str):
263
264
  """
264
265
  Check if plugin has type
266
+
265
267
  :param id: plugin ID
266
268
  :param type: type to check
267
269
  :return: True if has type
@@ -342,7 +344,19 @@ class Plugins:
342
344
  cmds: List[Dict[str, Any]],
343
345
  all: bool = False,
344
346
  execute_only: bool = False
345
- ):
347
+ ) -> Optional[List[Any]]:
348
+ """
349
+ Common method to apply commands
350
+
351
+ This method is used for both inline and non-inline commands.
352
+
353
+ :param event_type: name of the event type, either Event.CMD_EXECUTE or Event.CMD_INLINE
354
+ :param ctx: CtxItem
355
+ :param cmds: commands list, each command is a dictionary with keys like "cmd", "args", etc.
356
+ :param all: True to apply all commands, False to apply only enabled commands
357
+ :param execute_only: True to execute commands only, without any additional event
358
+ :return: results: results of the command execution, if any (ctx.results)
359
+ """
346
360
  commands = self.window.core.command.from_commands(cmds)
347
361
  if len(commands) == 0:
348
362
  return
@@ -375,14 +389,15 @@ class Plugins:
375
389
  cmds: List[Dict[str, Any]],
376
390
  all: bool = False,
377
391
  execute_only: bool = False
378
- ):
392
+ ) -> Optional[List[Any]]:
379
393
  """
380
- Apply commands
394
+ Apply commands (CMD_EXECUTE event only)
381
395
 
382
396
  :param ctx: CtxItem
383
397
  :param cmds: commands list
384
398
  :param all: True to apply all commands, False to apply only enabled commands
385
399
  :param execute_only: True to execute commands only, without any additional event
400
+ :return: results: results of the command execution, if any (ctx.results)
386
401
  """
387
402
  return self._apply_cmds_common(Event.CMD_EXECUTE, ctx, cmds, all=all, execute_only=execute_only)
388
403
 
@@ -390,13 +405,13 @@ class Plugins:
390
405
  self,
391
406
  ctx: CtxItem,
392
407
  cmds: List[Dict[str, Any]]
393
- ):
408
+ ) -> Optional[List[Any]]:
394
409
  """
395
410
  Apply all commands (inline or not)
396
411
 
397
- :param ctx: context
398
- :param cmds: commands
399
- :return: results
412
+ :param ctx: CtxItem
413
+ :param cmds: commands list
414
+ :return: results: results of the command execution, if any (ctx.results)
400
415
  """
401
416
  if self.window.core.config.get("cmd"):
402
417
  return self.apply_cmds(ctx, cmds)
@@ -408,12 +423,13 @@ class Plugins:
408
423
  self,
409
424
  ctx: CtxItem,
410
425
  cmds: List[Dict[str, Any]]
411
- ):
426
+ ) -> Optional[List[Any]]:
412
427
  """
413
428
  Apply inline commands
414
429
 
415
430
  :param ctx: CtxItem
416
431
  :param cmds: commands list
432
+ :return: results: results of the command execution, if any (ctx.results)
417
433
  """
418
434
  return self._apply_cmds_common(Event.CMD_INLINE, ctx, cmds)
419
435
 
@@ -258,11 +258,7 @@ class Editor:
258
258
  self.window.ui.add_hook("update.preset.agent_provider_openai", self.hook_update)
259
259
 
260
260
  def toggle_extra_options(self):
261
- """
262
- Toggle extra options in preset editor
263
-
264
- :return: None
265
- """
261
+ """Toggle extra options in preset editor"""
266
262
  if not self.tab_options_idx:
267
263
  return
268
264
  mode = self.window.core.config.get('mode')
@@ -285,11 +281,7 @@ class Editor:
285
281
  self.toggle_extra_options_by_provider()
286
282
 
287
283
  def toggle_extra_options_by_provider(self):
288
- """
289
- Toggle extra options in preset editor by provider
290
-
291
- :return: None
292
- """
284
+ """Toggle extra options in preset editor by provider"""
293
285
  if not self.tab_options_idx:
294
286
  # show base prompt
295
287
  self.window.ui.tabs['preset.editor.extra'].setTabVisible(0, True)
@@ -398,11 +390,7 @@ class Editor:
398
390
  )
399
391
 
400
392
  def load_extra_defaults(self):
401
- """
402
- Load extra options defaults for preset editor
403
-
404
- :return: None
405
- """
393
+ """Load extra options defaults for preset editor"""
406
394
  if not self.tab_options_idx:
407
395
  return
408
396
  mode = self.window.core.config.get('mode')
@@ -431,11 +419,7 @@ class Editor:
431
419
  )
432
420
 
433
421
  def load_extra_defaults_current(self):
434
- """
435
- Load extra options defaults on mode change
436
-
437
- :return: None
438
- """
422
+ """Load extra options defaults on mode change"""
439
423
  if not self.tab_options_idx:
440
424
  return
441
425
 
@@ -491,9 +475,8 @@ class Editor:
491
475
 
492
476
  def append_extra_options(self, preset: PresetItem):
493
477
  """
494
- Get extra options for preset editor
478
+ Append extra options for preset editor
495
479
 
496
- :param id: preset id
497
480
  :param preset: preset item
498
481
  """
499
482
  mode = self.window.core.config.get('mode')
@@ -536,9 +519,7 @@ class Editor:
536
519
  preset.extra[id] = data_dict
537
520
 
538
521
  def append_extra_config(self):
539
- """
540
- Build extra configuration for the preset editor dialog
541
- """
522
+ """Build extra configuration for the preset editor dialog"""
542
523
  if self.built:
543
524
  return
544
525
 
@@ -592,11 +573,7 @@ class Editor:
592
573
  self.built = True
593
574
 
594
575
  def append_default_prompt(self):
595
- """
596
- Append default prompt to the preset editor
597
-
598
- :return: None
599
- """
576
+ """Append default prompt to the preset editor"""
600
577
  mode = self.window.core.config.get('mode')
601
578
  if mode not in [MODE_AGENT_OPENAI, MODE_AGENT_LLAMA]:
602
579
  return
@@ -691,6 +668,7 @@ class Editor:
691
668
 
692
669
  if id is None:
693
670
  self.experts.update_list()
671
+ self.window.ui.config[self.id]['idx'].set_value("_") # reset idx combo if new preset
694
672
 
695
673
  if id is not None and id != "":
696
674
  if id in self.window.core.presets.items:
@@ -769,6 +747,7 @@ class Editor:
769
747
 
770
748
  # set focus to name field
771
749
  current_model = self.window.core.config.get('model')
750
+
772
751
  # set current model in combo box as selected
773
752
  if id is None:
774
753
  self.window.ui.config[self.id]['model'].set_value(current_model)
@@ -784,7 +763,7 @@ class Editor:
784
763
  close: bool = True
785
764
  ):
786
765
  """
787
- Save ore create preset
766
+ Save preset
788
767
 
789
768
  :param force: force overwrite file
790
769
  :param close: close dialog
@@ -900,7 +879,7 @@ class Editor:
900
879
  if not is_new:
901
880
  no_scroll = True
902
881
  self.window.core.presets.save(id)
903
- self.window.controller.presets.refresh()
882
+ self.window.controller.presets.refresh(no_scroll=no_scroll)
904
883
 
905
884
  # close dialog
906
885
  if close:
@@ -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"""