pygpt-net 2.6.59__py3-none-any.whl → 2.6.61__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 (91) hide show
  1. pygpt_net/CHANGELOG.txt +11 -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/chat/common.py +115 -6
  6. pygpt_net/controller/chat/input.py +4 -1
  7. pygpt_net/controller/presets/editor.py +442 -39
  8. pygpt_net/controller/presets/presets.py +121 -6
  9. pygpt_net/controller/settings/editor.py +0 -15
  10. pygpt_net/controller/theme/markdown.py +2 -5
  11. pygpt_net/controller/ui/ui.py +4 -7
  12. pygpt_net/core/agents/custom/__init__.py +281 -0
  13. pygpt_net/core/agents/custom/debug.py +64 -0
  14. pygpt_net/core/agents/custom/factory.py +109 -0
  15. pygpt_net/core/agents/custom/graph.py +71 -0
  16. pygpt_net/core/agents/custom/llama_index/__init__.py +10 -0
  17. pygpt_net/core/agents/custom/llama_index/factory.py +100 -0
  18. pygpt_net/core/agents/custom/llama_index/router_streamer.py +106 -0
  19. pygpt_net/core/agents/custom/llama_index/runner.py +562 -0
  20. pygpt_net/core/agents/custom/llama_index/stream.py +56 -0
  21. pygpt_net/core/agents/custom/llama_index/utils.py +253 -0
  22. pygpt_net/core/agents/custom/logging.py +50 -0
  23. pygpt_net/core/agents/custom/memory.py +51 -0
  24. pygpt_net/core/agents/custom/router.py +155 -0
  25. pygpt_net/core/agents/custom/router_streamer.py +187 -0
  26. pygpt_net/core/agents/custom/runner.py +455 -0
  27. pygpt_net/core/agents/custom/schema.py +127 -0
  28. pygpt_net/core/agents/custom/utils.py +193 -0
  29. pygpt_net/core/agents/provider.py +72 -7
  30. pygpt_net/core/agents/runner.py +7 -4
  31. pygpt_net/core/agents/runners/helpers.py +1 -1
  32. pygpt_net/core/agents/runners/llama_workflow.py +3 -0
  33. pygpt_net/core/agents/runners/openai_workflow.py +8 -1
  34. pygpt_net/core/db/viewer.py +11 -5
  35. pygpt_net/{ui/widget/builder → core/node_editor}/__init__.py +2 -2
  36. pygpt_net/core/{builder → node_editor}/graph.py +28 -226
  37. pygpt_net/core/node_editor/models.py +118 -0
  38. pygpt_net/core/node_editor/types.py +78 -0
  39. pygpt_net/core/node_editor/utils.py +17 -0
  40. pygpt_net/core/presets/presets.py +216 -29
  41. pygpt_net/core/render/markdown/parser.py +0 -2
  42. pygpt_net/core/render/web/renderer.py +10 -8
  43. pygpt_net/data/config/config.json +5 -6
  44. pygpt_net/data/config/models.json +3 -3
  45. pygpt_net/data/config/settings.json +2 -38
  46. pygpt_net/data/locale/locale.de.ini +64 -1
  47. pygpt_net/data/locale/locale.en.ini +63 -4
  48. pygpt_net/data/locale/locale.es.ini +64 -1
  49. pygpt_net/data/locale/locale.fr.ini +64 -1
  50. pygpt_net/data/locale/locale.it.ini +64 -1
  51. pygpt_net/data/locale/locale.pl.ini +65 -2
  52. pygpt_net/data/locale/locale.uk.ini +64 -1
  53. pygpt_net/data/locale/locale.zh.ini +64 -1
  54. pygpt_net/data/locale/plugin.cmd_system.en.ini +62 -66
  55. pygpt_net/item/agent.py +5 -1
  56. pygpt_net/item/preset.py +19 -1
  57. pygpt_net/provider/agents/base.py +33 -2
  58. pygpt_net/provider/agents/llama_index/flow_from_schema.py +92 -0
  59. pygpt_net/provider/agents/openai/flow_from_schema.py +96 -0
  60. pygpt_net/provider/core/agent/json_file.py +11 -5
  61. pygpt_net/provider/core/config/patch.py +10 -1
  62. pygpt_net/provider/core/config/patches/patch_before_2_6_42.py +0 -6
  63. pygpt_net/tools/agent_builder/tool.py +233 -52
  64. pygpt_net/tools/agent_builder/ui/dialogs.py +172 -28
  65. pygpt_net/tools/agent_builder/ui/list.py +37 -10
  66. pygpt_net/ui/__init__.py +2 -4
  67. pygpt_net/ui/dialog/about.py +58 -38
  68. pygpt_net/ui/dialog/db.py +142 -3
  69. pygpt_net/ui/dialog/preset.py +62 -8
  70. pygpt_net/ui/layout/toolbox/presets.py +52 -16
  71. pygpt_net/ui/main.py +1 -1
  72. pygpt_net/ui/widget/dialog/db.py +0 -0
  73. pygpt_net/ui/widget/lists/preset.py +644 -60
  74. pygpt_net/{core/builder → ui/widget/node_editor}/__init__.py +2 -2
  75. pygpt_net/ui/widget/node_editor/command.py +373 -0
  76. pygpt_net/ui/widget/node_editor/config.py +157 -0
  77. pygpt_net/ui/widget/node_editor/editor.py +2070 -0
  78. pygpt_net/ui/widget/node_editor/item.py +493 -0
  79. pygpt_net/ui/widget/node_editor/node.py +1460 -0
  80. pygpt_net/ui/widget/node_editor/utils.py +17 -0
  81. pygpt_net/ui/widget/node_editor/view.py +364 -0
  82. pygpt_net/ui/widget/tabs/output.py +1 -1
  83. pygpt_net/ui/widget/textarea/input.py +2 -2
  84. pygpt_net/utils.py +114 -2
  85. {pygpt_net-2.6.59.dist-info → pygpt_net-2.6.61.dist-info}/METADATA +80 -93
  86. {pygpt_net-2.6.59.dist-info → pygpt_net-2.6.61.dist-info}/RECORD +88 -61
  87. pygpt_net/core/agents/custom.py +0 -150
  88. pygpt_net/ui/widget/builder/editor.py +0 -2001
  89. {pygpt_net-2.6.59.dist-info → pygpt_net-2.6.61.dist-info}/LICENSE +0 -0
  90. {pygpt_net-2.6.59.dist-info → pygpt_net-2.6.61.dist-info}/WHEEL +0 -0
  91. {pygpt_net-2.6.59.dist-info → pygpt_net-2.6.61.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.25 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) ------------------------
@@ -294,16 +83,24 @@ class NodeGraph(QObject):
294
83
  props: Dict[str, PropertyModel] = {}
295
84
  for ps in spec.properties:
296
85
  props[ps.id] = PropertyModel(
297
- uuid=gen_uuid(), id=ps.id, type=ps.type, name=ps.name or ps.id,
298
- editable=ps.editable, value=ps.value,
299
- allowed_inputs=ps.allowed_inputs, allowed_outputs=ps.allowed_outputs,
300
- options=ps.options
86
+ uuid=gen_uuid(),
87
+ id=ps.id,
88
+ type=ps.type,
89
+ name=ps.name or ps.id,
90
+ editable=ps.editable,
91
+ value=ps.value,
92
+ allowed_inputs=ps.allowed_inputs,
93
+ allowed_outputs=ps.allowed_outputs,
94
+ options=ps.options,
95
+ placeholder=getattr(ps, "placeholder", None),
96
+ description=getattr(ps, "description", None),
301
97
  )
302
98
  # Auto inject read-only 'base_id' property for visibility if base_id defined and not present
303
99
  if spec.base_id and "base_id" not in props:
304
100
  props["base_id"] = PropertyModel(
305
101
  uuid=gen_uuid(), id="base_id", type="str", name="Base ID",
306
- editable=False, value=base_id, allowed_inputs=0, allowed_outputs=0
102
+ editable=False, value=base_id, allowed_inputs=0, allowed_outputs=0,
103
+ placeholder=None, description="Internal base identifier (read-only)."
307
104
  )
308
105
 
309
106
  node = NodeModel(uuid=gen_uuid(), id=nid, name=name or spec.title or nid, type=type_name, properties=props)
@@ -406,14 +203,15 @@ class NodeGraph(QObject):
406
203
  "type": n.type,
407
204
  "id": n.id,
408
205
  "name": n.name,
409
- "values": {pid: p.value for pid, p in n.properties.items()},
206
+ # UI-only fields like HelpLabel are skipped
207
+ "values": {pid: p.value for pid, p in n.properties.items() if p.type != "HelpLabel"},
410
208
  }
411
209
  conns_out = [{"src": [c.src_node, c.src_prop], "dst": [c.dst_node, c.dst_prop]}
412
210
  for c in self.connections.values()]
413
211
  return {"nodes": nodes_out, "connections": conns_out}
414
212
 
415
- # --- Export to requested agent schema (list of nodes with slots/in-out) ---
416
- def to_agent_schema(self) -> List[dict]:
213
+ # --- Export to list schema (list of nodes with slots/in-out) ---
214
+ def to_list_schema(self) -> List[dict]:
417
215
  # Build helper maps
418
216
  uuid_to_node: Dict[str, NodeModel] = dict(self.nodes)
419
217
  uuid_to_id: Dict[str, str] = {u: n.id for u, n in uuid_to_node.items()}
@@ -437,8 +235,8 @@ class NodeGraph(QObject):
437
235
  "out": list(outgoing.get((n.uuid, pid), [])),
438
236
  }
439
237
  else:
440
- # Skip internal helper fields if needed
441
- if pid == "base_id":
238
+ # Skip internal/helper and UI-only fields
239
+ if pid == "base_id" or prop.type == "HelpLabel":
442
240
  continue
443
241
  slots[pid] = prop.value
444
242
  result.append({
@@ -474,5 +272,9 @@ class NodeGraph(QObject):
474
272
  def clear(self, silent: bool = False):
475
273
  self.nodes.clear()
476
274
  self.connections.clear()
275
+ # Reset counters to keep friendly IDs strictly per-layout.
276
+ # After a clear, numbering starts again from 1 for each base prefix.
277
+ self._node_counter = 1
278
+ self._id_counters.clear()
477
279
  if not silent:
478
280
  self.cleared.emit()
@@ -0,0 +1,118 @@
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.25 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", "HelpLabel"
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
+ # UI helpers
33
+ placeholder: Optional[str] = None
34
+ description: Optional[str] = None
35
+
36
+ def to_dict(self) -> dict:
37
+ return {
38
+ "uuid": self.uuid,
39
+ "id": self.id,
40
+ "type": self.type,
41
+ "name": self.name,
42
+ "editable": self.editable,
43
+ "value": self.value,
44
+ "allowed_inputs": self.allowed_inputs,
45
+ "allowed_outputs": self.allowed_outputs,
46
+ "options": self.options or [],
47
+ "placeholder": self.placeholder,
48
+ "description": self.description,
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
+ placeholder=d.get("placeholder"),
64
+ description=d.get("description"),
65
+ )
66
+
67
+
68
+ @dataclass
69
+ class NodeModel:
70
+ uuid: str
71
+ id: str
72
+ name: str
73
+ type: str
74
+ properties: Dict[str, PropertyModel] = field(default_factory=dict)
75
+
76
+ def to_dict(self) -> dict:
77
+ return {
78
+ "uuid": self.uuid,
79
+ "id": self.id,
80
+ "name": self.name,
81
+ "type": self.type,
82
+ "properties": {pid: p.to_dict() for pid, p in self.properties.items()},
83
+ }
84
+
85
+ @staticmethod
86
+ def from_dict(d: dict) -> "NodeModel":
87
+ props = {pid: PropertyModel.from_dict(pd) for pid, pd in d.get("properties", {}).items()}
88
+ return NodeModel(
89
+ uuid=d.get("uuid", gen_uuid()),
90
+ id=d["id"],
91
+ name=d.get("name", d["id"]),
92
+ type=d["type"],
93
+ properties=props,
94
+ )
95
+
96
+
97
+ @dataclass
98
+ class ConnectionModel:
99
+ uuid: str
100
+ src_node: str
101
+ src_prop: str
102
+ dst_node: str
103
+ dst_prop: str
104
+
105
+ def to_dict(self) -> dict:
106
+ return {
107
+ "uuid": self.uuid,
108
+ "src_node": self.src_node, "src_prop": self.src_prop,
109
+ "dst_node": self.dst_node, "dst_prop": self.dst_prop,
110
+ }
111
+
112
+ @staticmethod
113
+ def from_dict(d: dict) -> "ConnectionModel":
114
+ return ConnectionModel(
115
+ uuid=d.get("uuid", gen_uuid()),
116
+ src_node=d["src_node"], src_prop=d["src_prop"],
117
+ dst_node=d["dst_node"], dst_prop=d["dst_prop"],
118
+ )
@@ -0,0 +1,78 @@
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.25 15: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
+ placeholder: Optional[str] = None # hint text for text editors
30
+ description: Optional[str] = None # tooltip/help text shown in UI
31
+
32
+
33
+ @dataclass
34
+ class NodeTypeSpec:
35
+ type_name: str
36
+ title: Optional[str] = None
37
+ properties: List[PropertySpec] = field(default_factory=list)
38
+ # Below are optional extensions for agent-flow needs:
39
+ base_id: Optional[str] = None # base prefix for friendly ids, e.g. "agent"
40
+ export_kind: Optional[str] = None # short kind for export, e.g. "agent", "start"
41
+ bg_color: Optional[str] = None # optional per-type background color (CSS/hex)
42
+
43
+ class NodeTypeRegistry:
44
+ """Registry for node type specifications. Extend/override in subclasses."""
45
+ def __init__(self, empty: bool = False):
46
+ self._types: Dict[str, NodeTypeSpec] = {}
47
+ if not empty:
48
+ self._install_default_types()
49
+
50
+ def register(self, spec: NodeTypeSpec):
51
+ self._types[spec.type_name] = spec
52
+
53
+ def types(self) -> List[str]:
54
+ return list(self._types.keys())
55
+
56
+ def get(self, type_name: str) -> Optional[NodeTypeSpec]:
57
+ return self._types.get(type_name)
58
+
59
+ def _install_default_types(self):
60
+ # Example/basic nodes kept intact
61
+ self.register(NodeTypeSpec(
62
+ type_name="Value/Float",
63
+ title="Float",
64
+ properties=[
65
+ PropertySpec(id="value", type="float", name="Value", editable=True, value=0.0,
66
+ allowed_inputs=0, allowed_outputs=1),
67
+ ]
68
+ ))
69
+ self.register(NodeTypeSpec(
70
+ type_name="Math/Add",
71
+ title="Add",
72
+ properties=[
73
+ PropertySpec(id="A", type="float", name="A", editable=True, value=0.0, allowed_inputs=1, allowed_outputs=0),
74
+ PropertySpec(id="B", type="float", name="B", editable=True, value=0.0, allowed_inputs=1, allowed_outputs=0),
75
+ PropertySpec(id="result", type="float", name="Result", editable=False, value=None, allowed_inputs=0, allowed_outputs=1),
76
+ ]
77
+ ))
78
+ # 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())