pygpt-net 2.6.8__py3-none-any.whl → 2.6.9__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 CHANGED
@@ -1,3 +1,7 @@
1
+ 2.6.9 (2025-08-17)
2
+
3
+ - Added two new agents for LlamaIndex and OpenAI: Supervisor and Worker (beta).
4
+
1
5
  2.6.8 (2025-08-16)
2
6
 
3
7
  - Fixed: updated paragraph color on theme switch.
pygpt_net/__init__.py CHANGED
@@ -6,15 +6,15 @@
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.08.15 00:00:00 #
9
+ # Updated Date: 2025.08.17 00:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  __author__ = "Marcin Szczygliński"
13
13
  __copyright__ = "Copyright 2025, Marcin Szczygliński"
14
14
  __credits__ = ["Marcin Szczygliński"]
15
15
  __license__ = "MIT"
16
- __version__ = "2.6.8"
17
- __build__ = "2025-08-16"
16
+ __version__ = "2.6.9"
17
+ __build__ = "2025-08-17"
18
18
  __maintainer__ = "Marcin Szczygliński"
19
19
  __github__ = "https://github.com/szczyglis-dev/py-gpt"
20
20
  __report__ = "https://github.com/szczyglis-dev/py-gpt/issues"
pygpt_net/app.py CHANGED
@@ -88,6 +88,7 @@ from pygpt_net.provider.agents.llama_index.openai_workflow import OpenAIAgent as
88
88
  # from pygpt_net.provider.agents.llama_index.legacy.react import ReactAgent
89
89
  from pygpt_net.provider.agents.llama_index.react_workflow import ReactWorkflowAgent
90
90
  from pygpt_net.provider.agents.llama_index.codeact_workflow import CodeActAgent
91
+ from pygpt_net.provider.agents.llama_index.supervisor_workflow import SupervisorAgent as LlamaSupervisorAgent
91
92
  from pygpt_net.provider.agents.openai.agent import Agent as OpenAIAgentsBase
92
93
  from pygpt_net.provider.agents.openai.agent_with_experts import Agent as OpenAIAgentsExperts
93
94
  from pygpt_net.provider.agents.openai.agent_with_experts_feedback import Agent as OpenAIAgentsExpertsFeedback
@@ -96,6 +97,7 @@ from pygpt_net.provider.agents.openai.bot_researcher import Agent as OpenAIAgent
96
97
  from pygpt_net.provider.agents.openai.agent_planner import Agent as OpenAIAgentPlanner
97
98
  from pygpt_net.provider.agents.openai.evolve import Agent as OpenAIAgentsEvolve
98
99
  from pygpt_net.provider.agents.openai.agent_b2b import Agent as OpenAIAgentsB2B
100
+ from pygpt_net.provider.agents.openai.supervisor import Agent as OpenAIAgentSupervisor
99
101
 
100
102
  # LLM wrapper providers (langchain, llama-index, embeddings)
101
103
  from pygpt_net.provider.llms.anthropic import AnthropicLLM
@@ -445,6 +447,7 @@ def run(**kwargs):
445
447
  # launcher.add_agent(ReactAgent()) # llama-index
446
448
  launcher.add_agent(ReactWorkflowAgent()) # llama-index
447
449
  launcher.add_agent(CodeActAgent()) # llama-index
450
+ launcher.add_agent(LlamaSupervisorAgent()) # llama-index
448
451
  launcher.add_agent(OpenAIAgentsBase()) # openai-agents
449
452
  launcher.add_agent(OpenAIAgentsExperts()) # openai-agents
450
453
  launcher.add_agent(OpenAIAgentFeedback()) # openai-agents
@@ -453,6 +456,7 @@ def run(**kwargs):
453
456
  launcher.add_agent(OpenAIAgentsExpertsFeedback()) # openai-agents
454
457
  launcher.add_agent(OpenAIAgentsEvolve()) # openai-agents
455
458
  launcher.add_agent(OpenAIAgentsB2B()) # openai-agents
459
+ launcher.add_agent(OpenAIAgentSupervisor()) # openai-agents
456
460
 
457
461
  # register custom agents
458
462
  agents = kwargs.get('agents', None)
@@ -31,7 +31,7 @@ from .reply import Reply
31
31
  from .stack import Stack
32
32
 
33
33
 
34
- class Kernel(QObject):
34
+ class Kernel:
35
35
 
36
36
  STATE_IDLE = "idle"
37
37
  STATE_BUSY = "busy"
@@ -81,7 +81,6 @@ class Kernel(QObject):
81
81
 
82
82
  :param window: The window context to which the kernel will be bound.
83
83
  """
84
- super(Kernel, self).__init__(window)
85
84
  self.window = window
86
85
  self.replies = Reply(window)
87
86
  self.stack = Stack(window)
@@ -985,9 +985,9 @@ class Body:
985
985
  syntax_style = self.window.core.config.get("render.code_syntax") or "default"
986
986
 
987
987
  theme_css = self.window.controller.theme.markdown.get_web_css().replace('%fonts%', fonts_path)
988
- parts = [self._SPINNER, theme_css]
989
- parts.append("pre { color: #fff; }" if syntax_style in self._syntax_dark else "pre { color: #000; }")
990
- parts.append(self.highlight.get_style_defs())
988
+ parts = [self._SPINNER, theme_css,
989
+ "pre { color: #fff; }" if syntax_style in self._syntax_dark else "pre { color: #000; }",
990
+ self.highlight.get_style_defs()]
991
991
  return "\n".join(parts)
992
992
 
993
993
  def prepare_action_icons(self, ctx: CtxItem) -> str:
@@ -1014,32 +1014,19 @@ class Body:
1014
1014
  if ctx.output:
1015
1015
  cid = ctx.id
1016
1016
  t = trans
1017
-
1018
1017
  icons.append(
1019
- f'<a href="extra-audio-read:{cid}" class="action-icon" data-id="{cid}" role="button">'
1020
- f'<span class="cmd">{self.get_icon("volume", t("ctx.extra.audio"), ctx)}</span></a>'
1021
- )
1018
+ f'<a href="extra-audio-read:{cid}" class="action-icon" data-id="{cid}" role="button"><span class="cmd">{self.get_icon("volume", t("ctx.extra.audio"), ctx)}</span></a>')
1022
1019
  icons.append(
1023
- f'<a href="extra-copy:{cid}" class="action-icon" data-id="{cid}" role="button">'
1024
- f'<span class="cmd">{self.get_icon("copy", t("ctx.extra.copy"), ctx)}</span></a>'
1025
- )
1020
+ f'<a href="extra-copy:{cid}" class="action-icon" data-id="{cid}" role="button"><span class="cmd">{self.get_icon("copy", t("ctx.extra.copy"), ctx)}</span></a>')
1026
1021
  icons.append(
1027
- f'<a href="extra-replay:{cid}" class="action-icon" data-id="{cid}" role="button">'
1028
- f'<span class="cmd">{self.get_icon("reload", t("ctx.extra.reply"), ctx)}</span></a>'
1029
- )
1022
+ f'<a href="extra-replay:{cid}" class="action-icon" data-id="{cid}" role="button"><span class="cmd">{self.get_icon("reload", t("ctx.extra.reply"), ctx)}</span></a>')
1030
1023
  icons.append(
1031
- f'<a href="extra-edit:{cid}" class="action-icon edit-icon" data-id="{cid}" role="button">'
1032
- f'<span class="cmd">{self.get_icon("edit", t("ctx.extra.edit"), ctx)}</span></a>'
1033
- )
1024
+ f'<a href="extra-edit:{cid}" class="action-icon edit-icon" data-id="{cid}" role="button"><span class="cmd">{self.get_icon("edit", t("ctx.extra.edit"), ctx)}</span></a>')
1034
1025
  icons.append(
1035
- f'<a href="extra-delete:{cid}" class="action-icon edit-icon" data-id="{cid}" role="button">'
1036
- f'<span class="cmd">{self.get_icon("delete", t("ctx.extra.delete"), ctx)}</span></a>'
1037
- )
1026
+ f'<a href="extra-delete:{cid}" class="action-icon edit-icon" data-id="{cid}" role="button"><span class="cmd">{self.get_icon("delete", t("ctx.extra.delete"), ctx)}</span></a>')
1038
1027
  if not self.window.core.ctx.is_first_item(cid):
1039
1028
  icons.append(
1040
- f'<a href="extra-join:{cid}" class="action-icon edit-icon" data-id="{cid}" role="button">'
1041
- f'<span class="cmd">{self.get_icon("playlist_add", t("ctx.extra.join"), ctx)}</span></a>'
1042
- )
1029
+ f'<a href="extra-join:{cid}" class="action-icon edit-icon" data-id="{cid}" role="button"><span class="cmd">{self.get_icon("playlist_add", t("ctx.extra.join"), ctx)}</span></a>')
1043
1030
  return icons
1044
1031
 
1045
1032
  def get_icon(
@@ -1058,9 +1045,7 @@ class Body:
1058
1045
  """
1059
1046
  app_path = self.window.core.config.get_app_path()
1060
1047
  icon_path = os.path.join(app_path, "data", "icons", f"{icon}.svg")
1061
- return (
1062
- f'<img src="file://{icon_path}" class="action-img" title="{title}" alt="{title}" data-id="{item.id}">'
1063
- )
1048
+ return f'<img src="file://{icon_path}" class="action-img" title="{title}" alt="{title}" data-id="{item.id}">'
1064
1049
 
1065
1050
  def get_image_html(
1066
1051
  self,
@@ -1078,14 +1063,7 @@ class Body:
1078
1063
  """
1079
1064
  url, path = self.window.core.filesystem.extract_local_url(url)
1080
1065
  basename = os.path.basename(path)
1081
- return (
1082
- f'<div class="extra-src-img-box" title="{url}">'
1083
- f'<div class="img-outer"><div class="img-wrapper">'
1084
- f'<a href="{url}"><img src="{path}" class="image"></a>'
1085
- f'</div>'
1086
- f'<a href="{url}" class="title">{basename}</a>'
1087
- f'</div></div><br/>'
1088
- )
1066
+ return f'<div class="extra-src-img-box" title="{url}"><div class="img-outer"><div class="img-wrapper"><a href="{url}"><img src="{path}" class="image"></a></div><a href="{url}" class="title">{basename}</a></div></div><br/>'
1089
1067
 
1090
1068
  def get_url_html(
1091
1069
  self,
@@ -13,7 +13,7 @@ import json
13
13
  import os
14
14
  import re
15
15
  from datetime import datetime
16
- from typing import Optional, List
16
+ from typing import Optional, List, Any
17
17
 
18
18
  from pygpt_net.core.render.base import BaseRenderer
19
19
  from pygpt_net.core.text.utils import has_unclosed_code_tag
@@ -159,6 +159,15 @@ class Renderer(BaseRenderer):
159
159
  else:
160
160
  self.clear_chunks(pid)
161
161
 
162
+ def to_json(self, data: Any) -> str:
163
+ """
164
+ Convert data to JSON object
165
+
166
+ :param data: data to convert
167
+ :return: JSON object or None
168
+ """
169
+ return json.dumps(data, ensure_ascii=False, separators=(',', ':'))
170
+
162
171
  def state_changed(
163
172
  self,
164
173
  state: str,
@@ -510,6 +519,15 @@ class Renderer(BaseRenderer):
510
519
  text_chunk = "".join(("\n", text_chunk)) # add newline to chunk
511
520
 
512
521
  self.prev_chunk_replace = replace_bool
522
+
523
+ # hide loading spinner if it is the beginning of the text
524
+ if begin:
525
+ try:
526
+ self.get_output_node(meta).page().runJavaScript("hideLoading();")
527
+ except Exception as e:
528
+ pass
529
+
530
+ # emit chunk to output node
513
531
  try:
514
532
  self.get_output_node(meta).page().bridge.chunk.emit(
515
533
  name_header_str or "",
@@ -566,10 +584,10 @@ class Renderer(BaseRenderer):
566
584
 
567
585
  pid = self.get_or_create_pid(meta)
568
586
  self.clear_chunks_input(pid)
569
- chunk = self.helpers.format_chunk(text_chunk)
570
- escaped_chunk = json.dumps(chunk)
571
587
  try:
572
- self.get_output_node(meta).page().runJavaScript(f"appendToInput({escaped_chunk});")
588
+ self.get_output_node(meta).page().runJavaScript(
589
+ f"appendToInput({self.to_json(self.helpers.format_chunk(text_chunk))});"
590
+ )
573
591
  except Exception as e:
574
592
  pass
575
593
 
@@ -610,11 +628,10 @@ class Renderer(BaseRenderer):
610
628
  to_append = self.pids[pid].live_buffer
611
629
  if has_unclosed_code_tag(self.pids[pid].live_buffer):
612
630
  to_append += "\n```"
613
- html = self.parser.parse(to_append)
614
- escaped_chunk = json.dumps(html)
615
631
  try:
616
632
  self.get_output_node(meta).page().runJavaScript(
617
- f"replaceLive({escaped_chunk});")
633
+ f"replaceLive({self.to_json(self.parser.parse(to_append))});"
634
+ )
618
635
  except Exception as e:
619
636
  pass
620
637
 
@@ -629,7 +646,7 @@ class Renderer(BaseRenderer):
629
646
  return
630
647
  pid = self.get_or_create_pid(meta)
631
648
  if not self.pids[pid].loaded:
632
- js = "var element = document.getElementById('_append_live_');if (element) { element.innerHTML = ''; }"
649
+ js = "var element = document.getElementById('_append_live_');if (element) { element.replaceChildren(); }"
633
650
  else:
634
651
  js = "clearLive();"
635
652
  try:
@@ -806,9 +823,8 @@ class Renderer(BaseRenderer):
806
823
  if footer:
807
824
  self.append(pid, html)
808
825
  else:
809
- escaped_html = json.dumps(html)
810
826
  try:
811
- self.get_output_node(meta).page().runJavaScript(f"appendExtra('{ctx.id}',{escaped_html});")
827
+ self.get_output_node(meta).page().runJavaScript(f"appendExtra('{ctx.id}',{self.to_json(html)});")
812
828
  except Exception as e:
813
829
  pass
814
830
 
@@ -918,7 +934,7 @@ class Renderer(BaseRenderer):
918
934
  if pid is None:
919
935
  return
920
936
  if not self.pids[pid].loaded:
921
- js = "var element = document.getElementById('_append_input_');if (element) { element.innerHTML = ''; }"
937
+ js = "var element = document.getElementById('_append_input_');if (element) { element.replaceChildren(); }"
922
938
  else:
923
939
  js = "clearInput();"
924
940
  try:
@@ -937,7 +953,7 @@ class Renderer(BaseRenderer):
937
953
  """
938
954
  self.prev_chunk_replace = False
939
955
  if not self.pids[pid].loaded:
940
- js = "var element = document.getElementById('_append_output_');if (element) { element.innerHTML = ''; }"
956
+ js = "var element = document.getElementById('_append_output_');if (element) { element.replaceChildren(); }"
941
957
  else:
942
958
  js = "clearOutput();"
943
959
  try:
@@ -955,7 +971,7 @@ class Renderer(BaseRenderer):
955
971
  :pid: context PID
956
972
  """
957
973
  if not self.pids[pid].loaded:
958
- js = "var element = document.getElementById('_nodes_');if (element) { element.innerHTML = ''; }"
974
+ js = "var element = document.getElementById('_nodes_');if (element) { element.replaceChildren(); }"
959
975
  else:
960
976
  js = "clearNodes();"
961
977
  try:
@@ -1043,18 +1059,8 @@ class Renderer(BaseRenderer):
1043
1059
  if ctx.extra is not None and "footer" in ctx.extra:
1044
1060
  extra = ctx.extra["footer"]
1045
1061
  extra_style = "display:block;"
1046
- html = (
1047
- f'<div class="msg-box msg-user" id="{msg_id}">'
1048
- f'<div class="name-header name-user">{name}</div>'
1049
- f'<div class="msg">'
1050
- f'{html}'
1051
- f'<div class="msg-extra" style="{extra_style}">{extra}</div>'
1052
- f'{debug}'
1053
- f'</div>'
1054
- f'</div>'
1055
- )
1056
1062
 
1057
- return html
1063
+ return f'<div class="msg-box msg-user" id="{msg_id}"><div class="name-header name-user">{name}</div><div class="msg">{html}<div class="msg-extra" style="{extra_style}">{extra}</div>{debug}</div></div>'
1058
1064
 
1059
1065
  def prepare_node_output(
1060
1066
  self,
@@ -1091,11 +1097,6 @@ class Renderer(BaseRenderer):
1091
1097
  tool_output = ""
1092
1098
  spinner = ""
1093
1099
  output_class = "display:none"
1094
- cmd_icon = f'<img src="{self._file_prefix}{self._icon_expand}" width="25" height="25" valign="middle">'
1095
- expand_btn = (
1096
- f"<span class='toggle-cmd-output' onclick='toggleToolOutput({ctx.id});' title='{trans('action.cmd.expand')}' "
1097
- f"role='button'>{cmd_icon}</span>"
1098
- )
1099
1100
 
1100
1101
  if is_cmd:
1101
1102
  if ctx.results is not None and len(ctx.results) > 0 \
@@ -1118,42 +1119,13 @@ class Renderer(BaseRenderer):
1118
1119
  or out.rstrip().endswith(('}</tool>', '}&lt;/tool&gt;'))
1119
1120
  ):
1120
1121
  spinner_class = "" if ctx.live else "display:none"
1121
- spinner = (
1122
- f'<span class="spinner" style="{spinner_class}">'
1123
- f'<img src="{self._file_prefix}{self._icon_sync}" width="30" height="30" '
1124
- f'class="loading"></span>'
1125
- )
1126
-
1127
- html_tools = (
1128
- f'<div class="tool-output" style="{output_class}">' +
1129
- expand_btn +
1130
- '<div class="content" style="display:none">' +
1131
- tool_output +
1132
- '</div></div>'
1133
- )
1134
- tool_extra = self.body.prepare_tool_extra(ctx)
1135
-
1136
- debug = ""
1137
- if self.is_debug():
1138
- debug = self.append_debug(ctx, pid, "output")
1122
+ spinner = f"<span class=\"spinner\" style=\"{spinner_class}\"><img src=\"{self._file_prefix}{self._icon_sync}\" width=\"30\" height=\"30\" class=\"loading\"></span>"
1139
1123
 
1124
+ tool_extra = self.body.prepare_tool_extra(ctx)
1125
+ debug = self.append_debug(ctx, pid, "output") if self.is_debug() else ""
1140
1126
  name_header = self.get_name_header(ctx)
1141
- html = (
1142
- f'<div class="msg-box msg-bot" id="{msg_id}">' +
1143
- name_header +
1144
- '<div class="msg">' +
1145
- f'{html}' +
1146
- f'{spinner}' +
1147
- f'<div class="msg-tool-extra">{tool_extra}</div>' +
1148
- f'{html_tools}' +
1149
- f'<div class="msg-extra">{extra}</div>' +
1150
- f'{footer}' +
1151
- f'{debug}' +
1152
- '</div>' +
1153
- '</div>'
1154
- )
1155
1127
 
1156
- return html
1128
+ return f"<div class='msg-box msg-bot' id='{msg_id}'>{name_header}<div class='msg'>{html}{spinner}<div class='msg-tool-extra'>{tool_extra}</div><div class='tool-output' style='{output_class}'><span class='toggle-cmd-output' onclick='toggleToolOutput({ctx.id});' title='{trans('action.cmd.expand')}' role='button'><img src='{self._file_prefix}{self._icon_expand}' width='25' height='25' valign='middle'></span><div class='content' style='display:none'>{tool_output}</div></div><div class='msg-extra'>{extra}</div>{footer}{debug}</div></div>"
1157
1129
 
1158
1130
  def get_name_header(self, ctx: CtxItem) -> str:
1159
1131
  """
@@ -1200,10 +1172,10 @@ class Renderer(BaseRenderer):
1200
1172
  :param pid: context PID
1201
1173
  :param html: HTML code
1202
1174
  """
1203
- escaped_html = json.dumps(html)
1204
1175
  try:
1205
- node = self.get_output_node_by_pid(pid)
1206
- node.page().runJavaScript(f"if (typeof window.appendNode !== 'undefined') appendNode({escaped_html});")
1176
+ self.get_output_node_by_pid(pid).page().runJavaScript(
1177
+ f"if (typeof window.appendNode !== 'undefined') appendNode({self.to_json(html)});"
1178
+ )
1207
1179
  except Exception as e:
1208
1180
  pass
1209
1181
 
@@ -1251,6 +1223,7 @@ class Renderer(BaseRenderer):
1251
1223
  # self.window.ui.nodes['output'][pid] = new_view
1252
1224
  node.resetPage()
1253
1225
  node.setHtml(html, baseUrl="file://")
1226
+ self.pids[pid].html = ""
1254
1227
 
1255
1228
  def get_output_node(
1256
1229
  self,
@@ -1291,9 +1264,8 @@ class Renderer(BaseRenderer):
1291
1264
  :param ctx: context item
1292
1265
  """
1293
1266
  try:
1294
- _id = json.dumps(ctx.id)
1295
1267
  self.get_output_node(ctx.meta).page().runJavaScript(
1296
- f"if (typeof window.removeNode !== 'undefined') removeNode({_id});")
1268
+ f"if (typeof window.removeNode !== 'undefined') removeNode({self.to_json(ctx.id)});")
1297
1269
  except Exception as e:
1298
1270
  pass
1299
1271
 
@@ -1304,9 +1276,8 @@ class Renderer(BaseRenderer):
1304
1276
  :param ctx: context item
1305
1277
  """
1306
1278
  try:
1307
- _id = json.dumps(ctx.id)
1308
1279
  self.get_output_node(ctx.meta).page().runJavaScript(
1309
- f"if (typeof window.removeNodesFromId !== 'undefined') removeNodesFromId({_id});")
1280
+ f"if (typeof window.removeNodesFromId !== 'undefined') removeNodesFromId({self.to_json(ctx.id)});")
1310
1281
  except Exception as e:
1311
1282
  pass
1312
1283
 
@@ -1460,7 +1431,7 @@ class Renderer(BaseRenderer):
1460
1431
 
1461
1432
  def reload_css(self):
1462
1433
  """Reload CSS - all, global"""
1463
- to_json = json.dumps(self.body.prepare_styles())
1434
+ to_json = self.to_json(self.body.prepare_styles())
1464
1435
  nodes = self.get_all_nodes()
1465
1436
  for pid in self.pids:
1466
1437
  if self.pids[pid].loaded:
@@ -1496,10 +1467,10 @@ class Renderer(BaseRenderer):
1496
1467
  :param meta: context meta
1497
1468
  :param content: content
1498
1469
  """
1499
- escaped_content = json.dumps(content)
1500
1470
  try:
1501
1471
  self.get_output_node(meta).page().runJavaScript(
1502
- f"if (typeof window.appendToolOutput !== 'undefined') appendToolOutput({escaped_content});")
1472
+ f"if (typeof window.appendToolOutput !== 'undefined') appendToolOutput({self.to_json(content)});"
1473
+ )
1503
1474
  except Exception as e:
1504
1475
  pass
1505
1476
 
@@ -1514,10 +1485,10 @@ class Renderer(BaseRenderer):
1514
1485
  :param meta: context meta
1515
1486
  :param content: content
1516
1487
  """
1517
- escaped_content = json.dumps(content)
1518
1488
  try:
1519
1489
  self.get_output_node(meta).page().runJavaScript(
1520
- f"if (typeof window.updateToolOutput !== 'undefined') updateToolOutput({escaped_content});")
1490
+ f"if (typeof window.updateToolOutput !== 'undefined') updateToolOutput({self.to_json(content)});"
1491
+ )
1521
1492
  except Exception as e:
1522
1493
  pass
1523
1494
 
@@ -1529,7 +1500,8 @@ class Renderer(BaseRenderer):
1529
1500
  """
1530
1501
  try:
1531
1502
  self.get_output_node(meta).page().runJavaScript(
1532
- f"if (typeof window.clearToolOutput !== 'undefined') clearToolOutput();")
1503
+ f"if (typeof window.clearToolOutput !== 'undefined') clearToolOutput();"
1504
+ )
1533
1505
  except Exception as e:
1534
1506
  pass
1535
1507
 
@@ -1541,7 +1513,8 @@ class Renderer(BaseRenderer):
1541
1513
  """
1542
1514
  try:
1543
1515
  self.get_output_node(meta).page().runJavaScript(
1544
- f"if (typeof window.beginToolOutput !== 'undefined') beginToolOutput();")
1516
+ f"if (typeof window.beginToolOutput !== 'undefined') beginToolOutput();"
1517
+ )
1545
1518
  except Exception as e:
1546
1519
  pass
1547
1520
 
@@ -1549,7 +1522,8 @@ class Renderer(BaseRenderer):
1549
1522
  """End tool output"""
1550
1523
  try:
1551
1524
  self.get_output_node().page().runJavaScript(
1552
- f"if (typeof window.endToolOutput !== 'undefined') endToolOutput();")
1525
+ f"if (typeof window.endToolOutput !== 'undefined') endToolOutput();"
1526
+ )
1553
1527
  except Exception as e:
1554
1528
  pass
1555
1529
 
@@ -1568,8 +1542,7 @@ class Renderer(BaseRenderer):
1568
1542
  """
1569
1543
  if title is None:
1570
1544
  title = "debug"
1571
- debug = "<b>" + title + ":</b> pid: " + str(pid) + ", ctx: " + str(ctx.to_dict())
1572
- return "<div class='debug'>" + debug + "</div>"
1545
+ return f"<div class='debug'><b>{title}:</b> pid: {pid}, ctx: {ctx.to_dict()}</div>"
1573
1546
 
1574
1547
  def is_debug(self) -> bool:
1575
1548
  """
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.6.8",
4
- "app.version": "2.6.8",
5
- "updated_at": "2025-08-16T00:00:00"
3
+ "version": "2.6.9",
4
+ "app.version": "2.6.9",
5
+ "updated_at": "2025-08-17T00:00:00"
6
6
  },
7
7
  "access.audio.event.speech": false,
8
8
  "access.audio.event.speech.disabled": [],
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.6.8",
4
- "app.version": "2.6.8",
5
- "updated_at": "2025-08-16T23:07:35"
3
+ "version": "2.6.9",
4
+ "app.version": "2.6.9",
5
+ "updated_at": "2025-08-17T23:07:35"
6
6
  },
7
7
  "items": {
8
8
  "SpeakLeash/bielik-11b-v2.3-instruct:Q4_K_M": {
@@ -0,0 +1,54 @@
1
+ {
2
+ "uuid": "a424e13a-b3c2-4cc7-81b5-f74821f47ec3",
3
+ "name": "Supervisor + worker",
4
+ "ai_name": "",
5
+ "ai_avatar": "",
6
+ "ai_personalize": false,
7
+ "user_name": "",
8
+ "prompt": "",
9
+ "chat": false,
10
+ "completion": false,
11
+ "img": false,
12
+ "vision": false,
13
+ "assistant": false,
14
+ "llama_index": false,
15
+ "agent": false,
16
+ "agent_llama": false,
17
+ "agent_openai": true,
18
+ "expert": false,
19
+ "audio": false,
20
+ "research": false,
21
+ "computer": false,
22
+ "temperature": 1.0,
23
+ "filename": "agent_openai_supervisor",
24
+ "model": "gpt-4o",
25
+ "tools": {
26
+ "function": []
27
+ },
28
+ "experts": [],
29
+ "idx": "_",
30
+ "agent_provider": "supervisor",
31
+ "agent_provider_openai": "openai_agent_supervisor",
32
+ "assistant_id": "",
33
+ "enabled": true,
34
+ "description": "",
35
+ "remote_tools": "",
36
+ "extra": {
37
+ "openai_agent_supervisor": {
38
+ "supervisor": {
39
+ "prompt": "\n You are the \u201cSupervisor\u201d (orchestrator). You never use tools directly except the tool that runs the Worker.\n Process:\n - Decompose the user's task into actionable instructions for the Worker.\n - Do NOT pass your conversation history to the Worker. Pass ONLY a concise, self-contained instruction.\n - After each Worker result, evaluate against a clear Definition of Done (DoD). If not met, call the Worker again with a refined instruction.\n - Ask the user only if absolutely necessary. If you must, STOP and output a single JSON with:\n {\"action\":\"ask_user\",\"question\":\"...\",\"reasoning\":\"...\"}\n - When done, output a single JSON:\n {\"action\":\"final\",\"final_answer\":\"...\",\"reasoning\":\"...\"}\n - Otherwise, to run the Worker, call the run_worker tool with a short instruction.\n Respond in the user's language. Keep outputs short and precise.\n "
40
+ },
41
+ "worker": {
42
+ "model": "gpt-4o",
43
+ "prompt": "\n You are the \u201cWorker\u201d. You execute Supervisor instructions strictly, using your tools.\n - Keep your own memory across calls (Worker session).\n - Return a concise result with key evidence/extracts from tools when applicable.\n - Do not ask the user questions directly; if instruction is underspecified, clearly state what is missing.\n Respond in the user's language.\n ",
44
+ "allow_local_tools": true,
45
+ "allow_remote_tools": true
46
+ }
47
+ }
48
+ },
49
+ "__meta__": {
50
+ "version": "2.6.8",
51
+ "app.version": "2.6.8",
52
+ "updated_at": "2025-08-17T03:03:45"
53
+ }
54
+ }
@@ -0,0 +1,52 @@
1
+ {
2
+ "uuid": "f5dd895c-3be8-4a73-aac9-7a20845e57b2",
3
+ "name": "Supervisor + worker",
4
+ "ai_name": "",
5
+ "ai_avatar": "",
6
+ "ai_personalize": false,
7
+ "user_name": "",
8
+ "prompt": "",
9
+ "chat": false,
10
+ "completion": false,
11
+ "img": false,
12
+ "vision": false,
13
+ "assistant": false,
14
+ "llama_index": false,
15
+ "agent": false,
16
+ "agent_llama": true,
17
+ "agent_openai": false,
18
+ "expert": false,
19
+ "audio": false,
20
+ "research": false,
21
+ "computer": false,
22
+ "temperature": 1.0,
23
+ "filename": "agent_supervisor",
24
+ "model": "gpt-4o",
25
+ "tools": {
26
+ "function": []
27
+ },
28
+ "experts": [],
29
+ "idx": "_",
30
+ "agent_provider": "supervisor",
31
+ "agent_provider_openai": "openai_agent_supervisor",
32
+ "assistant_id": "",
33
+ "enabled": true,
34
+ "description": "",
35
+ "remote_tools": "",
36
+ "extra": {
37
+ "supervisor": {
38
+ "supervisor": {
39
+ "prompt": "\nYou are the \u201cSupervisor\u201d \u2013 the main orchestrator. Do not use tools directly.\nYour tasks:\n- Break down the user's task into steps and create precise instructions for the \u201cWorker\u201d agent.\n- Do not pass your history/memory to the Worker. Only pass minimal, self-sufficient instructions.\n- After each Worker response, assess progress towards the Definition of Done (DoD). If not met \u2013 generate a better instruction.\n- Ask the user only when absolutely necessary. Then stop and return the question.\n- When the task is complete \u2013 return the final answer to the user.\nAlways return only ONE JSON object:\n{\n \"action\": \"task\" | \"final\" | \"ask_user\",\n \"instruction\": \"<Worker's instruction or ''>\",\n \"final_answer\": \"<final answer or ''>\",\n \"question\": \"<user question or ''>\",\n \"reasoning\": \"<brief reasoning and quality control>\",\n \"done_criteria\": \"<list/text of DoD criteria>\"\n}\nEnsure proper JSON (no comments, no trailing commas). Respond in the user's language.\n"
40
+ },
41
+ "worker": {
42
+ "model": "gpt-4o",
43
+ "prompt": "\nYou are the \u201cWorker\u201d \u2013 executor of the Supervisor's instructions. You have your own memory and tools.\n- Execute the Supervisor's instructions precisely and concisely.\n- Use the available tools and return a brief result + relevant data/reasoning.\n- Maintain the working context in your memory (only Worker).\n- Return plain text (not JSON) unless instructed otherwise by the Supervisor.\n- Respond in the user's language.\n"
44
+ }
45
+ }
46
+ },
47
+ "__meta__": {
48
+ "version": "2.6.8",
49
+ "app.version": "2.6.8",
50
+ "updated_at": "2025-08-17T03:03:21"
51
+ }
52
+ }