pygpt-net 2.6.59__py3-none-any.whl → 2.6.60__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 (61) hide show
  1. pygpt_net/CHANGELOG.txt +4 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/app.py +9 -5
  4. pygpt_net/controller/__init__.py +1 -0
  5. pygpt_net/controller/presets/editor.py +442 -39
  6. pygpt_net/core/agents/custom/__init__.py +275 -0
  7. pygpt_net/core/agents/custom/debug.py +64 -0
  8. pygpt_net/core/agents/custom/factory.py +109 -0
  9. pygpt_net/core/agents/custom/graph.py +71 -0
  10. pygpt_net/core/agents/custom/llama_index/__init__.py +10 -0
  11. pygpt_net/core/agents/custom/llama_index/factory.py +89 -0
  12. pygpt_net/core/agents/custom/llama_index/router_streamer.py +106 -0
  13. pygpt_net/core/agents/custom/llama_index/runner.py +529 -0
  14. pygpt_net/core/agents/custom/llama_index/stream.py +56 -0
  15. pygpt_net/core/agents/custom/llama_index/utils.py +242 -0
  16. pygpt_net/core/agents/custom/logging.py +50 -0
  17. pygpt_net/core/agents/custom/memory.py +51 -0
  18. pygpt_net/core/agents/custom/router.py +116 -0
  19. pygpt_net/core/agents/custom/router_streamer.py +187 -0
  20. pygpt_net/core/agents/custom/runner.py +454 -0
  21. pygpt_net/core/agents/custom/schema.py +125 -0
  22. pygpt_net/core/agents/custom/utils.py +181 -0
  23. pygpt_net/core/agents/provider.py +72 -7
  24. pygpt_net/core/agents/runner.py +7 -4
  25. pygpt_net/core/agents/runners/helpers.py +1 -1
  26. pygpt_net/core/agents/runners/llama_workflow.py +3 -0
  27. pygpt_net/core/agents/runners/openai_workflow.py +8 -1
  28. pygpt_net/{ui/widget/builder → core/node_editor}/__init__.py +2 -2
  29. pygpt_net/core/{builder → node_editor}/graph.py +11 -218
  30. pygpt_net/core/node_editor/models.py +111 -0
  31. pygpt_net/core/node_editor/types.py +76 -0
  32. pygpt_net/core/node_editor/utils.py +17 -0
  33. pygpt_net/core/render/web/renderer.py +10 -8
  34. pygpt_net/data/config/config.json +3 -3
  35. pygpt_net/data/config/models.json +3 -3
  36. pygpt_net/data/locale/locale.en.ini +4 -4
  37. pygpt_net/item/agent.py +5 -1
  38. pygpt_net/item/preset.py +19 -1
  39. pygpt_net/provider/agents/base.py +33 -2
  40. pygpt_net/provider/agents/llama_index/flow_from_schema.py +92 -0
  41. pygpt_net/provider/agents/openai/flow_from_schema.py +96 -0
  42. pygpt_net/provider/core/agent/json_file.py +11 -5
  43. pygpt_net/tools/agent_builder/tool.py +217 -52
  44. pygpt_net/tools/agent_builder/ui/dialogs.py +119 -24
  45. pygpt_net/tools/agent_builder/ui/list.py +37 -10
  46. pygpt_net/ui/dialog/preset.py +16 -1
  47. pygpt_net/ui/main.py +1 -1
  48. pygpt_net/{core/builder → ui/widget/node_editor}/__init__.py +2 -2
  49. pygpt_net/ui/widget/node_editor/command.py +373 -0
  50. pygpt_net/ui/widget/node_editor/editor.py +2038 -0
  51. pygpt_net/ui/widget/node_editor/item.py +492 -0
  52. pygpt_net/ui/widget/node_editor/node.py +1205 -0
  53. pygpt_net/ui/widget/node_editor/utils.py +17 -0
  54. pygpt_net/ui/widget/node_editor/view.py +247 -0
  55. {pygpt_net-2.6.59.dist-info → pygpt_net-2.6.60.dist-info}/METADATA +72 -2
  56. {pygpt_net-2.6.59.dist-info → pygpt_net-2.6.60.dist-info}/RECORD +59 -33
  57. pygpt_net/core/agents/custom.py +0 -150
  58. pygpt_net/ui/widget/builder/editor.py +0 -2001
  59. {pygpt_net-2.6.59.dist-info → pygpt_net-2.6.60.dist-info}/LICENSE +0 -0
  60. {pygpt_net-2.6.59.dist-info → pygpt_net-2.6.60.dist-info}/WHEEL +0 -0
  61. {pygpt_net-2.6.59.dist-info → pygpt_net-2.6.60.dist-info}/entry_points.txt +0 -0
@@ -6,229 +6,18 @@
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.19 00:00:00 #
9
+ # Updated Date: 2025.09.24 00:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from __future__ import annotations
13
13
  from typing import Dict, List, Optional, Tuple, Any
14
- from dataclasses import dataclass, field
15
- from uuid import uuid4
16
- from PySide6.QtCore import QObject, Signal
17
14
  import re
18
15
 
16
+ from PySide6.QtCore import QObject, Signal
19
17
 
20
- def gen_uuid() -> str:
21
- return str(uuid4())
22
-
23
-
24
- # ------------------------ Data models (pure data) ------------------------
25
-
26
- @dataclass
27
- class PropertyModel:
28
- uuid: str
29
- id: str
30
- type: str # "slot", "str", "int", "float", "bool", "combo", "text"
31
- name: str
32
- editable: bool = True
33
- value: Any = None
34
- allowed_inputs: int = 0 # 0 none, -1 unlimited, >0 limit
35
- allowed_outputs: int = 0 # 0 none, -1 unlimited, >0 limit
36
- options: Optional[List[str]] = None # for combo
37
-
38
- def to_dict(self) -> dict:
39
- return {
40
- "uuid": self.uuid,
41
- "id": self.id,
42
- "type": self.type,
43
- "name": self.name,
44
- "editable": self.editable,
45
- "value": self.value,
46
- "allowed_inputs": self.allowed_inputs,
47
- "allowed_outputs": self.allowed_outputs,
48
- "options": self.options or [],
49
- }
50
-
51
- @staticmethod
52
- def from_dict(d: dict) -> "PropertyModel":
53
- return PropertyModel(
54
- uuid=d.get("uuid", gen_uuid()),
55
- id=d["id"],
56
- type=d["type"],
57
- name=d.get("name", d["id"]),
58
- editable=d.get("editable", True),
59
- value=d.get("value"),
60
- allowed_inputs=d.get("allowed_inputs", 0),
61
- allowed_outputs=d.get("allowed_outputs", 0),
62
- options=d.get("options") or None,
63
- )
64
-
65
-
66
- @dataclass
67
- class NodeModel:
68
- uuid: str
69
- id: str
70
- name: str
71
- type: str
72
- properties: Dict[str, PropertyModel] = field(default_factory=dict)
73
-
74
- def to_dict(self) -> dict:
75
- return {
76
- "uuid": self.uuid,
77
- "id": self.id,
78
- "name": self.name,
79
- "type": self.type,
80
- "properties": {pid: p.to_dict() for pid, p in self.properties.items()},
81
- }
82
-
83
- @staticmethod
84
- def from_dict(d: dict) -> "NodeModel":
85
- props = {pid: PropertyModel.from_dict(pd) for pid, pd in d.get("properties", {}).items()}
86
- return NodeModel(
87
- uuid=d.get("uuid", gen_uuid()),
88
- id=d["id"],
89
- name=d.get("name", d["id"]),
90
- type=d["type"],
91
- properties=props,
92
- )
93
-
94
-
95
- @dataclass
96
- class ConnectionModel:
97
- uuid: str
98
- src_node: str
99
- src_prop: str
100
- dst_node: str
101
- dst_prop: str
102
-
103
- def to_dict(self) -> dict:
104
- return {
105
- "uuid": self.uuid,
106
- "src_node": self.src_node, "src_prop": self.src_prop,
107
- "dst_node": self.dst_node, "dst_prop": self.dst_prop,
108
- }
109
-
110
- @staticmethod
111
- def from_dict(d: dict) -> "ConnectionModel":
112
- return ConnectionModel(
113
- uuid=d.get("uuid", gen_uuid()),
114
- src_node=d["src_node"], src_prop=d["src_prop"],
115
- dst_node=d["dst_node"], dst_prop=d["dst_prop"],
116
- )
117
-
118
-
119
- # ------------------------ Types registry (templates) ------------------------
120
-
121
- @dataclass
122
- class PropertySpec:
123
- id: str
124
- type: str
125
- name: Optional[str] = None
126
- editable: bool = True
127
- value: Any = None
128
- allowed_inputs: int = 0
129
- allowed_outputs: int = 0
130
- options: Optional[List[str]] = None
131
-
132
-
133
- @dataclass
134
- class NodeTypeSpec:
135
- type_name: str
136
- title: Optional[str] = None
137
- properties: List[PropertySpec] = field(default_factory=list)
138
- # Below are optional extensions for agent-flow needs:
139
- base_id: Optional[str] = None # base prefix for friendly ids, e.g. "agent"
140
- export_kind: Optional[str] = None # short kind for export, e.g. "agent", "start"
141
- bg_color: Optional[str] = None # optional per-type background color (CSS/hex)
142
-
143
- class NodeTypeRegistry:
144
- """Registry for node type specifications. Extend/override in subclasses."""
145
- def __init__(self):
146
- self._types: Dict[str, NodeTypeSpec] = {}
147
- self._install_default_types()
148
-
149
- def register(self, spec: NodeTypeSpec):
150
- self._types[spec.type_name] = spec
151
-
152
- def types(self) -> List[str]:
153
- return list(self._types.keys())
154
-
155
- def get(self, type_name: str) -> Optional[NodeTypeSpec]:
156
- return self._types.get(type_name)
157
-
158
- def _install_default_types(self):
159
- # Example/basic nodes kept intact
160
- self.register(NodeTypeSpec(
161
- type_name="Value/Float",
162
- title="Float",
163
- properties=[
164
- PropertySpec(id="value", type="float", name="Value", editable=True, value=0.0,
165
- allowed_inputs=0, allowed_outputs=1),
166
- ]
167
- ))
168
- self.register(NodeTypeSpec(
169
- type_name="Math/Add",
170
- title="Add",
171
- properties=[
172
- PropertySpec(id="A", type="float", name="A", editable=True, value=0.0, allowed_inputs=1, allowed_outputs=0),
173
- PropertySpec(id="B", type="float", name="B", editable=True, value=0.0, allowed_inputs=1, allowed_outputs=0),
174
- PropertySpec(id="result", type="float", name="Result", editable=False, value=None, allowed_inputs=0, allowed_outputs=1),
175
- ]
176
- ))
177
- # Tip: to allow multiple connections to an input or output, set allowed_inputs/allowed_outputs to -1.
178
-
179
- # Agent-flow nodes
180
- # Start
181
- self.register(NodeTypeSpec(
182
- type_name="Flow/Start",
183
- title="Start",
184
- base_id="start",
185
- export_kind="start",
186
- bg_color="#2D5A27",
187
- properties=[
188
- PropertySpec(id="output", type="flow", name="Output", editable=False, allowed_inputs=0, allowed_outputs=1),
189
- # base_id will be auto-injected as read-only property at creation
190
- ],
191
- ))
192
- # Agent
193
- self.register(NodeTypeSpec(
194
- type_name="Flow/Agent",
195
- title="Agent",
196
- base_id="agent",
197
- export_kind="agent",
198
- bg_color="#304A6E",
199
- properties=[
200
- PropertySpec(id="name", type="str", name="Name", editable=True, value=""),
201
- PropertySpec(id="instruction", type="text", name="Instruction", editable=True, value=""),
202
- PropertySpec(id="remote_tools", type="bool", name="Remote tools", editable=True, value=True),
203
- PropertySpec(id="local_tools", type="bool", name="Local tools", editable=True, value=True),
204
- PropertySpec(id="input", type="flow", name="Input", editable=False, allowed_inputs=-1, allowed_outputs=0),
205
- PropertySpec(id="output", type="flow", name="Output", editable=False, allowed_inputs=0, allowed_outputs=1),
206
- PropertySpec(id="memory", type="memory", name="Memory", editable=False, allowed_inputs=0, allowed_outputs=1),
207
- ],
208
- ))
209
- # Memory
210
- self.register(NodeTypeSpec(
211
- type_name="Flow/Memory",
212
- title="Memory",
213
- base_id="mem",
214
- export_kind="memory",
215
- bg_color="#593E78",
216
- properties=[
217
- PropertySpec(id="name", type="str", name="Name", editable=True, value=""),
218
- PropertySpec(id="input", type="memory", name="Input", editable=False, allowed_inputs=-1, allowed_outputs=0),
219
- ],
220
- ))
221
- # End
222
- self.register(NodeTypeSpec(
223
- type_name="Flow/End",
224
- title="End",
225
- base_id="end",
226
- export_kind="end",
227
- bg_color="#6B2E2E",
228
- properties=[
229
- PropertySpec(id="input", type="flow", name="Input", editable=False, allowed_inputs=1, allowed_outputs=0),
230
- ],
231
- ))
18
+ from .models import NodeModel, ConnectionModel, PropertyModel
19
+ from .types import NodeTypeRegistry
20
+ from .utils import gen_uuid
232
21
 
233
22
 
234
23
  # ------------------------ Graph (Qt QObject + signals) ------------------------
@@ -412,8 +201,8 @@ class NodeGraph(QObject):
412
201
  for c in self.connections.values()]
413
202
  return {"nodes": nodes_out, "connections": conns_out}
414
203
 
415
- # --- Export to requested agent schema (list of nodes with slots/in-out) ---
416
- def to_agent_schema(self) -> List[dict]:
204
+ # --- Export to list schema (list of nodes with slots/in-out) ---
205
+ def to_list_schema(self) -> List[dict]:
417
206
  # Build helper maps
418
207
  uuid_to_node: Dict[str, NodeModel] = dict(self.nodes)
419
208
  uuid_to_id: Dict[str, str] = {u: n.id for u, n in uuid_to_node.items()}
@@ -474,5 +263,9 @@ class NodeGraph(QObject):
474
263
  def clear(self, silent: bool = False):
475
264
  self.nodes.clear()
476
265
  self.connections.clear()
266
+ # Reset counters to keep friendly IDs strictly per-layout.
267
+ # After a clear, numbering starts again from 1 for each base prefix.
268
+ self._node_counter = 1
269
+ self._id_counters.clear()
477
270
  if not silent:
478
271
  self.cleared.emit()
@@ -0,0 +1,111 @@
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.24 00:00:00 #
10
+ # ================================================== #
11
+
12
+ from __future__ import annotations
13
+ from typing import Dict, List, Optional, Any
14
+ from dataclasses import dataclass, field
15
+
16
+ from .utils import gen_uuid
17
+
18
+
19
+ # ------------------------ Data models (pure data) ------------------------
20
+
21
+ @dataclass
22
+ class PropertyModel:
23
+ uuid: str
24
+ id: str
25
+ type: str # "slot", "str", "int", "float", "bool", "combo", "text"
26
+ name: str
27
+ editable: bool = True
28
+ value: Any = None
29
+ allowed_inputs: int = 0 # 0 none, -1 unlimited, >0 limit
30
+ allowed_outputs: int = 0 # 0 none, -1 unlimited, >0 limit
31
+ options: Optional[List[str]] = None # for combo
32
+
33
+ def to_dict(self) -> dict:
34
+ return {
35
+ "uuid": self.uuid,
36
+ "id": self.id,
37
+ "type": self.type,
38
+ "name": self.name,
39
+ "editable": self.editable,
40
+ "value": self.value,
41
+ "allowed_inputs": self.allowed_inputs,
42
+ "allowed_outputs": self.allowed_outputs,
43
+ "options": self.options or [],
44
+ }
45
+
46
+ @staticmethod
47
+ def from_dict(d: dict) -> "PropertyModel":
48
+ return PropertyModel(
49
+ uuid=d.get("uuid", gen_uuid()),
50
+ id=d["id"],
51
+ type=d["type"],
52
+ name=d.get("name", d["id"]),
53
+ editable=d.get("editable", True),
54
+ value=d.get("value"),
55
+ allowed_inputs=d.get("allowed_inputs", 0),
56
+ allowed_outputs=d.get("allowed_outputs", 0),
57
+ options=d.get("options") or None,
58
+ )
59
+
60
+
61
+ @dataclass
62
+ class NodeModel:
63
+ uuid: str
64
+ id: str
65
+ name: str
66
+ type: str
67
+ properties: Dict[str, PropertyModel] = field(default_factory=dict)
68
+
69
+ def to_dict(self) -> dict:
70
+ return {
71
+ "uuid": self.uuid,
72
+ "id": self.id,
73
+ "name": self.name,
74
+ "type": self.type,
75
+ "properties": {pid: p.to_dict() for pid, p in self.properties.items()},
76
+ }
77
+
78
+ @staticmethod
79
+ def from_dict(d: dict) -> "NodeModel":
80
+ props = {pid: PropertyModel.from_dict(pd) for pid, pd in d.get("properties", {}).items()}
81
+ return NodeModel(
82
+ uuid=d.get("uuid", gen_uuid()),
83
+ id=d["id"],
84
+ name=d.get("name", d["id"]),
85
+ type=d["type"],
86
+ properties=props,
87
+ )
88
+
89
+
90
+ @dataclass
91
+ class ConnectionModel:
92
+ uuid: str
93
+ src_node: str
94
+ src_prop: str
95
+ dst_node: str
96
+ dst_prop: str
97
+
98
+ def to_dict(self) -> dict:
99
+ return {
100
+ "uuid": self.uuid,
101
+ "src_node": self.src_node, "src_prop": self.src_prop,
102
+ "dst_node": self.dst_node, "dst_prop": self.dst_prop,
103
+ }
104
+
105
+ @staticmethod
106
+ def from_dict(d: dict) -> "ConnectionModel":
107
+ return ConnectionModel(
108
+ uuid=d.get("uuid", gen_uuid()),
109
+ src_node=d["src_node"], src_prop=d["src_prop"],
110
+ dst_node=d["dst_node"], dst_prop=d["dst_prop"],
111
+ )
@@ -0,0 +1,76 @@
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.24 00:00:00 #
10
+ # ================================================== #
11
+
12
+ from __future__ import annotations
13
+ from typing import Dict, List, Optional, Any
14
+ from dataclasses import dataclass, field
15
+
16
+
17
+ # ------------------------ Types registry (templates) ------------------------
18
+
19
+ @dataclass
20
+ class PropertySpec:
21
+ id: str
22
+ type: str
23
+ name: Optional[str] = None
24
+ editable: bool = True
25
+ value: Any = None
26
+ allowed_inputs: int = 0
27
+ allowed_outputs: int = 0
28
+ options: Optional[List[str]] = None
29
+
30
+
31
+ @dataclass
32
+ class NodeTypeSpec:
33
+ type_name: str
34
+ title: Optional[str] = None
35
+ properties: List[PropertySpec] = field(default_factory=list)
36
+ # Below are optional extensions for agent-flow needs:
37
+ base_id: Optional[str] = None # base prefix for friendly ids, e.g. "agent"
38
+ export_kind: Optional[str] = None # short kind for export, e.g. "agent", "start"
39
+ bg_color: Optional[str] = None # optional per-type background color (CSS/hex)
40
+
41
+ class NodeTypeRegistry:
42
+ """Registry for node type specifications. Extend/override in subclasses."""
43
+ def __init__(self, empty: bool = False):
44
+ self._types: Dict[str, NodeTypeSpec] = {}
45
+ if not empty:
46
+ self._install_default_types()
47
+
48
+ def register(self, spec: NodeTypeSpec):
49
+ self._types[spec.type_name] = spec
50
+
51
+ def types(self) -> List[str]:
52
+ return list(self._types.keys())
53
+
54
+ def get(self, type_name: str) -> Optional[NodeTypeSpec]:
55
+ return self._types.get(type_name)
56
+
57
+ def _install_default_types(self):
58
+ # Example/basic nodes kept intact
59
+ self.register(NodeTypeSpec(
60
+ type_name="Value/Float",
61
+ title="Float",
62
+ properties=[
63
+ PropertySpec(id="value", type="float", name="Value", editable=True, value=0.0,
64
+ allowed_inputs=0, allowed_outputs=1),
65
+ ]
66
+ ))
67
+ self.register(NodeTypeSpec(
68
+ type_name="Math/Add",
69
+ title="Add",
70
+ properties=[
71
+ PropertySpec(id="A", type="float", name="A", editable=True, value=0.0, allowed_inputs=1, allowed_outputs=0),
72
+ PropertySpec(id="B", type="float", name="B", editable=True, value=0.0, allowed_inputs=1, allowed_outputs=0),
73
+ PropertySpec(id="result", type="float", name="Result", editable=False, value=None, allowed_inputs=0, allowed_outputs=1),
74
+ ]
75
+ ))
76
+ # Tip: to allow multiple connections to an input or output, set allowed_inputs/allowed_outputs to -1.
@@ -0,0 +1,17 @@
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.24 00:00:00 #
10
+ # ================================================== #
11
+
12
+ from __future__ import annotations
13
+ from uuid import uuid4
14
+
15
+
16
+ def gen_uuid() -> str:
17
+ return str(uuid4())
@@ -9,7 +9,6 @@
9
9
  # Updated Date: 2025.09.17 05:00:00 #
10
10
  # ================================================== #
11
11
 
12
- import gc
13
12
  import json
14
13
  import os
15
14
  import re
@@ -21,7 +20,7 @@ from typing import Optional, List, Any, Dict, Tuple
21
20
  from time import monotonic
22
21
  from io import StringIO
23
22
 
24
- from PySide6.QtCore import QTimer, QUrl
23
+ from PySide6.QtCore import QTimer, QUrl, QCoreApplication, QEventLoop, QEvent
25
24
  from PySide6.QtWebEngineCore import QWebEnginePage
26
25
 
27
26
  from pygpt_net.core.render.base import BaseRenderer
@@ -496,9 +495,10 @@ class Renderer(BaseRenderer):
496
495
 
497
496
  Soft cleanup, called after each context is done.
498
497
  """
499
- try:
500
- gc.collect()
498
+ def cleanup():
501
499
  malloc_trim_linux()
500
+ try:
501
+ QTimer.singleShot(0, cleanup)
502
502
  except Exception:
503
503
  pass
504
504
 
@@ -1300,6 +1300,12 @@ class Renderer(BaseRenderer):
1300
1300
  tab.unwrap(node)
1301
1301
  self.window.ui.nodes['output'].pop(tab.pid, None)
1302
1302
 
1303
+ try:
1304
+ QCoreApplication.sendPostedEvents(None, QEvent.DeferredDelete)
1305
+ QCoreApplication.processEvents(QEventLoop.AllEvents, 0)
1306
+ except Exception:
1307
+ pass
1308
+
1303
1309
  view = ChatWebOutput(self.window)
1304
1310
  view.set_tab(tab)
1305
1311
  view.set_meta(meta)
@@ -1310,10 +1316,6 @@ class Renderer(BaseRenderer):
1310
1316
  tab.add_ref(view)
1311
1317
  view.setVisible(True)
1312
1318
  self.window.ui.nodes['output'][tab.pid] = view
1313
- try:
1314
- gc.collect()
1315
- except Exception:
1316
- pass
1317
1319
  self.auto_cleanup_soft(meta)
1318
1320
 
1319
1321
  def get_output_node(self, meta: Optional[CtxMeta] = None) -> Optional[ChatWebOutput]:
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.6.59",
4
- "app.version": "2.6.59",
5
- "updated_at": "2025-09-23T00:00:00"
3
+ "version": "2.6.60",
4
+ "app.version": "2.6.60",
5
+ "updated_at": "2025-09-25T00:00:00"
6
6
  },
7
7
  "access.audio.event.speech": false,
8
8
  "access.audio.event.speech.disabled": [],
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.6.59",
4
- "app.version": "2.6.59",
5
- "updated_at": "2025-09-23T00:00:00"
3
+ "version": "2.6.60",
4
+ "app.version": "2.6.60",
5
+ "updated_at": "2025-09-25T00:00:00"
6
6
  },
7
7
  "items": {
8
8
  "SpeakLeash/bielik-11b-v2.3-instruct:Q4_K_M": {
@@ -75,7 +75,7 @@ action.video.transcribe = Transcribe audio...
75
75
  agent.builder.confirm.clear.msg = Do you really want to clear the graph?
76
76
  agent.builder.confirm.clear.title = Clear
77
77
  agent.builder.confirm.delete.msg = Do you really want to delete the agent?
78
- agent.builder.title = Agent Builder
78
+ agent.builder.title = Agents Builder (beta)
79
79
  agent.coder.additional.label = Additional prompt
80
80
  agent.coder.additional.prompt.desc = Additional prompt for agent (will be added to the base prompt)
81
81
  agent.coder.base.label = Base prompt
@@ -115,7 +115,7 @@ agent.option.section.worker = Worker
115
115
  agent.option.section.writer = Writer
116
116
  agent.option.tools.local = Allow local tools
117
117
  agent.option.tools.local.desc = Allow usage of local tools for this agent
118
- agent.option.tools.remote = Allowe remote tools
118
+ agent.option.tools.remote = Allow remote tools
119
119
  agent.option.tools.remote.desc = Allow usage of remote tools for this agent
120
120
  agent.planner.plan.label = Planner (initial)
121
121
  agent.planner.plan.prompt.desc = Initial plan prompt
@@ -780,7 +780,7 @@ menu.config.save = Save config
780
780
  menu.config.settings = Settings...
781
781
  menu.debug = Debug
782
782
  menu.debug.agent = Agent...
783
- menu.debug.agent_builder = Agent Builder
783
+ menu.debug.agent_builder = Agents Builder (beta)
784
784
  menu.debug.app.log = View log file (app.log)
785
785
  menu.debug.assistants = Assistants...
786
786
  menu.debug.attachments = Files / attachments...
@@ -835,7 +835,7 @@ menu.theme.style = Style...
835
835
  menu.theme.syntax = Code syntax highlight...
836
836
  menu.theme.tooltips = Show tooltips
837
837
  menu.tools = Tools
838
- menu.tools.agent.builder = Agent Builder
838
+ menu.tools.agent.builder = Agents Builder (beta)
839
839
  menu.tools.audio.transcribe = Transcribe Audio/Video Files
840
840
  menu.tools.html_canvas = HTML/JS Canvas
841
841
  menu.tools.image.viewer = Image Viewer
pygpt_net/item/agent.py CHANGED
@@ -20,18 +20,21 @@ class AgentItem:
20
20
  id: Optional[object] = None
21
21
  name: Optional[object] = None
22
22
  layout: dict = field(default_factory=dict)
23
+ schema: list = field(default_factory=list)
23
24
 
24
25
  def __init__(self):
25
26
  """Custom agent item"""
26
27
  self.id = None
27
28
  self.name = None
28
29
  self.layout = {}
30
+ self.schema = []
29
31
 
30
32
  def reset(self):
31
33
  """Reset"""
32
34
  self.id = None
33
35
  self.name = None
34
36
  self.layout = {}
37
+ self.schema = {}
35
38
 
36
39
  def to_dict(self) -> dict:
37
40
  """
@@ -42,7 +45,8 @@ class AgentItem:
42
45
  return {
43
46
  "id": self.id,
44
47
  "name": self.name,
45
- "layout": self.layout
48
+ "layout": self.layout,
49
+ "schema": self.schema,
46
50
  }
47
51
 
48
52
  def dump(self) -> str:
pygpt_net/item/preset.py CHANGED
@@ -215,11 +215,29 @@ class PresetItem:
215
215
  if "user_name" in data:
216
216
  self.user_name = data["user_name"]
217
217
  if "uuid" in data:
218
- self.uuid = uuid.UUID(data["uuid"])
218
+ self.uuid = str(uuid.UUID(data["uuid"]))
219
219
  if "vision" in data:
220
220
  self.vision = data["vision"]
221
221
  return self
222
222
 
223
+ def reset_modes(self):
224
+ """
225
+ Reset modes
226
+ """
227
+ self.agent = False
228
+ self.agent_llama = False
229
+ self.agent_openai = False
230
+ self.audio = False
231
+ self.assistant = False
232
+ self.chat = False
233
+ self.completion = False
234
+ self.computer = False
235
+ self.expert = False
236
+ self.langchain = False
237
+ self.llama_index = False
238
+ self.research = False
239
+ self.vision = False
240
+
223
241
  def add_function(self, name: str, parameters: str, desc: str):
224
242
  """
225
243
  Add function to preset