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.
- pygpt_net/CHANGELOG.txt +11 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +9 -5
- pygpt_net/controller/__init__.py +1 -0
- pygpt_net/controller/chat/common.py +115 -6
- pygpt_net/controller/chat/input.py +4 -1
- pygpt_net/controller/presets/editor.py +442 -39
- 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 +281 -0
- pygpt_net/core/agents/custom/debug.py +64 -0
- pygpt_net/core/agents/custom/factory.py +109 -0
- pygpt_net/core/agents/custom/graph.py +71 -0
- pygpt_net/core/agents/custom/llama_index/__init__.py +10 -0
- pygpt_net/core/agents/custom/llama_index/factory.py +100 -0
- pygpt_net/core/agents/custom/llama_index/router_streamer.py +106 -0
- pygpt_net/core/agents/custom/llama_index/runner.py +562 -0
- pygpt_net/core/agents/custom/llama_index/stream.py +56 -0
- pygpt_net/core/agents/custom/llama_index/utils.py +253 -0
- pygpt_net/core/agents/custom/logging.py +50 -0
- pygpt_net/core/agents/custom/memory.py +51 -0
- pygpt_net/core/agents/custom/router.py +155 -0
- pygpt_net/core/agents/custom/router_streamer.py +187 -0
- pygpt_net/core/agents/custom/runner.py +455 -0
- pygpt_net/core/agents/custom/schema.py +127 -0
- pygpt_net/core/agents/custom/utils.py +193 -0
- pygpt_net/core/agents/provider.py +72 -7
- pygpt_net/core/agents/runner.py +7 -4
- pygpt_net/core/agents/runners/helpers.py +1 -1
- pygpt_net/core/agents/runners/llama_workflow.py +3 -0
- pygpt_net/core/agents/runners/openai_workflow.py +8 -1
- pygpt_net/core/db/viewer.py +11 -5
- pygpt_net/{ui/widget/builder → core/node_editor}/__init__.py +2 -2
- pygpt_net/core/{builder → node_editor}/graph.py +28 -226
- pygpt_net/core/node_editor/models.py +118 -0
- pygpt_net/core/node_editor/types.py +78 -0
- pygpt_net/core/node_editor/utils.py +17 -0
- pygpt_net/core/presets/presets.py +216 -29
- pygpt_net/core/render/markdown/parser.py +0 -2
- pygpt_net/core/render/web/renderer.py +10 -8
- 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 +63 -4
- 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/item/agent.py +5 -1
- pygpt_net/item/preset.py +19 -1
- pygpt_net/provider/agents/base.py +33 -2
- pygpt_net/provider/agents/llama_index/flow_from_schema.py +92 -0
- pygpt_net/provider/agents/openai/flow_from_schema.py +96 -0
- pygpt_net/provider/core/agent/json_file.py +11 -5
- 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 +233 -52
- pygpt_net/tools/agent_builder/ui/dialogs.py +172 -28
- pygpt_net/tools/agent_builder/ui/list.py +37 -10
- 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 +62 -8
- pygpt_net/ui/layout/toolbox/presets.py +52 -16
- pygpt_net/ui/main.py +1 -1
- pygpt_net/ui/widget/dialog/db.py +0 -0
- pygpt_net/ui/widget/lists/preset.py +644 -60
- pygpt_net/{core/builder → ui/widget/node_editor}/__init__.py +2 -2
- pygpt_net/ui/widget/node_editor/command.py +373 -0
- pygpt_net/ui/widget/node_editor/config.py +157 -0
- pygpt_net/ui/widget/node_editor/editor.py +2070 -0
- pygpt_net/ui/widget/node_editor/item.py +493 -0
- pygpt_net/ui/widget/node_editor/node.py +1460 -0
- pygpt_net/ui/widget/node_editor/utils.py +17 -0
- pygpt_net/ui/widget/node_editor/view.py +364 -0
- 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.59.dist-info → pygpt_net-2.6.61.dist-info}/METADATA +80 -93
- {pygpt_net-2.6.59.dist-info → pygpt_net-2.6.61.dist-info}/RECORD +88 -61
- pygpt_net/core/agents/custom.py +0 -150
- pygpt_net/ui/widget/builder/editor.py +0 -2001
- {pygpt_net-2.6.59.dist-info → pygpt_net-2.6.61.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.59.dist-info → pygpt_net-2.6.61.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.59.dist-info → pygpt_net-2.6.61.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,193 @@
|
|
|
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 14:00:00 #
|
|
10
|
+
# ================================================== #
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
15
|
+
|
|
16
|
+
from agents import TResponseInputItem
|
|
17
|
+
from pygpt_net.item.model import ModelItem
|
|
18
|
+
from pygpt_net.item.preset import PresetItem
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# ---------- IO sanitization / output helpers ----------
|
|
22
|
+
|
|
23
|
+
def sanitize_input_items(items: List[TResponseInputItem]) -> List[TResponseInputItem]:
|
|
24
|
+
"""Remove server-assigned ids from items and content parts to avoid duplication errors."""
|
|
25
|
+
sanitized: List[TResponseInputItem] = []
|
|
26
|
+
for it in items or []:
|
|
27
|
+
if isinstance(it, dict):
|
|
28
|
+
new_it: Dict[str, Any] = dict(it)
|
|
29
|
+
# top-level ids that might reappear
|
|
30
|
+
new_it.pop("id", None)
|
|
31
|
+
new_it.pop("message_id", None)
|
|
32
|
+
# sanitize content list parts
|
|
33
|
+
if "content" in new_it and isinstance(new_it["content"], list):
|
|
34
|
+
new_content = []
|
|
35
|
+
for part in new_it["content"]:
|
|
36
|
+
if isinstance(part, dict):
|
|
37
|
+
p = dict(part)
|
|
38
|
+
p.pop("id", None)
|
|
39
|
+
new_content.append(p)
|
|
40
|
+
else:
|
|
41
|
+
new_content.append(part)
|
|
42
|
+
new_it["content"] = new_content
|
|
43
|
+
sanitized.append(new_it)
|
|
44
|
+
else:
|
|
45
|
+
sanitized.append(it)
|
|
46
|
+
return sanitized
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def extract_text_output(result: Any) -> str:
|
|
50
|
+
"""
|
|
51
|
+
Best-effort to get a human-facing text from openai-agents Runner result
|
|
52
|
+
without relying on app-specific helpers.
|
|
53
|
+
"""
|
|
54
|
+
out = getattr(result, "final_output", None)
|
|
55
|
+
if out is None:
|
|
56
|
+
return ""
|
|
57
|
+
try:
|
|
58
|
+
return str(out)
|
|
59
|
+
except Exception:
|
|
60
|
+
return ""
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def patch_last_assistant_output(items: List[TResponseInputItem], text: str) -> List[TResponseInputItem]:
|
|
64
|
+
"""
|
|
65
|
+
Replace the content of the last assistant message with plain text content.
|
|
66
|
+
This prevents leaking router JSON to subsequent agents.
|
|
67
|
+
"""
|
|
68
|
+
if not items:
|
|
69
|
+
return items
|
|
70
|
+
patched = list(items)
|
|
71
|
+
# find last assistant
|
|
72
|
+
idx: Optional[int] = None
|
|
73
|
+
for i in range(len(patched) - 1, -1, -1):
|
|
74
|
+
it = patched[i]
|
|
75
|
+
if isinstance(it, dict) and it.get("role") == "assistant":
|
|
76
|
+
idx = i
|
|
77
|
+
break
|
|
78
|
+
if idx is None:
|
|
79
|
+
return patched
|
|
80
|
+
|
|
81
|
+
# set standard output_text content
|
|
82
|
+
patched[idx] = {
|
|
83
|
+
"role": "assistant",
|
|
84
|
+
"content": [
|
|
85
|
+
{
|
|
86
|
+
"type": "output_text",
|
|
87
|
+
"text": text or "",
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
}
|
|
91
|
+
return sanitize_input_items(patched)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# ---------- Per-agent options resolution ----------
|
|
95
|
+
|
|
96
|
+
OptionGetter = Callable[[str, str, Any], Any]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def make_option_getter(base_agent, preset: Optional[PresetItem]) -> OptionGetter:
|
|
100
|
+
"""
|
|
101
|
+
Returns option_get(section, key, default) bound to your BaseAgent.get_option semantics.
|
|
102
|
+
section == node.id (e.g. "agent_1"), key in {"model","prompt","allow_local_tools","allow_remote_tools"}.
|
|
103
|
+
"""
|
|
104
|
+
def option_get(section: str, key: str, default: Any = None) -> Any:
|
|
105
|
+
if preset is None:
|
|
106
|
+
return default
|
|
107
|
+
try:
|
|
108
|
+
val = base_agent.get_option(preset, section, key)
|
|
109
|
+
return default if val in (None, "") else val
|
|
110
|
+
except Exception:
|
|
111
|
+
return default
|
|
112
|
+
return option_get
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@dataclass
|
|
116
|
+
class NodeRuntime:
|
|
117
|
+
model: ModelItem
|
|
118
|
+
instructions: str
|
|
119
|
+
role: Optional[str]
|
|
120
|
+
allow_local_tools: bool
|
|
121
|
+
allow_remote_tools: bool
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def resolve_node_runtime(
|
|
125
|
+
*,
|
|
126
|
+
window,
|
|
127
|
+
node,
|
|
128
|
+
option_get: OptionGetter,
|
|
129
|
+
default_model: ModelItem,
|
|
130
|
+
base_prompt: Optional[str],
|
|
131
|
+
schema_allow_local: Optional[bool],
|
|
132
|
+
schema_allow_remote: Optional[bool],
|
|
133
|
+
default_allow_local: bool,
|
|
134
|
+
default_allow_remote: bool,
|
|
135
|
+
) -> NodeRuntime:
|
|
136
|
+
"""
|
|
137
|
+
Resolve per-node runtime using get_option() overrides, schema slots and defaults.
|
|
138
|
+
|
|
139
|
+
Priority:
|
|
140
|
+
- model: get_option(node.id, "model") -> window.core.models.get(name) -> default_model
|
|
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)
|
|
143
|
+
- allow_*: get_option(node.id, "allow_local_tools"/"allow_remote_tools")
|
|
144
|
+
-> schema flags -> defaults
|
|
145
|
+
"""
|
|
146
|
+
# Model resolve
|
|
147
|
+
model_name = option_get(node.id, "model", None)
|
|
148
|
+
model_item: ModelItem = default_model
|
|
149
|
+
try:
|
|
150
|
+
if model_name:
|
|
151
|
+
cand = window.core.models.get(model_name)
|
|
152
|
+
if cand:
|
|
153
|
+
model_item = cand
|
|
154
|
+
except Exception:
|
|
155
|
+
# fallback to default_model
|
|
156
|
+
model_item = default_model
|
|
157
|
+
|
|
158
|
+
# Instructions resolve
|
|
159
|
+
prompt_opt = option_get(node.id, "prompt", None)
|
|
160
|
+
instructions = (prompt_opt or getattr(node, "instruction", None) or base_prompt or "").strip()
|
|
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
|
+
|
|
171
|
+
# Tools flags resolve
|
|
172
|
+
allow_local_tools = bool(
|
|
173
|
+
option_get(
|
|
174
|
+
node.id,
|
|
175
|
+
"allow_local_tools",
|
|
176
|
+
schema_allow_local if schema_allow_local is not None else default_allow_local,
|
|
177
|
+
)
|
|
178
|
+
)
|
|
179
|
+
allow_remote_tools = bool(
|
|
180
|
+
option_get(
|
|
181
|
+
node.id,
|
|
182
|
+
"allow_remote_tools",
|
|
183
|
+
schema_allow_remote if schema_allow_remote is not None else default_allow_remote,
|
|
184
|
+
)
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
return NodeRuntime(
|
|
188
|
+
model=model_item,
|
|
189
|
+
instructions=instructions,
|
|
190
|
+
role=role,
|
|
191
|
+
allow_local_tools=allow_local_tools,
|
|
192
|
+
allow_remote_tools=allow_remote_tools,
|
|
193
|
+
)
|
|
@@ -6,12 +6,13 @@
|
|
|
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.24 00:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
import copy
|
|
13
|
+
from typing import List, Dict, Any, Optional
|
|
13
14
|
|
|
14
|
-
from pygpt_net.core.types import MODE_CHAT
|
|
15
|
+
from pygpt_net.core.types import MODE_CHAT, MODE_AGENT_LLAMA
|
|
15
16
|
from pygpt_net.item.model import ModelItem
|
|
16
17
|
from pygpt_net.provider.agents.base import BaseAgent
|
|
17
18
|
|
|
@@ -25,6 +26,7 @@ class Provider:
|
|
|
25
26
|
"""
|
|
26
27
|
self.window = window
|
|
27
28
|
self.agents = {}
|
|
29
|
+
self.hidden = ["openai_custom", "llama_custom"] # builder hidden agents (hide provider on list)
|
|
28
30
|
|
|
29
31
|
def get_ids(self) -> List[str]:
|
|
30
32
|
"""
|
|
@@ -34,32 +36,90 @@ class Provider:
|
|
|
34
36
|
"""
|
|
35
37
|
return list(self.agents.keys())
|
|
36
38
|
|
|
37
|
-
def has(self, id: str) -> bool:
|
|
39
|
+
def has(self, id: str, mode: str = MODE_AGENT_LLAMA) -> bool:
|
|
38
40
|
"""
|
|
39
41
|
Check if agent exists
|
|
40
42
|
|
|
41
43
|
:param id: agent id
|
|
44
|
+
:param mode: agent mode, used for custom agents (optional)
|
|
42
45
|
:return: True if exists
|
|
43
46
|
"""
|
|
47
|
+
custom = self.get_custom(id, mode) # shared instance
|
|
48
|
+
if custom is not None:
|
|
49
|
+
return True
|
|
44
50
|
return id in self.agents
|
|
45
51
|
|
|
46
|
-
def get(self, id: str) -> BaseAgent:
|
|
52
|
+
def get(self, id: str, mode: str = MODE_AGENT_LLAMA) -> BaseAgent:
|
|
47
53
|
"""
|
|
48
54
|
Get agent provider
|
|
49
55
|
|
|
50
56
|
:param id: agent id
|
|
57
|
+
:param mode: agent mode, used for custom agents (optional)
|
|
51
58
|
:return: agent provider
|
|
52
59
|
"""
|
|
60
|
+
# custom agents
|
|
61
|
+
custom = self.get_custom(id, mode) # shared instance
|
|
62
|
+
if custom is not None:
|
|
63
|
+
return custom
|
|
64
|
+
|
|
65
|
+
# predefined agents
|
|
53
66
|
if id in self.agents:
|
|
54
67
|
return self.agents[id]
|
|
55
68
|
|
|
69
|
+
def get_custom(
|
|
70
|
+
self,
|
|
71
|
+
id: str,
|
|
72
|
+
mode: str = MODE_AGENT_LLAMA,
|
|
73
|
+
as_copy: bool = True
|
|
74
|
+
) -> Optional[BaseAgent]:
|
|
75
|
+
"""
|
|
76
|
+
Get custom agent provider by id
|
|
77
|
+
|
|
78
|
+
:param id: agent id
|
|
79
|
+
:param mode: agent mode, used for custom agents (optional)
|
|
80
|
+
:param as_copy: return a copy of the agent (default: False)
|
|
81
|
+
:return: custom agent provider
|
|
82
|
+
"""
|
|
83
|
+
custom = None
|
|
84
|
+
if self.window and self.window.core.agents.custom.is_custom(id):
|
|
85
|
+
try:
|
|
86
|
+
if mode == MODE_AGENT_LLAMA:
|
|
87
|
+
if "llama_custom" in self.agents:
|
|
88
|
+
custom = copy.deepcopy(self.agents["llama_custom"]) if as_copy else self.agents["llama_custom"]
|
|
89
|
+
else:
|
|
90
|
+
if "openai_custom" in self.agents:
|
|
91
|
+
custom = copy.deepcopy(self.agents["openai_custom"]) if as_copy else self.agents["openai_custom"]
|
|
92
|
+
except Exception as e:
|
|
93
|
+
self.window.core.debug.log(f"Failed to get custom agent '{id}': {e}")
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
# append custom id and build options
|
|
97
|
+
if custom is not None:
|
|
98
|
+
options = self.window.core.agents.custom.build_options(id)
|
|
99
|
+
custom.set_id(id)
|
|
100
|
+
custom.set_options(options)
|
|
101
|
+
return custom
|
|
102
|
+
|
|
56
103
|
def all(self) -> Dict[str, BaseAgent]:
|
|
57
104
|
"""
|
|
58
|
-
Get all agents
|
|
105
|
+
Get all agents (predefined + custom, for build options)
|
|
59
106
|
|
|
60
107
|
:return: dict of agent providers
|
|
61
108
|
"""
|
|
62
|
-
|
|
109
|
+
all_agents = {}
|
|
110
|
+
|
|
111
|
+
# predefined agents
|
|
112
|
+
for id in self.get_ids():
|
|
113
|
+
if id in self.hidden:
|
|
114
|
+
continue
|
|
115
|
+
all_agents[id] = self.agents[id]
|
|
116
|
+
|
|
117
|
+
# custom agents
|
|
118
|
+
if self.window:
|
|
119
|
+
for id in self.window.core.agents.custom.get_ids():
|
|
120
|
+
all_agents[id] = self.get_custom(id, as_copy=True) # copy to avoid overwriting options
|
|
121
|
+
return all_agents
|
|
122
|
+
|
|
63
123
|
|
|
64
124
|
def register(self, id: str, agent):
|
|
65
125
|
"""
|
|
@@ -87,6 +147,8 @@ class Provider:
|
|
|
87
147
|
"""
|
|
88
148
|
choices = []
|
|
89
149
|
for id in self.get_ids():
|
|
150
|
+
if id in self.hidden:
|
|
151
|
+
continue
|
|
90
152
|
agent = self.get(id)
|
|
91
153
|
if type is not None:
|
|
92
154
|
if agent.type != type:
|
|
@@ -94,6 +156,9 @@ class Provider:
|
|
|
94
156
|
choices.append({id: agent.name})
|
|
95
157
|
|
|
96
158
|
# sort by name
|
|
159
|
+
if self.window:
|
|
160
|
+
custom = self.window.core.agents.custom.get_choices()
|
|
161
|
+
choices.extend(custom)
|
|
97
162
|
choices.sort(key=lambda x: list(x.values())[0].lower())
|
|
98
163
|
return choices
|
|
99
164
|
|
pygpt_net/core/agents/runner.py
CHANGED
|
@@ -81,7 +81,7 @@ class Runner:
|
|
|
81
81
|
|
|
82
82
|
try:
|
|
83
83
|
# first, check if agent exists
|
|
84
|
-
if not self.window.core.agents.provider.has(agent_id):
|
|
84
|
+
if not self.window.core.agents.provider.has(agent_id, context.mode):
|
|
85
85
|
raise Exception(f"Agent not found: {agent_id}")
|
|
86
86
|
|
|
87
87
|
# prepare input ctx
|
|
@@ -155,6 +155,8 @@ class Runner:
|
|
|
155
155
|
)
|
|
156
156
|
history.insert(0, msg)
|
|
157
157
|
|
|
158
|
+
# append custom schema if available
|
|
159
|
+
schema = self.window.core.agents.custom.get_schema(agent_id)
|
|
158
160
|
agent_kwargs = {
|
|
159
161
|
"context": context,
|
|
160
162
|
"tools": tools,
|
|
@@ -171,9 +173,9 @@ class Runner:
|
|
|
171
173
|
"are_commands": is_cmd,
|
|
172
174
|
"workdir": workdir,
|
|
173
175
|
"preset": context.preset if context else None,
|
|
176
|
+
"schema": schema,
|
|
174
177
|
}
|
|
175
|
-
|
|
176
|
-
provider = self.window.core.agents.provider.get(agent_id)
|
|
178
|
+
provider = self.window.core.agents.provider.get(agent_id, context.mode)
|
|
177
179
|
agent = provider.get_agent(self.window, agent_kwargs)
|
|
178
180
|
agent_run = provider.run
|
|
179
181
|
if verbose:
|
|
@@ -188,6 +190,8 @@ class Runner:
|
|
|
188
190
|
"signals": signals,
|
|
189
191
|
"verbose": verbose,
|
|
190
192
|
}
|
|
193
|
+
if schema:
|
|
194
|
+
kwargs["schema"] = schema
|
|
191
195
|
|
|
192
196
|
if mode == AGENT_MODE_PLAN:
|
|
193
197
|
return self.llama_plan.run(**kwargs)
|
|
@@ -291,7 +295,6 @@ class Runner:
|
|
|
291
295
|
"workdir": workdir,
|
|
292
296
|
"preset": context.preset if context else None,
|
|
293
297
|
}
|
|
294
|
-
|
|
295
298
|
provider = self.window.core.agents.provider.get(agent_id)
|
|
296
299
|
agent = provider.get_agent(self.window, agent_kwargs)
|
|
297
300
|
if verbose:
|
|
@@ -100,7 +100,7 @@ class Helpers:
|
|
|
100
100
|
"""
|
|
101
101
|
if signals is None:
|
|
102
102
|
return
|
|
103
|
-
chunk = ctx.stream.replace("<execute>", "\n```python\n").replace("</execute>", "\n```\n")
|
|
103
|
+
chunk = ctx.stream.replace("<execute>", "\n```python\n").replace("</execute>", "\n```\n") if ctx.stream else ""
|
|
104
104
|
data = {
|
|
105
105
|
"meta": ctx.meta,
|
|
106
106
|
"ctx": ctx,
|
|
@@ -48,6 +48,7 @@ class LlamaWorkflow(BaseRunner):
|
|
|
48
48
|
verbose: bool = False,
|
|
49
49
|
history: List[CtxItem] = None,
|
|
50
50
|
llm: Any = None,
|
|
51
|
+
schema: Optional[List] = None,
|
|
51
52
|
) -> bool:
|
|
52
53
|
"""
|
|
53
54
|
Run agent workflow
|
|
@@ -59,6 +60,7 @@ class LlamaWorkflow(BaseRunner):
|
|
|
59
60
|
:param verbose: verbose mode
|
|
60
61
|
:param history: chat history
|
|
61
62
|
:param llm: LLM instance
|
|
63
|
+
:param schema: custom agent flow schema
|
|
62
64
|
:return: True if success
|
|
63
65
|
"""
|
|
64
66
|
if self.is_stopped():
|
|
@@ -253,6 +255,7 @@ class LlamaWorkflow(BaseRunner):
|
|
|
253
255
|
item_ctx.stream = "" # for stream
|
|
254
256
|
|
|
255
257
|
async for event in handler.stream_events():
|
|
258
|
+
print(event)
|
|
256
259
|
if self.is_stopped():
|
|
257
260
|
# persist current output on stop
|
|
258
261
|
item_ctx.output = item_ctx.live_output
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
# Updated Date: 2025.08.24 03:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
|
-
from typing import Dict, Any, List
|
|
12
|
+
from typing import Dict, Any, List, Optional
|
|
13
13
|
|
|
14
14
|
from pygpt_net.core.bridge.context import BridgeContext
|
|
15
15
|
from pygpt_net.core.bridge.worker import BridgeSignals
|
|
@@ -18,6 +18,7 @@ from pygpt_net.item.ctx import CtxItem
|
|
|
18
18
|
|
|
19
19
|
from ..bridge import ConnectionContext
|
|
20
20
|
from .base import BaseRunner
|
|
21
|
+
from ..custom.logging import StdLogger
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
class OpenAIWorkflow(BaseRunner):
|
|
@@ -41,6 +42,7 @@ class OpenAIWorkflow(BaseRunner):
|
|
|
41
42
|
verbose: bool = False,
|
|
42
43
|
history: List[CtxItem] = None,
|
|
43
44
|
stream: bool = False,
|
|
45
|
+
schema: Optional[List] = None,
|
|
44
46
|
) -> bool:
|
|
45
47
|
"""
|
|
46
48
|
Run OpenAI agents
|
|
@@ -54,6 +56,7 @@ class OpenAIWorkflow(BaseRunner):
|
|
|
54
56
|
:param verbose: verbose mode
|
|
55
57
|
:param history: chat history
|
|
56
58
|
:param stream: use streaming
|
|
59
|
+
:param schema: custom agent flow schema
|
|
57
60
|
:return: True if success
|
|
58
61
|
"""
|
|
59
62
|
if self.is_stopped():
|
|
@@ -193,6 +196,10 @@ class OpenAIWorkflow(BaseRunner):
|
|
|
193
196
|
if previous_response_id:
|
|
194
197
|
run_kwargs["previous_response_id"] = previous_response_id
|
|
195
198
|
|
|
199
|
+
# custom agent schema
|
|
200
|
+
if schema:
|
|
201
|
+
run_kwargs["schema"] = schema
|
|
202
|
+
|
|
196
203
|
# split response messages to separated context items
|
|
197
204
|
run_kwargs["use_partial_ctx"] = self.window.core.config.get("agent.openai.response.split", True)
|
|
198
205
|
|
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.24 00:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
|
-
from .
|
|
12
|
+
from .graph import NodeGraph
|