pygpt-net 2.6.50__py3-none-any.whl → 2.6.52__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.
- pygpt_net/CHANGELOG.txt +10 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +3 -1
- pygpt_net/controller/__init__.py +4 -2
- pygpt_net/controller/calendar/calendar.py +2 -4
- pygpt_net/controller/calendar/note.py +0 -0
- pygpt_net/controller/ctx/ctx.py +8 -3
- pygpt_net/controller/ui/tabs.py +31 -7
- pygpt_net/core/calendar/calendar.py +2 -2
- pygpt_net/core/ctx/output.py +4 -2
- pygpt_net/core/render/web/renderer.py +3 -4
- pygpt_net/core/tabs/tab.py +42 -9
- pygpt_net/core/tabs/tabs.py +7 -9
- pygpt_net/data/config/config.json +5 -5
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/css/style.dark.css +5 -0
- pygpt_net/data/locale/plugin.mcp.en.ini +12 -0
- pygpt_net/plugin/mcp/__init__.py +12 -0
- pygpt_net/plugin/mcp/config.py +103 -0
- pygpt_net/plugin/mcp/plugin.py +513 -0
- pygpt_net/plugin/mcp/worker.py +263 -0
- pygpt_net/provider/core/config/patch.py +8 -1
- pygpt_net/ui/dialog/plugins.py +1 -3
- pygpt_net/ui/widget/element/labels.py +1 -2
- pygpt_net/ui/widget/tabs/body.py +24 -5
- {pygpt_net-2.6.50.dist-info → pygpt_net-2.6.52.dist-info}/METADATA +24 -4
- {pygpt_net-2.6.50.dist-info → pygpt_net-2.6.52.dist-info}/RECORD +29 -24
- {pygpt_net-2.6.50.dist-info → pygpt_net-2.6.52.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.50.dist-info → pygpt_net-2.6.52.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.50.dist-info → pygpt_net-2.6.52.dist-info}/entry_points.txt +0 -0
pygpt_net/CHANGELOG.txt
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
2.6.52 (2025-09-17)
|
|
2
|
+
|
|
3
|
+
- Added MCP plugin: Provides access to remote tools via the Model Context Protocol (MCP), including stdio, SSE, and Streamable HTTP transports, with per-server allow/deny filtering, Authorization header support, and a tools cache.
|
|
4
|
+
- Fixed: tab tooltips reload on profile switch.
|
|
5
|
+
|
|
6
|
+
2.6.51 (2025-09-16)
|
|
7
|
+
|
|
8
|
+
- Fix: Automatically reloading calendar notes.
|
|
9
|
+
- Fix: Context menu CSS background color for calendar items.
|
|
10
|
+
|
|
1
11
|
2.6.50 (2025-09-16)
|
|
2
12
|
|
|
3
13
|
- Optimized: Improved memory cleanup when switching profiles and unloading tabs.
|
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.09.
|
|
9
|
+
# Updated Date: 2025.09.17 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.
|
|
17
|
-
__build__ = "2025-09-
|
|
16
|
+
__version__ = "2.6.52"
|
|
17
|
+
__build__ = "2025-09-17"
|
|
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/app.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.09.
|
|
9
|
+
# Updated Date: 2025.09.16 22:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import os
|
|
@@ -96,6 +96,7 @@ from pygpt_net.plugin.bitbucket import Plugin as BitbucketPlugin
|
|
|
96
96
|
from pygpt_net.plugin.server import Plugin as ServerPlugin
|
|
97
97
|
from pygpt_net.plugin.tuya import Plugin as TuyaPlugin
|
|
98
98
|
from pygpt_net.plugin.wikipedia import Plugin as WikipediaPlugin
|
|
99
|
+
from pygpt_net.plugin.mcp import Plugin as MCPPlugin
|
|
99
100
|
|
|
100
101
|
# agents (Llama-index)
|
|
101
102
|
# from pygpt_net.provider.agents.llama_index.legacy.openai import OpenAIAgent
|
|
@@ -425,6 +426,7 @@ def run(**kwargs):
|
|
|
425
426
|
launcher.add_plugin(ServerPlugin())
|
|
426
427
|
launcher.add_plugin(TuyaPlugin())
|
|
427
428
|
launcher.add_plugin(WikipediaPlugin())
|
|
429
|
+
launcher.add_plugin(MCPPlugin())
|
|
428
430
|
|
|
429
431
|
# register custom plugins
|
|
430
432
|
plugins = kwargs.get('plugins', None)
|
pygpt_net/controller/__init__.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.09.
|
|
9
|
+
# Updated Date: 2025.09.16 22:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from .access import Access
|
|
@@ -156,9 +156,12 @@ class Controller:
|
|
|
156
156
|
print(trans("status.reloading.profile.begin"))
|
|
157
157
|
|
|
158
158
|
try:
|
|
159
|
+
self.ui.tabs.locked = True # lock tabs
|
|
159
160
|
self.window.core.reload() # db, config, patch, etc.
|
|
160
161
|
self.ui.tabs.reload()
|
|
161
162
|
self.ctx.reload()
|
|
163
|
+
self.ui.tabs.locked = False # unlock tabs
|
|
164
|
+
|
|
162
165
|
self.settings.reload()
|
|
163
166
|
self.assistant.reload()
|
|
164
167
|
self.attachment.reload()
|
|
@@ -181,7 +184,6 @@ class Controller:
|
|
|
181
184
|
# post-reload
|
|
182
185
|
self.ui.tabs.reload_after()
|
|
183
186
|
self.ctx.reload_after()
|
|
184
|
-
self.ui.tabs.restore_data() # restore opened tabs data
|
|
185
187
|
self.kernel.restart()
|
|
186
188
|
self.theme.reload_all() # do not reload theme if no change
|
|
187
189
|
|
|
@@ -6,11 +6,9 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date:
|
|
9
|
+
# Updated Date: 2025.09.16 11:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
|
-
from typing import Optional
|
|
13
|
-
|
|
14
12
|
from pygpt_net.core.tabs.tab import Tab
|
|
15
13
|
|
|
16
14
|
from .note import Note
|
|
@@ -42,7 +40,7 @@ class Calendar:
|
|
|
42
40
|
|
|
43
41
|
:return: True if calendar is loaded
|
|
44
42
|
"""
|
|
45
|
-
return hasattr(self.window.ui, 'calendar') and
|
|
43
|
+
return hasattr(self.window.ui, 'calendar') and "select" in self.window.ui.calendar
|
|
46
44
|
|
|
47
45
|
def update(self, all: bool = True):
|
|
48
46
|
"""
|
|
File without changes
|
pygpt_net/controller/ctx/ctx.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.09.16
|
|
9
|
+
# Updated Date: 2025.09.16 22:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from typing import Optional, List
|
|
@@ -1289,14 +1289,19 @@ class Ctx:
|
|
|
1289
1289
|
|
|
1290
1290
|
def reload(self):
|
|
1291
1291
|
"""Reload ctx"""
|
|
1292
|
+
self.edit_meta_id = None
|
|
1293
|
+
self.edit_item_id = None
|
|
1294
|
+
self.group_id = None
|
|
1295
|
+
self.selected = []
|
|
1296
|
+
self._infinite_scroll_refresh = False
|
|
1292
1297
|
self.reset_loaded_total() # reset paging
|
|
1293
1298
|
self.window.core.ctx.reset()
|
|
1294
1299
|
self.setup()
|
|
1295
|
-
self.update()
|
|
1296
|
-
self.refresh()
|
|
1297
1300
|
|
|
1298
1301
|
def reload_after(self):
|
|
1299
1302
|
"""After reload"""
|
|
1303
|
+
self.update()
|
|
1304
|
+
self.refresh()
|
|
1300
1305
|
self.new_if_empty()
|
|
1301
1306
|
|
|
1302
1307
|
def add_selected(self, id: int):
|
pygpt_net/controller/ui/tabs.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.09.16
|
|
9
|
+
# Updated Date: 2025.09.16 22:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from typing import Any, Optional, Tuple
|
|
@@ -40,12 +40,13 @@ class Tabs:
|
|
|
40
40
|
self.create_new_on_tab = True
|
|
41
41
|
self.col = {}
|
|
42
42
|
|
|
43
|
-
def setup(self):
|
|
43
|
+
def setup(self, reload: bool = False):
|
|
44
44
|
"""Setup tabs"""
|
|
45
45
|
w = self.window
|
|
46
46
|
w.core.tabs.load()
|
|
47
47
|
w.controller.notepad.load()
|
|
48
|
-
|
|
48
|
+
if not reload:
|
|
49
|
+
self.setup_options()
|
|
49
50
|
self.initialized = True
|
|
50
51
|
|
|
51
52
|
def setup_options(self):
|
|
@@ -130,13 +131,31 @@ class Tabs:
|
|
|
130
131
|
self.col[curr_column] = curr_tab.pid
|
|
131
132
|
self.debug()
|
|
132
133
|
|
|
134
|
+
def unload(self):
|
|
135
|
+
"""Unload tabs"""
|
|
136
|
+
self.active_idx = 0
|
|
137
|
+
self.prev_idx = 0
|
|
138
|
+
self.appended = False
|
|
139
|
+
self.current = 0
|
|
140
|
+
self.column_idx = 0
|
|
141
|
+
self.tmp_column_idx = 0
|
|
142
|
+
self.create_new_on_tab = True
|
|
143
|
+
self.col = {}
|
|
144
|
+
columns = self.window.ui.layout.columns
|
|
145
|
+
for col in columns:
|
|
146
|
+
col.setUpdatesEnabled(False)
|
|
147
|
+
self.window.core.tabs.remove_all()
|
|
148
|
+
for col in columns:
|
|
149
|
+
col.setUpdatesEnabled(True)
|
|
150
|
+
|
|
133
151
|
def reload(self):
|
|
134
152
|
"""Reload tabs"""
|
|
153
|
+
self.unload()
|
|
135
154
|
columns = self.window.ui.layout.columns
|
|
136
155
|
for col in columns:
|
|
137
156
|
col.setUpdatesEnabled(False)
|
|
138
|
-
self.
|
|
139
|
-
self.
|
|
157
|
+
self.setup(reload=True)
|
|
158
|
+
self.restore_data()
|
|
140
159
|
self.window.dispatch(RenderEvent(RenderEvent.PREPARE))
|
|
141
160
|
self.debug()
|
|
142
161
|
for col in columns:
|
|
@@ -172,6 +191,9 @@ class Tabs:
|
|
|
172
191
|
:param idx: tab index
|
|
173
192
|
:param column_idx: column index
|
|
174
193
|
"""
|
|
194
|
+
if idx == -1:
|
|
195
|
+
return
|
|
196
|
+
|
|
175
197
|
w = self.window
|
|
176
198
|
core = w.core
|
|
177
199
|
tabs_core = core.tabs
|
|
@@ -594,7 +616,9 @@ class Tabs:
|
|
|
594
616
|
|
|
595
617
|
:param tooltip: tooltip text
|
|
596
618
|
"""
|
|
597
|
-
tabs = self.window.ui.layout.
|
|
619
|
+
tabs = self.window.ui.layout.get_tabs_by_idx(self.column_idx)
|
|
620
|
+
if tabs is not None and 0 <= self.current < tabs.count():
|
|
621
|
+
tabs.setTabToolTip(self.current, tooltip)
|
|
598
622
|
tabs.setTabToolTip(self.current, tooltip)
|
|
599
623
|
self.debug()
|
|
600
624
|
|
|
@@ -656,7 +680,7 @@ class Tabs:
|
|
|
656
680
|
"""
|
|
657
681
|
if self.get_current_type() != Tab.TAB_CHAT:
|
|
658
682
|
return
|
|
659
|
-
tabs = self.window.ui.layout.
|
|
683
|
+
tabs = self.window.ui.layout.get_tabs_by_idx(self.column_idx)
|
|
660
684
|
tooltip = title
|
|
661
685
|
tabs.setTabToolTip(idx, tooltip)
|
|
662
686
|
if len(title) > self.TAB_CHAT_MAX_CHARS:
|
|
@@ -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:
|
|
9
|
+
# Updated Date: 2025.09.16 11:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import datetime
|
|
@@ -102,7 +102,7 @@ class Calendar:
|
|
|
102
102
|
dt_key = datetime.datetime(note.year, note.month, note.day).strftime("%Y-%m-%d")
|
|
103
103
|
if dt_key not in self.items:
|
|
104
104
|
return False
|
|
105
|
-
note.
|
|
105
|
+
note.updated = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S")
|
|
106
106
|
self.items[dt_key] = note
|
|
107
107
|
self.save(note.year, note.month, note.day)
|
|
108
108
|
return True
|
pygpt_net/core/ctx/output.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.
|
|
9
|
+
# Updated Date: 2025.09.16 22:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from typing import Optional, List, Dict
|
|
@@ -71,7 +71,7 @@ class Output:
|
|
|
71
71
|
col_idx = tab.column_idx
|
|
72
72
|
|
|
73
73
|
col_map = self.mapping.get(col_idx)
|
|
74
|
-
if col_map is None:
|
|
74
|
+
if col_map is None or not isinstance(col_map, dict):
|
|
75
75
|
col_map = self.mapping[col_idx] = {}
|
|
76
76
|
last_map = self.last_pids.get(col_idx)
|
|
77
77
|
if last_map is None:
|
|
@@ -175,6 +175,8 @@ class Output:
|
|
|
175
175
|
return None
|
|
176
176
|
col_idx = tab.column_idx
|
|
177
177
|
col_map = self.mapping.get(col_idx, {})
|
|
178
|
+
if not isinstance(col_map, dict):
|
|
179
|
+
return None
|
|
178
180
|
|
|
179
181
|
candidates = [pid for pid, meta_id in col_map.items() if meta_id == meta.id]
|
|
180
182
|
for pid in candidates:
|
|
@@ -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.16
|
|
9
|
+
# Updated Date: 2025.09.16 22:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import gc
|
|
@@ -1290,11 +1290,9 @@ class Renderer(BaseRenderer):
|
|
|
1290
1290
|
"""
|
|
1291
1291
|
tab = node.get_tab()
|
|
1292
1292
|
layout = tab.child.layout()
|
|
1293
|
-
tab.
|
|
1293
|
+
tab.unwrap(node)
|
|
1294
1294
|
self.window.ui.nodes['output'].pop(tab.pid, None)
|
|
1295
1295
|
|
|
1296
|
-
node.on_delete()
|
|
1297
|
-
|
|
1298
1296
|
view = ChatWebOutput(self.window)
|
|
1299
1297
|
view.set_tab(tab)
|
|
1300
1298
|
view.set_meta(meta)
|
|
@@ -1302,6 +1300,7 @@ class Renderer(BaseRenderer):
|
|
|
1302
1300
|
view.signals.audio_read.connect(self.window.controller.chat.render.handle_audio_read)
|
|
1303
1301
|
|
|
1304
1302
|
layout.addWidget(view) # tab body layout
|
|
1303
|
+
tab.add_ref(view)
|
|
1305
1304
|
view.setVisible(True)
|
|
1306
1305
|
self.window.ui.nodes['output'][tab.pid] = view
|
|
1307
1306
|
try:
|
pygpt_net/core/tabs/tab.py
CHANGED
|
@@ -6,13 +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.09.
|
|
9
|
+
# Updated Date: 2025.09.16 22:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from datetime import datetime
|
|
13
13
|
from typing import Dict, Any, Optional
|
|
14
14
|
from dataclasses import dataclass, field
|
|
15
15
|
|
|
16
|
+
from PySide6.QtWidgets import QWidget
|
|
17
|
+
|
|
16
18
|
|
|
17
19
|
@dataclass(slots=True)
|
|
18
20
|
class Tab:
|
|
@@ -146,12 +148,37 @@ class Tab:
|
|
|
146
148
|
|
|
147
149
|
:param widget: widget reference
|
|
148
150
|
"""
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
151
|
+
try:
|
|
152
|
+
for ref in self.refs:
|
|
153
|
+
if ref and ref is widget:
|
|
154
|
+
self.refs.remove(ref)
|
|
155
|
+
break
|
|
156
|
+
except Exception:
|
|
157
|
+
pass
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
if self.child and hasattr(self.child, 'delete_ref'):
|
|
161
|
+
self.child.delete_ref(widget)
|
|
162
|
+
except Exception:
|
|
163
|
+
pass
|
|
164
|
+
|
|
165
|
+
def unwrap(self, widget: QWidget):
|
|
166
|
+
"""
|
|
167
|
+
Unwrap widget from this tab
|
|
168
|
+
|
|
169
|
+
:param widget: widget reference
|
|
170
|
+
"""
|
|
171
|
+
self.delete_ref(widget)
|
|
172
|
+
try:
|
|
173
|
+
if widget and hasattr(widget, 'on_delete'):
|
|
174
|
+
widget.on_delete()
|
|
175
|
+
except Exception:
|
|
176
|
+
pass
|
|
177
|
+
try:
|
|
178
|
+
if self.child and hasattr(self.child, 'unwrap'):
|
|
179
|
+
self.child.unwrap(widget)
|
|
180
|
+
except Exception:
|
|
181
|
+
pass
|
|
155
182
|
|
|
156
183
|
def to_dict(self) -> Dict[str, Any]:
|
|
157
184
|
"""
|
|
@@ -159,7 +186,7 @@ class Tab:
|
|
|
159
186
|
|
|
160
187
|
:return: dict
|
|
161
188
|
"""
|
|
162
|
-
|
|
189
|
+
data = {
|
|
163
190
|
"uuid": str(self.uuid),
|
|
164
191
|
"pid": self.pid,
|
|
165
192
|
"idx": self.idx,
|
|
@@ -169,7 +196,6 @@ class Tab:
|
|
|
169
196
|
"icon": self.icon,
|
|
170
197
|
"tooltip": self.tooltip,
|
|
171
198
|
"data_id": self.data_id,
|
|
172
|
-
"child": str(self.child), # child widget
|
|
173
199
|
"parent": str(self.parent), # parent column
|
|
174
200
|
"custom_name": self.custom_name,
|
|
175
201
|
"custom_idx": self.new_idx,
|
|
@@ -179,6 +205,13 @@ class Tab:
|
|
|
179
205
|
"tool_id": self.tool_id,
|
|
180
206
|
"refs": [str(ref) for ref in self.refs], # references to widgets
|
|
181
207
|
}
|
|
208
|
+
if self.child:
|
|
209
|
+
try:
|
|
210
|
+
if hasattr(self.child, 'to_dict'):
|
|
211
|
+
data['child'] = self.child.to_dict()
|
|
212
|
+
except Exception:
|
|
213
|
+
pass
|
|
214
|
+
return data
|
|
182
215
|
|
|
183
216
|
def __str__(self) -> str:
|
|
184
217
|
"""
|
pygpt_net/core/tabs/tabs.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.09.16
|
|
9
|
+
# Updated Date: 2025.09.16 22:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import uuid
|
|
@@ -299,20 +299,17 @@ class Tabs:
|
|
|
299
299
|
if tab.type == Tab.TAB_CHAT:
|
|
300
300
|
node = self.window.ui.nodes['output'].get(tab.pid)
|
|
301
301
|
if node:
|
|
302
|
-
node.unload() # unload
|
|
303
|
-
tab.
|
|
302
|
+
node.unload() # unload page completely
|
|
303
|
+
tab.unwrap(node)
|
|
304
304
|
self.window.ui.nodes['output'].pop(pid, None)
|
|
305
|
-
node.on_delete()
|
|
306
305
|
node_plain = self.window.ui.nodes['output_plain'].get(tab.pid)
|
|
307
306
|
if node_plain:
|
|
308
|
-
tab.
|
|
307
|
+
tab.unwrap(node_plain)
|
|
309
308
|
self.window.ui.nodes['output_plain'].pop(pid, None)
|
|
310
|
-
node_plain.on_delete()
|
|
311
309
|
|
|
312
310
|
if tab.type in (Tab.TAB_CHAT, Tab.TAB_NOTEPAD, Tab.TAB_TOOL):
|
|
313
|
-
tab.cleanup() # unload
|
|
314
|
-
|
|
315
|
-
# tab.delete_refs()
|
|
311
|
+
tab.cleanup() # unload refs from memory
|
|
312
|
+
# IMPORTANT: leave refs to painter and calendar to keep only one instance of each
|
|
316
313
|
|
|
317
314
|
except Exception as e:
|
|
318
315
|
print(f"Error unloading tab {pid}: {e}")
|
|
@@ -328,6 +325,7 @@ class Tabs:
|
|
|
328
325
|
"""Remove all tabs"""
|
|
329
326
|
for pid in list(self.pids.keys()):
|
|
330
327
|
self.remove(pid) # delete from PIDs and UI
|
|
328
|
+
self.window.controller.chat.render.remove_pid(pid) # remove pid data from renderer registry
|
|
331
329
|
self.pids = {}
|
|
332
330
|
self.window.core.ctx.output.clear() # clear mapping
|
|
333
331
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"__meta__": {
|
|
3
|
-
"version": "2.6.
|
|
4
|
-
"app.version": "2.6.
|
|
5
|
-
"updated_at": "2025-09-
|
|
3
|
+
"version": "2.6.52",
|
|
4
|
+
"app.version": "2.6.52",
|
|
5
|
+
"updated_at": "2025-09-17T00:00:00"
|
|
6
6
|
},
|
|
7
7
|
"access.audio.event.speech": false,
|
|
8
8
|
"access.audio.event.speech.disabled": [],
|
|
@@ -434,8 +434,8 @@
|
|
|
434
434
|
"render.code_syntax.final_max_chars": 350000,
|
|
435
435
|
"render.code_syntax.final_max_lines": 1500,
|
|
436
436
|
"render.code_syntax.stream_max_lines": 1000,
|
|
437
|
-
"render.code_syntax.stream_n_line":
|
|
438
|
-
"render.code_syntax.stream_n_chars":
|
|
437
|
+
"render.code_syntax.stream_n_line": 10,
|
|
438
|
+
"render.code_syntax.stream_n_chars": 1000,
|
|
439
439
|
"render.engine": "web",
|
|
440
440
|
"render.memory.limit": "2.5GB",
|
|
441
441
|
"render.msg.user.collapse.px": 1500,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"__meta__": {
|
|
3
|
-
"version": "2.6.
|
|
4
|
-
"app.version": "2.6.
|
|
5
|
-
"updated_at": "2025-09-
|
|
3
|
+
"version": "2.6.52",
|
|
4
|
+
"app.version": "2.6.52",
|
|
5
|
+
"updated_at": "2025-09-17T08:03:34"
|
|
6
6
|
},
|
|
7
7
|
"items": {
|
|
8
8
|
"SpeakLeash/bielik-11b-v2.3-instruct:Q4_K_M": {
|
|
@@ -139,4 +139,9 @@ QCalendarWidget QAbstractItemView::item:hover {{
|
|
|
139
139
|
.DebugList::item:selected:focus {{
|
|
140
140
|
color: #000;
|
|
141
141
|
selection-color: #000000;
|
|
142
|
+
}}
|
|
143
|
+
|
|
144
|
+
QCalendarWidget QMenu::item:selected:focus,
|
|
145
|
+
QCalendarWidget QMenu::item:selected {{
|
|
146
|
+
background: #3a4045;
|
|
142
147
|
}}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
[LOCALE]
|
|
2
|
+
servers.description = Configure MCP servers. Supported transports: 'stdio: <command ...>' for stdio servers, 'http(s)://...' for Streamable HTTP, and 'http(s)://.../sse' (or 'sse://', 'sse+http(s)://') for SSE. Use 'label' as a short, human-friendly server name used in tool names. Use 'authorization' to send an Authorization header for HTTP/SSE connections. Use 'allowed_commands' (comma-separated) to whitelist tools; if provided, only those tools are exposed. Use 'disabled_commands' to blacklist tools from this server.
|
|
3
|
+
servers.label = MCP servers
|
|
4
|
+
servers.tooltip = Requires the MCP Python SDK. Install: pip install "mcp[cli]"
|
|
5
|
+
tools_cache_enabled.label = Cache tools list
|
|
6
|
+
tools_cache_enabled.description = Enable an in-memory cache of discovered tools to avoid re-discovery on every prompt.
|
|
7
|
+
tools_cache_enabled.tooltip = If enabled, tool discovery results are cached per server for the TTL duration.
|
|
8
|
+
tools_cache_ttl.label = Cache TTL (seconds)
|
|
9
|
+
tools_cache_ttl.description = Time-to-live for the tools cache per server.
|
|
10
|
+
tools_cache_ttl.tooltip = Set to 0 to disable TTL (not recommended).
|
|
11
|
+
plugin.description = Provides access to remote tools via the Model Context Protocol (MCP), including stdio, SSE, and Streamable HTTP transports, with per-server allow/deny filtering, Authorization header support, and a tools cache.
|
|
12
|
+
plugin.name = MCP
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# ================================================== #
|
|
4
|
+
# This file is a part of PYGPT package #
|
|
5
|
+
# Website: https://pygpt.net #
|
|
6
|
+
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
|
+
# MIT License #
|
|
8
|
+
# Created By : Marcin Szczygliński #
|
|
9
|
+
# Updated Date: 2025.09.16 22:00:00 #
|
|
10
|
+
# ================================================== #
|
|
11
|
+
|
|
12
|
+
from .plugin import *
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# ================================================== #
|
|
4
|
+
# This file is a part of PYGPT package #
|
|
5
|
+
# Website: https://pygpt.net #
|
|
6
|
+
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
|
+
# MIT License #
|
|
8
|
+
# Created By : Marcin Szczygliński #
|
|
9
|
+
# Updated Date: 2025.09.16 22:00:00 #
|
|
10
|
+
# ================================================== #
|
|
11
|
+
|
|
12
|
+
from pygpt_net.plugin.base.config import BaseConfig, BasePlugin
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Config(BaseConfig):
|
|
16
|
+
def __init__(self, plugin: BasePlugin = None, *args, **kwargs):
|
|
17
|
+
super(Config, self).__init__(plugin)
|
|
18
|
+
self.plugin = plugin
|
|
19
|
+
|
|
20
|
+
def from_defaults(self, plugin: BasePlugin = None):
|
|
21
|
+
"""
|
|
22
|
+
Set default options for plugin
|
|
23
|
+
|
|
24
|
+
:param plugin: plugin instance
|
|
25
|
+
"""
|
|
26
|
+
keys = {
|
|
27
|
+
"active": "bool",
|
|
28
|
+
"label": "text",
|
|
29
|
+
"server_address": "text",
|
|
30
|
+
"authorization": "text",
|
|
31
|
+
"allowed_commands": "text",
|
|
32
|
+
"disabled_commands": "text",
|
|
33
|
+
}
|
|
34
|
+
items = [
|
|
35
|
+
{
|
|
36
|
+
"active": False,
|
|
37
|
+
"label": "quickstart",
|
|
38
|
+
"server_address": "stdio: uv run server fastmcp_quickstart stdio",
|
|
39
|
+
"authorization": "",
|
|
40
|
+
"allowed_commands": "",
|
|
41
|
+
"disabled_commands": "",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"active": False,
|
|
45
|
+
"label": "local_http",
|
|
46
|
+
"server_address": "http://localhost:8000/mcp",
|
|
47
|
+
"authorization": "",
|
|
48
|
+
"allowed_commands": "",
|
|
49
|
+
"disabled_commands": "",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"active": False,
|
|
53
|
+
"label": "local_sse",
|
|
54
|
+
"server_address": "http://localhost:8000/sse",
|
|
55
|
+
"authorization": "",
|
|
56
|
+
"allowed_commands": "",
|
|
57
|
+
"disabled_commands": "",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"active": False,
|
|
61
|
+
"label": "deep_wiki",
|
|
62
|
+
"server_address": "https://mcp.deepwiki.com/mcp",
|
|
63
|
+
"authorization": "",
|
|
64
|
+
"allowed_commands": "",
|
|
65
|
+
"disabled_commands": "",
|
|
66
|
+
},
|
|
67
|
+
]
|
|
68
|
+
desc = (
|
|
69
|
+
"Configure MCP servers. Supported transports: "
|
|
70
|
+
"'stdio: <command ...>' for stdio servers, 'http(s)://...' for Streamable HTTP, "
|
|
71
|
+
"and 'http(s)://.../sse' (or 'sse://', 'sse+http(s)://') for SSE. "
|
|
72
|
+
"Use 'label' as a short, human-friendly server name used in tool names. "
|
|
73
|
+
"Use 'authorization' to send an Authorization header for HTTP/SSE connections. "
|
|
74
|
+
"Use 'allowed_commands' (comma-separated) to whitelist tools; "
|
|
75
|
+
"use 'disabled_commands' to blacklist tools."
|
|
76
|
+
)
|
|
77
|
+
tooltip = "Requires MCP Python SDK. Install: pip install \"mcp[cli]\""
|
|
78
|
+
plugin.add_option(
|
|
79
|
+
"servers",
|
|
80
|
+
type="dict",
|
|
81
|
+
value=items,
|
|
82
|
+
label="MCP servers",
|
|
83
|
+
description=desc,
|
|
84
|
+
tooltip=tooltip,
|
|
85
|
+
keys=keys,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
plugin.add_option(
|
|
89
|
+
"tools_cache_enabled",
|
|
90
|
+
type="bool",
|
|
91
|
+
value=True,
|
|
92
|
+
label="Cache tools list",
|
|
93
|
+
description="Enable in-memory cache for discovered tools to avoid re-discovery on each prompt.",
|
|
94
|
+
tooltip="If enabled, tools discovery results are cached per server.",
|
|
95
|
+
)
|
|
96
|
+
plugin.add_option(
|
|
97
|
+
"tools_cache_ttl",
|
|
98
|
+
type="text",
|
|
99
|
+
value="300",
|
|
100
|
+
label="Cache TTL (seconds)",
|
|
101
|
+
description="Time-to-live for tools cache per server.",
|
|
102
|
+
tooltip="Set to 0 to disable TTL (not recommended).",
|
|
103
|
+
)
|