pygpt-net 2.6.61__py3-none-any.whl → 2.6.62__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 +1 -1
- pygpt_net/controller/chat/response.py +8 -2
- pygpt_net/controller/settings/profile.py +16 -4
- pygpt_net/controller/settings/workdir.py +30 -5
- pygpt_net/controller/theme/common.py +4 -2
- pygpt_net/controller/theme/markdown.py +2 -2
- pygpt_net/controller/theme/theme.py +2 -1
- pygpt_net/controller/ui/ui.py +31 -3
- pygpt_net/core/agents/custom/llama_index/runner.py +18 -3
- pygpt_net/core/agents/custom/runner.py +10 -5
- pygpt_net/core/agents/runners/llama_workflow.py +65 -5
- pygpt_net/core/agents/runners/openai_workflow.py +2 -1
- pygpt_net/core/node_editor/types.py +13 -1
- pygpt_net/core/render/web/renderer.py +76 -11
- pygpt_net/data/config/config.json +2 -2
- pygpt_net/data/config/models.json +2 -2
- pygpt_net/data/css/style.dark.css +18 -0
- pygpt_net/data/css/style.light.css +20 -1
- pygpt_net/data/locale/locale.de.ini +2 -0
- pygpt_net/data/locale/locale.en.ini +2 -0
- pygpt_net/data/locale/locale.es.ini +2 -0
- pygpt_net/data/locale/locale.fr.ini +2 -0
- pygpt_net/data/locale/locale.it.ini +2 -0
- pygpt_net/data/locale/locale.pl.ini +3 -1
- pygpt_net/data/locale/locale.uk.ini +2 -0
- pygpt_net/data/locale/locale.zh.ini +2 -0
- pygpt_net/item/ctx.py +23 -1
- pygpt_net/provider/agents/llama_index/workflow/codeact.py +9 -6
- pygpt_net/provider/agents/llama_index/workflow/openai.py +38 -11
- pygpt_net/provider/agents/llama_index/workflow/planner.py +36 -16
- pygpt_net/provider/agents/llama_index/workflow/supervisor.py +60 -10
- pygpt_net/provider/agents/openai/agent.py +3 -1
- pygpt_net/provider/agents/openai/agent_b2b.py +13 -9
- pygpt_net/provider/agents/openai/agent_planner.py +6 -2
- pygpt_net/provider/agents/openai/agent_with_experts.py +4 -1
- pygpt_net/provider/agents/openai/agent_with_experts_feedback.py +4 -2
- pygpt_net/provider/agents/openai/agent_with_feedback.py +4 -2
- pygpt_net/provider/agents/openai/evolve.py +6 -2
- pygpt_net/provider/agents/openai/supervisor.py +3 -1
- pygpt_net/provider/api/openai/agents/response.py +1 -0
- pygpt_net/provider/core/config/patch.py +8 -0
- pygpt_net/tools/agent_builder/tool.py +6 -0
- pygpt_net/tools/agent_builder/ui/dialogs.py +0 -41
- pygpt_net/ui/layout/toolbox/presets.py +14 -2
- pygpt_net/ui/main.py +2 -2
- pygpt_net/ui/widget/dialog/confirm.py +27 -3
- pygpt_net/ui/widget/draw/painter.py +90 -1
- pygpt_net/ui/widget/lists/preset.py +289 -25
- pygpt_net/ui/widget/node_editor/editor.py +53 -15
- pygpt_net/ui/widget/node_editor/node.py +82 -104
- pygpt_net/ui/widget/node_editor/view.py +4 -5
- pygpt_net/ui/widget/textarea/input.py +155 -21
- {pygpt_net-2.6.61.dist-info → pygpt_net-2.6.62.dist-info}/METADATA +17 -8
- {pygpt_net-2.6.61.dist-info → pygpt_net-2.6.62.dist-info}/RECORD +58 -58
- {pygpt_net-2.6.61.dist-info → pygpt_net-2.6.62.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.61.dist-info → pygpt_net-2.6.62.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.61.dist-info → pygpt_net-2.6.62.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.17
|
|
9
|
+
# Updated Date: 2025.09.26 17:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import json
|
|
@@ -16,15 +16,13 @@ import html as _html
|
|
|
16
16
|
from dataclasses import dataclass, field
|
|
17
17
|
|
|
18
18
|
from datetime import datetime
|
|
19
|
-
from typing import Optional, List, Any,
|
|
19
|
+
from typing import Optional, List, Any, Tuple
|
|
20
20
|
from time import monotonic
|
|
21
21
|
from io import StringIO
|
|
22
22
|
|
|
23
|
-
from PySide6.QtCore import QTimer,
|
|
24
|
-
from PySide6.QtWebEngineCore import QWebEnginePage
|
|
23
|
+
from PySide6.QtCore import QTimer, QCoreApplication, QEventLoop, QEvent
|
|
25
24
|
|
|
26
25
|
from pygpt_net.core.render.base import BaseRenderer
|
|
27
|
-
from pygpt_net.core.text.utils import has_unclosed_code_tag
|
|
28
26
|
from pygpt_net.item.ctx import CtxItem, CtxMeta
|
|
29
27
|
from pygpt_net.ui.widget.textarea.input import ChatInput
|
|
30
28
|
from pygpt_net.ui.widget.textarea.web import ChatWebOutput
|
|
@@ -155,6 +153,7 @@ class Renderer(BaseRenderer):
|
|
|
155
153
|
app_path = self.window.core.config.get_app_path() if self.window else ""
|
|
156
154
|
self._icon_expand = os.path.join(app_path, "data", "icons", "expand.svg")
|
|
157
155
|
self._icon_sync = os.path.join(app_path, "data", "icons", "sync.svg")
|
|
156
|
+
self._agent_avatar = os.path.join(app_path, "data", "icons", "robot.svg")
|
|
158
157
|
self._file_prefix = 'file:///' if self.window and self.window.core.platforms.is_windows() else 'file://'
|
|
159
158
|
|
|
160
159
|
# Bridge readiness for node append/replace path
|
|
@@ -378,6 +377,15 @@ class Renderer(BaseRenderer):
|
|
|
378
377
|
self.tool_output_end()
|
|
379
378
|
self.prev_chunk_replace = False
|
|
380
379
|
|
|
380
|
+
# Ensure stream header identity is up-to-date (agent/preset override)
|
|
381
|
+
try:
|
|
382
|
+
header = self.get_name_header(ctx, stream=True)
|
|
383
|
+
if pid is not None:
|
|
384
|
+
self.pids[pid].header = header
|
|
385
|
+
self._stream_header[pid] = header or ""
|
|
386
|
+
except Exception:
|
|
387
|
+
pass
|
|
388
|
+
|
|
381
389
|
def end(self, meta: CtxMeta, ctx: CtxItem, stream: bool = False):
|
|
382
390
|
"""
|
|
383
391
|
Render end
|
|
@@ -1163,6 +1171,26 @@ class Renderer(BaseRenderer):
|
|
|
1163
1171
|
meta = ctx.meta
|
|
1164
1172
|
if meta is None:
|
|
1165
1173
|
return ""
|
|
1174
|
+
|
|
1175
|
+
# Agent-provided display name override:
|
|
1176
|
+
# If ctx.get_agent_name() returns a non-empty name, force "fake personalize":
|
|
1177
|
+
# - use that name
|
|
1178
|
+
# - optionally attach default avatar when enabled via config
|
|
1179
|
+
# - treat as personalized header regardless of preset
|
|
1180
|
+
agent_name = self._get_agent_name(ctx)
|
|
1181
|
+
if agent_name:
|
|
1182
|
+
avatar_html = ""
|
|
1183
|
+
try:
|
|
1184
|
+
use_default = self.window.core.config.get("agent.avatar.default", True)
|
|
1185
|
+
if use_default and os.path.exists(self._agent_avatar):
|
|
1186
|
+
avatar_html = f"<img src=\"{self._file_prefix}{self._agent_avatar}\" class=\"avatar\"> "
|
|
1187
|
+
except Exception:
|
|
1188
|
+
pass
|
|
1189
|
+
if stream:
|
|
1190
|
+
return f"{avatar_html}{agent_name}"
|
|
1191
|
+
else:
|
|
1192
|
+
return f"<div class=\"name-header name-bot\">{avatar_html}{agent_name}</div>"
|
|
1193
|
+
|
|
1166
1194
|
preset_id = meta.preset
|
|
1167
1195
|
if preset_id is None or preset_id == "":
|
|
1168
1196
|
return ""
|
|
@@ -1904,23 +1932,60 @@ class Renderer(BaseRenderer):
|
|
|
1904
1932
|
|
|
1905
1933
|
# ------------------------- Helpers: build JSON blocks -------------------------
|
|
1906
1934
|
|
|
1935
|
+
def _get_agent_name(self, ctx: CtxItem) -> Optional[str]:
|
|
1936
|
+
"""
|
|
1937
|
+
Resolve agent-provided name from ctx if available.
|
|
1938
|
+
|
|
1939
|
+
This is used to force "fake personalize" on the UI:
|
|
1940
|
+
- when present and non-empty, we use this name,
|
|
1941
|
+
- optionally attach default avatar when enabled via config,
|
|
1942
|
+
- we set personalize flag to True in node payloads.
|
|
1943
|
+
"""
|
|
1944
|
+
try:
|
|
1945
|
+
if hasattr(ctx, "get_agent_name"):
|
|
1946
|
+
name = ctx.get_agent_name()
|
|
1947
|
+
if isinstance(name, str):
|
|
1948
|
+
name = name.strip()
|
|
1949
|
+
return name or None
|
|
1950
|
+
except Exception:
|
|
1951
|
+
pass
|
|
1952
|
+
return None
|
|
1953
|
+
|
|
1907
1954
|
def _output_identity(self, ctx: CtxItem) -> Tuple[str, Optional[str], bool]:
|
|
1908
1955
|
"""
|
|
1909
|
-
Resolve output identity (name, avatar file:// path) based on preset.
|
|
1956
|
+
Resolve output identity (name, avatar file:// path) based on preset or ctx-provided agent name.
|
|
1910
1957
|
|
|
1911
1958
|
:param ctx: context item
|
|
1912
1959
|
:return: (name, avatar, personalize)
|
|
1913
1960
|
"""
|
|
1961
|
+
# 1) Agent-provided name override -> force personalize, optionally default avatar
|
|
1962
|
+
agent_name = self._get_agent_name(ctx)
|
|
1963
|
+
if agent_name:
|
|
1964
|
+
avatar = None
|
|
1965
|
+
try:
|
|
1966
|
+
if self.window.core.config.get("agent.avatar.default", True) and os.path.exists(self._agent_avatar):
|
|
1967
|
+
avatar = f"{self._file_prefix}{self._agent_avatar}"
|
|
1968
|
+
except Exception:
|
|
1969
|
+
pass
|
|
1970
|
+
return agent_name, avatar, True
|
|
1971
|
+
|
|
1972
|
+
# 2) Fallback to preset-based personalize
|
|
1914
1973
|
meta = ctx.meta
|
|
1915
1974
|
if meta is None:
|
|
1916
|
-
return
|
|
1975
|
+
return "", None, False
|
|
1976
|
+
|
|
1977
|
+
pid = self.get_or_create_pid(meta)
|
|
1978
|
+
default_name = self.pids[pid].name_bot if pid in self.pids else ""
|
|
1979
|
+
|
|
1917
1980
|
preset_id = meta.preset
|
|
1918
1981
|
if not preset_id:
|
|
1919
|
-
return
|
|
1982
|
+
return default_name, None, False
|
|
1983
|
+
|
|
1920
1984
|
preset = self.window.core.presets.get(preset_id)
|
|
1921
1985
|
if preset is None or not preset.ai_personalize:
|
|
1922
|
-
return
|
|
1923
|
-
|
|
1986
|
+
return default_name, None, False
|
|
1987
|
+
|
|
1988
|
+
name = preset.ai_name or default_name
|
|
1924
1989
|
avatar = None
|
|
1925
1990
|
if preset.ai_avatar:
|
|
1926
1991
|
presets_dir = self.window.core.config.get_user_dir("presets")
|
|
@@ -1928,7 +1993,7 @@ class Renderer(BaseRenderer):
|
|
|
1928
1993
|
avatar_path = os.path.join(avatars_dir, preset.ai_avatar)
|
|
1929
1994
|
if os.path.exists(avatar_path):
|
|
1930
1995
|
avatar = f"{self._file_prefix}{avatar_path}"
|
|
1931
|
-
return name, avatar,
|
|
1996
|
+
return name, avatar, True
|
|
1932
1997
|
|
|
1933
1998
|
def _build_render_block(
|
|
1934
1999
|
self,
|
|
@@ -144,4 +144,22 @@ QCalendarWidget QAbstractItemView::item:hover {{
|
|
|
144
144
|
QCalendarWidget QMenu::item:selected:focus,
|
|
145
145
|
QCalendarWidget QMenu::item:selected {{
|
|
146
146
|
background: #3a4045;
|
|
147
|
+
}}
|
|
148
|
+
|
|
149
|
+
/* Node editor */
|
|
150
|
+
NodeEditor {{
|
|
151
|
+
qproperty-gridBackColor: #242629;
|
|
152
|
+
qproperty-gridPenColor: #3b3f46;
|
|
153
|
+
|
|
154
|
+
qproperty-nodeBackgroundColor: #2d2f34;
|
|
155
|
+
qproperty-nodeBorderColor: #4b4f57;
|
|
156
|
+
qproperty-nodeSelectionColor: #ff9900;
|
|
157
|
+
qproperty-nodeTitleColor: #3a3d44;
|
|
158
|
+
|
|
159
|
+
qproperty-portInputColor: #66b2ff;
|
|
160
|
+
qproperty-portOutputColor: #70e070;
|
|
161
|
+
qproperty-portConnectedColor: #ffd166;
|
|
162
|
+
|
|
163
|
+
qproperty-edgeColor: #c0c0c0;
|
|
164
|
+
qproperty-edgeSelectedColor: #ff8a5c;
|
|
147
165
|
}}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
QWidget {{
|
|
7
7
|
color: #000;
|
|
8
8
|
margin: 1px;
|
|
9
|
+
background-color: #eeeeee;
|
|
9
10
|
}}
|
|
10
11
|
|
|
11
12
|
QListView,
|
|
@@ -248,7 +249,7 @@ QCalendarWidget QToolButton:hover {{
|
|
|
248
249
|
height: 20px;
|
|
249
250
|
}}
|
|
250
251
|
QMenu::indicator {{
|
|
251
|
-
border: 1px solid gray;
|
|
252
|
+
border: 1px solid gray;
|
|
252
253
|
}}
|
|
253
254
|
QCalendarWidget QAbstractItemView::item:selected:focus,
|
|
254
255
|
QCalendarWidget QAbstractItemView::item:selected {{
|
|
@@ -259,4 +260,22 @@ QCalendarWidget QAbstractItemView::item:hover {{
|
|
|
259
260
|
}}
|
|
260
261
|
.file-explorer QTreeView::branch {{
|
|
261
262
|
background: #fff;
|
|
263
|
+
}}
|
|
264
|
+
|
|
265
|
+
/* Node editor */
|
|
266
|
+
NodeEditor {{
|
|
267
|
+
qproperty-gridBackColor: #ffffff;
|
|
268
|
+
qproperty-gridPenColor: #eaeaea;
|
|
269
|
+
|
|
270
|
+
qproperty-nodeBackgroundColor: #2d2f34;
|
|
271
|
+
qproperty-nodeBorderColor: #4b4f57;
|
|
272
|
+
qproperty-nodeSelectionColor: #ff9900;
|
|
273
|
+
qproperty-nodeTitleColor: #3a3d44;
|
|
274
|
+
|
|
275
|
+
qproperty-portInputColor: #66b2ff;
|
|
276
|
+
qproperty-portOutputColor: #70e070;
|
|
277
|
+
qproperty-portConnectedColor: #ffd166;
|
|
278
|
+
|
|
279
|
+
qproperty-edgeColor: #c0c0c0;
|
|
280
|
+
qproperty-edgeSelectedColor: #ff8a5c;
|
|
262
281
|
}}
|
|
@@ -658,6 +658,7 @@ event.control.voice_cmd.toggle = Sprachsteuerung: Umschalten
|
|
|
658
658
|
event.control.voice_msg.start = Spracheingabe: Start
|
|
659
659
|
event.control.voice_msg.stop = Spracheingabe: Stopp
|
|
660
660
|
event.control.voice_msg.toggle = Spracheingabe: Umschalten
|
|
661
|
+
exit.msg = Gefällt dir PyGPT? Unterstütze die Entwicklung des Projekts:
|
|
661
662
|
expert.wait.failed: Aufruf des Experten fehlgeschlagen
|
|
662
663
|
expert.wait.status: Warten auf Experten...
|
|
663
664
|
files.delete.confirm = Datei/Verzeichnis löschen?
|
|
@@ -734,6 +735,7 @@ input.search.placeholder = Suchen...
|
|
|
734
735
|
input.send_clear = Nach dem Senden löschen
|
|
735
736
|
input.stream = Streamen
|
|
736
737
|
input.tab = Eingabe
|
|
738
|
+
input.tab.tooltip = {chars} Zeichen (~{tokens} Token)
|
|
737
739
|
interpreter.all = Verlauf ausführen (alle)
|
|
738
740
|
interpreter.auto_clear = Bei Senden löschen
|
|
739
741
|
interpreter.btn.clear = Ausgabe löschen
|
|
@@ -663,6 +663,7 @@ event.control.voice_cmd.toggle = Voice control: Toggle
|
|
|
663
663
|
event.control.voice_msg.start = Voice input: Start
|
|
664
664
|
event.control.voice_msg.stop = Voice input: Stop
|
|
665
665
|
event.control.voice_msg.toggle = Voice input: Toggle
|
|
666
|
+
exit.msg = Do you like PyGPT? Support the development of the project:
|
|
666
667
|
expert.wait.failed: Failed calling expert
|
|
667
668
|
expert.wait.status: Waiting for expert...
|
|
668
669
|
files.delete.confirm = Delete file/directory?
|
|
@@ -739,6 +740,7 @@ input.search.placeholder = Search...
|
|
|
739
740
|
input.send_clear = Clear on send
|
|
740
741
|
input.stream = Stream
|
|
741
742
|
input.tab = Input
|
|
743
|
+
input.tab.tooltip = {chars} chars (~{tokens} tokens)
|
|
742
744
|
interpreter.all = Execute history (all)
|
|
743
745
|
interpreter.auto_clear = Clear output on send
|
|
744
746
|
interpreter.btn.clear = Clear output
|
|
@@ -659,6 +659,7 @@ event.control.voice_cmd.toggle = Control de voz: Conmutar
|
|
|
659
659
|
event.control.voice_msg.start = Entrada de voz: Iniciar
|
|
660
660
|
event.control.voice_msg.stop = Entrada de voz: Detener
|
|
661
661
|
event.control.voice_msg.toggle = Entrada de voz: Conmutar
|
|
662
|
+
exit.msg = ¿Te gusta PyGPT? Apoya el desarrollo del proyecto:
|
|
662
663
|
expert.wait.failed: Error al llamar al experto
|
|
663
664
|
expert.wait.status: Esperando al experto...
|
|
664
665
|
files.delete.confirm = ¿Eliminar archivo/directorio?
|
|
@@ -735,6 +736,7 @@ input.search.placeholder = Buscar...
|
|
|
735
736
|
input.send_clear = Limpiar al enviar
|
|
736
737
|
input.stream = Transmisión
|
|
737
738
|
input.tab = Entrada
|
|
739
|
+
input.tab.tooltip = {chars} caracteres (~{tokens} fichas)
|
|
738
740
|
interpreter.all = Ejecutar historial (todo)
|
|
739
741
|
interpreter.auto_clear = Limpiar al enviar
|
|
740
742
|
interpreter.btn.clear = Limpiar salida
|
|
@@ -658,6 +658,7 @@ event.control.voice_cmd.toggle = Commande vocale : Basculer
|
|
|
658
658
|
event.control.voice_msg.start = Entrée vocale : Commencer
|
|
659
659
|
event.control.voice_msg.stop = Entrée vocale : Arrêter
|
|
660
660
|
event.control.voice_msg.toggle = Entrée vocale : Basculer
|
|
661
|
+
exit.msg = PyGPT vous plaît-il ? Soutenez le développement du projet :
|
|
661
662
|
expert.wait.failed: Échec de l'appel à l'expert
|
|
662
663
|
expert.wait.status: En attente de l'expert...
|
|
663
664
|
files.delete.confirm = Supprimer le fichier/répertoire ?
|
|
@@ -734,6 +735,7 @@ input.search.placeholder = Rechercher...
|
|
|
734
735
|
input.send_clear = Effacer après envoi
|
|
735
736
|
input.stream = Flux
|
|
736
737
|
input.tab = Entrée
|
|
738
|
+
input.tab.tooltip = {chars} caractères (~{tokens} jetons)
|
|
737
739
|
interpreter.all = Exécuter l'historique (tous)
|
|
738
740
|
interpreter.auto_clear = Effacer à l'envoi
|
|
739
741
|
interpreter.btn.clear = Effacer la sortie
|
|
@@ -658,6 +658,7 @@ event.control.voice_cmd.toggle = Comando vocale: Commuta
|
|
|
658
658
|
event.control.voice_msg.start = Input vocale: Avvia
|
|
659
659
|
event.control.voice_msg.stop = Input vocale: Arresta
|
|
660
660
|
event.control.voice_msg.toggle = Input vocale: Commuta
|
|
661
|
+
exit.msg = Ti piace PyGPT? Sostieni lo sviluppo del progetto:
|
|
661
662
|
expert.wait.failed: Chiamata all'esperto non riuscita
|
|
662
663
|
expert.wait.status: In attesa dell'esperto...
|
|
663
664
|
files.delete.confirm = Eliminare il file/la cartella?
|
|
@@ -734,6 +735,7 @@ input.search.placeholder = Cerca...
|
|
|
734
735
|
input.send_clear = Pulisci dopo l'invio
|
|
735
736
|
input.stream = Flusso
|
|
736
737
|
input.tab = Input
|
|
738
|
+
input.tab.tooltip = {chars} caratteri (~{tokens} token)
|
|
737
739
|
interpreter.all = Esegui cronologia (tutto)
|
|
738
740
|
interpreter.auto_clear = Cancella all'invio
|
|
739
741
|
interpreter.btn.clear = Cancella output
|
|
@@ -244,7 +244,7 @@ clipboard.copied_to = Skopiowano do schowka:
|
|
|
244
244
|
cmd.enabled = + Narzędzia
|
|
245
245
|
cmd.tip = Wskazówka: Aby umożliwić wykonanie narzędzi z wtyczek, musisz włączyć opcję "+ Narzędzia".
|
|
246
246
|
coming_soon = Dostępne wkrótce...
|
|
247
|
-
common.down = Przesuń w dół
|
|
247
|
+
common.down = Przesuń w dół
|
|
248
248
|
common.up = Przesuń w górę
|
|
249
249
|
confirm.assistant.delete = Na pewno usunąć asystenta?
|
|
250
250
|
confirm.assistant.files.clear = Wyczyścić pliki (tylko lokalnie)?
|
|
@@ -659,6 +659,7 @@ event.control.voice_cmd.toggle = Kontrola głosowa: Przełącz
|
|
|
659
659
|
event.control.voice_msg.start = Wejście głosowe: Rozpocznij
|
|
660
660
|
event.control.voice_msg.stop = Wejście głosowe: Zatrzymaj
|
|
661
661
|
event.control.voice_msg.toggle = Wejście głosowe: Przełącz
|
|
662
|
+
exit.msg = Podoba Ci się PyGPT? Wesprzyj rozwój projektu:
|
|
662
663
|
expert.wait.failed: Nie udało się wywołać eksperta
|
|
663
664
|
expert.wait.status: Oczekiwanie na eksperta...
|
|
664
665
|
files.delete.confirm = Usunąć plik/katalog?
|
|
@@ -735,6 +736,7 @@ input.search.placeholder = Szukaj...
|
|
|
735
736
|
input.send_clear = Wyczyść po wysłaniu
|
|
736
737
|
input.stream = Stream
|
|
737
738
|
input.tab = Input
|
|
739
|
+
input.tab.tooltip = {chars} znaków (~{tokens} tokenów)
|
|
738
740
|
interpreter.all = Wykonaj historię (wszystko)
|
|
739
741
|
interpreter.auto_clear = Wyczyść wyjście przy wysyłaniu
|
|
740
742
|
interpreter.btn.clear = Wyczyść wyjście
|
|
@@ -658,6 +658,7 @@ event.control.voice_cmd.toggle = Керування голосом: Перемк
|
|
|
658
658
|
event.control.voice_msg.start = Голосовий вхід: Розпочати
|
|
659
659
|
event.control.voice_msg.stop = Голосовий вхід: Зупинити
|
|
660
660
|
event.control.voice_msg.toggle = Голосовий вхід: Перемкнути
|
|
661
|
+
exit.msg = Вам подобається PyGPT? Підтримайте розвиток проєкту:
|
|
661
662
|
expert.wait.failed: Виклик експерта не вдався
|
|
662
663
|
expert.wait.status: Очікування експерта...
|
|
663
664
|
files.delete.confirm = Видалити файл/директорію?
|
|
@@ -734,6 +735,7 @@ input.search.placeholder = Пошук...
|
|
|
734
735
|
input.send_clear = Очистити після відправлення
|
|
735
736
|
input.stream = Потік
|
|
736
737
|
input.tab = Введення
|
|
738
|
+
input.tab.tooltip = {chars} символів (~{tokens} токенів)
|
|
737
739
|
interpreter.all = Виконати історію (все)
|
|
738
740
|
interpreter.auto_clear = Очистити при відправці
|
|
739
741
|
interpreter.btn.clear = Очистити вивід
|
|
@@ -658,6 +658,7 @@ event.control.voice_cmd.toggle = 语音控制:切换
|
|
|
658
658
|
event.control.voice_msg.start = 语音输入:开始
|
|
659
659
|
event.control.voice_msg.stop = 语音输入:停止
|
|
660
660
|
event.control.voice_msg.toggle = 语音输入:切换
|
|
661
|
+
exit.msg = 你喜欢PyGPT吗?支持项目的发展:
|
|
661
662
|
expert.wait.failed: 调用专家失败
|
|
662
663
|
expert.wait.status: 等待专家...
|
|
663
664
|
files.delete.confirm = 刪除文件/目錄?
|
|
@@ -734,6 +735,7 @@ input.search.placeholder = 搜索...
|
|
|
734
735
|
input.send_clear = 發送後清除
|
|
735
736
|
input.stream = 流
|
|
736
737
|
input.tab = 輸入
|
|
738
|
+
input.tab.tooltip = {chars} 字符 (~{tokens} 令牌)
|
|
737
739
|
interpreter.all = 执行历史记录(全部)
|
|
738
740
|
interpreter.auto_clear = 发送时清除
|
|
739
741
|
interpreter.btn.clear = 清除输出
|
pygpt_net/item/ctx.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 17:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import copy
|
|
@@ -209,6 +209,28 @@ class CtxItem:
|
|
|
209
209
|
if src:
|
|
210
210
|
setattr(self, name, dp(src))
|
|
211
211
|
|
|
212
|
+
def set_agent_name(self, name: Optional[str]):
|
|
213
|
+
"""
|
|
214
|
+
Set AI/agent name
|
|
215
|
+
|
|
216
|
+
:param name: name
|
|
217
|
+
"""
|
|
218
|
+
self.ai_name = name
|
|
219
|
+
if name:
|
|
220
|
+
if self.extra is None:
|
|
221
|
+
self.extra = {}
|
|
222
|
+
self.extra['agent_name'] = name
|
|
223
|
+
|
|
224
|
+
def get_agent_name(self) -> Optional[str]:
|
|
225
|
+
"""
|
|
226
|
+
Get AI/agent name
|
|
227
|
+
|
|
228
|
+
:return: name
|
|
229
|
+
"""
|
|
230
|
+
if self.extra and isinstance(self.extra, dict):
|
|
231
|
+
return self.extra.get('agent_name', None)
|
|
232
|
+
return None
|
|
233
|
+
|
|
212
234
|
def is_empty(self) -> bool:
|
|
213
235
|
"""
|
|
214
236
|
Check if context item is empty
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
6
6
|
# MIT License #
|
|
7
7
|
# Created By : Marcin Szczygliński #
|
|
8
|
-
# Updated Date: 2025.
|
|
8
|
+
# Updated Date: 2025.09.26 14:00:00 #
|
|
9
9
|
# ================================================== #
|
|
10
10
|
|
|
11
11
|
# >>> Based on LlamaIndex CodeActAgent implementation, with custom plugin tool support <<<
|
|
@@ -124,6 +124,9 @@ class CodeActAgent(BaseWorkflowAgent):
|
|
|
124
124
|
_plugin_tool_fn: Union[Callable, Awaitable] = PrivateAttr(default=None)
|
|
125
125
|
_on_stop: Optional[Callable] = PrivateAttr(default=None)
|
|
126
126
|
|
|
127
|
+
# Always emit this human-friendly agent name in workflow events for UI consumption.
|
|
128
|
+
_display_agent_name: str = PrivateAttr(default="CodeAct")
|
|
129
|
+
|
|
127
130
|
def __init__(
|
|
128
131
|
self,
|
|
129
132
|
code_execute_fn: Union[Callable, Awaitable],
|
|
@@ -296,13 +299,13 @@ class CodeActAgent(BaseWorkflowAgent):
|
|
|
296
299
|
StepEvent(name=name, index=index, total=total, meta=meta or {})
|
|
297
300
|
)
|
|
298
301
|
except Exception:
|
|
299
|
-
# Fallback for
|
|
302
|
+
# Fallback for environments lacking StepEvent wiring.
|
|
300
303
|
try:
|
|
301
304
|
ctx.write_event_to_stream(
|
|
302
305
|
AgentStream(
|
|
303
306
|
delta="",
|
|
304
307
|
response="",
|
|
305
|
-
current_agent_name="
|
|
308
|
+
current_agent_name=self._display_agent_name, # always "CodeAct"
|
|
306
309
|
tool_calls=[],
|
|
307
310
|
raw={"StepEvent": {"name": name, "index": index, "total": total, "meta": meta or {}}}
|
|
308
311
|
)
|
|
@@ -367,7 +370,7 @@ class CodeActAgent(BaseWorkflowAgent):
|
|
|
367
370
|
current_llm_input.insert(0, ChatMessage(role="system", content=system_prompt))
|
|
368
371
|
|
|
369
372
|
ctx.write_event_to_stream(
|
|
370
|
-
AgentInput(input=current_llm_input, current_agent_name=self.
|
|
373
|
+
AgentInput(input=current_llm_input, current_agent_name=self._display_agent_name) # always "CodeAct"
|
|
371
374
|
)
|
|
372
375
|
|
|
373
376
|
if any(tool.metadata.name == "handoff" for tool in tools):
|
|
@@ -400,7 +403,7 @@ class CodeActAgent(BaseWorkflowAgent):
|
|
|
400
403
|
response=full_response_text,
|
|
401
404
|
tool_calls=[],
|
|
402
405
|
raw=raw,
|
|
403
|
-
current_agent_name=self.
|
|
406
|
+
current_agent_name=self._display_agent_name, # always "CodeAct"
|
|
404
407
|
)
|
|
405
408
|
)
|
|
406
409
|
|
|
@@ -443,7 +446,7 @@ class CodeActAgent(BaseWorkflowAgent):
|
|
|
443
446
|
response=message,
|
|
444
447
|
tool_calls=tool_calls,
|
|
445
448
|
raw=raw,
|
|
446
|
-
current_agent_name=self.
|
|
449
|
+
current_agent_name=self._display_agent_name, # always "CodeAct"
|
|
447
450
|
)
|
|
448
451
|
|
|
449
452
|
async def handle_tool_call_results(
|
|
@@ -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.
|
|
9
|
+
# Updated Date: 2025.09.26 15:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
@@ -34,6 +34,7 @@ from llama_index.core.agent.workflow import (
|
|
|
34
34
|
ToolCallResult,
|
|
35
35
|
AgentStream,
|
|
36
36
|
AgentOutput,
|
|
37
|
+
AgentInput, # ensure AgentInput propagation includes agent name
|
|
37
38
|
)
|
|
38
39
|
|
|
39
40
|
# v12/v13 compatibility imports
|
|
@@ -167,6 +168,9 @@ class OpenAIWorkflowAgent(Workflow):
|
|
|
167
168
|
self._on_stop = on_stop
|
|
168
169
|
self.verbose = verbose
|
|
169
170
|
|
|
171
|
+
# human-friendly display name propagated to UI via workflow events
|
|
172
|
+
self._display_agent_name: str = "FunctionAgent"
|
|
173
|
+
|
|
170
174
|
# construct FunctionAgent once, will override tools/system_prompt/memory per run
|
|
171
175
|
self._agent = FunctionAgent(
|
|
172
176
|
name="OpenAIWorkflowAgent",
|
|
@@ -287,9 +291,13 @@ class OpenAIWorkflowAgent(Workflow):
|
|
|
287
291
|
:param total: Total number of steps (optional)
|
|
288
292
|
:param meta: Optional metadata dictionary for the step event
|
|
289
293
|
"""
|
|
294
|
+
# Always include agent_name so UI can set it before first token arrives.
|
|
295
|
+
m = dict(meta or {})
|
|
296
|
+
m.setdefault("agent_name", self._display_agent_name)
|
|
297
|
+
|
|
290
298
|
try:
|
|
291
299
|
if StepEvent is not None:
|
|
292
|
-
ctx.write_event_to_stream(StepEvent(name=name, index=index, total=total, meta=
|
|
300
|
+
ctx.write_event_to_stream(StepEvent(name=name, index=index, total=total, meta=m))
|
|
293
301
|
return
|
|
294
302
|
except Exception:
|
|
295
303
|
pass
|
|
@@ -300,9 +308,9 @@ class OpenAIWorkflowAgent(Workflow):
|
|
|
300
308
|
AgentStream(
|
|
301
309
|
delta="",
|
|
302
310
|
response="",
|
|
303
|
-
current_agent_name=
|
|
311
|
+
current_agent_name=self._display_agent_name,
|
|
304
312
|
tool_calls=[],
|
|
305
|
-
raw={"StepEvent": {"name": name, "index": index, "total": total, "meta":
|
|
313
|
+
raw={"StepEvent": {"name": name, "index": index, "total": total, "meta": m}},
|
|
306
314
|
)
|
|
307
315
|
)
|
|
308
316
|
except Exception:
|
|
@@ -499,14 +507,14 @@ class OpenAIWorkflowAgent(Workflow):
|
|
|
499
507
|
self,
|
|
500
508
|
ctx: Context,
|
|
501
509
|
text: str,
|
|
502
|
-
agent_name: str = "
|
|
510
|
+
agent_name: str = "FunctionAgent"
|
|
503
511
|
):
|
|
504
512
|
"""
|
|
505
513
|
Emit text to the context stream, handling validation errors gracefully.
|
|
506
514
|
|
|
507
515
|
:param ctx: Context for the workflow
|
|
508
516
|
:param text: Text to emit to the stream
|
|
509
|
-
:param agent_name: Name of the agent to set in the event (default: "
|
|
517
|
+
:param agent_name: Name of the agent to set in the event (default: "FunctionAgent")
|
|
510
518
|
"""
|
|
511
519
|
try:
|
|
512
520
|
ctx.write_event_to_stream(AgentStream(delta=text))
|
|
@@ -561,12 +569,31 @@ class OpenAIWorkflowAgent(Workflow):
|
|
|
561
569
|
pass
|
|
562
570
|
return last_answer
|
|
563
571
|
|
|
572
|
+
if isinstance(e, AgentInput):
|
|
573
|
+
# Ensure the input event also carries the display name for UI
|
|
574
|
+
try:
|
|
575
|
+
e.current_agent_name = self._display_agent_name
|
|
576
|
+
except Exception:
|
|
577
|
+
pass
|
|
578
|
+
ctx.write_event_to_stream(e)
|
|
579
|
+
continue
|
|
580
|
+
|
|
564
581
|
if isinstance(e, AgentStream):
|
|
565
582
|
if getattr(e, "delta", None):
|
|
566
583
|
has_stream = True
|
|
567
|
-
|
|
584
|
+
# Always enforce agent name for consistency in UI
|
|
585
|
+
try:
|
|
586
|
+
e.current_agent_name = self._display_agent_name
|
|
587
|
+
except Exception:
|
|
588
|
+
# If immutable, rebuild a compatible event object
|
|
568
589
|
try:
|
|
569
|
-
e
|
|
590
|
+
e = AgentStream(
|
|
591
|
+
delta=getattr(e, "delta", ""),
|
|
592
|
+
response=getattr(e, "response", ""),
|
|
593
|
+
current_agent_name=self._display_agent_name,
|
|
594
|
+
tool_calls=getattr(e, "tool_calls", []),
|
|
595
|
+
raw=getattr(e, "raw", {}),
|
|
596
|
+
)
|
|
570
597
|
except Exception:
|
|
571
598
|
pass
|
|
572
599
|
ctx.write_event_to_stream(e)
|
|
@@ -581,9 +608,9 @@ class OpenAIWorkflowAgent(Workflow):
|
|
|
581
608
|
AgentStream(
|
|
582
609
|
delta=content,
|
|
583
610
|
response=content,
|
|
584
|
-
current_agent_name=
|
|
585
|
-
tool_calls=e
|
|
586
|
-
raw=e
|
|
611
|
+
current_agent_name=self._display_agent_name,
|
|
612
|
+
tool_calls=getattr(e, "tool_calls", []),
|
|
613
|
+
raw=getattr(e, "raw", {}),
|
|
587
614
|
)
|
|
588
615
|
)
|
|
589
616
|
continue
|