pygpt-net 2.6.10__py3-none-any.whl → 2.6.11__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 (37) hide show
  1. pygpt_net/CHANGELOG.txt +6 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/config.py +11 -11
  4. pygpt_net/controller/access/access.py +49 -2
  5. pygpt_net/controller/chat/attachment.py +13 -13
  6. pygpt_net/controller/chat/command.py +4 -4
  7. pygpt_net/controller/chat/common.py +9 -14
  8. pygpt_net/controller/chat/files.py +2 -2
  9. pygpt_net/controller/chat/input.py +4 -4
  10. pygpt_net/controller/chat/output.py +4 -4
  11. pygpt_net/controller/chat/render.py +11 -6
  12. pygpt_net/controller/chat/response.py +5 -5
  13. pygpt_net/controller/chat/stream.py +2 -3
  14. pygpt_net/controller/chat/text.py +15 -10
  15. pygpt_net/controller/command/command.py +7 -7
  16. pygpt_net/controller/ctx/ctx.py +9 -5
  17. pygpt_net/controller/debug/debug.py +2 -2
  18. pygpt_net/core/debug/debug.py +6 -1
  19. pygpt_net/core/dispatcher/dispatcher.py +5 -3
  20. pygpt_net/core/events/render.py +3 -0
  21. pygpt_net/core/render/base.py +4 -4
  22. pygpt_net/core/render/web/body.py +35 -82
  23. pygpt_net/core/render/web/parser.py +11 -6
  24. pygpt_net/core/render/web/renderer.py +71 -37
  25. pygpt_net/data/config/config.json +3 -3
  26. pygpt_net/data/config/models.json +3 -3
  27. pygpt_net/data/config/presets/agent_openai.json +1 -1
  28. pygpt_net/data/config/presets/agent_openai_assistant.json +1 -1
  29. pygpt_net/data/config/presets/agent_planner.json +1 -1
  30. pygpt_net/data/config/presets/agent_react.json +1 -1
  31. pygpt_net/ui/main.py +4 -2
  32. pygpt_net/ui/widget/textarea/web.py +17 -3
  33. {pygpt_net-2.6.10.dist-info → pygpt_net-2.6.11.dist-info}/METADATA +8 -2
  34. {pygpt_net-2.6.10.dist-info → pygpt_net-2.6.11.dist-info}/RECORD +37 -37
  35. {pygpt_net-2.6.10.dist-info → pygpt_net-2.6.11.dist-info}/LICENSE +0 -0
  36. {pygpt_net-2.6.10.dist-info → pygpt_net-2.6.11.dist-info}/WHEEL +0 -0
  37. {pygpt_net-2.6.10.dist-info → pygpt_net-2.6.11.dist-info}/entry_points.txt +0 -0
pygpt_net/CHANGELOG.txt CHANGED
@@ -1,3 +1,9 @@
1
+ 2.6.11 (2025-08-18)
2
+
3
+ - Added the ability to close the dialog window with the Esc key.
4
+ - Made context item deletion without output refresh.
5
+ - Optimizations.
6
+
1
7
  2.6.10 (2025-08-17)
2
8
 
3
9
  - Enhanced the handling of the context list.
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.17 00:00:00 #
9
+ # Updated Date: 2025.08.18 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.10"
17
- __build__ = "2025-08-17"
16
+ __version__ = "2.6.11"
17
+ __build__ = "2025-08-18"
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"
pygpt_net/config.py CHANGED
@@ -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 23:00:00 #
9
+ # Updated Date: 2025.08.18 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -112,14 +112,14 @@ class Config:
112
112
  """
113
113
  path = os.path.join(Path.home(), '.config', Config.CONFIG_DIR)
114
114
  if "PYGPT_WORKDIR" in os.environ and os.environ["PYGPT_WORKDIR"] != "":
115
- print("FORCE using workdir: {}".format(os.environ["PYGPT_WORKDIR"]))
115
+ print(f"FORCE using workdir: {os.environ['PYGPT_WORKDIR']}")
116
116
  if not os.path.isabs(os.environ["PYGPT_WORKDIR"]):
117
117
  path = os.path.join(os.getcwd(), os.environ["PYGPT_WORKDIR"])
118
118
  else:
119
119
  path = os.environ["PYGPT_WORKDIR"]
120
120
  if not os.path.exists(path):
121
- print("Workdir path not exists: {}".format(path))
122
- print("Creating workdir path: {}".format(path))
121
+ print(f"Workdir path not exists: {path}")
122
+ print(f"Creating workdir path: {path}")
123
123
  os.makedirs(path, exist_ok=True)
124
124
  return path
125
125
 
@@ -147,7 +147,7 @@ class Config:
147
147
  if os.path.exists(tmp_path):
148
148
  path = Path(tmp_path)
149
149
  else:
150
- print("CRITICAL: Workdir path not exists: {}".format(tmp_path))
150
+ print(f"CRITICAL: Workdir path not exists: {tmp_path}")
151
151
  return str(path)
152
152
 
153
153
  def set_workdir(self, path: str, reload: bool = False):
@@ -181,7 +181,7 @@ class Config:
181
181
  :return: user dir
182
182
  """
183
183
  if dir not in self.dirs:
184
- raise Exception('Unknown dir: {}'.format(dir))
184
+ raise Exception(f'Unknown dir: {dir}')
185
185
 
186
186
  dir_data_allowed = ("img", "capture", "upload")
187
187
 
@@ -244,7 +244,7 @@ class Config:
244
244
 
245
245
  print("===================================================")
246
246
  print(f" {Color.BOLD}PyGPT {v}{Color.ENDC} build {build} ({os_name}, {architecture})")
247
- print(" Author: Marcin Szczyglinski")
247
+ print(" Author: Marcin Szczygliński")
248
248
  print(" GitHub: https://github.com/szczyglis-dev/py-gpt")
249
249
  print(" Website: https://pygpt.net")
250
250
  print(" Email: info@pygpt.net")
@@ -276,7 +276,7 @@ class Config:
276
276
  if self.window is not None:
277
277
  self.window.core.debug.log(e)
278
278
  else:
279
- print("Error loading version file: {}".format(e))
279
+ print(f"Error loading version file: {e}")
280
280
 
281
281
  def get_build(self) -> str:
282
282
  """
@@ -297,7 +297,7 @@ class Config:
297
297
  if self.window is not None:
298
298
  self.window.core.debug.log(e)
299
299
  else:
300
- print("Error loading version file: {}".format(e))
300
+ print(f"Error loading version file: {e}")
301
301
 
302
302
  def get_options(self) -> dict:
303
303
  """
@@ -541,9 +541,9 @@ class Config:
541
541
  os.environ[item['name']] = value
542
542
  list_loaded.append(item['name'])
543
543
  except Exception as e:
544
- print("Error setting env var: {}".format(e))
544
+ print(f"Error setting env var: {e}")
545
545
  if list_loaded:
546
- print("Setting environment vars: {}".format(", ".join(list_loaded)))
546
+ print(f"Setting environment vars: {', '.join(list_loaded)}")
547
547
 
548
548
  def save(self, filename: str = "config.json"):
549
549
  """
@@ -6,9 +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.01.19 02:00:00 #
9
+ # Updated Date: 2025.08.18 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
+ from PySide6.QtCore import Qt
13
+ from PySide6.QtWidgets import QApplication, QDialog, QMainWindow
14
+
12
15
  from pygpt_net.core.events import BaseEvent, ControlEvent, AppEvent
13
16
 
14
17
  from .control import Control
@@ -76,4 +79,48 @@ class Access:
76
79
  self.window.controller.audio.stop_output()
77
80
 
78
81
  # stop generating if active
79
- self.window.controller.kernel.stop()
82
+ self.window.controller.kernel.stop()
83
+
84
+ # close top dialog if any
85
+ self.close_top_dialog_if_any()
86
+
87
+ def close_top_dialog_if_any(self) -> bool:
88
+ """Close top dialog if any"""
89
+ app = QApplication.instance()
90
+
91
+ try:
92
+ w = app.activeModalWidget()
93
+ if w:
94
+ top = w.window()
95
+ if top and (top.windowFlags() & (Qt.Dialog | Qt.Sheet | Qt.Tool | Qt.Popup)):
96
+ top.close()
97
+ return True
98
+ except Exception:
99
+ pass
100
+
101
+ try:
102
+ w = app.activeWindow()
103
+ if w:
104
+ top = w.window()
105
+ if isinstance(top, QMainWindow):
106
+ pass
107
+ else:
108
+ if top and (top.windowFlags() & (Qt.Dialog | Qt.Sheet | Qt.Tool | Qt.Popup)):
109
+ top.close()
110
+ return True
111
+ except Exception:
112
+ pass
113
+
114
+ try:
115
+ for top in reversed(QApplication.topLevelWidgets()):
116
+ if not top.isVisible():
117
+ continue
118
+ if isinstance(top, QMainWindow):
119
+ continue
120
+ if top.windowFlags() & (Qt.Dialog | Qt.Sheet | Qt.Tool | Qt.Popup):
121
+ top.close()
122
+ return True
123
+ except Exception:
124
+ pass
125
+
126
+ return False
@@ -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.16 01:00:00 #
9
+ # Updated Date: 2025.08.18 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -128,7 +128,7 @@ class Attachment(QObject):
128
128
  attachments = self.window.core.attachments.get_all(mode, only_files=True)
129
129
 
130
130
  if self.is_verbose() and len(attachments) > 0:
131
- print("\nUploading attachments...\nWork Mode: {}".format(mode))
131
+ print(f"\nUploading attachments...\nWork Mode: {mode}")
132
132
 
133
133
  for uuid in attachments:
134
134
  attachment = attachments[uuid]
@@ -175,7 +175,7 @@ class Attachment(QObject):
175
175
  return False
176
176
  if self.window.core.filesystem.packer.is_archive(attachment.path):
177
177
  if self.is_verbose():
178
- print("Unpacking archive: {}".format(attachment.path))
178
+ print(f"Unpacking archive: {attachment.path}")
179
179
  tmp_path = self.window.core.filesystem.packer.unpack(attachment.path)
180
180
  if tmp_path:
181
181
  for root, dirs, files in os.walk(tmp_path):
@@ -188,7 +188,7 @@ class Attachment(QObject):
188
188
  path_relative = os.path.relpath(path, tmp_path)
189
189
  if self.is_allowed(str(path)):
190
190
  if self.is_verbose():
191
- print("Uploading unpacked from archive: {}".format(path_relative))
191
+ print(f"Uploading unpacked from archive: {path_relative}")
192
192
  item = self.window.core.attachments.context.upload(
193
193
  meta=meta,
194
194
  attachment=sub_attachment,
@@ -197,7 +197,7 @@ class Attachment(QObject):
197
197
  auto_index=auto_index,
198
198
  )
199
199
  if item:
200
- item["path"] = os.path.basename(attachment.path) + "/" + str(path_relative)
200
+ item["path"] = f"{os.path.basename(attachment.path)}/{str(path_relative)}"
201
201
  item["size"] = os.path.getsize(path)
202
202
  self.append_to_meta(meta, item)
203
203
  uploaded = True
@@ -296,7 +296,7 @@ class Attachment(QObject):
296
296
  """
297
297
  if self.mode != self.MODE_DISABLED:
298
298
  if self.is_verbose():
299
- print("\nPreparing additional context...\nContext Mode: {}".format(self.mode))
299
+ print(f"\nPreparing additional context...\nContext Mode: {self.mode}")
300
300
 
301
301
  self.window.core.attachments.context.reset() # reset used files and urls
302
302
 
@@ -313,8 +313,8 @@ class Attachment(QObject):
313
313
 
314
314
  if content:
315
315
  if self.is_verbose():
316
- print("\n--- Using additional context ---\n\n{}".format(content))
317
- return "====================================\nADDITIONAL CONTEXT FROM ATTACHMENT(s): {}".format(content)
316
+ print(f"\n--- Using additional context ---\n\n{content}")
317
+ return f"====================================\nADDITIONAL CONTEXT FROM ATTACHMENT(s): {content}"
318
318
  return ""
319
319
 
320
320
  def update(self):
@@ -355,7 +355,7 @@ class Attachment(QObject):
355
355
  suffix = f' ({num_files})'
356
356
  self.window.ui.tabs['input'].setTabText(
357
357
  3,
358
- trans('attachments_uploaded.tab') + suffix,
358
+ f"{trans('attachments_uploaded.tab')}{suffix}",
359
359
  )
360
360
  """
361
361
  if num_files > 0:
@@ -462,7 +462,7 @@ class Attachment(QObject):
462
462
  if "real_path" in item:
463
463
  path = item["real_path"]
464
464
  if os.path.exists(path) and os.path.isfile(path):
465
- print("Opening attachment: {}".format(path))
465
+ print(f"Opening attachment: {path}")
466
466
  self.window.controller.files.open(path)
467
467
 
468
468
  def open_dir_src_by_idx(self, idx: int):
@@ -482,7 +482,7 @@ class Attachment(QObject):
482
482
  path = item["real_path"]
483
483
  dir = os.path.dirname(path)
484
484
  if os.path.exists(dir) and os.path.isdir(dir):
485
- print("Opening source directory: {}".format(dir))
485
+ print(f"Opening source directory: {dir}")
486
486
  self.window.controller.files.open(dir)
487
487
 
488
488
  def open_dir_dest_by_idx(self, idx: int):
@@ -501,7 +501,7 @@ class Attachment(QObject):
501
501
  dir = os.path.join(root_dir, item["uuid"])
502
502
  if os.path.exists(dir) and os.path.isdir(dir):
503
503
  self.window.controller.files.open(dir)
504
- print("Opening destination directory: {}".format(dir))
504
+ print(f"Opening destination directory: {dir}")
505
505
 
506
506
  def has_file_by_idx(self, idx: int) -> bool:
507
507
  """
@@ -591,7 +591,7 @@ class Attachment(QObject):
591
591
  """
592
592
  self.window.dispatch(KernelEvent(KernelEvent.STATE_ERROR, {
593
593
  "id": "chat",
594
- "msg": "Error reading attachments: {}".format(str(error))
594
+ "msg": f"Error reading attachments: {str(error)}"
595
595
  }))
596
596
 
597
597
  @Slot(str)
@@ -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.26 18:00:00 #
9
+ # Updated Date: 2025.08.18 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -52,12 +52,12 @@ class Command:
52
52
  # check if commands are enabled, leave only enabled commands
53
53
  for cmd in list(cmds):
54
54
  if "cmd" not in cmd:
55
- self.log("[cmd] Command without 'cmd' key: " + str(cmd))
55
+ self.log(f"[cmd] Command without 'cmd' key: {cmd}")
56
56
  cmds.remove(cmd)
57
57
  continue
58
58
  cmd_id = str(cmd["cmd"])
59
59
  if not self.window.core.command.is_enabled(cmd_id) and not ctx.force_call:
60
- self.log("[cmd] Command not allowed: " + cmd_id)
60
+ self.log(f"[cmd] Command not allowed: {cmd_id}")
61
61
  cmds.remove(cmd) # remove command from execution list
62
62
 
63
63
  # agent mode
@@ -134,4 +134,4 @@ class Command:
134
134
 
135
135
  :param data: Data to log
136
136
  """
137
- self.window.core.debug.info(data)
137
+ self.window.core.debug.info(data)
@@ -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.25 22:00:00 #
9
+ # Updated Date: 2025.08.18 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -15,6 +15,7 @@ from PySide6.QtGui import QTextCursor
15
15
  from PySide6.QtWidgets import QFileDialog, QApplication
16
16
 
17
17
  from pygpt_net.core.events import Event, AppEvent, RenderEvent
18
+ from pygpt_net.core.types import MODE_ASSISTANT
18
19
  from pygpt_net.item.ctx import CtxItem
19
20
  from pygpt_net.item.model import ModelItem
20
21
  from pygpt_net.utils import trans
@@ -138,7 +139,7 @@ class Common:
138
139
  cur.movePosition(QTextCursor.End)
139
140
  text = str(text).strip()
140
141
  if prev_text.strip() != "":
141
- text = separator + text
142
+ text = f"{separator}{text}"
142
143
  s = text
143
144
  while s:
144
145
  head, sep, s = s.partition("\n") # Split line at LF
@@ -283,7 +284,7 @@ class Common:
283
284
  self.window.stateChanged.emit(self.window.STATE_IDLE)
284
285
 
285
286
  # remotely stop assistant
286
- if mode == "assistant" and not exit:
287
+ if mode == MODE_ASSISTANT and not exit:
287
288
  try:
288
289
  self.window.controller.assistant.run_stop()
289
290
  except Exception as e:
@@ -329,14 +330,14 @@ class Common:
329
330
  if monit:
330
331
  self.window.ui.nodes['start.api_key.provider'].setText(name)
331
332
  self.window.controller.launcher.show_api_monit()
332
- self.window.update_status("Missing API KEY for provider: {}".format(name))
333
+ self.window.update_status(f"Missing API KEY for provider: {name}")
333
334
  return False
334
335
  else:
335
336
  if api_key is None or api_key == '':
336
337
  if monit:
337
338
  self.window.ui.nodes['start.api_key.provider'].setText(name)
338
339
  self.window.controller.launcher.show_api_monit()
339
- self.window.update_status("Missing API KEY for provider: {}".format(name))
340
+ self.window.update_status(f"Missing API KEY for provider: {name}")
340
341
  return False
341
342
  return True
342
343
 
@@ -450,7 +451,7 @@ class Common:
450
451
  )
451
452
  with open(file_name, 'w', encoding="utf-8") as f:
452
453
  f.write(str(text).strip())
453
- self.window.update_status(trans('status.saved') + ": " + os.path.basename(file_name))
454
+ self.window.update_status(f"{trans('status.saved')}: {os.path.basename(file_name)}")
454
455
 
455
456
  def show_response_tokens(self, ctx: CtxItem):
456
457
  """
@@ -462,11 +463,5 @@ class Common:
462
463
  if ctx.is_vision:
463
464
  extra_data = " (VISION)"
464
465
  self.window.update_status(
465
- trans('status.tokens') + ": {} + {} = {}{}".
466
- format(
467
- ctx.input_tokens,
468
- ctx.output_tokens,
469
- ctx.total_tokens,
470
- extra_data,
471
- ))
472
-
466
+ f"{trans('status.tokens')}: {ctx.input_tokens} + {ctx.output_tokens} = {ctx.total_tokens}{extra_data}"
467
+ )
@@ -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.18 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Dict
@@ -41,7 +41,7 @@ class Files:
41
41
  if len(attachments) > 0:
42
42
  ctx.attachments = attachments
43
43
  self.window.update_status(trans('status.sending'))
44
- self.window.controller.chat.log("Uploaded attachments (Assistant): {}".format(len(attachments)))
44
+ self.window.controller.chat.log(f"Uploaded attachments (Assistant): {len(attachments)}")
45
45
  return attachments
46
46
 
47
47
  def upload(self, mode: str) -> Dict[str, AttachmentItem]:
@@ -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.05 21:00:00 #
9
+ # Updated Date: 2025.08.18 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -148,7 +148,7 @@ class Input:
148
148
  except Exception as e:
149
149
  self.window.dispatch(KernelEvent(KernelEvent.STATE_ERROR, {
150
150
  "id": "chat",
151
- "msg": "Error reading attachments: {}".format(str(e))
151
+ "msg": f"Error reading attachments: {str(e)}"
152
152
  }))
153
153
  return
154
154
 
@@ -237,11 +237,11 @@ class Input:
237
237
  self.window.controller.assistant.threads.stop = False
238
238
  self.window.controller.kernel.resume()
239
239
 
240
- self.log("Input prompt: {}".format(text)) # log
240
+ self.log(f"Input prompt: {text}") # log
241
241
 
242
242
  # agent mode
243
243
  if mode == MODE_AGENT:
244
- self.log("Agent: input before: {}".format(text))
244
+ self.log(f"Agent: input before: {text}")
245
245
  text = self.window.controller.agent.legacy.on_input_before(text)
246
246
 
247
247
  # event: before input
@@ -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 00:00:00 #
9
+ # Updated Date: 2025.08.18 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Any, Optional
@@ -257,14 +257,14 @@ class Output:
257
257
  self.log("Attachments cleared.") # log
258
258
 
259
259
  if self.window.core.config.get("log.ctx"):
260
- self.log("Context: END: {}".format(ctx))
260
+ self.log(f"Context: END: {ctx}")
261
261
  else:
262
262
  self.log("Context: END.")
263
263
 
264
264
  # agent mode
265
265
  if mode == MODE_AGENT:
266
266
  agent_iterations = int(self.window.core.config.get("agent.iterations"))
267
- self.log("Agent: ctx end, iterations: {}".format(agent_iterations))
267
+ self.log(f"Agent: ctx end, iterations: {agent_iterations}")
268
268
  self.window.controller.agent.legacy.on_ctx_end(
269
269
  ctx,
270
270
  iterations=agent_iterations,
@@ -304,4 +304,4 @@ class Output:
304
304
 
305
305
  :param data: Data to log
306
306
  """
307
- self.window.controller.chat.log(data)
307
+ self.window.controller.chat.log(data)
@@ -166,6 +166,11 @@ class Render:
166
166
  meta = data.get("meta") or self.window.core.ctx.get_current_meta()
167
167
  self.on_state_changed(name, meta)
168
168
 
169
+ elif name == RenderEvent.ITEM_DELETE_ID:
170
+ self.remove_item(data.get("ctx"))
171
+ elif name == RenderEvent.ITEM_DELETE_FROM_ID:
172
+ self.remove_items_from(data.get("ctx"))
173
+
169
174
  def on_state_changed(self, state: str, meta: Optional[CtxMeta] = None) -> None:
170
175
  """
171
176
  Handle state change event
@@ -404,22 +409,22 @@ class Render:
404
409
  self.instance().on_disable_timestamp(live)
405
410
  self.update()
406
411
 
407
- def remove_item(self, id: int) -> None:
412
+ def remove_item(self, ctx: CtxItem) -> None:
408
413
  """
409
414
  Remove item from output
410
415
 
411
- :param id: context item ID
416
+ :param ctx: context item
412
417
  """
413
- self.instance().remove_item(id)
418
+ self.instance().remove_item(ctx)
414
419
  self.update()
415
420
 
416
- def remove_items_from(self, id: int) -> None:
421
+ def remove_items_from(self, ctx: CtxItem) -> None:
417
422
  """
418
423
  Remove item from output
419
424
 
420
- :param id: context item ID
425
+ :param ctx: context item
421
426
  """
422
- self.instance().remove_items_from(id)
427
+ self.instance().remove_items_from(ctx)
423
428
  self.update()
424
429
 
425
430
  def on_edit_submit(self, ctx: CtxItem) -> None:
@@ -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.18 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Dict, Any
@@ -251,9 +251,9 @@ class Response:
251
251
  try:
252
252
  self.window.controller.chat.output.handle(ctx, mode, stream)
253
253
  except Exception as e:
254
- self.window.controller.chat.log("Output ERROR: {}".format(e)) # log
254
+ self.window.controller.chat.log(f"Output ERROR: {e}") # log
255
255
  self.window.controller.chat.handle_error(e)
256
- print("Error in append text: " + str(e))
256
+ print(f"Error in append text: {e}")
257
257
 
258
258
  # post-handle, execute cmd, etc.
259
259
  self.window.controller.chat.output.post_handle(ctx, mode, stream, reply, internal)
@@ -314,10 +314,10 @@ class Response:
314
314
  :param extra: Extra data
315
315
  """
316
316
  err = extra.get("error") if "error" in extra else None
317
- self.window.controller.chat.log("Output ERROR: {}".format(err)) # log
317
+ self.window.controller.chat.log(f"Output ERROR: {err}") # log
318
318
  self.window.controller.chat.handle_error(err)
319
319
  self.window.controller.chat.common.unlock_input() # unlock input
320
- print("Error in sending text: " + str(err))
320
+ print(f"Error in sending text: {err}")
321
321
  # set state to: error
322
322
  self.window.dispatch(KernelEvent(KernelEvent.STATE_ERROR, {
323
323
  "id": "chat",
@@ -6,11 +6,10 @@
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.18 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import base64
13
- import gc
14
13
  import io
15
14
  from typing import Optional, Literal
16
15
 
@@ -327,7 +326,7 @@ class StreamWorker(QRunnable):
327
326
 
328
327
  else:
329
328
  if chunk is not None:
330
- response = str(chunk)
329
+ response = chunk if isinstance(chunk, str) else str(chunk)
331
330
 
332
331
  if response is not None and response != "" and not stopped:
333
332
  if begin and response == "":
@@ -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.06 01:00:00 #
9
+ # Updated Date: 2025.08.18 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Optional
@@ -73,6 +73,7 @@ class Text:
73
73
  ai_name = event.data['value']
74
74
 
75
75
  # prepare mode, model, etc.
76
+ agent_provider = None # agent provider (llama or openai)
76
77
  mode = self.window.core.config.get('mode')
77
78
  model = self.window.core.config.get('model')
78
79
  model_data = self.window.core.models.get(model)
@@ -93,11 +94,11 @@ class Text:
93
94
  agent_provider = self.window.core.config.get('agent.openai.provider')
94
95
 
95
96
  # o1 models: disable stream mode
96
- if mode in [MODE_AGENT_LLAMA, MODE_AUDIO]:
97
+ if mode in (MODE_AGENT_LLAMA, MODE_AUDIO):
97
98
  stream_mode = False
98
- if mode in [MODE_LLAMA_INDEX] and idx_mode == "retrieval":
99
+ if mode == MODE_LLAMA_INDEX and idx_mode == "retrieval":
99
100
  stream_mode = False
100
- if mode in [MODE_LLAMA_INDEX]:
101
+ if mode == MODE_LLAMA_INDEX:
101
102
  if not self.window.core.idx.chat.is_stream_allowed():
102
103
  stream_mode = False
103
104
 
@@ -156,7 +157,11 @@ class Text:
156
157
  self.window.dispatch(event)
157
158
 
158
159
  # agent or expert mode
159
- sys_prompt = self.window.controller.agent.experts.append_prompts(mode, sys_prompt, parent_id)
160
+ sys_prompt = self.window.controller.agent.experts.append_prompts(
161
+ mode,
162
+ sys_prompt,
163
+ parent_id
164
+ )
160
165
 
161
166
  # on pre prompt event
162
167
  event = Event(Event.PRE_PROMPT, {
@@ -221,7 +226,7 @@ class Text:
221
226
  files = self.window.core.attachments.get_all(mode)
222
227
  num_files = len(files)
223
228
  if num_files > 0:
224
- self.window.controller.chat.log("Attachments ({}): {}".format(mode, num_files))
229
+ self.window.controller.chat.log(f"Attachments ({mode}): {num_files}")
225
230
 
226
231
  # assistant
227
232
  assistant_id = self.window.core.config.get('assistant')
@@ -257,7 +262,7 @@ class Text:
257
262
  'reply': reply,
258
263
  'internal': internal,
259
264
  }
260
- if mode in [MODE_AGENT_LLAMA, MODE_AGENT_OPENAI]:
265
+ if mode in (MODE_AGENT_LLAMA, MODE_AGENT_OPENAI):
261
266
  extra['agent_idx'] = agent_idx
262
267
  extra['agent_provider'] = agent_provider
263
268
 
@@ -269,8 +274,8 @@ class Text:
269
274
  self.window.dispatch(event)
270
275
 
271
276
  except Exception as e:
272
- self.window.controller.chat.log("Bridge call ERROR: {}".format(e)) # log
277
+ self.window.controller.chat.log(f"Bridge call ERROR: {e}") # log
273
278
  self.window.controller.chat.handle_error(e)
274
- print("Error when calling bridge: " + str(e))
279
+ print(f"Error when calling bridge: {e}")
275
280
 
276
- return ctx
281
+ return ctx