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.
Files changed (60) hide show
  1. pygpt_net/CHANGELOG.txt +7 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/controller/chat/common.py +115 -6
  4. pygpt_net/controller/chat/input.py +4 -1
  5. pygpt_net/controller/presets/presets.py +121 -6
  6. pygpt_net/controller/settings/editor.py +0 -15
  7. pygpt_net/controller/theme/markdown.py +2 -5
  8. pygpt_net/controller/ui/ui.py +4 -7
  9. pygpt_net/core/agents/custom/__init__.py +7 -1
  10. pygpt_net/core/agents/custom/llama_index/factory.py +17 -6
  11. pygpt_net/core/agents/custom/llama_index/runner.py +35 -2
  12. pygpt_net/core/agents/custom/llama_index/utils.py +12 -1
  13. pygpt_net/core/agents/custom/router.py +45 -6
  14. pygpt_net/core/agents/custom/runner.py +2 -1
  15. pygpt_net/core/agents/custom/schema.py +3 -1
  16. pygpt_net/core/agents/custom/utils.py +13 -1
  17. pygpt_net/core/db/viewer.py +11 -5
  18. pygpt_net/core/node_editor/graph.py +18 -9
  19. pygpt_net/core/node_editor/models.py +9 -2
  20. pygpt_net/core/node_editor/types.py +3 -1
  21. pygpt_net/core/presets/presets.py +216 -29
  22. pygpt_net/core/render/markdown/parser.py +0 -2
  23. pygpt_net/data/config/config.json +5 -6
  24. pygpt_net/data/config/models.json +3 -3
  25. pygpt_net/data/config/settings.json +2 -38
  26. pygpt_net/data/locale/locale.de.ini +64 -1
  27. pygpt_net/data/locale/locale.en.ini +62 -3
  28. pygpt_net/data/locale/locale.es.ini +64 -1
  29. pygpt_net/data/locale/locale.fr.ini +64 -1
  30. pygpt_net/data/locale/locale.it.ini +64 -1
  31. pygpt_net/data/locale/locale.pl.ini +65 -2
  32. pygpt_net/data/locale/locale.uk.ini +64 -1
  33. pygpt_net/data/locale/locale.zh.ini +64 -1
  34. pygpt_net/data/locale/plugin.cmd_system.en.ini +62 -66
  35. pygpt_net/provider/agents/llama_index/flow_from_schema.py +2 -2
  36. pygpt_net/provider/core/config/patch.py +10 -1
  37. pygpt_net/provider/core/config/patches/patch_before_2_6_42.py +0 -6
  38. pygpt_net/tools/agent_builder/tool.py +42 -26
  39. pygpt_net/tools/agent_builder/ui/dialogs.py +60 -11
  40. pygpt_net/ui/__init__.py +2 -4
  41. pygpt_net/ui/dialog/about.py +58 -38
  42. pygpt_net/ui/dialog/db.py +142 -3
  43. pygpt_net/ui/dialog/preset.py +47 -8
  44. pygpt_net/ui/layout/toolbox/presets.py +52 -16
  45. pygpt_net/ui/widget/dialog/db.py +0 -0
  46. pygpt_net/ui/widget/lists/preset.py +644 -60
  47. pygpt_net/ui/widget/node_editor/command.py +10 -10
  48. pygpt_net/ui/widget/node_editor/config.py +157 -0
  49. pygpt_net/ui/widget/node_editor/editor.py +183 -151
  50. pygpt_net/ui/widget/node_editor/item.py +12 -11
  51. pygpt_net/ui/widget/node_editor/node.py +267 -12
  52. pygpt_net/ui/widget/node_editor/view.py +180 -63
  53. pygpt_net/ui/widget/tabs/output.py +1 -1
  54. pygpt_net/ui/widget/textarea/input.py +2 -2
  55. pygpt_net/utils.py +114 -2
  56. {pygpt_net-2.6.60.dist-info → pygpt_net-2.6.61.dist-info}/METADATA +11 -94
  57. {pygpt_net-2.6.60.dist-info → pygpt_net-2.6.61.dist-info}/RECORD +59 -58
  58. {pygpt_net-2.6.60.dist-info → pygpt_net-2.6.61.dist-info}/LICENSE +0 -0
  59. {pygpt_net-2.6.60.dist-info → pygpt_net-2.6.61.dist-info}/WHEEL +0 -0
  60. {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.24 23:00:00 #
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.24 23:00:00 #
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(agent_name: str, current_id: str, allowed_routes: List[str], friendly_map: dict[str, str]) -> str:
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
- friendly = {rid: friendly_map.get(rid, rid) for rid in allowed_routes}
34
- return (
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(friendly)}\n"
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.24 23:00:00 #
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.24 23:00:00 #
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.24 23:00:00 #
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
  )
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.09.05 18:00:00 #
9
+ # Updated Date: 2025.09.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 id = :row_id")
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
- self.database.window.ui.debug["db"].browser.update_table_view()
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
- self.database.window.ui.debug["db"].browser.update_table_view()
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
- self.database.window.ui.debug["db"].browser.update_table_view()
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.24 00:00:00 #
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(), id=ps.id, type=ps.type, name=ps.name or ps.id,
87
- editable=ps.editable, value=ps.value,
88
- allowed_inputs=ps.allowed_inputs, allowed_outputs=ps.allowed_outputs,
89
- 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),
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
- "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"},
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 helper fields if needed
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.24 00:00:00 #
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.24 00:00:00 #
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