pygpt-net 2.4.37__py3-none-any.whl → 2.4.42__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 (340) hide show
  1. CHANGELOG.md +37 -0
  2. README.md +176 -182
  3. pygpt_net/CHANGELOG.txt +37 -0
  4. pygpt_net/__init__.py +3 -3
  5. pygpt_net/app.py +3 -1
  6. pygpt_net/controller/__init__.py +7 -3
  7. pygpt_net/controller/access/control.py +1 -1
  8. pygpt_net/controller/access/voice.py +11 -5
  9. pygpt_net/controller/agent/experts.py +11 -6
  10. pygpt_net/controller/agent/legacy.py +8 -6
  11. pygpt_net/controller/agent/llama.py +4 -2
  12. pygpt_net/controller/assistant/__init__.py +9 -4
  13. pygpt_net/controller/assistant/batch.py +38 -21
  14. pygpt_net/controller/assistant/editor.py +7 -6
  15. pygpt_net/controller/assistant/files.py +23 -7
  16. pygpt_net/controller/assistant/store.py +20 -7
  17. pygpt_net/controller/assistant/threads.py +34 -8
  18. pygpt_net/controller/attachment.py +29 -10
  19. pygpt_net/controller/audio/__init__.py +26 -5
  20. pygpt_net/controller/calendar/__init__.py +23 -4
  21. pygpt_net/controller/calendar/note.py +57 -11
  22. pygpt_net/controller/camera.py +4 -12
  23. pygpt_net/controller/chat/__init__.py +5 -3
  24. pygpt_net/controller/chat/attachment.py +34 -7
  25. pygpt_net/controller/chat/audio.py +2 -2
  26. pygpt_net/controller/chat/command.py +4 -2
  27. pygpt_net/controller/chat/common.py +11 -4
  28. pygpt_net/controller/chat/files.py +10 -3
  29. pygpt_net/controller/chat/image.py +17 -5
  30. pygpt_net/controller/chat/input.py +10 -7
  31. pygpt_net/controller/chat/output.py +21 -6
  32. pygpt_net/controller/chat/render.py +100 -21
  33. pygpt_net/controller/chat/response.py +34 -7
  34. pygpt_net/controller/chat/stream.py +4 -2
  35. pygpt_net/controller/chat/text.py +6 -4
  36. pygpt_net/controller/command.py +11 -3
  37. pygpt_net/controller/config/__init__.py +34 -6
  38. pygpt_net/controller/config/field/checkbox.py +7 -4
  39. pygpt_net/controller/config/field/cmd.py +7 -5
  40. pygpt_net/controller/config/field/combo.py +14 -6
  41. pygpt_net/controller/config/field/dictionary.py +14 -11
  42. pygpt_net/controller/config/field/input.py +9 -6
  43. pygpt_net/controller/config/field/slider.py +11 -8
  44. pygpt_net/controller/config/field/textarea.py +8 -5
  45. pygpt_net/controller/config/placeholder.py +66 -21
  46. pygpt_net/controller/ctx/__init__.py +138 -49
  47. pygpt_net/controller/ctx/common.py +15 -4
  48. pygpt_net/controller/ctx/extra.py +11 -3
  49. pygpt_net/controller/ctx/summarizer.py +24 -5
  50. pygpt_net/controller/debug/__init__.py +27 -6
  51. pygpt_net/controller/dialogs/confirm.py +34 -7
  52. pygpt_net/controller/dialogs/debug.py +4 -2
  53. pygpt_net/controller/dialogs/info.py +7 -2
  54. pygpt_net/controller/files.py +48 -10
  55. pygpt_net/controller/finder.py +11 -5
  56. pygpt_net/controller/idx/__init__.py +10 -3
  57. pygpt_net/controller/idx/common.py +4 -2
  58. pygpt_net/controller/idx/indexer.py +25 -17
  59. pygpt_net/controller/idx/settings.py +9 -3
  60. pygpt_net/controller/kernel/__init__.py +34 -8
  61. pygpt_net/controller/kernel/reply.py +12 -3
  62. pygpt_net/controller/kernel/stack.py +5 -3
  63. pygpt_net/controller/lang/custom.py +2 -7
  64. pygpt_net/controller/lang/mapping.py +5 -3
  65. pygpt_net/controller/layout.py +2 -2
  66. pygpt_net/controller/mode.py +16 -4
  67. pygpt_net/controller/model/__init__.py +14 -3
  68. pygpt_net/controller/model/editor.py +8 -3
  69. pygpt_net/controller/notepad.py +26 -12
  70. pygpt_net/controller/painter/capture.py +23 -4
  71. pygpt_net/controller/painter/common.py +9 -7
  72. pygpt_net/controller/plugins/__init__.py +19 -5
  73. pygpt_net/controller/plugins/presets.py +15 -6
  74. pygpt_net/controller/plugins/settings.py +9 -3
  75. pygpt_net/controller/presets/__init__.py +55 -16
  76. pygpt_net/controller/presets/editor.py +26 -10
  77. pygpt_net/controller/settings/__init__.py +3 -2
  78. pygpt_net/controller/settings/editor.py +29 -7
  79. pygpt_net/controller/settings/profile.py +22 -5
  80. pygpt_net/controller/theme/__init__.py +54 -12
  81. pygpt_net/controller/theme/common.py +24 -2
  82. pygpt_net/controller/theme/markdown.py +32 -16
  83. pygpt_net/controller/theme/menu.py +26 -5
  84. pygpt_net/controller/theme/nodes.py +2 -5
  85. pygpt_net/controller/tools/__init__.py +40 -2
  86. pygpt_net/controller/ui/__init__.py +4 -6
  87. pygpt_net/controller/ui/mode.py +16 -21
  88. pygpt_net/controller/ui/tabs.py +363 -65
  89. pygpt_net/core/access/actions.py +6 -4
  90. pygpt_net/core/access/shortcuts.py +4 -3
  91. pygpt_net/core/access/voice.py +6 -5
  92. pygpt_net/core/agents/legacy.py +4 -2
  93. pygpt_net/core/agents/memory.py +7 -2
  94. pygpt_net/core/agents/observer/evaluation.py +15 -7
  95. pygpt_net/core/agents/provider.py +9 -4
  96. pygpt_net/core/agents/runner.py +61 -15
  97. pygpt_net/core/agents/tools.py +23 -5
  98. pygpt_net/core/assistants/__init__.py +6 -4
  99. pygpt_net/core/assistants/files.py +35 -12
  100. pygpt_net/core/assistants/store.py +20 -10
  101. pygpt_net/core/attachments/__init__.py +54 -15
  102. pygpt_net/core/attachments/context.py +92 -29
  103. pygpt_net/core/audio/__init__.py +74 -3
  104. pygpt_net/core/audio/context.py +7 -2
  105. pygpt_net/core/audio/whisper.py +37 -0
  106. pygpt_net/core/bridge/__init__.py +22 -6
  107. pygpt_net/core/bridge/context.py +5 -3
  108. pygpt_net/core/bridge/worker.py +2 -2
  109. pygpt_net/core/calendar/__init__.py +57 -11
  110. pygpt_net/core/chain/__init__.py +8 -2
  111. pygpt_net/core/chain/chat.py +10 -8
  112. pygpt_net/core/chain/completion.py +10 -7
  113. pygpt_net/core/command.py +62 -17
  114. pygpt_net/core/ctx/__init__.py +260 -58
  115. pygpt_net/core/ctx/bag.py +25 -4
  116. pygpt_net/core/ctx/container.py +28 -17
  117. pygpt_net/core/ctx/idx.py +45 -8
  118. pygpt_net/core/ctx/output.py +95 -74
  119. pygpt_net/core/ctx/reply.py +5 -2
  120. pygpt_net/core/db/__init__.py +8 -7
  121. pygpt_net/core/db/viewer.py +17 -11
  122. pygpt_net/core/debug/__init__.py +10 -9
  123. pygpt_net/core/debug/events.py +22 -10
  124. pygpt_net/core/debug/tabs.py +9 -3
  125. pygpt_net/core/docker/__init__.py +11 -5
  126. pygpt_net/core/docker/builder.py +11 -3
  127. pygpt_net/core/events/app.py +5 -3
  128. pygpt_net/core/events/base.py +11 -5
  129. pygpt_net/core/events/control.py +5 -3
  130. pygpt_net/core/events/event.py +17 -7
  131. pygpt_net/core/events/kernel.py +5 -3
  132. pygpt_net/core/events/render.py +5 -3
  133. pygpt_net/core/experts/__init__.py +5 -4
  134. pygpt_net/core/filesystem/__init__.py +52 -34
  135. pygpt_net/core/filesystem/actions.py +8 -5
  136. pygpt_net/core/filesystem/editor.py +13 -3
  137. pygpt_net/core/filesystem/types.py +12 -7
  138. pygpt_net/core/filesystem/url.py +7 -3
  139. pygpt_net/core/history.py +3 -2
  140. pygpt_net/core/idx/__init__.py +48 -27
  141. pygpt_net/core/idx/chat.py +51 -17
  142. pygpt_net/core/idx/context.py +6 -2
  143. pygpt_net/core/idx/indexing.py +107 -42
  144. pygpt_net/core/idx/llm.py +11 -3
  145. pygpt_net/core/idx/metadata.py +13 -3
  146. pygpt_net/core/idx/types/ctx.py +32 -6
  147. pygpt_net/core/idx/types/external.py +41 -7
  148. pygpt_net/core/idx/types/files.py +31 -6
  149. pygpt_net/core/image.py +15 -4
  150. pygpt_net/core/installer.py +2 -4
  151. pygpt_net/core/llm/__init__.py +13 -3
  152. pygpt_net/core/locale.py +34 -8
  153. pygpt_net/core/models.py +63 -17
  154. pygpt_net/core/modes.py +11 -13
  155. pygpt_net/core/notepad.py +10 -5
  156. pygpt_net/core/plugins.py +31 -19
  157. pygpt_net/core/presets.py +37 -17
  158. pygpt_net/core/profile.py +21 -7
  159. pygpt_net/core/prompt/__init__.py +10 -3
  160. pygpt_net/core/prompt/custom.py +7 -6
  161. pygpt_net/core/prompt/template.py +9 -3
  162. pygpt_net/core/render/base.py +117 -22
  163. pygpt_net/core/render/markdown/body.py +27 -7
  164. pygpt_net/core/render/markdown/renderer.py +119 -22
  165. pygpt_net/core/render/plain/body.py +22 -5
  166. pygpt_net/core/render/plain/renderer.py +97 -21
  167. pygpt_net/core/render/web/body.py +75 -25
  168. pygpt_net/core/render/web/parser.py +3 -1
  169. pygpt_net/core/render/web/renderer.py +313 -63
  170. pygpt_net/core/settings.py +10 -5
  171. pygpt_net/core/tabs/__init__.py +290 -103
  172. pygpt_net/core/tabs/tab.py +26 -5
  173. pygpt_net/core/tokens.py +47 -12
  174. pygpt_net/core/updater/__init__.py +20 -7
  175. pygpt_net/core/vision/analyzer.py +29 -6
  176. pygpt_net/core/{web.py → web/__init__.py} +29 -7
  177. pygpt_net/core/web/helpers.py +237 -0
  178. pygpt_net/data/config/config.json +15 -4
  179. pygpt_net/data/config/models.json +3 -3
  180. pygpt_net/data/config/modes.json +3 -3
  181. pygpt_net/data/config/settings.json +55 -10
  182. pygpt_net/data/config/settings_section.json +3 -0
  183. pygpt_net/data/css/style.light.css +1 -0
  184. pygpt_net/data/css/{web.css → web-blocks.css} +162 -133
  185. pygpt_net/data/css/{web.light.css → web-blocks.light.css} +7 -0
  186. pygpt_net/data/css/web-chatgpt.css +350 -0
  187. pygpt_net/data/css/web-chatgpt.dark.css +64 -0
  188. pygpt_net/data/css/web-chatgpt.light.css +75 -0
  189. pygpt_net/data/css/web-chatgpt_wide.css +350 -0
  190. pygpt_net/data/css/web-chatgpt_wide.dark.css +64 -0
  191. pygpt_net/data/css/web-chatgpt_wide.light.css +75 -0
  192. pygpt_net/data/icons/split_screen.svg +1 -0
  193. pygpt_net/data/locale/locale.de.ini +12 -0
  194. pygpt_net/data/locale/locale.en.ini +18 -2
  195. pygpt_net/data/locale/locale.es.ini +12 -0
  196. pygpt_net/data/locale/locale.fr.ini +12 -0
  197. pygpt_net/data/locale/locale.it.ini +12 -0
  198. pygpt_net/data/locale/locale.pl.ini +12 -0
  199. pygpt_net/data/locale/locale.uk.ini +12 -0
  200. pygpt_net/data/locale/locale.zh.ini +12 -0
  201. pygpt_net/data/locale/plugin.cmd_web.de.ini +2 -0
  202. pygpt_net/data/locale/plugin.cmd_web.en.ini +22 -10
  203. pygpt_net/data/locale/plugin.cmd_web.es.ini +2 -0
  204. pygpt_net/data/locale/plugin.cmd_web.fr.ini +2 -0
  205. pygpt_net/data/locale/plugin.cmd_web.it.ini +2 -0
  206. pygpt_net/data/locale/plugin.cmd_web.pl.ini +2 -0
  207. pygpt_net/data/locale/plugin.cmd_web.uk.ini +2 -0
  208. pygpt_net/data/locale/plugin.cmd_web.zh.ini +2 -0
  209. pygpt_net/data/locale/plugin.mailer.en.ini +21 -0
  210. pygpt_net/icons.qrc +1 -0
  211. pygpt_net/icons_rc.py +165 -136
  212. pygpt_net/item/ctx.py +58 -25
  213. pygpt_net/plugin/agent/__init__.py +7 -2
  214. pygpt_net/plugin/audio_input/simple.py +21 -5
  215. pygpt_net/plugin/audio_output/__init__.py +9 -1
  216. pygpt_net/plugin/base/config.py +4 -2
  217. pygpt_net/plugin/base/plugin.py +75 -23
  218. pygpt_net/plugin/base/worker.py +42 -11
  219. pygpt_net/plugin/cmd_code_interpreter/__init__.py +39 -37
  220. pygpt_net/plugin/cmd_code_interpreter/runner.py +25 -12
  221. pygpt_net/plugin/cmd_history/config.py +2 -2
  222. pygpt_net/plugin/cmd_web/__init__.py +48 -9
  223. pygpt_net/plugin/cmd_web/config.py +135 -41
  224. pygpt_net/plugin/cmd_web/websearch.py +74 -33
  225. pygpt_net/plugin/cmd_web/worker.py +142 -13
  226. pygpt_net/plugin/idx_llama_index/config.py +3 -3
  227. pygpt_net/plugin/mailer/__init__.py +123 -0
  228. pygpt_net/plugin/mailer/config.py +149 -0
  229. pygpt_net/plugin/mailer/runner.py +285 -0
  230. pygpt_net/plugin/mailer/worker.py +123 -0
  231. pygpt_net/provider/agents/base.py +5 -2
  232. pygpt_net/provider/agents/openai.py +4 -2
  233. pygpt_net/provider/agents/openai_assistant.py +4 -2
  234. pygpt_net/provider/agents/planner.py +4 -2
  235. pygpt_net/provider/agents/react.py +4 -2
  236. pygpt_net/provider/audio_output/openai_tts.py +5 -11
  237. pygpt_net/provider/core/assistant/base.py +5 -3
  238. pygpt_net/provider/core/assistant/json_file.py +8 -5
  239. pygpt_net/provider/core/assistant_file/base.py +4 -3
  240. pygpt_net/provider/core/assistant_file/db_sqlite/__init__.py +4 -3
  241. pygpt_net/provider/core/assistant_file/db_sqlite/storage.py +3 -2
  242. pygpt_net/provider/core/assistant_store/base.py +6 -4
  243. pygpt_net/provider/core/assistant_store/db_sqlite/__init__.py +5 -4
  244. pygpt_net/provider/core/assistant_store/db_sqlite/storage.py +5 -3
  245. pygpt_net/provider/core/attachment/base.py +5 -3
  246. pygpt_net/provider/core/attachment/json_file.py +4 -3
  247. pygpt_net/provider/core/calendar/base.py +5 -3
  248. pygpt_net/provider/core/calendar/db_sqlite/__init__.py +6 -5
  249. pygpt_net/provider/core/calendar/db_sqlite/storage.py +5 -4
  250. pygpt_net/provider/core/config/base.py +8 -6
  251. pygpt_net/provider/core/config/json_file.py +9 -7
  252. pygpt_net/provider/core/config/patch.py +43 -1
  253. pygpt_net/provider/core/ctx/base.py +30 -25
  254. pygpt_net/provider/core/ctx/db_sqlite/__init__.py +59 -34
  255. pygpt_net/provider/core/ctx/db_sqlite/storage.py +62 -30
  256. pygpt_net/provider/core/ctx/db_sqlite/utils.py +11 -9
  257. pygpt_net/provider/core/index/base.py +129 -23
  258. pygpt_net/provider/core/index/db_sqlite/__init__.py +130 -23
  259. pygpt_net/provider/core/index/db_sqlite/storage.py +130 -23
  260. pygpt_net/provider/core/index/db_sqlite/utils.py +4 -2
  261. pygpt_net/provider/core/mode/base.py +5 -3
  262. pygpt_net/provider/core/mode/json_file.py +7 -6
  263. pygpt_net/provider/core/model/base.py +6 -4
  264. pygpt_net/provider/core/model/json_file.py +9 -7
  265. pygpt_net/provider/core/notepad/base.py +5 -3
  266. pygpt_net/provider/core/notepad/db_sqlite/__init__.py +5 -4
  267. pygpt_net/provider/core/notepad/db_sqlite/storage.py +4 -3
  268. pygpt_net/provider/core/plugin_preset/base.py +4 -2
  269. pygpt_net/provider/core/plugin_preset/json_file.py +5 -3
  270. pygpt_net/provider/core/preset/base.py +6 -4
  271. pygpt_net/provider/core/preset/json_file.py +9 -9
  272. pygpt_net/provider/core/prompt/base.py +6 -3
  273. pygpt_net/provider/core/prompt/json_file.py +11 -6
  274. pygpt_net/provider/gpt/assistants.py +21 -11
  275. pygpt_net/provider/gpt/audio.py +6 -5
  276. pygpt_net/provider/gpt/chat.py +10 -7
  277. pygpt_net/provider/gpt/completion.py +11 -5
  278. pygpt_net/provider/gpt/image.py +9 -2
  279. pygpt_net/provider/gpt/store.py +53 -18
  280. pygpt_net/provider/gpt/vision.py +17 -11
  281. pygpt_net/provider/llms/anthropic.py +7 -2
  282. pygpt_net/provider/llms/azure_openai.py +26 -5
  283. pygpt_net/provider/llms/base.py +47 -9
  284. pygpt_net/provider/llms/google.py +7 -2
  285. pygpt_net/provider/llms/hugging_face.py +13 -3
  286. pygpt_net/provider/llms/hugging_face_api.py +18 -4
  287. pygpt_net/provider/llms/local.py +7 -2
  288. pygpt_net/provider/llms/ollama.py +30 -6
  289. pygpt_net/provider/llms/openai.py +32 -6
  290. pygpt_net/provider/vector_stores/__init__.py +45 -14
  291. pygpt_net/provider/vector_stores/base.py +35 -8
  292. pygpt_net/provider/vector_stores/chroma.py +13 -3
  293. pygpt_net/provider/vector_stores/ctx_attachment.py +31 -12
  294. pygpt_net/provider/vector_stores/elasticsearch.py +12 -3
  295. pygpt_net/provider/vector_stores/pinecode.py +12 -3
  296. pygpt_net/provider/vector_stores/redis.py +12 -3
  297. pygpt_net/provider/vector_stores/simple.py +12 -3
  298. pygpt_net/provider/vector_stores/temp.py +16 -4
  299. pygpt_net/provider/web/base.py +10 -3
  300. pygpt_net/provider/web/google_custom_search.py +9 -3
  301. pygpt_net/provider/web/microsoft_bing.py +9 -3
  302. pygpt_net/tools/__init__.py +20 -4
  303. pygpt_net/tools/audio_transcriber/__init__.py +4 -3
  304. pygpt_net/tools/base.py +28 -7
  305. pygpt_net/tools/code_interpreter/__init__.py +177 -77
  306. pygpt_net/tools/code_interpreter/ui/dialogs.py +21 -103
  307. pygpt_net/tools/code_interpreter/ui/widgets.py +284 -9
  308. pygpt_net/tools/html_canvas/__init__.py +81 -25
  309. pygpt_net/tools/html_canvas/ui/dialogs.py +46 -62
  310. pygpt_net/tools/html_canvas/ui/widgets.py +96 -3
  311. pygpt_net/tools/image_viewer/__init__.py +10 -4
  312. pygpt_net/tools/indexer/__init__.py +8 -7
  313. pygpt_net/tools/media_player/__init__.py +4 -3
  314. pygpt_net/tools/text_editor/__init__.py +36 -10
  315. pygpt_net/ui/base/context_menu.py +2 -2
  316. pygpt_net/ui/layout/chat/input.py +10 -18
  317. pygpt_net/ui/layout/chat/output.py +27 -45
  318. pygpt_net/ui/layout/ctx/ctx_list.py +13 -4
  319. pygpt_net/ui/layout/toolbox/footer.py +18 -2
  320. pygpt_net/ui/main.py +2 -2
  321. pygpt_net/ui/menu/audio.py +12 -1
  322. pygpt_net/ui/menu/config.py +7 -11
  323. pygpt_net/ui/menu/debug.py +11 -1
  324. pygpt_net/ui/menu/theme.py +9 -2
  325. pygpt_net/ui/widget/filesystem/explorer.py +2 -2
  326. pygpt_net/ui/widget/lists/context.py +27 -5
  327. pygpt_net/ui/widget/tabs/Input.py +2 -2
  328. pygpt_net/ui/widget/tabs/body.py +2 -1
  329. pygpt_net/ui/widget/tabs/layout.py +195 -0
  330. pygpt_net/ui/widget/tabs/output.py +218 -55
  331. pygpt_net/ui/widget/textarea/html.py +11 -1
  332. pygpt_net/ui/widget/textarea/output.py +10 -1
  333. pygpt_net/ui/widget/textarea/search_input.py +4 -1
  334. pygpt_net/ui/widget/textarea/web.py +49 -9
  335. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.42.dist-info}/METADATA +177 -183
  336. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.42.dist-info}/RECORD +340 -325
  337. /pygpt_net/data/css/{web.dark.css → web-blocks.dark.css} +0 -0
  338. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.42.dist-info}/LICENSE +0 -0
  339. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.42.dist-info}/WHEEL +0 -0
  340. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.42.dist-info}/entry_points.txt +0 -0
@@ -6,19 +6,21 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.11.26 04:00:00 #
9
+ # Updated Date: 2024.12.14 08:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import json
13
13
  import os
14
14
  import re
15
15
  from datetime import datetime
16
+ from typing import Optional, List
16
17
 
17
18
  from pygpt_net.core.render.base import BaseRenderer
18
19
  from pygpt_net.core.text.utils import has_unclosed_code_tag
19
20
  from pygpt_net.item.ctx import CtxItem, CtxMeta
20
21
  from pygpt_net.ui.widget.textarea.input import ChatInput
21
22
  from pygpt_net.utils import trans
23
+ from pygpt_net.core.tabs.tab import Tab
22
24
 
23
25
  from .body import Body
24
26
  from .helpers import Helpers
@@ -59,16 +61,21 @@ class Renderer(BaseRenderer):
59
61
  node.set_meta(meta)
60
62
  self.reset(meta)
61
63
 
62
- def on_page_loaded(self, meta: CtxMeta = None):
64
+ def on_page_loaded(
65
+ self,
66
+ meta: Optional[CtxMeta] = None,
67
+ tab: Optional[Tab] = None
68
+ ):
63
69
  """
64
70
  On page loaded callback from WebEngine widget
65
71
 
66
72
  :param meta: context meta
73
+ :param tab: Tab
67
74
  """
68
75
  if meta is None:
69
76
  return
70
- pid = self.get_or_create_pid(meta)
71
- if pid is None:
77
+ pid = tab.pid
78
+ if pid is None or pid not in self.pids:
72
79
  return
73
80
  self.pids[pid].loaded = True
74
81
  if self.pids[pid].html != "" and not self.pids[pid].use_buffer:
@@ -98,7 +105,11 @@ class Renderer(BaseRenderer):
98
105
  self.pid_create(pid, meta)
99
106
  return pid
100
107
 
101
- def pid_create(self, pid, meta: CtxMeta):
108
+ def pid_create(
109
+ self,
110
+ pid: Optional[int],
111
+ meta: CtxMeta
112
+ ):
102
113
  """
103
114
  Create PID data
104
115
 
@@ -108,7 +119,7 @@ class Renderer(BaseRenderer):
108
119
  if pid is not None:
109
120
  self.pids[pid] = PidData(pid, meta)
110
121
 
111
- def init(self, pid):
122
+ def init(self, pid: Optional[int]):
112
123
  """
113
124
  Initialize renderer
114
125
 
@@ -120,7 +131,12 @@ class Renderer(BaseRenderer):
120
131
  else:
121
132
  self.clear_chunks(pid)
122
133
 
123
- def begin(self, meta: CtxMeta, ctx: CtxItem, stream: bool = False):
134
+ def begin(
135
+ self,
136
+ meta: CtxMeta,
137
+ ctx: CtxItem,
138
+ stream: bool = False
139
+ ):
124
140
  """
125
141
  Render begin
126
142
 
@@ -133,7 +149,12 @@ class Renderer(BaseRenderer):
133
149
  self.reset_names(meta)
134
150
  self.tool_output_end() # reset tools
135
151
 
136
- def end(self, meta: CtxMeta, ctx: CtxItem, stream: bool = False):
152
+ def end(
153
+ self,
154
+ meta: CtxMeta,
155
+ ctx: CtxItem,
156
+ stream: bool = False
157
+ ):
137
158
  """
138
159
  Render end
139
160
 
@@ -148,7 +169,12 @@ class Renderer(BaseRenderer):
148
169
  self.append_context_item(meta, self.pids[pid].item)
149
170
  self.pids[pid].item = None
150
171
 
151
- def end_extra(self, meta: CtxMeta, ctx: CtxItem, stream: bool = False):
172
+ def end_extra(
173
+ self,
174
+ meta: CtxMeta,
175
+ ctx: CtxItem,
176
+ stream: bool = False
177
+ ):
152
178
  """
153
179
  Render end extra
154
180
 
@@ -158,16 +184,24 @@ class Renderer(BaseRenderer):
158
184
  """
159
185
  self.to_end(ctx)
160
186
 
161
- def stream_begin(self, meta: CtxMeta, ctx: CtxItem):
187
+ def stream_begin(
188
+ self,
189
+ meta: CtxMeta,
190
+ ctx: CtxItem
191
+ ):
162
192
  """
163
193
  Render stream begin
164
194
 
165
195
  :param meta: context meta
166
196
  :param ctx: context item
167
197
  """
168
- pass # do nothing
198
+ pass
169
199
 
170
- def stream_end(self, meta: CtxMeta, ctx: CtxItem):
200
+ def stream_end(
201
+ self,
202
+ meta: CtxMeta,
203
+ ctx: CtxItem
204
+ ):
171
205
  """
172
206
  Render stream end
173
207
 
@@ -180,7 +214,12 @@ class Renderer(BaseRenderer):
180
214
  self.append_context_item(meta, self.pids[pid].item)
181
215
  self.pids[pid].item = None
182
216
 
183
- def append_context(self, meta: CtxMeta, items: list, clear: bool = True):
217
+ def append_context(
218
+ self,
219
+ meta: CtxMeta,
220
+ items: List[CtxItem],
221
+ clear: bool = True
222
+ ):
184
223
  """
185
224
  Append all context to output
186
225
 
@@ -201,22 +240,37 @@ class Renderer(BaseRenderer):
201
240
 
202
241
  self.pids[pid].use_buffer = True
203
242
  self.pids[pid].html = ""
243
+ prev_ctx = None
204
244
  for item in items:
205
245
  self.update_names(meta, item)
206
246
  item.idx = i
207
247
  if i == 0:
208
248
  item.first = True
209
249
  next_item = items[i + 1] if i + 1 < len(items) else None # append next item if exists
210
- self.append_context_item(meta, item, next_item) # to html buffer
250
+ self.append_context_item(
251
+ meta,
252
+ item,
253
+ prev_ctx=prev_ctx,
254
+ next_ctx=next_item
255
+ ) # to html buffer
256
+ prev_ctx = item
211
257
  i += 1
212
258
  self.pids[pid].use_buffer = False
213
259
 
214
260
  # flush
215
261
  if self.pids[pid].html != "":
216
- self.append(pid, self.pids[pid].html,
217
- flush=True) # flush buffer if page loaded, otherwise it will be flushed on page load
218
-
219
- def append_input(self, meta: CtxMeta, ctx: CtxItem, flush: bool = True, append: bool = False):
262
+ self.append(
263
+ pid,
264
+ self.pids[pid].html,
265
+ flush=True
266
+ ) # flush buffer if page loaded, otherwise it will be flushed on page load
267
+
268
+ def append_input(
269
+ self, meta: CtxMeta,
270
+ ctx: CtxItem,
271
+ flush: bool = True,
272
+ append: bool = False
273
+ ):
220
274
  """
221
275
  Append text input to output
222
276
 
@@ -248,29 +302,49 @@ class Renderer(BaseRenderer):
248
302
  text = re.sub(r'^user: ', '> ', ctx.input)
249
303
 
250
304
  if flush: # to chunk buffer
251
- content = self.prepare_node(meta, ctx, text.strip(), self.NODE_INPUT)
252
305
  if self.is_stream() and not append:
306
+ content = self.prepare_node(meta, ctx, text.strip(), self.NODE_INPUT)
253
307
  self.append_chunk_input(meta, ctx, content, False)
254
- else:
255
- self.append_node(meta, ctx, text.strip(), self.NODE_INPUT)
256
- else:
257
- self.append_node(meta, ctx, text.strip(), self.NODE_INPUT)
308
+ return
309
+
310
+ self.append_node(meta, ctx, text.strip(), self.NODE_INPUT)
258
311
 
259
- def append_output(self, meta: CtxMeta, ctx: CtxItem, flush: bool = True, next_ctx: CtxItem = None):
312
+ def append_output(
313
+ self,
314
+ meta: CtxMeta,
315
+ ctx: CtxItem,
316
+ flush: bool = True,
317
+ prev_ctx: Optional[CtxItem] = None,
318
+ next_ctx: Optional[CtxItem] = None
319
+ ):
260
320
  """
261
321
  Append text output to output
262
322
 
263
323
  :param meta: context meta
264
324
  :param ctx: context item
265
325
  :param flush: flush HTML
326
+ :param prev_ctx: previous context
266
327
  :param next_ctx: next context
267
328
  """
268
329
  self.tool_output_end() # reset tools
269
330
  if ctx.output is None or ctx.output == "":
270
331
  return
271
- self.append_node(meta, ctx, ctx.output.strip(), self.NODE_OUTPUT, next_ctx)
332
+ self.append_node(
333
+ meta=meta,
334
+ ctx=ctx,
335
+ html=ctx.output.strip(),
336
+ type=self.NODE_OUTPUT,
337
+ prev_ctx=prev_ctx,
338
+ next_ctx=next_ctx
339
+ )
272
340
 
273
- def append_chunk(self, meta: CtxMeta, ctx: CtxItem, text_chunk: str, begin: bool = False):
341
+ def append_chunk(
342
+ self,
343
+ meta: CtxMeta,
344
+ ctx: CtxItem,
345
+ text_chunk: str,
346
+ begin: bool = False
347
+ ):
274
348
  """
275
349
  Append output chunk to output
276
350
 
@@ -289,6 +363,12 @@ class Renderer(BaseRenderer):
289
363
  self.update_names(meta, ctx)
290
364
  raw_chunk = str(text_chunk)
291
365
  if begin:
366
+ # debug
367
+ debug = ""
368
+ if self.is_debug():
369
+ debug = self.append_debug(ctx, pid, "stream")
370
+ if debug:
371
+ raw_chunk = debug + raw_chunk
292
372
  self.pids[pid].buffer = "" # reset buffer
293
373
  self.pids[pid].is_cmd = False # reset command flag
294
374
  self.clear_chunks_output(pid)
@@ -316,7 +396,13 @@ class Renderer(BaseRenderer):
316
396
  except Exception as e:
317
397
  pass
318
398
 
319
- def append_chunk_input(self, meta: CtxMeta, ctx: CtxItem, text_chunk: str, begin: bool = False):
399
+ def append_chunk_input(
400
+ self,
401
+ meta: CtxMeta,
402
+ ctx: CtxItem,
403
+ text_chunk: str,
404
+ begin: bool = False
405
+ ):
320
406
  """
321
407
  Append output chunk to output
322
408
 
@@ -339,7 +425,15 @@ class Renderer(BaseRenderer):
339
425
  except Exception as e:
340
426
  pass
341
427
 
342
- def append_node(self, meta: CtxMeta, ctx: CtxItem, html: str, type: int = 1, next_ctx: CtxItem = None):
428
+ def append_node(
429
+ self,
430
+ meta: CtxMeta,
431
+ ctx: CtxItem,
432
+ html: str,
433
+ type: int = 1,
434
+ prev_ctx: Optional[CtxItem] = None,
435
+ next_ctx: Optional[CtxItem] = None
436
+ ):
343
437
  """
344
438
  Append and format raw text to output
345
439
 
@@ -347,15 +441,31 @@ class Renderer(BaseRenderer):
347
441
  :param html: text to append
348
442
  :param type: type of message
349
443
  :param ctx: CtxItem instance
444
+ :param prev_ctx: previous context item
350
445
  :param next_ctx: next context item
351
446
  """
352
447
  if ctx.hidden:
353
448
  return
354
449
 
355
450
  pid = self.get_or_create_pid(meta)
356
- self.append(pid, self.prepare_node(meta, ctx, html, type, next_ctx))
451
+ self.append(
452
+ pid,
453
+ self.prepare_node(
454
+ meta=meta,
455
+ ctx=ctx,
456
+ html=html,
457
+ type=type,
458
+ prev_ctx=prev_ctx,
459
+ next_ctx=next_ctx
460
+ )
461
+ )
357
462
 
358
- def append(self, pid, html: str, flush: bool = False):
463
+ def append(
464
+ self,
465
+ pid,
466
+ html: str,
467
+ flush: bool = False
468
+ ):
359
469
  """
360
470
  Append text to output
361
471
 
@@ -371,18 +481,41 @@ class Renderer(BaseRenderer):
371
481
  if not flush:
372
482
  self.pids[pid].html += html # to buffer
373
483
 
374
- def append_context_item(self, meta: CtxMeta, ctx: CtxItem, next_ctx: CtxItem = None):
484
+ def append_context_item(
485
+ self,
486
+ meta: CtxMeta,
487
+ ctx: CtxItem,
488
+ prev_ctx: Optional[CtxItem] = None,
489
+ next_ctx: Optional[CtxItem] = None
490
+ ):
375
491
  """
376
492
  Append context item to output
377
493
 
378
494
  :param meta: context meta
379
495
  :param ctx: context item
496
+ :param prev_ctx: previous context item
380
497
  :param next_ctx: next context item
381
498
  """
382
- self.append_input(meta, ctx, flush=False)
383
- self.append_output(meta, ctx, flush=False, next_ctx=next_ctx) # + extra
499
+ self.append_input(
500
+ meta,
501
+ ctx,
502
+ flush=False
503
+ )
504
+ self.append_output(
505
+ meta,
506
+ ctx,
507
+ flush=False,
508
+ prev_ctx=prev_ctx,
509
+ next_ctx=next_ctx
510
+ ) # + extra
384
511
 
385
- def append_extra(self, meta: CtxMeta, ctx: CtxItem, footer: bool = False, render: bool = True) -> str:
512
+ def append_extra(
513
+ self,
514
+ meta: CtxMeta,
515
+ ctx: CtxItem,
516
+ footer: bool = False,
517
+ render: bool = True
518
+ ) -> str:
386
519
  """
387
520
  Append extra data (images, files, etc.) to output
388
521
 
@@ -405,8 +538,8 @@ class Renderer(BaseRenderer):
405
538
  if image is None:
406
539
  continue
407
540
  # don't append if it is an external url
408
- if image.startswith("http"):
409
- continue
541
+ # if image.startswith("http"):
542
+ # continue
410
543
  if image in appended or image in self.pids[pid].images_appended:
411
544
  continue
412
545
  try:
@@ -473,7 +606,12 @@ class Renderer(BaseRenderer):
473
606
 
474
607
  return html
475
608
 
476
- def append_timestamp(self, ctx: CtxItem, text: str, type: int = None) -> str:
609
+ def append_timestamp(
610
+ self,
611
+ ctx: CtxItem,
612
+ text: str,
613
+ type: Optional[int] = None
614
+ ) -> str:
477
615
  """
478
616
  Append timestamp to text
479
617
 
@@ -494,7 +632,10 @@ class Renderer(BaseRenderer):
494
632
  text = '<span class="ts">{}: </span>{}'.format(hour, text)
495
633
  return text
496
634
 
497
- def reset(self, meta: CtxMeta = None):
635
+ def reset(
636
+ self,
637
+ meta: Optional[CtxMeta] = None
638
+ ):
498
639
  """
499
640
  Reset
500
641
 
@@ -510,7 +651,7 @@ class Renderer(BaseRenderer):
510
651
  pid = self.get_or_create_pid(meta)
511
652
  self.reset_by_pid(pid)
512
653
 
513
- def reset_by_pid(self, pid):
654
+ def reset_by_pid(self, pid: Optional[int]):
514
655
  """
515
656
  Reset by PID
516
657
 
@@ -531,7 +672,10 @@ class Renderer(BaseRenderer):
531
672
  """Clear input"""
532
673
  self.get_input_node().clear()
533
674
 
534
- def clear_output(self, meta: CtxMeta = None):
675
+ def clear_output(
676
+ self,
677
+ meta: Optional[CtxMeta] = None
678
+ ):
535
679
  """
536
680
  Clear output
537
681
 
@@ -550,12 +694,17 @@ class Renderer(BaseRenderer):
550
694
  self.clear_chunks_input(pid)
551
695
  self.clear_chunks_output(pid)
552
696
 
553
- def clear_chunks_input(self, pid):
697
+ def clear_chunks_input(
698
+ self,
699
+ pid: Optional[int]
700
+ ):
554
701
  """
555
702
  Clear chunks from input
556
703
 
557
704
  :pid: context PID
558
705
  """
706
+ if pid is None:
707
+ return
559
708
  if not self.pids[pid].loaded:
560
709
  js = "var element = document.getElementById('_append_input_');"
561
710
  js += "if (element) { element.innerHTML = ''; }"
@@ -566,7 +715,10 @@ class Renderer(BaseRenderer):
566
715
  except Exception as e:
567
716
  pass
568
717
 
569
- def clear_chunks_output(self, pid):
718
+ def clear_chunks_output(
719
+ self,
720
+ pid: Optional[int]
721
+ ):
570
722
  """
571
723
  Clear chunks from output
572
724
 
@@ -582,7 +734,10 @@ class Renderer(BaseRenderer):
582
734
  except Exception as e:
583
735
  pass
584
736
 
585
- def clear_nodes(self, pid):
737
+ def clear_nodes(
738
+ self,
739
+ pid: Optional[int]
740
+ ):
586
741
  """
587
742
  Clear nodes from output
588
743
 
@@ -598,7 +753,15 @@ class Renderer(BaseRenderer):
598
753
  except Exception as e:
599
754
  pass
600
755
 
601
- def prepare_node(self, meta: CtxMeta, ctx: CtxItem, html: str, type: int = 1, next_ctx: CtxItem = None) -> str:
756
+ def prepare_node(
757
+ self,
758
+ meta: CtxMeta,
759
+ ctx: CtxItem,
760
+ html: str,
761
+ type: int = 1,
762
+ prev_ctx: Optional[CtxItem] = None,
763
+ next_ctx: Optional[CtxItem] = None
764
+ ) -> str:
602
765
  """
603
766
  Prepare node HTML
604
767
 
@@ -606,20 +769,35 @@ class Renderer(BaseRenderer):
606
769
  :param ctx: CtxItem instance
607
770
  :param html: html text
608
771
  :param type: type of message
772
+ :param prev_ctx: previous context item
609
773
  :param next_ctx: next context item
610
774
  :return: prepared HTML
611
775
  """
612
776
  pid = self.get_or_create_pid(meta)
613
777
  if type == self.NODE_OUTPUT:
614
- return self.prepare_node_output(meta, ctx, html, next_ctx)
778
+ return self.prepare_node_output(
779
+ meta=meta,
780
+ ctx=ctx,
781
+ html=html,
782
+ prev_ctx=prev_ctx,
783
+ next_ctx=next_ctx
784
+ )
615
785
  elif type == self.NODE_INPUT:
616
- return self.prepare_node_input(pid, ctx, html)
786
+ return self.prepare_node_input(
787
+ pid=pid,
788
+ ctx=ctx,
789
+ html=html,
790
+ prev_ctx=prev_ctx,
791
+ next_ctx=next_ctx
792
+ )
617
793
 
618
794
  def prepare_node_input(
619
795
  self,
620
796
  pid,
621
797
  ctx: CtxItem,
622
- html: str
798
+ html: str,
799
+ prev_ctx: Optional[CtxItem] = None,
800
+ next_ctx: Optional[CtxItem] = None
623
801
  ) -> str:
624
802
  """
625
803
  Prepare input node
@@ -627,6 +805,8 @@ class Renderer(BaseRenderer):
627
805
  :param pid: context PID
628
806
  :param ctx: CtxItem instance
629
807
  :param html: html text
808
+ :param prev_ctx: previous context item
809
+ :param next_ctx: next context item
630
810
  :return: prepared HTML
631
811
  """
632
812
  msg_id = "msg-user-" + str(ctx.id) if ctx is not None else ""
@@ -644,6 +824,11 @@ class Renderer(BaseRenderer):
644
824
  if type(ctx.extra) is dict and "agent_evaluate" in ctx.extra:
645
825
  name = trans("msg.name.evaluation")
646
826
 
827
+ # debug
828
+ debug = ""
829
+ if self.is_debug():
830
+ debug = self.append_debug(ctx, pid, "input")
831
+
647
832
  extra = ""
648
833
  if ctx.extra is not None and "footer" in ctx.extra:
649
834
  extra = ctx.extra["footer"]
@@ -653,6 +838,7 @@ class Renderer(BaseRenderer):
653
838
  '<div class="msg">'
654
839
  '{html}'
655
840
  '<div class="msg-extra">{extra}</div>'
841
+ '{debug}'
656
842
  '</div>'
657
843
  '</div>'
658
844
  ).format(
@@ -660,6 +846,7 @@ class Renderer(BaseRenderer):
660
846
  name=name,
661
847
  html=html,
662
848
  extra=extra,
849
+ debug=debug,
663
850
  )
664
851
 
665
852
  return html
@@ -669,7 +856,8 @@ class Renderer(BaseRenderer):
669
856
  meta: CtxMeta,
670
857
  ctx: CtxItem,
671
858
  html: str,
672
- next_ctx: CtxItem = None
859
+ prev_ctx: Optional[CtxItem] = None,
860
+ next_ctx: Optional[CtxItem] = None
673
861
  ) -> str:
674
862
  """
675
863
  Prepare output node
@@ -677,7 +865,8 @@ class Renderer(BaseRenderer):
677
865
  :param meta: context meta
678
866
  :param ctx: CtxItem instance
679
867
  :param html: html text
680
- :param next_ctx: previous context item
868
+ :param prev_ctx: previous context item
869
+ :param next_ctx: next context item
681
870
  :return: prepared HTML
682
871
  """
683
872
  is_cmd = False
@@ -689,8 +878,8 @@ class Renderer(BaseRenderer):
689
878
  is_cmd = True
690
879
  pid = self.get_or_create_pid(meta)
691
880
  msg_id = "msg-bot-" + str(ctx.id) if ctx is not None else ""
692
- #if is_cmd:
693
- #html = self.helpers.format_cmd_text(html)
881
+ # if is_cmd:
882
+ # html = self.helpers.format_cmd_text(html)
694
883
  html = self.helpers.pre_format_text(html)
695
884
  html = self.append_timestamp(ctx, html, type=self.NODE_OUTPUT)
696
885
  html = self.parser.parse(html)
@@ -730,7 +919,7 @@ class Renderer(BaseRenderer):
730
919
 
731
920
  # check if agent step and results in current ctx
732
921
  elif ctx.results is not None and len(ctx.results) > 0 \
733
- and isinstance(ctx.extra, dict) and "agent_step" in ctx.extra:
922
+ and isinstance(ctx.extra, dict) and "agent_step" in ctx.extra:
734
923
  tool_output = self.helpers.format_cmd_text(str(ctx.input))
735
924
  else:
736
925
  # loading spinner
@@ -766,16 +955,21 @@ class Renderer(BaseRenderer):
766
955
  )
767
956
  tool_extra = self.body.prepare_tool_extra(ctx)
768
957
 
958
+ # debug
959
+ debug = ""
960
+ if self.is_debug():
961
+ debug = self.append_debug(ctx, pid, "output")
962
+
769
963
  html = (
770
964
  '<div class="msg-box msg-bot" id="{msg_id}">'
771
965
  '<div class="name-header name-bot">{name_bot}</div>'
772
966
  '<div class="msg">'
773
967
  '{html}'
774
-
775
968
  '<div class="msg-tool-extra">{tool_extra}</div>'
776
969
  '{html_tools}'
777
970
  '<div class="msg-extra">{extra}</div>'
778
971
  '{footer}'
972
+ '{debug}'
779
973
  '</div>'
780
974
  '</div>'
781
975
  ).format(
@@ -786,11 +980,16 @@ class Renderer(BaseRenderer):
786
980
  extra=extra,
787
981
  footer=footer,
788
982
  tool_extra=tool_extra,
983
+ debug=debug,
789
984
  )
790
985
 
791
986
  return html
792
987
 
793
- def flush_output(self, pid, html: str):
988
+ def flush_output(
989
+ self,
990
+ pid: Optional[int],
991
+ html: str
992
+ ):
794
993
  """
795
994
  Flush output
796
995
 
@@ -809,7 +1008,11 @@ class Renderer(BaseRenderer):
809
1008
  """Reload output, called externally only on theme change to redraw content"""
810
1009
  self.window.controller.ctx.refresh_output() # if clear all and appends all items again
811
1010
 
812
- def flush(self, pid):
1011
+ def flush(
1012
+ self,
1013
+ pid:
1014
+ Optional[int]
1015
+ ):
813
1016
  """
814
1017
  Flush output
815
1018
 
@@ -818,11 +1021,14 @@ class Renderer(BaseRenderer):
818
1021
  if self.pids[pid].loaded:
819
1022
  return # wait for page load
820
1023
 
821
- html = self.body.get_html()
1024
+ html = self.body.get_html(pid)
822
1025
  self.pids[pid].document = html
823
1026
  self.get_output_node_by_pid(pid).setHtml(html, baseUrl="file://")
824
1027
 
825
- def get_output_node(self, meta: CtxMeta = None):
1028
+ def get_output_node(
1029
+ self,
1030
+ meta: Optional[CtxMeta] = None
1031
+ ):
826
1032
  """
827
1033
  Get output node
828
1034
 
@@ -831,7 +1037,10 @@ class Renderer(BaseRenderer):
831
1037
  """
832
1038
  return self.window.core.ctx.output.get_current(meta)
833
1039
 
834
- def get_output_node_by_pid(self, pid):
1040
+ def get_output_node_by_pid(
1041
+ self,
1042
+ pid: Optional[int]
1043
+ ):
835
1044
  """
836
1045
  Get output node by PID
837
1046
 
@@ -848,7 +1057,10 @@ class Renderer(BaseRenderer):
848
1057
  """
849
1058
  return self.window.ui.nodes['input']
850
1059
 
851
- def get_document(self, plain: bool = False):
1060
+ def get_document(
1061
+ self,
1062
+ plain: bool = False
1063
+ ):
852
1064
  """
853
1065
  Get document content (plain or HTML)
854
1066
 
@@ -895,7 +1107,7 @@ class Renderer(BaseRenderer):
895
1107
  pid = self.get_or_create_pid(meta)
896
1108
  self.reset_names_by_pid(pid)
897
1109
 
898
- def reset_names_by_pid(self, pid):
1110
+ def reset_names_by_pid(self, pid: int):
899
1111
  """
900
1112
  Reset names by PID
901
1113
 
@@ -982,7 +1194,11 @@ class Renderer(BaseRenderer):
982
1194
  except Exception as e:
983
1195
  pass
984
1196
 
985
- def update_names(self, meta: CtxMeta, ctx: CtxItem):
1197
+ def update_names(
1198
+ self,
1199
+ meta: CtxMeta,
1200
+ ctx: CtxItem
1201
+ ):
986
1202
  """
987
1203
  Update names
988
1204
 
@@ -1050,7 +1266,11 @@ class Renderer(BaseRenderer):
1050
1266
  self.reload_css()
1051
1267
  return
1052
1268
 
1053
- def tool_output_append(self, meta: CtxMeta, content: str):
1269
+ def tool_output_append(
1270
+ self,
1271
+ meta: CtxMeta,
1272
+ content: str
1273
+ ):
1054
1274
  """
1055
1275
  Add tool output (append)
1056
1276
 
@@ -1063,7 +1283,11 @@ class Renderer(BaseRenderer):
1063
1283
  except Exception as e:
1064
1284
  pass
1065
1285
 
1066
- def tool_output_update(self, meta: CtxMeta, content: str):
1286
+ def tool_output_update(
1287
+ self,
1288
+ meta: CtxMeta,
1289
+ content: str
1290
+ ):
1067
1291
  """
1068
1292
  Replace tool output
1069
1293
 
@@ -1104,3 +1328,29 @@ class Renderer(BaseRenderer):
1104
1328
  self.get_output_node().page().runJavaScript(f"endToolOutput();")
1105
1329
  except Exception as e:
1106
1330
  pass
1331
+
1332
+ def append_debug(
1333
+ self,
1334
+ ctx: CtxItem,
1335
+ pid,
1336
+ title: Optional[str] = None
1337
+ ) -> str:
1338
+ """
1339
+ Append debug info
1340
+
1341
+ :param ctx: context item
1342
+ :param pid: context PID
1343
+ :param title: debug title
1344
+ """
1345
+ if title is None:
1346
+ title = "debug"
1347
+ debug = "<b>" +title+ ":</b> pid: "+str(pid)+", ctx: " + str(ctx.to_dict())
1348
+ return "<div class='debug'>" + debug + "</div>"
1349
+
1350
+ def is_debug(self) -> bool:
1351
+ """
1352
+ Check if debug mode is enabled
1353
+
1354
+ :return: True if debug mode is enabled
1355
+ """
1356
+ return self.window.core.config.get("debug.render", False)