pygpt-net 2.6.43__py3-none-any.whl → 2.6.44__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.
@@ -6,9 +6,8 @@
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.09.07 05:00:00 #
9
+ # Updated Date: 2025.09.12 20:00:00 #
10
10
  # ================================================== #
11
- import os
12
11
 
13
12
  from openai import OpenAI
14
13
 
@@ -24,7 +23,6 @@ from pygpt_net.core.types import (
24
23
  )
25
24
  from pygpt_net.core.bridge.context import BridgeContext
26
25
  from pygpt_net.item.model import ModelItem
27
- from pygpt_net.provider.api.fake.generator import FakeOpenAIStream
28
26
 
29
27
  from .audio import Audio
30
28
  from .assistants import Assistants
@@ -119,7 +117,7 @@ class ApiOpenAI:
119
117
  use_responses_api = self.responses.is_enabled(model, mode, parent_mode, is_expert_call, preset)
120
118
  ctx.use_responses_api = use_responses_api # set in context
121
119
 
122
- fake_stream = self.window.controller.debug.fake_stream_enabled() # for testing
120
+ fixtures = self.window.controller.debug.fixtures
123
121
 
124
122
  # get model id
125
123
  model_id = None
@@ -159,15 +157,9 @@ class ApiOpenAI:
159
157
  if is_realtime:
160
158
  return True
161
159
 
162
- if fake_stream:
163
- # fake stream for testing
160
+ if fixtures.is_enabled("stream"): # fake stream for testing
164
161
  use_responses_api = False
165
- ctx.use_responses_api = False
166
- test_code_path = os.path.join(self.window.core.config.get_app_path(), "data", "js", "app.js")
167
- response = FakeOpenAIStream(code_path=test_code_path).stream(
168
- api="raw",
169
- chunk="code",
170
- )
162
+ response = fixtures.get_stream_generator(ctx)
171
163
  else:
172
164
  # responses API
173
165
  if use_responses_api:
@@ -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.09.12 00:00:00 #
9
+ # Updated Date: 2025.09.12 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -62,6 +62,19 @@ class Patch:
62
62
  patch_css('web-blocks.css', True)
63
63
  updated = True
64
64
 
65
+ # < 2.6.44
66
+ if old < parse_version("2.6.44"):
67
+ print("Migrating config from < 2.6.44...")
68
+ if "render.code_syntax.stream_n_line" not in data:
69
+ data["render.code_syntax.stream_n_line"] = 25
70
+ if "render.code_syntax.stream_n_chars" not in data:
71
+ data["render.code_syntax.stream_n_chars"] = 5000
72
+ if "render.code_syntax.disabled" not in data:
73
+ data["render.code_syntax.disabled"] = False
74
+ if "render.msg.user.collapse.px" not in data:
75
+ data["render.msg.user.collapse.px"] = 1500
76
+ updated = True
77
+
65
78
  # update file
66
79
  migrated = False
67
80
  if updated:
@@ -23,6 +23,7 @@ class ContextMenu:
23
23
  _ICON_PASTE = QIcon(":/icons/paste.svg")
24
24
  _ICON_CODE = QIcon(":/icons/code.svg")
25
25
  _ICON_TEXT = QIcon(":/icons/text.svg")
26
+ _ICON_TRANSLATOR = QIcon(":/icons/translate.svg")
26
27
 
27
28
  def __init__(self, window=None):
28
29
  """
@@ -94,11 +95,11 @@ class ContextMenu:
94
95
  menu.addSeparator()
95
96
  translator = tools.get("translator")
96
97
  if add_left:
97
- action = QAction(self._ICON_TEXT, trans('text.context_menu.copy_to.translator_left'), menu)
98
+ action = QAction(self._ICON_TRANSLATOR, trans('text.context_menu.copy_to.translator_left'), menu)
98
99
  action.triggered.connect(lambda checked=False: translator.append_content("left", selected_text))
99
100
  menu.addAction(action)
100
101
  if add_right:
101
- action = QAction(self._ICON_TEXT, trans('text.context_menu.copy_to.translator_right'), menu)
102
+ action = QAction(self._ICON_TRANSLATOR, trans('text.context_menu.copy_to.translator_right'), menu)
102
103
  action.triggered.connect(lambda checked=False: translator.append_content("right", selected_text))
103
104
  menu.addAction(action)
104
105
 
@@ -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.09.05 18:00:00 #
9
+ # Updated Date: 2025.09.12 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6 import QtCore
@@ -264,7 +264,7 @@ class CtxList:
264
264
  is_important = data.important
265
265
  is_attachment = data.has_additional_ctx()
266
266
  in_group = bool(data.group)
267
- append_dt = False if (is_group and self._pinned_separators) or ((not is_group) and self._group_separators) else append_dt
267
+ append_dt = False if (is_group and self._group_separators) or ((not is_group) and self._group_separators) else append_dt
268
268
 
269
269
  dt = self.convert_date(data.updated)
270
270
  date_time_str = datetime.fromtimestamp(data.updated).strftime("%Y-%m-%d %H:%M")
@@ -337,4 +337,4 @@ class CtxList:
337
337
  elif 30 <= days_ago < 32:
338
338
  return trans('dt.month')
339
339
  else:
340
- return date.strftime("%Y-%m-%d")
340
+ return date.strftime("%Y-%m-%d")
@@ -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.24 23:00:00 #
9
+ # Updated Date: 2025.09.12 20:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QAction
@@ -46,7 +46,7 @@ class Debug:
46
46
  'db',
47
47
  'logger',
48
48
  'app.log',
49
- 'fake_stream',
49
+ 'fixtures.stream',
50
50
  'kernel',
51
51
  'render'
52
52
  )
@@ -72,32 +72,45 @@ class Debug:
72
72
  m['debug.logger'].triggered.connect(dbg.toggle_logger)
73
73
  m['debug.app.log'].triggered.connect(dbg.toggle_app_log)
74
74
  m['debug.render'].triggered.connect(dbg.toggle_render)
75
- m['debug.fake_stream'].triggered.connect(dbg.toggle_fake_stream)
75
+ m['debug.fixtures.stream'].triggered.connect(
76
+ lambda _=False: dbg.fixtures.toggle_from_menu("stream")
77
+ )
76
78
 
77
79
  m['menu.debug'] = win.menuBar().addMenu(trans("menu.debug"))
78
80
  menu = m['menu.debug']
79
81
  menu.addActions(
80
- [m['debug.logger'],
81
- m['debug.render'],
82
- m['debug.db'],
83
- m['debug.app.log'],
84
- m['debug.fake_stream']]
82
+ [
83
+ m['debug.logger'],
84
+ m['debug.render'],
85
+ m['debug.db'],
86
+ m['debug.app.log']
87
+ ]
88
+ )
89
+
90
+ menu.addSeparator()
91
+ menu.addActions(
92
+ [
93
+ m['debug.fixtures.stream']
94
+ ]
85
95
  )
96
+
86
97
  menu.addSeparator()
87
- menu.addActions([
88
- m['debug.agent'],
89
- m['debug.assistants'],
90
- m['debug.attachments'],
91
- m['debug.config'],
92
- m['debug.context'],
93
- m['debug.events'],
94
- m['debug.indexes'],
95
- m['debug.kernel'],
96
- m['debug.models'],
97
- m['debug.plugins'],
98
- m['debug.presets'],
99
- m['debug.tabs'],
100
- m['debug.ui'],
101
- ])
98
+ menu.addActions(
99
+ [
100
+ m['debug.agent'],
101
+ m['debug.assistants'],
102
+ m['debug.attachments'],
103
+ m['debug.config'],
104
+ m['debug.context'],
105
+ m['debug.events'],
106
+ m['debug.indexes'],
107
+ m['debug.kernel'],
108
+ m['debug.models'],
109
+ m['debug.plugins'],
110
+ m['debug.presets'],
111
+ m['debug.tabs'],
112
+ m['debug.ui'],
113
+ ]
114
+ )
102
115
 
103
116
  m['debug.render'].setChecked(bool(win.core.config.get('debug.render')))
@@ -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.24 23:00:00 #
9
+ # Updated Date: 2025.09.12 23:47:47 #
10
10
  # ================================================== #
11
11
 
12
12
  import datetime
@@ -47,12 +47,26 @@ class ContextList(BaseList):
47
47
  'attachment': QIcon(":/icons/attachment.svg"),
48
48
  }
49
49
  self._color_icon_cache = {}
50
+
51
+ # Use a custom delegate for labels/pinned/attachment indicators and group border indicator
50
52
  self.setItemDelegate(ImportantItemDelegate(self, self._icons['attachment']))
53
+
54
+ # Ensure context menu works as before
51
55
  self.setContextMenuPolicy(Qt.CustomContextMenu)
52
56
  self.customContextMenuRequested.connect(self.show_context_menu)
53
57
  self._backup_selection = None
54
58
  self.restore_after_ctx_menu = True
55
59
 
60
+ # Make group rows visually stick to the left edge (if this is a tree view).
61
+ # Children remain indented by delegate's manual shift (+15 px), preserving structure.
62
+ try:
63
+ if hasattr(self, 'setIndentation'):
64
+ # Set tree indentation to 0 so group/folder rows do not look like children
65
+ self.setIndentation(0)
66
+ except Exception:
67
+ # Safe no-op if the underlying view does not support setIndentation
68
+ pass
69
+
56
70
  @property
57
71
  def _model(self):
58
72
  return self.window.ui.models['ctx.list']
@@ -62,6 +76,9 @@ class ContextList(BaseList):
62
76
  return self.window.ui.nodes['ctx.list']
63
77
 
64
78
  def _color_icon(self, color: QColor) -> QIcon:
79
+ """
80
+ Returns (and caches) a solid color icon pixmap for menu items.
81
+ """
65
82
  key = color.rgba()
66
83
  icon = self._color_icon_cache.get(key)
67
84
  if icon is None:
@@ -405,11 +422,19 @@ class ContextList(BaseList):
405
422
 
406
423
  class ImportantItemDelegate(QtWidgets.QStyledItemDelegate):
407
424
  """
408
- Label color delegate
425
+ Item delegate that paints:
426
+ - Attachment icon on the right side (centered vertically),
427
+ - Pinned indicator (small circle) in the top-right corner (overlays if needed),
428
+ - Label color as a full-height vertical bar on the left for labeled items,
429
+ - Group enclosure indicator for expanded groups:
430
+ - thin vertical bar (default 2 px) on the left side of child rows area,
431
+ - thin horizontal bar (default 2 px) at the bottom of the last child row.
409
432
  """
410
433
  def __init__(self, parent=None, attachment_icon: QIcon = None):
411
434
  super().__init__(parent)
412
435
  self._attachment_icon = attachment_icon or QIcon(":/icons/attachment.svg")
436
+
437
+ # Predefined label colors (status -> QColor)
413
438
  self._status_colors = {
414
439
  0: QColor(100, 100, 100),
415
440
  1: QColor(255, 0, 0),
@@ -420,64 +445,219 @@ class ImportantItemDelegate(QtWidgets.QStyledItemDelegate):
420
445
  6: QColor(75, 0, 130),
421
446
  7: QColor(238, 130, 238),
422
447
  }
423
- self._pin_pen = QtGui.QPen(QtCore.Qt.black, 0.5, QtCore.Qt.SolidLine)
424
448
 
425
- def paint(self, painter, option, index):
426
- if index.parent().isValid():
427
- option.rect.adjust(15, 0, 0, 0)
428
-
429
- super(ImportantItemDelegate, self).paint(painter, option, index)
449
+ # Visual tuning constants
450
+ self._pin_pen = QtGui.QPen(QtCore.Qt.black, 0.5, QtCore.Qt.SolidLine)
451
+ self._pin_diameter = 4 # Small pinned circle diameter
452
+ self._pin_margin = 3 # Margin from top and right edges
453
+ self._attach_spacing = 4 # Kept for potential future layout tweaks
454
+ self._label_bar_width = 4 # Full-height label bar width (left side)
455
+ self._label_v_margin = 3 # 3px top/bottom margin for the label bar
456
+
457
+ # Manual child indent to keep hierarchy visible when view indentation is 0
458
+ self._child_indent = 15
459
+
460
+ # Group indicator defaults (can be overridden by config)
461
+ self._group_indicator_enabled = True
462
+ self._group_indicator_width = 2
463
+ self._group_indicator_color = QColor(67, 75, 78) # soft gray
464
+ self._group_indicator_gap = 6 # gap between child content left and the vertical bar
465
+ self._group_indicator_bottom_offset = 6
466
+
467
+ # Try to load customization from application config (safe if missing)
468
+ self._init_group_indicator_from_config()
469
+
470
+ def _init_group_indicator_from_config(self):
471
+ """
472
+ Initialize group indicator settings from config if available.
473
+ Accepts:
474
+ - color: list/tuple [r,g,b], dict {'r','g','b'}, "#RRGGBB", or "r,g,b"
475
+ - width: int
476
+ - enabled: bool
477
+ - gap: int
478
+ """
479
+ try:
480
+ view = self.parent()
481
+ window = getattr(view, 'window', None)
482
+ cfg = getattr(getattr(window, 'core', None), 'config', None)
483
+ if not cfg:
484
+ return
430
485
 
431
- data = index.data(QtCore.Qt.ItemDataRole.UserRole)
432
- if data:
433
- label = data.get("label", 0)
434
- is_important = data.get("is_important", False)
435
- is_attachment = data.get("is_attachment", False)
486
+ enabled = cfg.get('ctx.records.groups.indicator.enabled')
487
+ if enabled is not None:
488
+ self._group_indicator_enabled = bool(enabled)
489
+
490
+ width = cfg.get('ctx.records.groups.indicator.width')
491
+ if isinstance(width, int) and width >= 0:
492
+ self._group_indicator_width = int(width)
493
+
494
+ gap = cfg.get('ctx.records.groups.indicator.gap')
495
+ if isinstance(gap, int) and gap >= 0:
496
+ self._group_indicator_gap = int(gap)
497
+
498
+ color = cfg.get('ctx.records.groups.indicator.color')
499
+ qcolor = self._parse_qcolor(color)
500
+ if qcolor is not None:
501
+ self._group_indicator_color = qcolor
502
+ except Exception:
503
+ # Fail-safe: keep defaults if anything goes wrong
504
+ pass
505
+
506
+ def _parse_qcolor(self, value):
507
+ """
508
+ Parses various color formats into QColor.
509
+ Supports:
510
+ - QColor
511
+ - list/tuple [r, g, b]
512
+ - dict {'r':..,'g':..,'b':..} or {'red':..,'green':..,'blue':..}
513
+ - "#RRGGBB"
514
+ - "r,g,b" (also "r;g;b")
515
+ """
516
+ if value is None:
517
+ return None
518
+ if isinstance(value, QColor):
519
+ return value
520
+ if isinstance(value, (list, tuple)) and len(value) >= 3:
521
+ try:
522
+ r, g, b = int(value[0]), int(value[1]), int(value[2])
523
+ return QColor(r, g, b)
524
+ except Exception:
525
+ return None
526
+ if isinstance(value, dict):
527
+ keys = value.keys()
528
+ try:
529
+ if all(k in keys for k in ('r', 'g', 'b')):
530
+ return QColor(int(value['r']), int(value['g']), int(value['b']))
531
+ if all(k in keys for k in ('red', 'green', 'blue')):
532
+ return QColor(int(value['red']), int(value['green']), int(value['blue']))
533
+ except Exception:
534
+ return None
535
+ if isinstance(value, str):
536
+ s = value.strip()
537
+ if s.startswith('#'):
538
+ qc = QColor(s)
539
+ return qc if qc.isValid() else None
540
+ s = s.replace(';', ',')
541
+ parts = [p.strip() for p in s.split(',') if p.strip()]
542
+ if len(parts) >= 3:
543
+ try:
544
+ r, g, b = int(parts[0]), int(parts[1]), int(parts[2])
545
+ return QColor(r, g, b)
546
+ except Exception:
547
+ return None
548
+ return None
436
549
 
550
+ def paint(self, painter, option, index):
551
+ # Shift children by +15 px to keep them visually nested.
552
+ is_child = index.parent().isValid()
553
+ if is_child:
554
+ option.rect.adjust(self._child_indent, 0, 0, 0)
555
+
556
+ # Detect if this row is a group/folder (top-level section).
557
+ is_group = False
558
+ try:
559
+ model = index.model()
560
+ item = model.itemFromIndex(index) if hasattr(model, "itemFromIndex") else None
561
+ is_group = bool(item is not None and getattr(item, 'isFolder', False))
562
+ except Exception:
563
+ is_group = False
564
+
565
+ # Default painting:
566
+ # - For groups: translate painter -8 px to push folder/icon closer to the left edge.
567
+ # - For others: paint normally.
568
+ if is_group:
437
569
  painter.save()
570
+ painter.translate(-2, 0)
571
+ super(ImportantItemDelegate, self).paint(painter, option, index)
572
+ painter.restore()
573
+ else:
574
+ super(ImportantItemDelegate, self).paint(painter, option, index)
575
+
576
+ # Group enclosure indicator (left bar + bottom bar on last child)
577
+ # This applies only to child rows (i.e., when a group is expanded).
578
+ if self._group_indicator_enabled and not is_group and is_child and self._group_indicator_width > 0:
579
+ try:
580
+ painter.save()
581
+ # Use solid fill for crisp 2px bars (no anti-alias blur)
582
+ painter.setRenderHint(QtGui.QPainter.Antialiasing, False)
583
+ color = self._group_indicator_color
584
+ painter.setPen(QtCore.Qt.NoPen)
585
+ painter.setBrush(color)
438
586
 
439
- if is_attachment:
587
+ # Compute vertical bar geometry:
588
+ # Place the bar to the LEFT of the child content area, leaving a small gap.
589
+ child_left = option.rect.x()
590
+ bar_w = self._group_indicator_width
591
+ # Left edge of the vertical bar (never below 0)
592
+ vbar_left = max(0, child_left - (self._group_indicator_gap + bar_w))
593
+ vbar_rect = QtCore.QRect(vbar_left, option.rect.y(), bar_w, option.rect.height())
594
+ painter.drawRect(vbar_rect)
595
+
596
+ painter.restore()
597
+ except Exception:
598
+ # Fail-safe: do not block painting if anything goes wrong
599
+ pass
600
+
601
+ # Custom data painting for non-group items only (labels, pinned, attachments).
602
+ if not is_group:
603
+ data = index.data(QtCore.Qt.ItemDataRole.UserRole)
604
+ if data:
605
+ label = data.get("label", 0)
606
+ is_important = data.get("is_important", False)
607
+ is_attachment = data.get("is_attachment", False)
608
+
609
+ painter.save()
610
+
611
+ # Draw attachment icon on the right (centered vertically).
612
+ # This is painted first, so the pin can overlay it when needed.
440
613
  icon_size = option.decorationSize or QtCore.QSize(16, 16)
441
- icon_pos = option.rect.right() - icon_size.width()
442
- y = option.rect.top() + (option.rect.height() - icon_size.height()) // 2
443
- icon_rect = QtCore.QRect(
444
- icon_pos,
445
- y,
446
- icon_size.width(),
447
- icon_size.height()
448
- )
449
- self._attachment_icon.paint(painter, icon_rect, QtCore.Qt.AlignCenter)
450
-
451
- if is_important:
452
- color = self.get_color_for_status(3)
453
- square_size = 3
454
- square_rect = QtCore.QRect(
455
- option.rect.left(),
456
- option.rect.top() + 2,
457
- square_size,
458
- square_size,
459
- )
460
- painter.setBrush(color)
461
- painter.setPen(self._pin_pen)
462
- painter.drawRect(square_rect)
463
-
464
- if label > 0:
465
- color = self.get_color_for_status(label)
466
- square_size = 5
467
- y = option.rect.center().y() - (square_size // 2) + 2
468
- square_rect = QtCore.QRect(
469
- option.rect.left(),
470
- y,
471
- square_size,
472
- square_size,
473
- )
474
- painter.setBrush(color)
475
- painter.setPen(QtCore.Qt.NoPen)
476
- painter.drawRect(square_rect)
614
+ if is_attachment:
615
+ icon_pos_x = option.rect.right() - icon_size.width()
616
+ icon_pos_y = option.rect.top() + (option.rect.height() - icon_size.height()) // 2
617
+ icon_rect = QtCore.QRect(
618
+ icon_pos_x,
619
+ icon_pos_y,
620
+ icon_size.width(),
621
+ icon_size.height()
622
+ )
623
+ self._attachment_icon.paint(painter, icon_rect, QtCore.Qt.AlignCenter)
477
624
 
478
- painter.restore()
625
+ # Pinned indicator (small circle) kept at a fixed top-right position.
626
+ # It does not shift left when the attachment is present; it overlays above it.
627
+ if is_important:
628
+ painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
629
+ painter.setCompositionMode(QtGui.QPainter.CompositionMode_SourceOver)
630
+ color = self.get_color_for_status(3)
631
+
632
+ x = option.rect.x() + option.rect.width() - self._pin_margin - self._pin_diameter
633
+ y = option.rect.y() + self._pin_margin
634
+ pin_rect = QtCore.QRect(x, y, self._pin_diameter, self._pin_diameter)
635
+
636
+ painter.setBrush(color)
637
+ painter.setPen(self._pin_pen)
638
+ painter.drawEllipse(pin_rect)
639
+
640
+ # Label bar on the left with 3px vertical margins
641
+ if label > 0:
642
+ color = self.get_color_for_status(label)
643
+ bar_y = option.rect.y() + self._label_v_margin
644
+ bar_h = max(1, option.rect.height() - 2 * self._label_v_margin)
645
+ bar_rect = QtCore.QRect(
646
+ option.rect.x(),
647
+ bar_y,
648
+ self._label_bar_width,
649
+ bar_h,
650
+ )
651
+ painter.setBrush(color)
652
+ painter.setPen(QtCore.Qt.NoPen)
653
+ painter.drawRect(bar_rect)
654
+
655
+ painter.restore()
479
656
 
480
657
  def get_color_for_status(self, status: int) -> QColor:
658
+ """
659
+ Returns color mapped for given status value.
660
+ """
481
661
  return self._status_colors.get(status, self._status_colors[0])
482
662
 
483
663
 
@@ -485,6 +665,7 @@ class GroupItem(QStandardItem):
485
665
  def __init__(self, icon, name, id):
486
666
  super().__init__(icon, name)
487
667
  self.id = id
668
+ # Keep name as provided; display text is handled by the model/view
488
669
  self.name = name
489
670
  self.isFolder = True
490
671
  self.isPinned = False
@@ -496,6 +677,7 @@ class Item(QStandardItem):
496
677
  def __init__(self, name, id):
497
678
  super().__init__(name)
498
679
  self.id = id
680
+ # Keep name as provided; display text is handled by the model/view
499
681
  self.name = name
500
682
  self.isFolder = False
501
683
  self.isPinned = False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pygpt-net
3
- Version: 2.6.43
3
+ Version: 2.6.44
4
4
  Summary: Desktop AI Assistant powered by: OpenAI GPT-5, GPT-4, o1, o3, Gemini, Claude, Grok, DeepSeek, and other models supported by Llama Index, and Ollama. Chatbot, agents, completion, image generation, vision analysis, speech-to-text, plugins, internet access, file handling, command execution and more.
5
5
  License: MIT
6
6
  Keywords: ai,api,api key,app,assistant,bielik,chat,chatbot,chatgpt,claude,dall-e,deepseek,desktop,gemini,gpt,gpt-3.5,gpt-4,gpt-4-vision,gpt-4o,gpt-5,gpt-oss,gpt3.5,gpt4,grok,langchain,llama-index,llama3,mistral,o1,o3,ollama,openai,presets,py-gpt,py_gpt,pygpt,pyside,qt,text completion,tts,ui,vision,whisper
@@ -118,7 +118,7 @@ Description-Content-Type: text/markdown
118
118
 
119
119
  [![pygpt](https://snapcraft.io/pygpt/badge.svg)](https://snapcraft.io/pygpt)
120
120
 
121
- Release: **2.6.43** | build: **2025-09-12** | Python: **>=3.10, <3.14**
121
+ Release: **2.6.44** | build: **2025-09-12** | Python: **>=3.10, <3.14**
122
122
 
123
123
  > Official website: https://pygpt.net | Documentation: https://pygpt.readthedocs.io
124
124
  >
@@ -3567,6 +3567,14 @@ may consume additional tokens that are not displayed in the main window.
3567
3567
 
3568
3568
  ## Recent changes:
3569
3569
 
3570
+ **2.6.44 (2025-09-12)**
3571
+
3572
+ - Added: Auto-collapse for large user input blocks.
3573
+ - Added: Configuration for syntax highlighting intervals.
3574
+ - Improved: Visibility of label icons.
3575
+ - Improved: Scrolling of code blocks.
3576
+ - Fixed: Parsing of quotes in custom markdown blocks.
3577
+
3570
3578
  **2.6.43 (2025-09-12)**
3571
3579
 
3572
3580
  - Fixed: preset restoration when switching profiles.