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: 2025.08.03 14:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import datetime
@@ -14,7 +14,7 @@ import os
14
14
  from typing import Any, List, Dict
15
15
 
16
16
  from PySide6.QtCore import Slot, QObject
17
- from qasync import QApplication
17
+ from PySide6.QtWidgets import QApplication
18
18
 
19
19
  from pygpt_net.core.idx.worker import IndexWorker
20
20
  from pygpt_net.item.ctx import CtxMeta
@@ -83,7 +83,7 @@ class Indexer(QObject):
83
83
  """
84
84
  if not force:
85
85
  self.tmp_idx = idx # store tmp index name (for confirmation)
86
- content = trans('idx.confirm.db.content') + "\n" + trans('idx.token.warn')
86
+ content = f"{trans('idx.confirm.db.content')}\n{trans('idx.token.warn')}"
87
87
  self.window.ui.dialogs.confirm(
88
88
  type='idx.index.db',
89
89
  id=meta_id,
@@ -92,18 +92,19 @@ class Indexer(QObject):
92
92
  return
93
93
 
94
94
  meta = self.window.core.ctx.get_meta_by_id(meta_id)
95
- from_ts = meta.indexed
96
95
  self.window.update_status(trans('idx.status.indexing'))
97
96
 
98
- self.worker = IndexWorker()
99
- self.worker.window = self.window
100
- self.worker.content = meta_id
101
- self.worker.idx = idx
102
- self.worker.type = "db_meta"
103
- self.worker.from_ts = from_ts
104
- self.worker.signals.finished.connect(self.handle_finished_db_meta)
105
- self.worker.signals.error.connect(self.handle_error)
106
- self.window.threadpool.start(self.worker)
97
+ worker = IndexWorker()
98
+ worker.window = self.window
99
+ worker.content = meta_id
100
+ worker.idx = idx
101
+ worker.type = "db_meta"
102
+ worker.from_ts = meta.indexed
103
+ worker.signals.finished.connect(self.handle_finished_db_meta)
104
+ worker.signals.error.connect(self.handle_error)
105
+ self.window.threadpool.start(worker)
106
+ self.worker = worker
107
+
107
108
  self.window.controller.idx.on_idx_start() # on start
108
109
 
109
110
  def index_ctx_current(
@@ -146,15 +147,16 @@ class Indexer(QObject):
146
147
  :param idx: index name
147
148
  :param sync: sync mode
148
149
  """
149
- self.worker = IndexWorker()
150
- self.worker.window = self.window
151
- self.worker.content = meta.id
152
- self.worker.idx = idx
153
- self.worker.type = "db_meta"
154
- self.worker.from_ts = meta.indexed
155
- self.worker.silent = True
156
- self.worker.signals.finished.connect(self.handle_finished_db_meta)
157
- self.worker.signals.error.connect(self.handle_error)
150
+ worker = IndexWorker()
151
+ worker.window = self.window
152
+ worker.content = meta.id
153
+ worker.idx = idx
154
+ worker.type = "db_meta"
155
+ worker.from_ts = meta.indexed
156
+ worker.silent = True
157
+ worker.signals.finished.connect(self.handle_finished_db_meta)
158
+ worker.signals.error.connect(self.handle_error)
159
+ self.worker = worker
158
160
 
159
161
  if sync:
160
162
  self.worker.run()
@@ -204,15 +206,17 @@ class Indexer(QObject):
204
206
  )
205
207
  return
206
208
 
207
- self.worker = IndexWorker()
208
- self.worker.window = self.window
209
- self.worker.content = ts
210
- self.worker.idx = idx
211
- self.worker.type = "db_current"
212
- self.worker.silent = silent
213
- self.worker.signals.finished.connect(self.handle_finished_db_current)
214
- self.worker.signals.error.connect(self.handle_error)
215
- self.window.threadpool.start(self.worker)
209
+ worker = IndexWorker()
210
+ worker.window = self.window
211
+ worker.content = ts
212
+ worker.idx = idx
213
+ worker.type = "db_current"
214
+ worker.silent = silent
215
+ worker.signals.finished.connect(self.handle_finished_db_current)
216
+ worker.signals.error.connect(self.handle_error)
217
+ self.window.threadpool.start(worker)
218
+ self.worker = worker
219
+
216
220
  self.window.controller.idx.on_idx_start() # on start
217
221
 
218
222
  def index_path(
@@ -231,16 +235,19 @@ class Indexer(QObject):
231
235
  :param recursive: recursive indexing
232
236
  """
233
237
  self.window.update_status(trans('idx.status.indexing'))
234
- self.worker = IndexWorker()
235
- self.worker.window = self.window
236
- self.worker.content = path
237
- self.worker.idx = idx
238
- self.worker.type = "file"
239
- self.worker.replace = replace
240
- self.worker.recursive = recursive
241
- self.worker.signals.finished.connect(self.handle_finished_file)
242
- self.worker.signals.error.connect(self.handle_error)
243
- self.window.threadpool.start(self.worker)
238
+
239
+ worker = IndexWorker()
240
+ worker.window = self.window
241
+ worker.content = path
242
+ worker.idx = idx
243
+ worker.type = "file"
244
+ worker.replace = replace
245
+ worker.recursive = recursive
246
+ worker.signals.finished.connect(self.handle_finished_file)
247
+ worker.signals.error.connect(self.handle_error)
248
+ self.window.threadpool.start(worker)
249
+ self.worker = worker
250
+
244
251
  self.window.controller.idx.on_idx_start() # on start
245
252
 
246
253
  def index_paths(
@@ -259,17 +266,20 @@ class Indexer(QObject):
259
266
  :param recursive: recursive indexing
260
267
  """
261
268
  self.window.update_status(trans('idx.status.indexing'))
262
- self.worker = IndexWorker()
263
- self.worker.window = self.window
264
- self.worker.content = paths
265
- self.worker.idx = idx
266
- self.worker.type = "files"
267
- self.worker.replace = replace
268
- self.worker.recursive = recursive
269
- self.worker.silent = False
270
- self.worker.signals.finished.connect(self.handle_finished_file)
271
- self.worker.signals.error.connect(self.handle_error)
272
- self.window.threadpool.start(self.worker)
269
+
270
+ worker = IndexWorker()
271
+ worker.window = self.window
272
+ worker.content = paths
273
+ worker.idx = idx
274
+ worker.type = "files"
275
+ worker.replace = replace
276
+ worker.recursive = recursive
277
+ worker.silent = False
278
+ worker.signals.finished.connect(self.handle_finished_file)
279
+ worker.signals.error.connect(self.handle_error)
280
+ self.window.threadpool.start(worker)
281
+ self.worker = worker
282
+
273
283
  self.window.controller.idx.on_idx_start() # on start
274
284
 
275
285
  def index_all_files(
@@ -393,19 +403,21 @@ class Indexer(QObject):
393
403
  :param config: loader config
394
404
  :param replace: replace index
395
405
  """
396
- self.worker = IndexWorker()
397
- self.worker.window = self.window
398
- self.worker.content = None
399
- self.worker.loader = loader
400
- self.worker.params = params
401
- self.worker.config = config
402
- self.worker.replace = replace
403
- self.worker.silent = False
404
- self.worker.idx = idx
405
- self.worker.type = "web"
406
- self.worker.signals.finished.connect(self.handle_finished_web)
407
- self.worker.signals.error.connect(self.handle_error)
408
- self.window.threadpool.start(self.worker)
406
+ worker = IndexWorker()
407
+ worker.window = self.window
408
+ worker.content = None
409
+ worker.loader = loader
410
+ worker.params = params
411
+ worker.config = config
412
+ worker.replace = replace
413
+ worker.silent = False
414
+ worker.idx = idx
415
+ worker.type = "web"
416
+ worker.signals.finished.connect(self.handle_finished_web)
417
+ worker.signals.error.connect(self.handle_error)
418
+ self.window.threadpool.start(worker)
419
+ self.worker = worker
420
+
409
421
  self.window.controller.idx.on_idx_start() # on start
410
422
 
411
423
  def index_ctx_meta_remove(
@@ -444,8 +456,7 @@ class Indexer(QObject):
444
456
 
445
457
  :param idx: on list idx
446
458
  """
447
- idx_name = self.window.core.idx.get_by_idx(idx)
448
- self.clear(idx_name)
459
+ self.clear(self.window.core.idx.get_by_idx(idx))
449
460
 
450
461
  def truncate_by_idx(self, idx: int):
451
462
  """
@@ -453,8 +464,7 @@ class Indexer(QObject):
453
464
 
454
465
  :param idx: on list idx
455
466
  """
456
- idx_name = self.window.core.idx.get_by_idx(idx)
457
- self.clear(idx_name)
467
+ self.clear(self.window.core.idx.get_by_idx(idx))
458
468
 
459
469
  def clear(
460
470
  self,
@@ -496,7 +506,7 @@ class Indexer(QObject):
496
506
  else:
497
507
  self.window.update_status(trans('idx.status.truncate.error'))
498
508
  except Exception as e:
499
- print(e)
509
+ self.window.core.debug.log(e)
500
510
  self.window.update_status(e)
501
511
 
502
512
  self.window.tools.get("indexer").refresh()
@@ -544,7 +554,7 @@ class Indexer(QObject):
544
554
  else:
545
555
  self.window.update_status(trans('idx.status.truncate.error'))
546
556
  except Exception as e:
547
- print(e)
557
+ self.window.core.debug.log(e)
548
558
  self.window.update_status(e)
549
559
 
550
560
  self.window.tools.get("indexer").refresh()
@@ -559,7 +569,6 @@ class Indexer(QObject):
559
569
  self.window.ui.dialogs.alert(err)
560
570
  self.window.update_status(str(err))
561
571
  self.window.core.debug.log(err)
562
- print(err)
563
572
  self.window.tools.get("indexer").refresh()
564
573
  self.window.controller.idx.on_idx_error() # on error
565
574
 
@@ -580,7 +589,7 @@ class Indexer(QObject):
580
589
  :param silent: silent mode (no msg and status update)
581
590
  """
582
591
  if num > 0:
583
- msg = trans('idx.status.success') + f" {num}"
592
+ msg = f"{trans('idx.status.success')} {num}"
584
593
 
585
594
  # store last DB update timestamp
586
595
  self.window.core.config.set('llama.idx.db.index', idx)
@@ -620,7 +629,7 @@ class Indexer(QObject):
620
629
  :param silent: silent mode (no msg and status update)
621
630
  """
622
631
  if num > 0:
623
- msg = trans('idx.status.success') + f" {num}"
632
+ msg = f"{trans('idx.status.success')} {num}"
624
633
  self.update_idx_status(idx)
625
634
  self.window.controller.idx.after_index(idx) # post-actions (update UI, etc.)
626
635
  if not silent:
@@ -654,7 +663,7 @@ class Indexer(QObject):
654
663
  """
655
664
  num = len(files)
656
665
  if num > 0:
657
- msg = trans('idx.status.success') + f" {num}"
666
+ msg = f"{trans('idx.status.success')} {num}"
658
667
  self.window.core.idx.append(idx, files) # append files list to index
659
668
  self.update_idx_status(idx)
660
669
  self.window.controller.idx.after_index(idx) # post-actions (update UI, etc.)
@@ -688,7 +697,7 @@ class Indexer(QObject):
688
697
  :param silent: silent mode (no msg and status update)
689
698
  """
690
699
  if num > 0:
691
- msg = trans('idx.status.success') + f" {num}"
700
+ msg = f"{trans('idx.status.success')} {num}"
692
701
  if not silent:
693
702
  self.window.update_status(msg)
694
703
  self.window.ui.dialogs.alert(msg)
@@ -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.07.01 01:00:00 #
9
+ # Updated Date: 2025.08.23 15:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import json
@@ -20,7 +20,7 @@ from pygpt_net.item.ctx import CtxItem
20
20
  class Reply:
21
21
  def __init__(self, window=None):
22
22
  """
23
- Reply handler
23
+ Reply handler (response from plugins, tools, etc.)
24
24
 
25
25
  :param window: Window instance
26
26
  """
@@ -42,28 +42,33 @@ class Reply:
42
42
  :param extra: extra data
43
43
  :return: list of results
44
44
  """
45
- flush = False
46
- if "flush" in extra and extra["flush"]:
47
- flush = True
45
+ flush = extra.get("flush", False) if isinstance(extra, dict) else False
48
46
  ctx = context.ctx
49
- if ctx is not None:
50
- self.run_post_response(ctx, extra)
51
- self.last_result = ctx.results
52
- if ctx.agent_call:
53
- return ctx.results # abort if called in agent and return here, TODO: check if needed!!!!!
54
- self.window.core.debug.info("Reply...")
55
- if self.window.core.debug.enabled() and self.is_log():
56
- self.window.core.debug.debug("CTX REPLY: " + str(ctx))
57
- if ctx.reply:
58
- if self.reply_idx >= ctx.pid: # skip if reply already sent for this context
59
- # >>> this prevents multiple replies from the same ctx item <<<
60
- return []
61
- self.reply_idx = ctx.pid
62
- self.append(ctx)
63
- if flush or self.window.controller.kernel.async_allowed(ctx):
64
- self.flush()
65
- return ctx.results
66
- return []
47
+ if ctx is None:
48
+ return []
49
+
50
+ core = self.window.core
51
+ self.last_result = ctx.results
52
+ self.on_post_response(ctx, extra)
53
+
54
+ if ctx.agent_call:
55
+ # TODO: clear() here?
56
+ return ctx.results # abort if called by agent, TODO: check if needed!!!!!
57
+
58
+ core.debug.info("Reply...")
59
+ if core.debug.enabled() and self.is_log():
60
+ core.debug.debug("CTX REPLY: " + str(ctx))
61
+
62
+ if ctx.reply:
63
+ if self.reply_idx >= ctx.pid: # prevent multiple replies per ctx
64
+ return []
65
+ self.reply_idx = ctx.pid
66
+ self.append(ctx)
67
+
68
+ if flush or self.window.controller.kernel.async_allowed(ctx):
69
+ self.flush()
70
+
71
+ return ctx.results
67
72
 
68
73
  def append(self, ctx: CtxItem):
69
74
  """
@@ -73,76 +78,63 @@ class Reply:
73
78
  """
74
79
  self.window.core.debug.info("Reply stack (add)...")
75
80
  self.reply_stack.append(ctx.results)
76
- ctx.results = [] # clear results
77
81
  self.reply_ctx = ctx
82
+ self.reply_ctx.results = [] # clear results
78
83
 
79
84
  def flush(self):
80
85
  """Flush reply stack"""
81
86
  if self.reply_ctx is None or len(self.reply_stack) == 0:
82
87
  return
83
88
 
84
- self.window.core.debug.info("Reply stack (flush)...")
89
+ core = self.window.core
90
+ dispatch = self.window.dispatch
91
+ core.debug.info("Reply stack (flush)...")
92
+
85
93
  results = []
86
94
  for responses in self.reply_stack:
87
95
  for result in responses:
88
96
  results.append(result)
89
97
 
90
98
  self.window.update_status("") # clear status
91
- if self.reply_ctx.internal:
92
- if self.window.controller.agent.legacy.enabled():
93
- self.window.controller.agent.legacy.add_run()
94
- self.window.controller.agent.legacy.update()
99
+ self.window.controller.agent.on_reply(self.reply_ctx) # handle reply in agent
95
100
 
96
101
  # prepare data to send as reply
97
102
  tool_data = json.dumps(results)
98
103
  if (len(self.reply_stack) < 2
99
104
  and self.reply_ctx.extra_ctx
100
- and self.window.core.config.get("ctx.use_extra")):
105
+ and core.config.get("ctx.use_extra")):
101
106
  tool_data = self.reply_ctx.extra_ctx # if extra content is set, use it as data to send
102
107
 
103
- prev_ctx = self.window.core.ctx.as_previous(self.reply_ctx) # copy result to previous ctx and clear current ctx
104
- self.window.core.ctx.update_item(self.reply_ctx) # update context in db
108
+ prev_ctx = core.ctx.as_previous(self.reply_ctx) # copy result to previous ctx and clear current ctx
109
+ core.ctx.update_item(self.reply_ctx) # update context in db
105
110
  self.window.update_status('...')
106
111
 
107
- # if response from sub call, from experts
108
- parent_id = None
109
- if self.reply_ctx.sub_call:
110
- if self.reply_ctx.meta is not None:
111
- parent_id = self.reply_ctx.meta.id # slave meta id
112
-
113
112
  # tool output append
114
- data = {
113
+ dispatch(RenderEvent(RenderEvent.TOOL_UPDATE, {
115
114
  "meta": self.reply_ctx.meta,
116
115
  "tool_data": tool_data,
117
- }
118
- event = RenderEvent(RenderEvent.TOOL_UPDATE, data)
119
- self.window.dispatch(event)
116
+ }))
120
117
  self.clear()
121
118
 
122
119
  # disable reply if LlamaIndex agent is used
123
- mode = self.window.core.config.get("mode")
124
- if mode == MODE_LLAMA_INDEX:
125
- if self.window.core.config.get("llama.idx.react", False):
126
- self.window.core.debug.info("Reply disabled for LlamaIndex ReAct agent")
127
- return
120
+ mode = core.config.get("mode")
121
+ if mode == MODE_LLAMA_INDEX and core.config.get("llama.idx.react", False):
122
+ return
128
123
 
129
124
  # send reply
130
125
  context = BridgeContext()
131
126
  context.ctx = prev_ctx
132
127
  context.prompt = str(tool_data)
133
- extra = {
134
- "force": True,
135
- "reply": True,
136
- "internal": True,
137
- "parent_id": parent_id,
138
- }
139
- event = KernelEvent(KernelEvent.REPLY_RETURN, {
128
+ dispatch(KernelEvent(KernelEvent.REPLY_RETURN, {
140
129
  'context': context,
141
- 'extra': extra,
142
- })
143
- self.window.dispatch(event)
144
-
145
- def run_post_response(
130
+ 'extra': {
131
+ "force": True,
132
+ "reply": True,
133
+ "internal": True,
134
+ },
135
+ }))
136
+
137
+ def on_post_response(
146
138
  self,
147
139
  ctx: CtxItem,
148
140
  extra_data: Optional[Dict[str, Any]] = None
@@ -157,8 +149,7 @@ class Reply:
157
149
  if (ctx is None or not ctx.agent_call) or not self.window.controller.kernel.is_threaded():
158
150
  if "post_update" in extra_data and isinstance(extra_data["post_update"], list):
159
151
  if "file_explorer" in extra_data["post_update"]:
160
- # update file explorer view
161
- self.window.controller.files.update_explorer()
152
+ self.window.controller.files.update_explorer() # update file explorer view
162
153
 
163
154
  def clear(self):
164
155
  """Clear reply stack"""
@@ -172,8 +163,4 @@ class Reply:
172
163
 
173
164
  :return: true if can be logged
174
165
  """
175
- is_log = False
176
- if self.window.core.config.has("log.events") \
177
- and self.window.core.config.get("log.events"):
178
- is_log = True
179
- return is_log
166
+ return self.window.core.config.get("log.events", False)
@@ -6,12 +6,12 @@
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.03 14:00:00 #
9
+ # Updated Date: 2025.08.23 15:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Any
13
13
 
14
- from qasync import QApplication
14
+ from PySide6.QtWidgets import QApplication
15
15
 
16
16
  from pygpt_net.core.events import KernelEvent
17
17
  from pygpt_net.core.bridge.context import BridgeContext
@@ -44,14 +44,12 @@ class Stack:
44
44
  """
45
45
  Check if reply stack has any item
46
46
 
47
- :return: True if has
47
+ :return: True if has items
48
48
  """
49
49
  return self.current is not None
50
50
 
51
51
  def clear(self):
52
- """
53
- Clear reply stack
54
- """
52
+ """Clear reply stack"""
55
53
  self.current = None
56
54
  self.unlock()
57
55
 
@@ -71,35 +69,37 @@ class Stack:
71
69
  context.parent_id, # expert id
72
70
  context.input, # query
73
71
  )
72
+ # cmd execute
74
73
  elif context.type == ReplyContext.CMD_EXECUTE:
75
74
  self.window.controller.plugins.apply_cmds(
76
75
  context.ctx, # current ctx
77
76
  context.cmds, # commands
78
77
  )
78
+ # cmd execute (force)
79
79
  elif context.type == ReplyContext.CMD_EXECUTE_FORCE:
80
80
  self.window.controller.plugins.apply_cmds(
81
81
  context.ctx, # current ctx
82
82
  context.cmds, # commands
83
83
  all=True,
84
84
  )
85
+ # cmd execute (inline)
85
86
  elif context.type == ReplyContext.CMD_EXECUTE_INLINE:
86
87
  self.window.controller.plugins.apply_cmds_inline(
87
88
  context.ctx, # current ctx
88
89
  context.cmds, # commands
89
90
  )
91
+ # agent continue
90
92
  elif context.type == ReplyContext.AGENT_CONTINUE:
91
93
  bridge_context = BridgeContext()
92
94
  bridge_context.ctx = context.ctx
93
- bridge_context.prompt = context.input
94
- extra = {
95
- "force": True,
96
- "internal": True,
97
- }
98
- event = KernelEvent(KernelEvent.INPUT_SYSTEM, {
95
+ bridge_context.prompt = context.input # from reply context
96
+ self.window.dispatch(KernelEvent(KernelEvent.INPUT_SYSTEM, {
99
97
  'context': bridge_context,
100
- 'extra': extra,
101
- })
102
- self.window.dispatch(event)
98
+ 'extra': {
99
+ "force": True,
100
+ "internal": True,
101
+ },
102
+ }))
103
103
 
104
104
  def is_locked(self) -> bool:
105
105
  """
@@ -131,7 +131,7 @@ class Stack:
131
131
 
132
132
  def waiting(self) -> bool:
133
133
  """
134
- Check if reply stack is waiting
134
+ Check if reply stack is waiting for processing
135
135
 
136
136
  :return: True if waiting
137
137
  """