pygpt-net 2.6.20__py3-none-any.whl → 2.6.22__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 (221) hide show
  1. pygpt_net/CHANGELOG.txt +13 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/app.py +3 -1
  4. pygpt_net/controller/__init__.py +4 -8
  5. pygpt_net/controller/access/voice.py +2 -2
  6. pygpt_net/controller/agent/agent.py +130 -2
  7. pygpt_net/controller/agent/experts.py +93 -96
  8. pygpt_net/controller/agent/llama.py +2 -1
  9. pygpt_net/controller/assistant/assistant.py +18 -1
  10. pygpt_net/controller/assistant/batch.py +2 -3
  11. pygpt_net/controller/assistant/editor.py +2 -2
  12. pygpt_net/controller/assistant/files.py +2 -3
  13. pygpt_net/controller/assistant/store.py +2 -2
  14. pygpt_net/controller/attachment/attachment.py +17 -1
  15. pygpt_net/controller/audio/audio.py +2 -2
  16. pygpt_net/controller/camera/camera.py +15 -7
  17. pygpt_net/controller/chat/chat.py +2 -2
  18. pygpt_net/controller/chat/common.py +50 -33
  19. pygpt_net/controller/chat/image.py +67 -77
  20. pygpt_net/controller/chat/input.py +94 -166
  21. pygpt_net/controller/chat/output.py +83 -140
  22. pygpt_net/controller/chat/response.py +83 -102
  23. pygpt_net/controller/chat/text.py +116 -149
  24. pygpt_net/controller/ctx/common.py +2 -1
  25. pygpt_net/controller/ctx/ctx.py +87 -6
  26. pygpt_net/controller/files/files.py +13 -1
  27. pygpt_net/controller/idx/idx.py +26 -2
  28. pygpt_net/controller/idx/indexer.py +85 -76
  29. pygpt_net/controller/kernel/reply.py +53 -66
  30. pygpt_net/controller/kernel/stack.py +16 -16
  31. pygpt_net/controller/lang/lang.py +52 -34
  32. pygpt_net/controller/model/importer.py +3 -2
  33. pygpt_net/controller/model/model.py +62 -3
  34. pygpt_net/controller/notepad/notepad.py +86 -84
  35. pygpt_net/controller/plugins/settings.py +3 -4
  36. pygpt_net/controller/settings/editor.py +4 -4
  37. pygpt_net/controller/settings/profile.py +105 -124
  38. pygpt_net/controller/theme/menu.py +154 -57
  39. pygpt_net/controller/theme/nodes.py +51 -44
  40. pygpt_net/controller/theme/theme.py +33 -9
  41. pygpt_net/controller/tools/tools.py +2 -2
  42. pygpt_net/controller/ui/tabs.py +2 -3
  43. pygpt_net/controller/ui/ui.py +16 -2
  44. pygpt_net/core/agents/observer/evaluation.py +3 -3
  45. pygpt_net/core/agents/provider.py +25 -3
  46. pygpt_net/core/agents/runner.py +4 -1
  47. pygpt_net/core/agents/runners/llama_workflow.py +19 -7
  48. pygpt_net/core/agents/runners/loop.py +3 -1
  49. pygpt_net/core/agents/runners/openai_workflow.py +17 -3
  50. pygpt_net/core/agents/tools.py +4 -1
  51. pygpt_net/core/bridge/context.py +34 -37
  52. pygpt_net/core/ctx/container.py +13 -12
  53. pygpt_net/core/ctx/ctx.py +1 -1
  54. pygpt_net/core/ctx/output.py +7 -4
  55. pygpt_net/core/db/database.py +2 -2
  56. pygpt_net/core/debug/console/console.py +2 -2
  57. pygpt_net/core/debug/debug.py +12 -1
  58. pygpt_net/core/dispatcher/dispatcher.py +24 -1
  59. pygpt_net/core/events/app.py +7 -7
  60. pygpt_net/core/events/control.py +26 -26
  61. pygpt_net/core/events/event.py +6 -3
  62. pygpt_net/core/events/kernel.py +2 -2
  63. pygpt_net/core/events/render.py +13 -13
  64. pygpt_net/core/experts/experts.py +76 -82
  65. pygpt_net/core/experts/worker.py +12 -12
  66. pygpt_net/core/filesystem/actions.py +1 -2
  67. pygpt_net/core/models/models.py +5 -1
  68. pygpt_net/core/models/ollama.py +14 -5
  69. pygpt_net/core/render/plain/helpers.py +2 -5
  70. pygpt_net/core/render/plain/renderer.py +26 -30
  71. pygpt_net/core/render/web/body.py +1 -1
  72. pygpt_net/core/render/web/helpers.py +2 -2
  73. pygpt_net/core/render/web/renderer.py +4 -4
  74. pygpt_net/core/settings/settings.py +43 -13
  75. pygpt_net/core/tabs/tabs.py +20 -13
  76. pygpt_net/core/types/__init__.py +2 -1
  77. pygpt_net/core/types/agent.py +4 -4
  78. pygpt_net/core/types/base.py +19 -0
  79. pygpt_net/core/types/console.py +6 -6
  80. pygpt_net/core/types/mode.py +8 -8
  81. pygpt_net/core/types/multimodal.py +3 -3
  82. pygpt_net/core/types/openai.py +2 -1
  83. pygpt_net/data/config/config.json +5 -5
  84. pygpt_net/data/config/models.json +19 -3
  85. pygpt_net/data/config/settings.json +14 -14
  86. pygpt_net/data/locale/locale.de.ini +4 -1
  87. pygpt_net/data/locale/locale.en.ini +6 -3
  88. pygpt_net/data/locale/locale.es.ini +4 -1
  89. pygpt_net/data/locale/locale.fr.ini +4 -1
  90. pygpt_net/data/locale/locale.it.ini +4 -1
  91. pygpt_net/data/locale/locale.pl.ini +5 -4
  92. pygpt_net/data/locale/locale.uk.ini +4 -1
  93. pygpt_net/data/locale/locale.zh.ini +4 -1
  94. pygpt_net/item/ctx.py +256 -240
  95. pygpt_net/item/model.py +59 -116
  96. pygpt_net/item/preset.py +122 -105
  97. pygpt_net/plugin/twitter/plugin.py +2 -2
  98. pygpt_net/provider/agents/llama_index/workflow/planner.py +3 -3
  99. pygpt_net/provider/agents/openai/agent.py +4 -12
  100. pygpt_net/provider/agents/openai/agent_b2b.py +10 -15
  101. pygpt_net/provider/agents/openai/agent_planner.py +4 -4
  102. pygpt_net/provider/agents/openai/agent_with_experts.py +3 -7
  103. pygpt_net/provider/agents/openai/agent_with_experts_feedback.py +4 -8
  104. pygpt_net/provider/agents/openai/agent_with_feedback.py +4 -8
  105. pygpt_net/provider/agents/openai/bot_researcher.py +2 -18
  106. pygpt_net/provider/agents/openai/bots/__init__.py +0 -0
  107. pygpt_net/provider/agents/openai/bots/research_bot/__init__.py +0 -0
  108. pygpt_net/provider/agents/openai/bots/research_bot/agents/__init__.py +0 -0
  109. pygpt_net/provider/agents/openai/bots/research_bot/agents/planner_agent.py +1 -1
  110. pygpt_net/provider/agents/openai/bots/research_bot/agents/search_agent.py +1 -0
  111. pygpt_net/provider/agents/openai/bots/research_bot/agents/writer_agent.py +1 -1
  112. pygpt_net/provider/agents/openai/bots/research_bot/manager.py +1 -10
  113. pygpt_net/provider/agents/openai/evolve.py +5 -9
  114. pygpt_net/provider/agents/openai/supervisor.py +4 -8
  115. pygpt_net/provider/core/config/patch.py +10 -3
  116. pygpt_net/provider/core/ctx/db_sqlite/utils.py +43 -43
  117. pygpt_net/provider/core/model/patch.py +11 -1
  118. pygpt_net/provider/core/preset/json_file.py +47 -49
  119. pygpt_net/provider/gpt/agents/experts.py +2 -2
  120. pygpt_net/tools/audio_transcriber/ui/dialogs.py +44 -54
  121. pygpt_net/tools/code_interpreter/body.py +1 -2
  122. pygpt_net/tools/code_interpreter/tool.py +7 -4
  123. pygpt_net/tools/code_interpreter/ui/html.py +1 -3
  124. pygpt_net/tools/code_interpreter/ui/widgets.py +2 -3
  125. pygpt_net/tools/html_canvas/ui/widgets.py +1 -3
  126. pygpt_net/tools/image_viewer/ui/dialogs.py +40 -37
  127. pygpt_net/tools/indexer/ui/widgets.py +2 -4
  128. pygpt_net/tools/media_player/tool.py +2 -5
  129. pygpt_net/tools/media_player/ui/widgets.py +60 -36
  130. pygpt_net/tools/text_editor/ui/widgets.py +18 -19
  131. pygpt_net/tools/translator/ui/widgets.py +39 -35
  132. pygpt_net/ui/base/context_menu.py +9 -4
  133. pygpt_net/ui/dialog/db.py +1 -3
  134. pygpt_net/ui/dialog/models.py +1 -3
  135. pygpt_net/ui/dialog/models_importer.py +2 -4
  136. pygpt_net/ui/dialogs.py +34 -30
  137. pygpt_net/ui/layout/chat/attachments.py +72 -84
  138. pygpt_net/ui/layout/chat/attachments_ctx.py +40 -44
  139. pygpt_net/ui/layout/chat/attachments_uploaded.py +36 -39
  140. pygpt_net/ui/layout/chat/calendar.py +100 -70
  141. pygpt_net/ui/layout/chat/chat.py +23 -17
  142. pygpt_net/ui/layout/chat/input.py +95 -118
  143. pygpt_net/ui/layout/chat/output.py +100 -162
  144. pygpt_net/ui/layout/chat/painter.py +89 -61
  145. pygpt_net/ui/layout/ctx/ctx_list.py +43 -52
  146. pygpt_net/ui/layout/status.py +23 -14
  147. pygpt_net/ui/layout/toolbox/agent.py +27 -38
  148. pygpt_net/ui/layout/toolbox/agent_llama.py +42 -45
  149. pygpt_net/ui/layout/toolbox/assistants.py +42 -38
  150. pygpt_net/ui/layout/toolbox/computer_env.py +32 -23
  151. pygpt_net/ui/layout/toolbox/footer.py +13 -16
  152. pygpt_net/ui/layout/toolbox/image.py +18 -21
  153. pygpt_net/ui/layout/toolbox/indexes.py +46 -89
  154. pygpt_net/ui/layout/toolbox/mode.py +20 -7
  155. pygpt_net/ui/layout/toolbox/model.py +12 -10
  156. pygpt_net/ui/layout/toolbox/presets.py +68 -52
  157. pygpt_net/ui/layout/toolbox/prompt.py +31 -58
  158. pygpt_net/ui/layout/toolbox/toolbox.py +25 -21
  159. pygpt_net/ui/layout/toolbox/vision.py +20 -22
  160. pygpt_net/ui/main.py +2 -4
  161. pygpt_net/ui/menu/about.py +64 -84
  162. pygpt_net/ui/menu/audio.py +87 -63
  163. pygpt_net/ui/menu/config.py +121 -127
  164. pygpt_net/ui/menu/debug.py +69 -76
  165. pygpt_net/ui/menu/file.py +32 -35
  166. pygpt_net/ui/menu/menu.py +2 -3
  167. pygpt_net/ui/menu/plugins.py +69 -33
  168. pygpt_net/ui/menu/theme.py +45 -46
  169. pygpt_net/ui/menu/tools.py +56 -60
  170. pygpt_net/ui/menu/video.py +20 -25
  171. pygpt_net/ui/tray.py +1 -2
  172. pygpt_net/ui/widget/audio/bar.py +1 -3
  173. pygpt_net/ui/widget/audio/input_button.py +3 -4
  174. pygpt_net/ui/widget/calendar/select.py +1 -2
  175. pygpt_net/ui/widget/dialog/base.py +12 -9
  176. pygpt_net/ui/widget/dialog/editor_file.py +20 -23
  177. pygpt_net/ui/widget/dialog/find.py +25 -24
  178. pygpt_net/ui/widget/dialog/profile.py +57 -53
  179. pygpt_net/ui/widget/draw/painter.py +62 -93
  180. pygpt_net/ui/widget/element/button.py +42 -30
  181. pygpt_net/ui/widget/element/checkbox.py +23 -15
  182. pygpt_net/ui/widget/element/group.py +6 -5
  183. pygpt_net/ui/widget/element/labels.py +1 -2
  184. pygpt_net/ui/widget/filesystem/explorer.py +93 -102
  185. pygpt_net/ui/widget/image/display.py +1 -2
  186. pygpt_net/ui/widget/lists/assistant.py +1 -2
  187. pygpt_net/ui/widget/lists/attachment.py +1 -2
  188. pygpt_net/ui/widget/lists/attachment_ctx.py +1 -2
  189. pygpt_net/ui/widget/lists/context.py +2 -4
  190. pygpt_net/ui/widget/lists/index.py +1 -2
  191. pygpt_net/ui/widget/lists/model.py +1 -2
  192. pygpt_net/ui/widget/lists/model_editor.py +1 -2
  193. pygpt_net/ui/widget/lists/model_importer.py +1 -2
  194. pygpt_net/ui/widget/lists/preset.py +1 -2
  195. pygpt_net/ui/widget/lists/preset_plugins.py +1 -2
  196. pygpt_net/ui/widget/lists/profile.py +1 -2
  197. pygpt_net/ui/widget/lists/uploaded.py +1 -2
  198. pygpt_net/ui/widget/option/checkbox.py +2 -4
  199. pygpt_net/ui/widget/option/checkbox_list.py +1 -4
  200. pygpt_net/ui/widget/option/cmd.py +1 -4
  201. pygpt_net/ui/widget/option/dictionary.py +25 -28
  202. pygpt_net/ui/widget/option/input.py +1 -3
  203. pygpt_net/ui/widget/tabs/Input.py +16 -12
  204. pygpt_net/ui/widget/tabs/body.py +5 -3
  205. pygpt_net/ui/widget/tabs/layout.py +36 -25
  206. pygpt_net/ui/widget/tabs/output.py +96 -74
  207. pygpt_net/ui/widget/textarea/calendar_note.py +1 -2
  208. pygpt_net/ui/widget/textarea/editor.py +41 -73
  209. pygpt_net/ui/widget/textarea/find.py +11 -10
  210. pygpt_net/ui/widget/textarea/html.py +3 -6
  211. pygpt_net/ui/widget/textarea/input.py +63 -64
  212. pygpt_net/ui/widget/textarea/notepad.py +54 -38
  213. pygpt_net/ui/widget/textarea/output.py +65 -54
  214. pygpt_net/ui/widget/textarea/search_input.py +5 -4
  215. pygpt_net/ui/widget/textarea/web.py +2 -4
  216. pygpt_net/ui/widget/vision/camera.py +2 -31
  217. {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/METADATA +25 -154
  218. {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/RECORD +218 -217
  219. {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/LICENSE +0 -0
  220. {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/WHEEL +0 -0
  221. {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/entry_points.txt +0 -0
@@ -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.12 01:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from pygpt_net.core.events import RenderEvent
@@ -28,24 +28,33 @@ class Nodes:
28
28
  :param key: UI node key
29
29
  :param type: stylesheet type
30
30
  """
31
- if key not in self.window.ui.nodes:
31
+ nodes = self.window.ui.nodes
32
+ theme = self.window.controller.theme
33
+
34
+ if key not in nodes:
32
35
  return
33
36
 
34
37
  if type == 'font.toolbox':
35
- self.window.ui.nodes[key].setStyleSheet(self.window.controller.theme.style('font.toolbox'))
38
+ nodes[key].setStyleSheet(theme.style('font.toolbox'))
36
39
  elif type == 'font.chat.output':
37
- for pid in self.window.ui.nodes[key]:
40
+ style_output = theme.style('font.chat.output')
41
+ for pid in nodes[key]:
38
42
  try:
39
- self.window.ui.nodes[key][pid].setStyleSheet(self.window.controller.theme.style('font.chat.output'))
43
+ nodes[key][pid].setStyleSheet(style_output)
40
44
  except Exception as e:
41
45
  pass
42
46
  elif type == 'font.chat.input':
43
- self.window.ui.nodes[key].setStyleSheet(self.window.controller.theme.style('font.chat.input'))
47
+ nodes[key].setStyleSheet(theme.style('font.chat.input'))
44
48
  elif type == 'font.ctx.list':
45
- self.window.ui.nodes[key].setStyleSheet(self.window.controller.theme.style('font.ctx.list'))
49
+ nodes[key].setStyleSheet(theme.style('font.ctx.list'))
46
50
 
47
51
  def apply_all(self):
48
52
  """Apply stylesheets to nodes"""
53
+ w = self.window
54
+ ui = w.ui
55
+ ctrl = w.controller
56
+ engine = ctrl.chat.render.get_engine()
57
+
49
58
  nodes = {
50
59
  'font.chat.input': [
51
60
  'input',
@@ -90,58 +99,56 @@ class Nodes:
90
99
  }
91
100
 
92
101
  # apply to nodes
93
- for type in nodes:
94
- for key in nodes[type]:
95
- if key == "output" and self.window.controller.chat.render.get_engine() != 'legacy':
102
+ apply_ref = self.apply
103
+ skip_output = engine != 'legacy'
104
+ for t, keys in nodes.items():
105
+ for k in keys:
106
+ if skip_output and k == "output":
96
107
  continue
97
- self.apply(key, type)
108
+ apply_ref(k, t)
98
109
 
99
110
  # apply to notepads
100
- num_notepads = self.window.controller.notepad.get_num_notepads()
101
- if num_notepads > 0:
102
- for id in self.window.ui.notepad:
103
- self.window.ui.notepad[id].textarea.setStyleSheet(self.window.controller.theme.style('font.chat.output'))
111
+ size = w.core.config.get('font_size')
112
+ style_output = ctrl.theme.style('font.chat.output')
113
+ if ui.notepad:
114
+ for np in ui.notepad.values():
115
+ ta = np.textarea
116
+ ta.setStyleSheet(style_output)
117
+ ta.value = size
104
118
 
105
119
  # apply to calendar
106
- if 'note' in self.window.ui.calendar:
107
- self.window.ui.calendar['note'].setStyleSheet(self.window.controller.theme.style('font.chat.output'))
108
-
109
- # update value
110
- size = self.window.core.config.get('font_size')
111
- if 'note' in self.window.ui.calendar:
112
- self.window.ui.calendar['note'].value = size
113
- if num_notepads > 0:
114
- for id in range(1, num_notepads + 1):
115
- if id in self.window.ui.notepad:
116
- self.window.ui.notepad[id].textarea.value = size
120
+ note = ui.calendar.get('note')
121
+ if note is not None:
122
+ note.setStyleSheet(style_output)
123
+ note.value = size
117
124
 
118
125
  # plain text/markdown
119
- for pid in self.window.ui.nodes['output_plain']:
126
+ output_plain = ui.nodes.get('output_plain', {})
127
+ for obj in output_plain.values():
120
128
  try:
121
- self.window.ui.nodes['output_plain'][pid].value = size
122
- self.window.ui.nodes['output_plain'][pid].update()
123
- except Exception as e:
129
+ obj.value = size
130
+ obj.update()
131
+ except Exception:
124
132
  pass
125
133
 
126
134
  # ------------------------
127
135
 
128
136
  # zoom, (Chromium, web engine)
129
- if self.window.controller.chat.render.get_engine() == 'web':
130
- zoom = self.window.core.config.get('zoom')
131
- for pid in self.window.ui.nodes['output']:
137
+ output_nodes = ui.nodes.get('output', {})
138
+ if engine == 'web':
139
+ zoom = w.core.config.get('zoom')
140
+ for obj in output_nodes.values():
132
141
  try:
133
- self.window.ui.nodes['output'][pid].value = zoom
134
- self.window.ui.nodes['output'][pid].update_zoom()
135
- except Exception as e:
142
+ obj.value = zoom
143
+ obj.update_zoom()
144
+ except Exception:
136
145
  pass
137
- event = RenderEvent(RenderEvent.ON_THEME_CHANGE)
138
- self.window.dispatch(event)
146
+ w.dispatch(RenderEvent(RenderEvent.ON_THEME_CHANGE))
139
147
 
140
148
  # font size, legacy (markdown)
141
- elif self.window.controller.chat.render.get_engine() == 'legacy':
142
- for pid in self.window.ui.nodes['output']:
143
- self.window.ui.nodes['output'][pid].value = size
144
- self.window.ui.nodes['output'][pid].update()
149
+ elif engine == 'legacy':
150
+ for obj in output_nodes.values():
151
+ obj.value = size
152
+ obj.update()
145
153
 
146
- # update tools
147
- self.window.tools.setup_theme()
154
+ w.tools.setup_theme() # update tools
@@ -6,13 +6,16 @@
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 23:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
13
  from typing import Any, Optional
14
14
 
15
+ from PySide6.QtWidgets import QApplication
16
+
15
17
  from pygpt_net.core.events import RenderEvent
18
+ from pygpt_net.utils import trans
16
19
 
17
20
  from .common import Common
18
21
  from .markdown import Markdown
@@ -41,6 +44,29 @@ class Theme:
41
44
  self.common.toggle_tooltips()
42
45
  self.reload(force=False)
43
46
 
47
+ def toggle_theme_by_menu(self, name):
48
+ """
49
+ Toggle theme by menu action
50
+
51
+ :param name: theme name
52
+ """
53
+ self.window.update_status(trans("status.loading"))
54
+ QApplication.processEvents()
55
+ self.toggle(name, force=True)
56
+ self.window.update_status("")
57
+
58
+ def toggle_option_by_menu(self, name: str, value: Any = None):
59
+ """
60
+ Toggle theme option by menu action
61
+
62
+ :param name: option name
63
+ :param value: option value
64
+ """
65
+ self.window.update_status(trans("status.loading"))
66
+ QApplication.processEvents()
67
+ self.toggle_option(name, value)
68
+ self.window.update_status("")
69
+
44
70
  def toggle(
45
71
  self,
46
72
  name: str,
@@ -85,6 +111,7 @@ class Theme:
85
111
 
86
112
  :param name: web style name
87
113
  """
114
+ QApplication.processEvents()
88
115
  core = self.window.core
89
116
  core.config.set('theme.style', name)
90
117
  core.config.save()
@@ -103,6 +130,7 @@ class Theme:
103
130
  :param name: option name
104
131
  :param value: option value
105
132
  """
133
+ QApplication.processEvents()
106
134
  window = self.window
107
135
  core = window.core
108
136
  cfg = core.config
@@ -149,8 +177,7 @@ class Theme:
149
177
 
150
178
  def update_style(self):
151
179
  """Update style"""
152
- current = self.window.core.config.get('theme.style')
153
- self.toggle_style(current)
180
+ self.toggle_style(self.window.core.config.get('theme.style'))
154
181
 
155
182
  def update_theme(self, force: bool = True):
156
183
  """
@@ -158,13 +185,11 @@ class Theme:
158
185
 
159
186
  :param force: force theme change (manual trigger)
160
187
  """
161
- current = self.window.core.config.get('theme')
162
- self.toggle(current, force=force)
188
+ self.toggle(self.window.core.config.get('theme'), force=force)
163
189
 
164
190
  def update_syntax(self):
165
191
  """Update syntax menu"""
166
- current = self.window.core.config.get('render.code_syntax')
167
- self.toggle_syntax(current, update_menu=True)
192
+ self.toggle_syntax(self.window.core.config.get('render.code_syntax'), update_menu=True)
168
193
 
169
194
  def reload(self, force: bool = True):
170
195
  """
@@ -254,8 +279,7 @@ class Theme:
254
279
 
255
280
  :param prev_theme: previous theme name
256
281
  """
257
- current_theme = self.window.core.config.get('theme')
258
- if not prev_theme or prev_theme != current_theme:
282
+ if not prev_theme or prev_theme != self.window.core.config.get('theme'):
259
283
  self.setup()
260
284
  self.update_style()
261
285
  self.update_syntax()
@@ -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.14 08:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Dict, List
@@ -81,7 +81,7 @@ class Tools:
81
81
  caller = parent
82
82
  action = QAction(QIcon(icon), title, parent)
83
83
  action.triggered.connect(
84
- lambda idx=idx, column_idx=column_idx, id=id, caller=caller: caller.add_tab(idx, column_idx, Tab.TAB_TOOL, id)
84
+ lambda checked=False, idx=idx, column_idx=column_idx, id=id, caller=caller: caller.add_tab(idx, column_idx, Tab.TAB_TOOL, id)
85
85
  )
86
86
  submenu.addAction(action)
87
87
  return submenu
@@ -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.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Any, Optional, Tuple
@@ -134,8 +134,7 @@ class Tabs:
134
134
  def reload(self):
135
135
  """Reload tabs"""
136
136
  self.window.core.tabs.reload()
137
- event = RenderEvent(RenderEvent.PREPARE)
138
- self.window.dispatch(event)
137
+ self.window.dispatch(RenderEvent(RenderEvent.PREPARE))
139
138
  self.debug()
140
139
 
141
140
  def reload_after(self):
@@ -6,20 +6,20 @@
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.23 15:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Optional
13
13
 
14
14
  from PySide6.QtGui import QColor
15
15
 
16
+ from pygpt_net.core.events import BaseEvent, Event
16
17
  from pygpt_net.utils import trans
17
18
 
18
19
  from .mode import Mode
19
20
  from .tabs import Tabs
20
21
  from .vision import Vision
21
22
 
22
-
23
23
  class UI:
24
24
  def __init__(self, window=None):
25
25
  """
@@ -65,6 +65,20 @@ class UI:
65
65
  self.vision.update()
66
66
  self.window.controller.agent.legacy.update()
67
67
 
68
+ def handle(self, event: BaseEvent):
69
+ """
70
+ Handle events
71
+
72
+ :param event: BaseEvent: Event to handle
73
+ """
74
+ name = event.name
75
+
76
+ # on input begin
77
+ if name == Event.INPUT_BEGIN:
78
+ self.tabs.switch_to_first_chat() # switch to first active chat tab
79
+ elif name == Event.CTX_END:
80
+ self.update_tokens() # update UI
81
+
68
82
  def get_colors(self) -> dict:
69
83
  """
70
84
  Get color labels
@@ -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.12 00:00:00 #
9
+ # Updated Date: 2025.08.24 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import List
@@ -188,8 +188,8 @@ class Evaluation:
188
188
  i = 0
189
189
  for ctx in history:
190
190
  # if next input (but not last) then clear outputs - use only output after last user input
191
- if self.is_input(ctx) and i < len(history) - 1:
192
- outputs.clear()
191
+ # if self.is_input(ctx) and i < len(history) - 1:
192
+ # outputs.clear()
193
193
 
194
194
  if self.is_output(ctx):
195
195
  if ctx.output:
@@ -6,11 +6,13 @@
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.01 03:00:00 #
9
+ # Updated Date: 2025.08.24 03:00:00 #
10
10
  # ================================================== #
11
+ import os
12
+ from typing import List, Dict, Any
11
13
 
12
- from typing import List, Dict
13
-
14
+ from pygpt_net.core.types import MODE_CHAT
15
+ from pygpt_net.item.model import ModelItem
14
16
  from pygpt_net.provider.agents.base import BaseAgent
15
17
 
16
18
 
@@ -94,3 +96,23 @@ class Provider:
94
96
  # sort by name
95
97
  choices.sort(key=lambda x: list(x.values())[0].lower())
96
98
  return choices
99
+
100
+ def get_openai_model(self, model: ModelItem) -> Any:
101
+ """
102
+ Get OpenAI model by model id
103
+
104
+ :param model: ModelItem
105
+ :return: OpenAI model provider
106
+ """
107
+ from openai import AsyncOpenAI
108
+ from agents import (
109
+ OpenAIChatCompletionsModel,
110
+ )
111
+ if model.provider == "openai":
112
+ return model.id
113
+ else:
114
+ args = self.window.core.models.prepare_client_args(MODE_CHAT, model)
115
+ return OpenAIChatCompletionsModel(
116
+ model=model.id,
117
+ openai_client=AsyncOpenAI(**args),
118
+ )
@@ -105,6 +105,7 @@ class Runner:
105
105
  # vector store idx from preset
106
106
  if preset:
107
107
  vector_store_idx = preset.idx
108
+ extra["agent_idx"] = vector_store_idx
108
109
 
109
110
  # tools
110
111
  agent_tools = self.window.core.agents.tools
@@ -126,7 +127,9 @@ class Runner:
126
127
 
127
128
  # --- ADDITIONAL CONTEXT ---
128
129
  # append additional context from RAG if available
129
- if vector_store_idx and self.window.core.config.get("agent.idx.auto_retrieve", True):
130
+ if (vector_store_idx
131
+ and vector_store_idx != "_"
132
+ and self.window.core.config.get("agent.idx.auto_retrieve", True)):
130
133
  ad_context = self.window.core.idx.chat.query_retrieval(
131
134
  query=prompt,
132
135
  idx=vector_store_idx,
@@ -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.14 01:00:00 #
9
+ # Updated Date: 2025.08.24 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import re
@@ -87,13 +87,14 @@ class LlamaWorkflow(BaseRunner):
87
87
  self.set_idle(signals)
88
88
  return False
89
89
 
90
+ use_current = False
90
91
  if ctx.partial:
92
+ use_current = True # use current item as response if partial item (do not create new one)
91
93
  ctx.partial = False # reset partial flag
92
94
 
93
- response_ctx = self.make_response(ctx)
95
+ response_ctx = self.make_response(ctx, use_current=use_current)
94
96
  self.end_stream(response_ctx, signals)
95
97
  self.send_response(response_ctx, signals, KernelEvent.APPEND_DATA) # send response
96
-
97
98
  self.set_idle(signals)
98
99
  return True
99
100
 
@@ -152,19 +153,24 @@ class LlamaWorkflow(BaseRunner):
152
153
  ctx.output = ctx.agent_final_response # set output to current context
153
154
  else:
154
155
  ctx.output = ctx.live_output
155
-
156
156
  return ctx
157
157
 
158
158
  def make_response(
159
159
  self,
160
- ctx: CtxItem
160
+ ctx: CtxItem,
161
+ use_current: bool = False
161
162
  ) -> CtxItem:
162
163
  """
163
164
  Create a response context item with the given input and output.
164
165
 
165
166
  :param ctx: CtxItem - the context item to use as a base
167
+ :param use_current: If True, use the current context item instead of creating a new one
166
168
  """
167
- response_ctx = self.add_ctx(ctx, with_tool_outputs=True)
169
+ if use_current:
170
+ response_ctx = ctx # use current context item
171
+ else:
172
+ response_ctx = self.add_ctx(ctx, with_tool_outputs=True)
173
+
168
174
  response_ctx.set_input("")
169
175
 
170
176
  prev_output = ctx.live_output
@@ -176,6 +182,9 @@ class LlamaWorkflow(BaseRunner):
176
182
  response_ctx.extra["agent_output"] = True # mark as output response
177
183
  response_ctx.extra["agent_finish"] = True # mark as finished
178
184
 
185
+ if "agent_input" in response_ctx.extra:
186
+ del response_ctx.extra["agent_input"] # remove agent input from extra
187
+
179
188
  if ctx.agent_final_response: # only if not empty
180
189
  response_ctx.extra["output"] = ctx.agent_final_response
181
190
 
@@ -194,9 +203,12 @@ class LlamaWorkflow(BaseRunner):
194
203
  :param output: Output string
195
204
  :return: Filtered output string
196
205
  """
206
+ if output is None:
207
+ return ""
208
+
197
209
  # Remove <execute>...</execute> tags
198
210
  filtered_output = re.sub(r'<execute>.*?</execute>', '', output, flags=re.DOTALL)
199
- return filtered_output
211
+ return filtered_output.strip()
200
212
 
201
213
  async def run_agent(
202
214
  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.14 03:00:00 #
9
+ # Updated Date: 2025.08.24 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Optional, List
@@ -136,6 +136,7 @@ class Loop(BaseRunner):
136
136
  self.set_status(signals, msg)
137
137
  if score < 0:
138
138
  self.send_response(ctx, signals, KernelEvent.APPEND_END)
139
+ self.set_idle(signals)
139
140
  return True
140
141
  good_score = self.window.core.config.get("agent.llama.loop.score", 75)
141
142
  if score >= good_score != 0:
@@ -145,6 +146,7 @@ class Loop(BaseRunner):
145
146
  score=str(score)
146
147
  )
147
148
  self.send_response(ctx, signals, KernelEvent.APPEND_END, msg=msg)
149
+ self.set_idle(signals)
148
150
  return True
149
151
 
150
152
  # print("Instruction: " + instruction, "Score: " + str(score))
@@ -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.12 19:00:00 #
9
+ # Updated Date: 2025.08.24 03:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Dict, Any, List
@@ -59,6 +59,9 @@ class OpenAIWorkflow(BaseRunner):
59
59
  if self.is_stopped():
60
60
  return True # abort if stopped
61
61
 
62
+ if "llm" in agent_kwargs:
63
+ agent_kwargs["llm"] = None # clear llm if provided, as it is not used in OpenAI workflow
64
+
62
65
  self.set_busy(signals)
63
66
 
64
67
  # append input to messages
@@ -69,7 +72,7 @@ class OpenAIWorkflow(BaseRunner):
69
72
  self.window.core.gpt.vision.append_images(ctx) # append images to ctx if provided
70
73
  history = history + msg
71
74
 
72
- # callbacks
75
+ # ------------ callbacks ----------------
73
76
  def on_step(
74
77
  ctx: CtxItem,
75
78
  begin: bool = False
@@ -136,6 +139,16 @@ class OpenAIWorkflow(BaseRunner):
136
139
  self.send_stream(ctx, signals, False)
137
140
  self.end_stream(ctx, signals)
138
141
 
142
+ # fix: prevent race condition with next context if feedback after response
143
+ if finish and input == output:
144
+ ctx.extra["agent_finish"] = True # mark as finished and ready for evaluation
145
+ ctx.extra["agent_finish_evaluate"] = True # mark as feedback response (ignored in loop evaluation)
146
+ if stream:
147
+ self.send_stream(ctx, signals, False)
148
+ self.end_stream(ctx, signals)
149
+ self.send_response(ctx, signals, KernelEvent.APPEND_DATA)
150
+ return ctx
151
+
139
152
  # create and return next context item
140
153
  next_ctx = self.add_next_ctx(ctx)
141
154
  next_ctx.set_input(input)
@@ -158,7 +171,8 @@ class OpenAIWorkflow(BaseRunner):
158
171
  self.set_idle(signals)
159
172
  self.set_error(error)
160
173
 
161
- # callbacks
174
+ # ------------ / callbacks ----------------
175
+
162
176
  bridge = ConnectionContext(
163
177
  stopped=self.is_stopped,
164
178
  on_step=on_step,
@@ -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.21 07:00:00 #
9
+ # Updated Date: 2025.08.24 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import json
@@ -564,6 +564,9 @@ class CodeExecutor:
564
564
  :param code: Python code to execute
565
565
  :return: Output from the code execution
566
566
  """
567
+ if not self.window.core.command.is_cmd():
568
+ return "Tool execution is not enabled. Abort execution and ask user for tool enable."
569
+
567
570
  self.window.core.agents.tools.last_tool_output = None
568
571
  if code == "/restart":
569
572
  commands = [