pygpt-net 2.6.60__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.
- pygpt_net/CHANGELOG.txt +7 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/controller/chat/common.py +115 -6
- pygpt_net/controller/chat/input.py +4 -1
- pygpt_net/controller/presets/presets.py +121 -6
- pygpt_net/controller/settings/editor.py +0 -15
- pygpt_net/controller/theme/markdown.py +2 -5
- pygpt_net/controller/ui/ui.py +4 -7
- pygpt_net/core/agents/custom/__init__.py +7 -1
- pygpt_net/core/agents/custom/llama_index/factory.py +17 -6
- pygpt_net/core/agents/custom/llama_index/runner.py +35 -2
- pygpt_net/core/agents/custom/llama_index/utils.py +12 -1
- pygpt_net/core/agents/custom/router.py +45 -6
- pygpt_net/core/agents/custom/runner.py +2 -1
- pygpt_net/core/agents/custom/schema.py +3 -1
- pygpt_net/core/agents/custom/utils.py +13 -1
- pygpt_net/core/db/viewer.py +11 -5
- pygpt_net/core/node_editor/graph.py +18 -9
- pygpt_net/core/node_editor/models.py +9 -2
- pygpt_net/core/node_editor/types.py +3 -1
- pygpt_net/core/presets/presets.py +216 -29
- pygpt_net/core/render/markdown/parser.py +0 -2
- pygpt_net/data/config/config.json +5 -6
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/config/settings.json +2 -38
- pygpt_net/data/locale/locale.de.ini +64 -1
- pygpt_net/data/locale/locale.en.ini +62 -3
- pygpt_net/data/locale/locale.es.ini +64 -1
- pygpt_net/data/locale/locale.fr.ini +64 -1
- pygpt_net/data/locale/locale.it.ini +64 -1
- pygpt_net/data/locale/locale.pl.ini +65 -2
- pygpt_net/data/locale/locale.uk.ini +64 -1
- pygpt_net/data/locale/locale.zh.ini +64 -1
- pygpt_net/data/locale/plugin.cmd_system.en.ini +62 -66
- pygpt_net/provider/agents/llama_index/flow_from_schema.py +2 -2
- pygpt_net/provider/core/config/patch.py +10 -1
- pygpt_net/provider/core/config/patches/patch_before_2_6_42.py +0 -6
- pygpt_net/tools/agent_builder/tool.py +42 -26
- pygpt_net/tools/agent_builder/ui/dialogs.py +60 -11
- pygpt_net/ui/__init__.py +2 -4
- pygpt_net/ui/dialog/about.py +58 -38
- pygpt_net/ui/dialog/db.py +142 -3
- pygpt_net/ui/dialog/preset.py +47 -8
- pygpt_net/ui/layout/toolbox/presets.py +52 -16
- pygpt_net/ui/widget/dialog/db.py +0 -0
- pygpt_net/ui/widget/lists/preset.py +644 -60
- pygpt_net/ui/widget/node_editor/command.py +10 -10
- pygpt_net/ui/widget/node_editor/config.py +157 -0
- pygpt_net/ui/widget/node_editor/editor.py +183 -151
- pygpt_net/ui/widget/node_editor/item.py +12 -11
- pygpt_net/ui/widget/node_editor/node.py +267 -12
- pygpt_net/ui/widget/node_editor/view.py +180 -63
- pygpt_net/ui/widget/tabs/output.py +1 -1
- pygpt_net/ui/widget/textarea/input.py +2 -2
- pygpt_net/utils.py +114 -2
- {pygpt_net-2.6.60.dist-info → pygpt_net-2.6.61.dist-info}/METADATA +11 -94
- {pygpt_net-2.6.60.dist-info → pygpt_net-2.6.61.dist-info}/RECORD +59 -58
- {pygpt_net-2.6.60.dist-info → pygpt_net-2.6.61.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.60.dist-info → pygpt_net-2.6.61.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.60.dist-info → pygpt_net-2.6.61.dist-info}/entry_points.txt +0 -0
|
@@ -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.25 14:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
@@ -47,6 +47,7 @@ def make_option_getter(base_agent, preset: Optional[PresetItem]) -> OptionGetter
|
|
|
47
47
|
class NodeRuntime:
|
|
48
48
|
model: ModelItem
|
|
49
49
|
instructions: str
|
|
50
|
+
role: Optional[str]
|
|
50
51
|
allow_local_tools: bool
|
|
51
52
|
allow_remote_tools: bool
|
|
52
53
|
|
|
@@ -76,6 +77,15 @@ def resolve_node_runtime(
|
|
|
76
77
|
prompt_opt = option_get(node.id, "prompt", None)
|
|
77
78
|
instructions = (prompt_opt or getattr(node, "instruction", None) or base_prompt or "").strip()
|
|
78
79
|
|
|
80
|
+
# Role resolve (optional)
|
|
81
|
+
role_opt = option_get(node.id, "role", None)
|
|
82
|
+
role_from_schema = getattr(node, "role", None) if hasattr(node, "role") else None
|
|
83
|
+
role: Optional[str] = None
|
|
84
|
+
if isinstance(role_opt, str) and role_opt.strip():
|
|
85
|
+
role = role_opt.strip()
|
|
86
|
+
elif isinstance(role_from_schema, str) and role_from_schema.strip():
|
|
87
|
+
role = role_from_schema.strip()
|
|
88
|
+
|
|
79
89
|
allow_local_tools = bool(
|
|
80
90
|
option_get(
|
|
81
91
|
node.id, "allow_local_tools",
|
|
@@ -92,6 +102,7 @@ def resolve_node_runtime(
|
|
|
92
102
|
return NodeRuntime(
|
|
93
103
|
model=model_item,
|
|
94
104
|
instructions=instructions,
|
|
105
|
+
role=role,
|
|
95
106
|
allow_local_tools=allow_local_tools,
|
|
96
107
|
allow_remote_tools=allow_remote_tools,
|
|
97
108
|
)
|
|
@@ -6,14 +6,14 @@
|
|
|
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.25 14:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
import json
|
|
14
14
|
import re
|
|
15
15
|
from dataclasses import dataclass
|
|
16
|
-
from typing import List, Optional, Tuple, Any
|
|
16
|
+
from typing import List, Optional, Tuple, Any, Dict
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
@dataclass
|
|
@@ -25,13 +25,46 @@ class RouteDecision:
|
|
|
25
25
|
error: Optional[str] = None
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
def build_router_instruction(
|
|
28
|
+
def build_router_instruction(
|
|
29
|
+
agent_name: str,
|
|
30
|
+
current_id: str,
|
|
31
|
+
allowed_routes: List[str],
|
|
32
|
+
friendly_map: Dict[str, Any],
|
|
33
|
+
) -> str:
|
|
29
34
|
"""
|
|
30
35
|
Builds an instruction that forces the model to output JSON with next route and content.
|
|
36
|
+
|
|
37
|
+
Additionally, if the provided friendly_map contains role information for any of the
|
|
38
|
+
allowed routes (e.g. friendly_map[id] is a dict with a "role" key), these roles
|
|
39
|
+
are included in the instruction to improve routing. This is optional and included
|
|
40
|
+
only when present and non-empty.
|
|
31
41
|
"""
|
|
32
42
|
allowed = ", ".join(allowed_routes)
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
|
|
44
|
+
# Normalize human-friendly names: accept either a plain string or a dict with
|
|
45
|
+
# common name keys such as "name", "title" or "label".
|
|
46
|
+
def _extract_name(val: Any, default_name: str) -> str:
|
|
47
|
+
if isinstance(val, str):
|
|
48
|
+
return val
|
|
49
|
+
if isinstance(val, dict):
|
|
50
|
+
return str(val.get("name") or val.get("title") or val.get("label") or default_name)
|
|
51
|
+
return default_name
|
|
52
|
+
|
|
53
|
+
# Extract names and optional roles for allowed routes, without changing input map semantics.
|
|
54
|
+
friendly_names = {rid: _extract_name(friendly_map.get(rid), rid) for rid in allowed_routes}
|
|
55
|
+
|
|
56
|
+
# Roles are optional; include only non-empty strings.
|
|
57
|
+
friendly_roles: Dict[str, str] = {}
|
|
58
|
+
for rid in allowed_routes:
|
|
59
|
+
val = friendly_map.get(rid)
|
|
60
|
+
role_val: Optional[str] = None
|
|
61
|
+
if isinstance(val, dict):
|
|
62
|
+
role_val = val.get("role")
|
|
63
|
+
if isinstance(role_val, str) and role_val.strip():
|
|
64
|
+
friendly_roles[rid] = role_val.strip()
|
|
65
|
+
|
|
66
|
+
# Base instruction
|
|
67
|
+
instr = (
|
|
35
68
|
"You are a routing-capable agent in a multi-agent flow.\n"
|
|
36
69
|
f"Your id is: {current_id}, name: {agent_name}.\n"
|
|
37
70
|
"You MUST respond ONLY with a single JSON object and nothing else.\n"
|
|
@@ -46,9 +79,15 @@ def build_router_instruction(agent_name: str, current_id: str, allowed_routes: L
|
|
|
46
79
|
"- content must contain the user-facing answer (you may include structured data as JSON or Markdown inside content).\n"
|
|
47
80
|
"- Do NOT add any commentary outside of the JSON. No leading or trailing text.\n"
|
|
48
81
|
"- If using tools, still return the final JSON with tool results summarized in content.\n"
|
|
49
|
-
f"- Human-friendly route names: {json.dumps(
|
|
82
|
+
f"- Human-friendly route names: {json.dumps(friendly_names)}\n"
|
|
50
83
|
)
|
|
51
84
|
|
|
85
|
+
# Append roles only if any are present (optional).
|
|
86
|
+
if friendly_roles:
|
|
87
|
+
instr += f"- Human-friendly route roles (optional): {json.dumps(friendly_roles)}\n"
|
|
88
|
+
|
|
89
|
+
return instr
|
|
90
|
+
|
|
52
91
|
|
|
53
92
|
def _extract_json_block(text: str) -> Optional[str]:
|
|
54
93
|
"""
|
|
@@ -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.25 14:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
@@ -171,6 +171,7 @@ class FlowOrchestrator:
|
|
|
171
171
|
f"[runtime] model={getattr(node_rt.model,'name',str(node_rt.model))} "
|
|
172
172
|
f"allow_local={node_rt.allow_local_tools} allow_remote={node_rt.allow_remote_tools} "
|
|
173
173
|
f"instructions='{instr_preview}'"
|
|
174
|
+
f" role='{node_rt.role}'"
|
|
174
175
|
)
|
|
175
176
|
|
|
176
177
|
# Memory selection and INPUT BUILD (memory-first policy)
|
|
@@ -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.25 14:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
@@ -31,6 +31,7 @@ class AgentNode(BaseNode):
|
|
|
31
31
|
inputs: List[str] = field(default_factory=list)
|
|
32
32
|
memory_out: Optional[str] = None # single mem by spec
|
|
33
33
|
memory_in: List[str] = field(default_factory=list) # not used, but kept for completeness
|
|
34
|
+
role: str = "" # Optional short description of agent's purpose
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
@dataclass
|
|
@@ -91,6 +92,7 @@ def parse_schema(schema: List[Dict[str, Any]]) -> FlowSchema:
|
|
|
91
92
|
inputs=list(_safe_get(slots, "input", "in", default=[])) or [],
|
|
92
93
|
memory_out=(_safe_get(slots, "memory", "out", default=[None]) or [None])[0],
|
|
93
94
|
memory_in=list(_safe_get(slots, "memory", "in", default=[])) or [],
|
|
95
|
+
role=_safe_get(slots, "role", default="") or "",
|
|
94
96
|
)
|
|
95
97
|
fs.agents[nid] = node
|
|
96
98
|
|
|
@@ -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.25 14:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
@@ -116,6 +116,7 @@ def make_option_getter(base_agent, preset: Optional[PresetItem]) -> OptionGetter
|
|
|
116
116
|
class NodeRuntime:
|
|
117
117
|
model: ModelItem
|
|
118
118
|
instructions: str
|
|
119
|
+
role: Optional[str]
|
|
119
120
|
allow_local_tools: bool
|
|
120
121
|
allow_remote_tools: bool
|
|
121
122
|
|
|
@@ -138,6 +139,7 @@ def resolve_node_runtime(
|
|
|
138
139
|
Priority:
|
|
139
140
|
- model: get_option(node.id, "model") -> window.core.models.get(name) -> default_model
|
|
140
141
|
- prompt: get_option(node.id, "prompt") -> node.instruction -> base_prompt -> ""
|
|
142
|
+
- role: get_option(node.id, "role") -> node.role -> None (only used if provided and non-empty)
|
|
141
143
|
- allow_*: get_option(node.id, "allow_local_tools"/"allow_remote_tools")
|
|
142
144
|
-> schema flags -> defaults
|
|
143
145
|
"""
|
|
@@ -157,6 +159,15 @@ def resolve_node_runtime(
|
|
|
157
159
|
prompt_opt = option_get(node.id, "prompt", None)
|
|
158
160
|
instructions = (prompt_opt or getattr(node, "instruction", None) or base_prompt or "").strip()
|
|
159
161
|
|
|
162
|
+
# Role resolve (optional)
|
|
163
|
+
role_opt = option_get(node.id, "role", None)
|
|
164
|
+
role_from_schema = getattr(node, "role", None) if hasattr(node, "role") else None
|
|
165
|
+
role: Optional[str] = None
|
|
166
|
+
if isinstance(role_opt, str) and role_opt.strip():
|
|
167
|
+
role = role_opt.strip()
|
|
168
|
+
elif isinstance(role_from_schema, str) and role_from_schema.strip():
|
|
169
|
+
role = role_from_schema.strip()
|
|
170
|
+
|
|
160
171
|
# Tools flags resolve
|
|
161
172
|
allow_local_tools = bool(
|
|
162
173
|
option_get(
|
|
@@ -176,6 +187,7 @@ def resolve_node_runtime(
|
|
|
176
187
|
return NodeRuntime(
|
|
177
188
|
model=model_item,
|
|
178
189
|
instructions=instructions,
|
|
190
|
+
role=role,
|
|
179
191
|
allow_local_tools=allow_local_tools,
|
|
180
192
|
allow_remote_tools=allow_remote_tools,
|
|
181
193
|
)
|
pygpt_net/core/db/viewer.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.26 03:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import json
|
|
@@ -154,14 +154,18 @@ class Viewer:
|
|
|
154
154
|
msg = f"[DB] Created DB backup: {backup_path}"
|
|
155
155
|
self.log(msg)
|
|
156
156
|
|
|
157
|
+
tables = self.database.get_tables()
|
|
158
|
+
primary_key = tables[data['table']]['primary_key']
|
|
159
|
+
|
|
157
160
|
with self.database.get_db().begin() as conn:
|
|
158
161
|
conn.execute(
|
|
159
|
-
text(f"DELETE FROM {data['table']} WHERE
|
|
162
|
+
text(f"DELETE FROM {data['table']} WHERE {primary_key} = :row_id")
|
|
160
163
|
.bindparams(row_id=data['row_id'])
|
|
161
164
|
)
|
|
162
165
|
msg = f"[DB] Deleted row ID {data['row_id']} from table {data['table']}"
|
|
163
166
|
self.log(msg)
|
|
164
|
-
|
|
167
|
+
# Force refresh to invalidate caches and handle pagination edge cases
|
|
168
|
+
self.database.window.ui.debug["db"].browser.force_refresh()
|
|
165
169
|
|
|
166
170
|
def update_row(self, data: Dict[str, Any]):
|
|
167
171
|
"""
|
|
@@ -207,7 +211,8 @@ class Viewer:
|
|
|
207
211
|
)
|
|
208
212
|
msg = f"[DB] Updated row ID {data['id']} in table {data['table']}"
|
|
209
213
|
self.log(msg)
|
|
210
|
-
|
|
214
|
+
# Force refresh to invalidate caches and handle pagination edge cases
|
|
215
|
+
self.database.window.ui.debug["db"].browser.force_refresh()
|
|
211
216
|
|
|
212
217
|
def truncate_table(self, data: Dict[str, Any], reset: bool = False):
|
|
213
218
|
"""
|
|
@@ -230,7 +235,8 @@ class Viewer:
|
|
|
230
235
|
else:
|
|
231
236
|
msg = f"[DB] Deleted all rows from table {data['table']}"
|
|
232
237
|
self.log(msg)
|
|
233
|
-
|
|
238
|
+
# Force refresh to invalidate caches and handle pagination edge cases
|
|
239
|
+
self.database.window.ui.debug["db"].browser.force_refresh()
|
|
234
240
|
|
|
235
241
|
def log(self, msg: str):
|
|
236
242
|
"""
|
|
@@ -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.25 00:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
@@ -83,16 +83,24 @@ class NodeGraph(QObject):
|
|
|
83
83
|
props: Dict[str, PropertyModel] = {}
|
|
84
84
|
for ps in spec.properties:
|
|
85
85
|
props[ps.id] = PropertyModel(
|
|
86
|
-
uuid=gen_uuid(),
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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),
|
|
90
97
|
)
|
|
91
98
|
# Auto inject read-only 'base_id' property for visibility if base_id defined and not present
|
|
92
99
|
if spec.base_id and "base_id" not in props:
|
|
93
100
|
props["base_id"] = PropertyModel(
|
|
94
101
|
uuid=gen_uuid(), id="base_id", type="str", name="Base ID",
|
|
95
|
-
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)."
|
|
96
104
|
)
|
|
97
105
|
|
|
98
106
|
node = NodeModel(uuid=gen_uuid(), id=nid, name=name or spec.title or nid, type=type_name, properties=props)
|
|
@@ -195,7 +203,8 @@ class NodeGraph(QObject):
|
|
|
195
203
|
"type": n.type,
|
|
196
204
|
"id": n.id,
|
|
197
205
|
"name": n.name,
|
|
198
|
-
|
|
206
|
+
# UI-only fields like HelpLabel are skipped
|
|
207
|
+
"values": {pid: p.value for pid, p in n.properties.items() if p.type != "HelpLabel"},
|
|
199
208
|
}
|
|
200
209
|
conns_out = [{"src": [c.src_node, c.src_prop], "dst": [c.dst_node, c.dst_prop]}
|
|
201
210
|
for c in self.connections.values()]
|
|
@@ -226,8 +235,8 @@ class NodeGraph(QObject):
|
|
|
226
235
|
"out": list(outgoing.get((n.uuid, pid), [])),
|
|
227
236
|
}
|
|
228
237
|
else:
|
|
229
|
-
# Skip internal
|
|
230
|
-
if pid == "base_id":
|
|
238
|
+
# Skip internal/helper and UI-only fields
|
|
239
|
+
if pid == "base_id" or prop.type == "HelpLabel":
|
|
231
240
|
continue
|
|
232
241
|
slots[pid] = prop.value
|
|
233
242
|
result.append({
|
|
@@ -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.25 00:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
@@ -22,13 +22,16 @@ from .utils import gen_uuid
|
|
|
22
22
|
class PropertyModel:
|
|
23
23
|
uuid: str
|
|
24
24
|
id: str
|
|
25
|
-
type: str # "slot", "str", "int", "float", "bool", "combo", "text"
|
|
25
|
+
type: str # "slot", "str", "int", "float", "bool", "combo", "text", "HelpLabel"
|
|
26
26
|
name: str
|
|
27
27
|
editable: bool = True
|
|
28
28
|
value: Any = None
|
|
29
29
|
allowed_inputs: int = 0 # 0 none, -1 unlimited, >0 limit
|
|
30
30
|
allowed_outputs: int = 0 # 0 none, -1 unlimited, >0 limit
|
|
31
31
|
options: Optional[List[str]] = None # for combo
|
|
32
|
+
# UI helpers
|
|
33
|
+
placeholder: Optional[str] = None
|
|
34
|
+
description: Optional[str] = None
|
|
32
35
|
|
|
33
36
|
def to_dict(self) -> dict:
|
|
34
37
|
return {
|
|
@@ -41,6 +44,8 @@ class PropertyModel:
|
|
|
41
44
|
"allowed_inputs": self.allowed_inputs,
|
|
42
45
|
"allowed_outputs": self.allowed_outputs,
|
|
43
46
|
"options": self.options or [],
|
|
47
|
+
"placeholder": self.placeholder,
|
|
48
|
+
"description": self.description,
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
@staticmethod
|
|
@@ -55,6 +60,8 @@ class PropertyModel:
|
|
|
55
60
|
allowed_inputs=d.get("allowed_inputs", 0),
|
|
56
61
|
allowed_outputs=d.get("allowed_outputs", 0),
|
|
57
62
|
options=d.get("options") or None,
|
|
63
|
+
placeholder=d.get("placeholder"),
|
|
64
|
+
description=d.get("description"),
|
|
58
65
|
)
|
|
59
66
|
|
|
60
67
|
|
|
@@ -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.25 15:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
@@ -26,6 +26,8 @@ class PropertySpec:
|
|
|
26
26
|
allowed_inputs: int = 0
|
|
27
27
|
allowed_outputs: int = 0
|
|
28
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
|
|
29
31
|
|
|
30
32
|
|
|
31
33
|
@dataclass
|