pygpt-net 2.6.54__py3-none-any.whl → 2.6.56__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 (371) hide show
  1. pygpt_net/CHANGELOG.txt +11 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/app.py +26 -22
  4. pygpt_net/controller/audio/audio.py +0 -0
  5. pygpt_net/controller/calendar/calendar.py +0 -0
  6. pygpt_net/controller/calendar/note.py +0 -0
  7. pygpt_net/controller/chat/chat.py +0 -0
  8. pygpt_net/controller/chat/handler/openai_stream.py +2 -1
  9. pygpt_net/controller/chat/handler/worker.py +0 -0
  10. pygpt_net/controller/chat/remote_tools.py +0 -0
  11. pygpt_net/controller/chat/render.py +0 -0
  12. pygpt_net/controller/chat/text.py +0 -0
  13. pygpt_net/controller/ctx/common.py +0 -0
  14. pygpt_net/controller/debug/debug.py +26 -2
  15. pygpt_net/controller/debug/fixtures.py +1 -1
  16. pygpt_net/controller/dialogs/confirm.py +15 -1
  17. pygpt_net/controller/dialogs/debug.py +2 -0
  18. pygpt_net/controller/lang/mapping.py +0 -0
  19. pygpt_net/controller/launcher/launcher.py +0 -0
  20. pygpt_net/controller/mode/mode.py +0 -0
  21. pygpt_net/controller/presets/presets.py +0 -0
  22. pygpt_net/controller/realtime/realtime.py +0 -0
  23. pygpt_net/controller/theme/theme.py +0 -0
  24. pygpt_net/controller/ui/mode.py +0 -0
  25. pygpt_net/controller/ui/tabs.py +0 -0
  26. pygpt_net/core/agents/agents.py +3 -1
  27. pygpt_net/core/agents/custom.py +150 -0
  28. pygpt_net/core/agents/provider.py +0 -0
  29. pygpt_net/core/builder/__init__.py +12 -0
  30. pygpt_net/core/builder/graph.py +478 -0
  31. pygpt_net/core/calendar/calendar.py +0 -0
  32. pygpt_net/core/ctx/ctx.py +2 -1
  33. pygpt_net/core/ctx/output.py +0 -0
  34. pygpt_net/core/debug/agent.py +0 -0
  35. pygpt_net/core/debug/agent_builder.py +29 -0
  36. pygpt_net/core/debug/console/console.py +0 -0
  37. pygpt_net/core/debug/db.py +0 -0
  38. pygpt_net/core/debug/debug.py +0 -0
  39. pygpt_net/core/debug/events.py +0 -0
  40. pygpt_net/core/debug/indexes.py +0 -0
  41. pygpt_net/core/debug/kernel.py +0 -0
  42. pygpt_net/core/debug/tabs.py +0 -0
  43. pygpt_net/core/filesystem/filesystem.py +0 -0
  44. pygpt_net/core/fixtures/__init__ +0 -0
  45. pygpt_net/core/fixtures/stream/__init__.py +0 -0
  46. pygpt_net/core/fixtures/stream/generator.py +0 -0
  47. pygpt_net/core/models/models.py +0 -0
  48. pygpt_net/core/render/plain/pid.py +0 -0
  49. pygpt_net/core/render/plain/renderer.py +26 -4
  50. pygpt_net/core/render/web/body.py +46 -4
  51. pygpt_net/core/render/web/debug.py +0 -0
  52. pygpt_net/core/render/web/helpers.py +0 -0
  53. pygpt_net/core/render/web/pid.py +0 -0
  54. pygpt_net/core/render/web/renderer.py +15 -20
  55. pygpt_net/core/tabs/tab.py +0 -0
  56. pygpt_net/core/tabs/tabs.py +0 -0
  57. pygpt_net/core/text/utils.py +0 -0
  58. pygpt_net/css.qrc +0 -0
  59. pygpt_net/css_rc.py +0 -0
  60. pygpt_net/data/config/config.json +7 -7
  61. pygpt_net/data/config/models.json +3 -3
  62. pygpt_net/data/css/web-blocks.css +9 -0
  63. pygpt_net/data/css/web-blocks.dark.css +6 -0
  64. pygpt_net/data/css/web-blocks.darkest.css +6 -0
  65. pygpt_net/data/css/web-chatgpt.css +14 -6
  66. pygpt_net/data/css/web-chatgpt.dark.css +6 -0
  67. pygpt_net/data/css/web-chatgpt.darkest.css +6 -0
  68. pygpt_net/data/css/web-chatgpt.light.css +6 -0
  69. pygpt_net/data/css/web-chatgpt_wide.css +14 -6
  70. pygpt_net/data/css/web-chatgpt_wide.dark.css +6 -0
  71. pygpt_net/data/css/web-chatgpt_wide.darkest.css +6 -0
  72. pygpt_net/data/css/web-chatgpt_wide.light.css +6 -0
  73. pygpt_net/data/fixtures/fake_stream.txt +14 -1
  74. pygpt_net/data/icons/case.svg +0 -0
  75. pygpt_net/data/icons/chat1.svg +0 -0
  76. pygpt_net/data/icons/chat2.svg +0 -0
  77. pygpt_net/data/icons/chat3.svg +0 -0
  78. pygpt_net/data/icons/chat4.svg +0 -0
  79. pygpt_net/data/icons/fit.svg +0 -0
  80. pygpt_net/data/icons/note1.svg +0 -0
  81. pygpt_net/data/icons/note2.svg +0 -0
  82. pygpt_net/data/icons/note3.svg +0 -0
  83. pygpt_net/data/icons/stt.svg +0 -0
  84. pygpt_net/data/icons/translate.svg +0 -0
  85. pygpt_net/data/icons/tts.svg +0 -0
  86. pygpt_net/data/icons/url.svg +0 -0
  87. pygpt_net/data/icons/vision.svg +0 -0
  88. pygpt_net/data/icons/web_off.svg +0 -0
  89. pygpt_net/data/icons/web_on.svg +0 -0
  90. pygpt_net/data/js/app/async.js +166 -0
  91. pygpt_net/data/js/app/bridge.js +88 -0
  92. pygpt_net/data/js/app/common.js +212 -0
  93. pygpt_net/data/js/app/config.js +223 -0
  94. pygpt_net/data/js/app/custom.js +961 -0
  95. pygpt_net/data/js/app/data.js +84 -0
  96. pygpt_net/data/js/app/dom.js +322 -0
  97. pygpt_net/data/js/app/events.js +400 -0
  98. pygpt_net/data/js/app/highlight.js +542 -0
  99. pygpt_net/data/js/app/logger.js +305 -0
  100. pygpt_net/data/js/app/markdown.js +1137 -0
  101. pygpt_net/data/js/app/math.js +167 -0
  102. pygpt_net/data/js/app/nodes.js +395 -0
  103. pygpt_net/data/js/app/queue.js +260 -0
  104. pygpt_net/data/js/app/raf.js +250 -0
  105. pygpt_net/data/js/app/runtime.js +582 -0
  106. pygpt_net/data/js/app/scroll.js +433 -0
  107. pygpt_net/data/js/app/stream.js +2708 -0
  108. pygpt_net/data/js/app/template.js +287 -0
  109. pygpt_net/data/js/app/tool.js +87 -0
  110. pygpt_net/data/js/app/ui.js +86 -0
  111. pygpt_net/data/js/app/user.js +380 -0
  112. pygpt_net/data/js/app/utils.js +64 -0
  113. pygpt_net/data/js/app.min.js +880 -0
  114. pygpt_net/data/js/markdown-it/markdown-it-katex.min.js +1 -1
  115. pygpt_net/data/js/markdown-it/markdown-it.min.js +0 -0
  116. pygpt_net/data/locale/locale.de.ini +0 -0
  117. pygpt_net/data/locale/locale.en.ini +7 -0
  118. pygpt_net/data/locale/locale.es.ini +0 -0
  119. pygpt_net/data/locale/locale.fr.ini +0 -0
  120. pygpt_net/data/locale/locale.it.ini +0 -0
  121. pygpt_net/data/locale/locale.pl.ini +0 -0
  122. pygpt_net/data/locale/locale.uk.ini +0 -0
  123. pygpt_net/data/locale/locale.zh.ini +0 -0
  124. pygpt_net/data/locale/plugin.agent.de.ini +0 -0
  125. pygpt_net/data/locale/plugin.agent.en.ini +0 -0
  126. pygpt_net/data/locale/plugin.agent.es.ini +0 -0
  127. pygpt_net/data/locale/plugin.agent.fr.ini +0 -0
  128. pygpt_net/data/locale/plugin.agent.it.ini +0 -0
  129. pygpt_net/data/locale/plugin.agent.pl.ini +0 -0
  130. pygpt_net/data/locale/plugin.agent.uk.ini +0 -0
  131. pygpt_net/data/locale/plugin.agent.zh.ini +0 -0
  132. pygpt_net/data/locale/plugin.audio_input.de.ini +0 -0
  133. pygpt_net/data/locale/plugin.audio_input.en.ini +0 -0
  134. pygpt_net/data/locale/plugin.audio_input.es.ini +0 -0
  135. pygpt_net/data/locale/plugin.audio_input.fr.ini +0 -0
  136. pygpt_net/data/locale/plugin.audio_input.it.ini +0 -0
  137. pygpt_net/data/locale/plugin.audio_input.pl.ini +0 -0
  138. pygpt_net/data/locale/plugin.audio_input.uk.ini +0 -0
  139. pygpt_net/data/locale/plugin.audio_input.zh.ini +0 -0
  140. pygpt_net/data/locale/plugin.audio_output.de.ini +0 -0
  141. pygpt_net/data/locale/plugin.audio_output.en.ini +0 -0
  142. pygpt_net/data/locale/plugin.audio_output.es.ini +0 -0
  143. pygpt_net/data/locale/plugin.audio_output.fr.ini +0 -0
  144. pygpt_net/data/locale/plugin.audio_output.it.ini +0 -0
  145. pygpt_net/data/locale/plugin.audio_output.pl.ini +0 -0
  146. pygpt_net/data/locale/plugin.audio_output.uk.ini +0 -0
  147. pygpt_net/data/locale/plugin.audio_output.zh.ini +0 -0
  148. pygpt_net/data/locale/plugin.cmd_api.de.ini +0 -0
  149. pygpt_net/data/locale/plugin.cmd_api.en.ini +0 -0
  150. pygpt_net/data/locale/plugin.cmd_api.es.ini +0 -0
  151. pygpt_net/data/locale/plugin.cmd_api.fr.ini +0 -0
  152. pygpt_net/data/locale/plugin.cmd_api.it.ini +0 -0
  153. pygpt_net/data/locale/plugin.cmd_api.pl.ini +0 -0
  154. pygpt_net/data/locale/plugin.cmd_api.uk.ini +0 -0
  155. pygpt_net/data/locale/plugin.cmd_api.zh.ini +0 -0
  156. pygpt_net/data/locale/plugin.cmd_code_interpreter.de.ini +0 -0
  157. pygpt_net/data/locale/plugin.cmd_code_interpreter.en.ini +0 -0
  158. pygpt_net/data/locale/plugin.cmd_code_interpreter.es.ini +0 -0
  159. pygpt_net/data/locale/plugin.cmd_code_interpreter.fr.ini +0 -0
  160. pygpt_net/data/locale/plugin.cmd_code_interpreter.it.ini +0 -0
  161. pygpt_net/data/locale/plugin.cmd_code_interpreter.pl.ini +0 -0
  162. pygpt_net/data/locale/plugin.cmd_code_interpreter.uk.ini +0 -0
  163. pygpt_net/data/locale/plugin.cmd_code_interpreter.zh.ini +0 -0
  164. pygpt_net/data/locale/plugin.cmd_custom.de.ini +0 -0
  165. pygpt_net/data/locale/plugin.cmd_custom.en.ini +0 -0
  166. pygpt_net/data/locale/plugin.cmd_custom.es.ini +0 -0
  167. pygpt_net/data/locale/plugin.cmd_custom.fr.ini +0 -0
  168. pygpt_net/data/locale/plugin.cmd_custom.it.ini +0 -0
  169. pygpt_net/data/locale/plugin.cmd_custom.pl.ini +0 -0
  170. pygpt_net/data/locale/plugin.cmd_custom.uk.ini +0 -0
  171. pygpt_net/data/locale/plugin.cmd_custom.zh.ini +0 -0
  172. pygpt_net/data/locale/plugin.cmd_files.de.ini +0 -0
  173. pygpt_net/data/locale/plugin.cmd_files.en.ini +0 -0
  174. pygpt_net/data/locale/plugin.cmd_files.es.ini +0 -0
  175. pygpt_net/data/locale/plugin.cmd_files.fr.ini +0 -0
  176. pygpt_net/data/locale/plugin.cmd_files.it.ini +0 -0
  177. pygpt_net/data/locale/plugin.cmd_files.pl.ini +0 -0
  178. pygpt_net/data/locale/plugin.cmd_files.uk.ini +0 -0
  179. pygpt_net/data/locale/plugin.cmd_files.zh.ini +0 -0
  180. pygpt_net/data/locale/plugin.cmd_history.de.ini +0 -0
  181. pygpt_net/data/locale/plugin.cmd_history.en.ini +0 -0
  182. pygpt_net/data/locale/plugin.cmd_history.es.ini +0 -0
  183. pygpt_net/data/locale/plugin.cmd_history.fr.ini +0 -0
  184. pygpt_net/data/locale/plugin.cmd_history.it.ini +0 -0
  185. pygpt_net/data/locale/plugin.cmd_history.pl.ini +0 -0
  186. pygpt_net/data/locale/plugin.cmd_history.uk.ini +0 -0
  187. pygpt_net/data/locale/plugin.cmd_history.zh.ini +0 -0
  188. pygpt_net/data/locale/plugin.cmd_mouse_control.de.ini +0 -0
  189. pygpt_net/data/locale/plugin.cmd_mouse_control.en.ini +0 -0
  190. pygpt_net/data/locale/plugin.cmd_mouse_control.es.ini +0 -0
  191. pygpt_net/data/locale/plugin.cmd_mouse_control.fr.ini +0 -0
  192. pygpt_net/data/locale/plugin.cmd_mouse_control.it.ini +0 -0
  193. pygpt_net/data/locale/plugin.cmd_mouse_control.pl.ini +0 -0
  194. pygpt_net/data/locale/plugin.cmd_mouse_control.uk.ini +0 -0
  195. pygpt_net/data/locale/plugin.cmd_mouse_control.zh.ini +0 -0
  196. pygpt_net/data/locale/plugin.cmd_serial.de.ini +0 -0
  197. pygpt_net/data/locale/plugin.cmd_serial.en.ini +0 -0
  198. pygpt_net/data/locale/plugin.cmd_serial.es.ini +0 -0
  199. pygpt_net/data/locale/plugin.cmd_serial.fr.ini +0 -0
  200. pygpt_net/data/locale/plugin.cmd_serial.it.ini +0 -0
  201. pygpt_net/data/locale/plugin.cmd_serial.pl.ini +0 -0
  202. pygpt_net/data/locale/plugin.cmd_serial.uk.ini +0 -0
  203. pygpt_net/data/locale/plugin.cmd_serial.zh.ini +0 -0
  204. pygpt_net/data/locale/plugin.cmd_system.de.ini +0 -0
  205. pygpt_net/data/locale/plugin.cmd_system.en.ini +0 -0
  206. pygpt_net/data/locale/plugin.cmd_system.es.ini +0 -0
  207. pygpt_net/data/locale/plugin.cmd_system.fr.ini +0 -0
  208. pygpt_net/data/locale/plugin.cmd_system.it.ini +0 -0
  209. pygpt_net/data/locale/plugin.cmd_system.pl.ini +0 -0
  210. pygpt_net/data/locale/plugin.cmd_system.uk.ini +0 -0
  211. pygpt_net/data/locale/plugin.cmd_system.zh.ini +0 -0
  212. pygpt_net/data/locale/plugin.cmd_web.de.ini +0 -0
  213. pygpt_net/data/locale/plugin.cmd_web.en.ini +0 -0
  214. pygpt_net/data/locale/plugin.cmd_web.es.ini +0 -0
  215. pygpt_net/data/locale/plugin.cmd_web.fr.ini +0 -0
  216. pygpt_net/data/locale/plugin.cmd_web.it.ini +0 -0
  217. pygpt_net/data/locale/plugin.cmd_web.pl.ini +0 -0
  218. pygpt_net/data/locale/plugin.cmd_web.uk.ini +0 -0
  219. pygpt_net/data/locale/plugin.cmd_web.zh.ini +0 -0
  220. pygpt_net/data/locale/plugin.crontab.de.ini +0 -0
  221. pygpt_net/data/locale/plugin.crontab.en.ini +0 -0
  222. pygpt_net/data/locale/plugin.crontab.es.ini +0 -0
  223. pygpt_net/data/locale/plugin.crontab.fr.ini +0 -0
  224. pygpt_net/data/locale/plugin.crontab.it.ini +0 -0
  225. pygpt_net/data/locale/plugin.crontab.pl.ini +0 -0
  226. pygpt_net/data/locale/plugin.crontab.uk.ini +0 -0
  227. pygpt_net/data/locale/plugin.crontab.zh.ini +0 -0
  228. pygpt_net/data/locale/plugin.experts.de.ini +0 -0
  229. pygpt_net/data/locale/plugin.experts.en.ini +0 -0
  230. pygpt_net/data/locale/plugin.experts.es.ini +0 -0
  231. pygpt_net/data/locale/plugin.experts.fr.ini +0 -0
  232. pygpt_net/data/locale/plugin.experts.it.ini +0 -0
  233. pygpt_net/data/locale/plugin.experts.pl.ini +0 -0
  234. pygpt_net/data/locale/plugin.experts.uk.ini +0 -0
  235. pygpt_net/data/locale/plugin.experts.zh.ini +0 -0
  236. pygpt_net/data/locale/plugin.extra_prompt.de.ini +0 -0
  237. pygpt_net/data/locale/plugin.extra_prompt.en.ini +0 -0
  238. pygpt_net/data/locale/plugin.extra_prompt.es.ini +0 -0
  239. pygpt_net/data/locale/plugin.extra_prompt.fr.ini +0 -0
  240. pygpt_net/data/locale/plugin.extra_prompt.it.ini +0 -0
  241. pygpt_net/data/locale/plugin.extra_prompt.pl.ini +0 -0
  242. pygpt_net/data/locale/plugin.extra_prompt.uk.ini +0 -0
  243. pygpt_net/data/locale/plugin.extra_prompt.zh.ini +0 -0
  244. pygpt_net/data/locale/plugin.idx_llama_index.de.ini +0 -0
  245. pygpt_net/data/locale/plugin.idx_llama_index.en.ini +0 -0
  246. pygpt_net/data/locale/plugin.idx_llama_index.es.ini +0 -0
  247. pygpt_net/data/locale/plugin.idx_llama_index.fr.ini +0 -0
  248. pygpt_net/data/locale/plugin.idx_llama_index.it.ini +0 -0
  249. pygpt_net/data/locale/plugin.idx_llama_index.pl.ini +0 -0
  250. pygpt_net/data/locale/plugin.idx_llama_index.uk.ini +0 -0
  251. pygpt_net/data/locale/plugin.idx_llama_index.zh.ini +0 -0
  252. pygpt_net/data/locale/plugin.mailer.en.ini +0 -0
  253. pygpt_net/data/locale/plugin.mcp.en.ini +0 -0
  254. pygpt_net/data/locale/plugin.openai_dalle.de.ini +0 -0
  255. pygpt_net/data/locale/plugin.openai_dalle.en.ini +0 -0
  256. pygpt_net/data/locale/plugin.openai_dalle.es.ini +0 -0
  257. pygpt_net/data/locale/plugin.openai_dalle.fr.ini +0 -0
  258. pygpt_net/data/locale/plugin.openai_dalle.it.ini +0 -0
  259. pygpt_net/data/locale/plugin.openai_dalle.pl.ini +0 -0
  260. pygpt_net/data/locale/plugin.openai_dalle.uk.ini +0 -0
  261. pygpt_net/data/locale/plugin.openai_dalle.zh.ini +0 -0
  262. pygpt_net/data/locale/plugin.openai_vision.de.ini +0 -0
  263. pygpt_net/data/locale/plugin.openai_vision.en.ini +0 -0
  264. pygpt_net/data/locale/plugin.openai_vision.es.ini +0 -0
  265. pygpt_net/data/locale/plugin.openai_vision.fr.ini +0 -0
  266. pygpt_net/data/locale/plugin.openai_vision.it.ini +0 -0
  267. pygpt_net/data/locale/plugin.openai_vision.pl.ini +0 -0
  268. pygpt_net/data/locale/plugin.openai_vision.uk.ini +0 -0
  269. pygpt_net/data/locale/plugin.openai_vision.zh.ini +0 -0
  270. pygpt_net/data/locale/plugin.osm.en.ini +0 -0
  271. pygpt_net/data/locale/plugin.real_time.de.ini +0 -0
  272. pygpt_net/data/locale/plugin.real_time.en.ini +0 -0
  273. pygpt_net/data/locale/plugin.real_time.es.ini +0 -0
  274. pygpt_net/data/locale/plugin.real_time.fr.ini +0 -0
  275. pygpt_net/data/locale/plugin.real_time.it.ini +0 -0
  276. pygpt_net/data/locale/plugin.real_time.pl.ini +0 -0
  277. pygpt_net/data/locale/plugin.real_time.uk.ini +0 -0
  278. pygpt_net/data/locale/plugin.real_time.zh.ini +0 -0
  279. pygpt_net/data/locale/plugin.voice_control.de.ini +0 -0
  280. pygpt_net/data/locale/plugin.voice_control.en.ini +0 -0
  281. pygpt_net/data/locale/plugin.voice_control.es.ini +0 -0
  282. pygpt_net/data/locale/plugin.voice_control.fr.ini +0 -0
  283. pygpt_net/data/locale/plugin.voice_control.it.ini +0 -0
  284. pygpt_net/data/locale/plugin.voice_control.pl.ini +0 -0
  285. pygpt_net/data/locale/plugin.voice_control.uk.ini +0 -0
  286. pygpt_net/data/locale/plugin.voice_control.zh.ini +0 -0
  287. pygpt_net/data/locale/plugin.wolfram.en.ini +0 -0
  288. pygpt_net/fonts.qrc +0 -0
  289. pygpt_net/fonts_rc.py +0 -0
  290. pygpt_net/icons.qrc +0 -0
  291. pygpt_net/icons_rc.py +0 -0
  292. pygpt_net/item/agent.py +62 -0
  293. pygpt_net/item/builder_layout.py +62 -0
  294. pygpt_net/js.qrc +24 -1
  295. pygpt_net/js_rc.py +51394 -33687
  296. pygpt_net/plugin/base/worker.py +0 -0
  297. pygpt_net/plugin/mcp/__init__.py +0 -0
  298. pygpt_net/plugin/mcp/config.py +0 -0
  299. pygpt_net/plugin/mcp/plugin.py +0 -0
  300. pygpt_net/plugin/mcp/worker.py +0 -0
  301. pygpt_net/plugin/osm/__init__.py +0 -0
  302. pygpt_net/plugin/osm/config.py +0 -0
  303. pygpt_net/plugin/osm/plugin.py +0 -0
  304. pygpt_net/plugin/osm/worker.py +0 -0
  305. pygpt_net/plugin/wolfram/__init__.py +0 -0
  306. pygpt_net/plugin/wolfram/config.py +0 -0
  307. pygpt_net/plugin/wolfram/plugin.py +0 -0
  308. pygpt_net/plugin/wolfram/worker.py +0 -0
  309. pygpt_net/provider/api/anthropic/tools.py +0 -0
  310. pygpt_net/provider/api/google/__init__.py +0 -0
  311. pygpt_net/provider/api/google/video.py +0 -0
  312. pygpt_net/provider/api/openai/agents/experts.py +0 -0
  313. pygpt_net/provider/api/openai/agents/remote_tools.py +0 -0
  314. pygpt_net/provider/api/openai/remote_tools.py +0 -0
  315. pygpt_net/provider/api/openai/responses.py +0 -0
  316. pygpt_net/provider/api/x_ai/__init__.py +0 -0
  317. pygpt_net/provider/api/x_ai/remote.py +0 -0
  318. pygpt_net/provider/core/agent/__init__.py +10 -0
  319. pygpt_net/provider/core/agent/base.py +51 -0
  320. pygpt_net/provider/core/agent/json_file.py +200 -0
  321. pygpt_net/provider/core/config/patch.py +18 -0
  322. pygpt_net/provider/core/config/patches/__init__.py +0 -0
  323. pygpt_net/provider/core/config/patches/patch_before_2_6_42.py +0 -0
  324. pygpt_net/provider/core/ctx/db_sqlite/storage.py +0 -0
  325. pygpt_net/provider/core/model/patches/__init__.py +0 -0
  326. pygpt_net/provider/core/model/patches/patch_before_2_6_42.py +0 -0
  327. pygpt_net/provider/core/preset/patch.py +0 -0
  328. pygpt_net/provider/core/preset/patches/__init__.py +0 -0
  329. pygpt_net/provider/core/preset/patches/patch_before_2_6_42.py +0 -0
  330. pygpt_net/provider/llms/base.py +0 -0
  331. pygpt_net/provider/llms/deepseek_api.py +0 -0
  332. pygpt_net/provider/llms/google.py +0 -0
  333. pygpt_net/provider/llms/hugging_face_api.py +0 -0
  334. pygpt_net/provider/llms/hugging_face_embedding.py +0 -0
  335. pygpt_net/provider/llms/hugging_face_router.py +0 -0
  336. pygpt_net/provider/llms/local.py +0 -0
  337. pygpt_net/provider/llms/mistral.py +0 -0
  338. pygpt_net/provider/llms/open_router.py +0 -0
  339. pygpt_net/provider/llms/perplexity.py +0 -0
  340. pygpt_net/provider/llms/utils.py +0 -0
  341. pygpt_net/provider/llms/voyage.py +0 -0
  342. pygpt_net/provider/llms/x_ai.py +0 -0
  343. pygpt_net/tools/agent_builder/__init__.py +12 -0
  344. pygpt_net/tools/agent_builder/tool.py +292 -0
  345. pygpt_net/tools/agent_builder/ui/__init__.py +0 -0
  346. pygpt_net/tools/agent_builder/ui/dialogs.py +152 -0
  347. pygpt_net/tools/agent_builder/ui/list.py +228 -0
  348. pygpt_net/tools/code_interpreter/ui/html.py +0 -0
  349. pygpt_net/tools/code_interpreter/ui/widgets.py +0 -0
  350. pygpt_net/tools/html_canvas/tool.py +23 -6
  351. pygpt_net/tools/html_canvas/ui/widgets.py +224 -2
  352. pygpt_net/ui/layout/chat/chat.py +0 -0
  353. pygpt_net/ui/main.py +10 -9
  354. pygpt_net/ui/menu/debug.py +39 -1
  355. pygpt_net/ui/widget/builder/__init__.py +12 -0
  356. pygpt_net/ui/widget/builder/editor.py +2001 -0
  357. pygpt_net/ui/widget/draw/painter.py +0 -0
  358. pygpt_net/ui/widget/element/labels.py +9 -4
  359. pygpt_net/ui/widget/lists/db.py +0 -0
  360. pygpt_net/ui/widget/lists/debug.py +0 -0
  361. pygpt_net/ui/widget/tabs/body.py +0 -0
  362. pygpt_net/ui/widget/textarea/input.py +17 -8
  363. pygpt_net/ui/widget/textarea/output.py +21 -1
  364. pygpt_net/ui/widget/textarea/web.py +29 -2
  365. pygpt_net/utils.py +40 -0
  366. {pygpt_net-2.6.54.dist-info → pygpt_net-2.6.56.dist-info}/METADATA +13 -2
  367. {pygpt_net-2.6.54.dist-info → pygpt_net-2.6.56.dist-info}/RECORD +86 -47
  368. pygpt_net/data/js/app.js +0 -5869
  369. {pygpt_net-2.6.54.dist-info → pygpt_net-2.6.56.dist-info}/LICENSE +0 -0
  370. {pygpt_net-2.6.54.dist-info → pygpt_net-2.6.56.dist-info}/WHEEL +0 -0
  371. {pygpt_net-2.6.54.dist-info → pygpt_net-2.6.56.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,478 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # ================================================== #
4
+ # This file is a part of PYGPT package #
5
+ # Website: https://pygpt.net #
6
+ # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
+ # MIT License #
8
+ # Created By : Marcin Szczygliński #
9
+ # Updated Date: 2025.09.19 00:00:00 #
10
+ # ================================================== #
11
+
12
+ from __future__ import annotations
13
+ from typing import Dict, List, Optional, Tuple, Any
14
+ from dataclasses import dataclass, field
15
+ from uuid import uuid4
16
+ from PySide6.QtCore import QObject, Signal
17
+ import re
18
+
19
+
20
+ def gen_uuid() -> str:
21
+ return str(uuid4())
22
+
23
+
24
+ # ------------------------ Data models (pure data) ------------------------
25
+
26
+ @dataclass
27
+ class PropertyModel:
28
+ uuid: str
29
+ id: str
30
+ type: str # "slot", "str", "int", "float", "bool", "combo", "text"
31
+ name: str
32
+ editable: bool = True
33
+ value: Any = None
34
+ allowed_inputs: int = 0 # 0 none, -1 unlimited, >0 limit
35
+ allowed_outputs: int = 0 # 0 none, -1 unlimited, >0 limit
36
+ options: Optional[List[str]] = None # for combo
37
+
38
+ def to_dict(self) -> dict:
39
+ return {
40
+ "uuid": self.uuid,
41
+ "id": self.id,
42
+ "type": self.type,
43
+ "name": self.name,
44
+ "editable": self.editable,
45
+ "value": self.value,
46
+ "allowed_inputs": self.allowed_inputs,
47
+ "allowed_outputs": self.allowed_outputs,
48
+ "options": self.options or [],
49
+ }
50
+
51
+ @staticmethod
52
+ def from_dict(d: dict) -> "PropertyModel":
53
+ return PropertyModel(
54
+ uuid=d.get("uuid", gen_uuid()),
55
+ id=d["id"],
56
+ type=d["type"],
57
+ name=d.get("name", d["id"]),
58
+ editable=d.get("editable", True),
59
+ value=d.get("value"),
60
+ allowed_inputs=d.get("allowed_inputs", 0),
61
+ allowed_outputs=d.get("allowed_outputs", 0),
62
+ options=d.get("options") or None,
63
+ )
64
+
65
+
66
+ @dataclass
67
+ class NodeModel:
68
+ uuid: str
69
+ id: str
70
+ name: str
71
+ type: str
72
+ properties: Dict[str, PropertyModel] = field(default_factory=dict)
73
+
74
+ def to_dict(self) -> dict:
75
+ return {
76
+ "uuid": self.uuid,
77
+ "id": self.id,
78
+ "name": self.name,
79
+ "type": self.type,
80
+ "properties": {pid: p.to_dict() for pid, p in self.properties.items()},
81
+ }
82
+
83
+ @staticmethod
84
+ def from_dict(d: dict) -> "NodeModel":
85
+ props = {pid: PropertyModel.from_dict(pd) for pid, pd in d.get("properties", {}).items()}
86
+ return NodeModel(
87
+ uuid=d.get("uuid", gen_uuid()),
88
+ id=d["id"],
89
+ name=d.get("name", d["id"]),
90
+ type=d["type"],
91
+ properties=props,
92
+ )
93
+
94
+
95
+ @dataclass
96
+ class ConnectionModel:
97
+ uuid: str
98
+ src_node: str
99
+ src_prop: str
100
+ dst_node: str
101
+ dst_prop: str
102
+
103
+ def to_dict(self) -> dict:
104
+ return {
105
+ "uuid": self.uuid,
106
+ "src_node": self.src_node, "src_prop": self.src_prop,
107
+ "dst_node": self.dst_node, "dst_prop": self.dst_prop,
108
+ }
109
+
110
+ @staticmethod
111
+ def from_dict(d: dict) -> "ConnectionModel":
112
+ return ConnectionModel(
113
+ uuid=d.get("uuid", gen_uuid()),
114
+ src_node=d["src_node"], src_prop=d["src_prop"],
115
+ dst_node=d["dst_node"], dst_prop=d["dst_prop"],
116
+ )
117
+
118
+
119
+ # ------------------------ Types registry (templates) ------------------------
120
+
121
+ @dataclass
122
+ class PropertySpec:
123
+ id: str
124
+ type: str
125
+ name: Optional[str] = None
126
+ editable: bool = True
127
+ value: Any = None
128
+ allowed_inputs: int = 0
129
+ allowed_outputs: int = 0
130
+ options: Optional[List[str]] = None
131
+
132
+
133
+ @dataclass
134
+ class NodeTypeSpec:
135
+ type_name: str
136
+ title: Optional[str] = None
137
+ properties: List[PropertySpec] = field(default_factory=list)
138
+ # Below are optional extensions for agent-flow needs:
139
+ base_id: Optional[str] = None # base prefix for friendly ids, e.g. "agent"
140
+ export_kind: Optional[str] = None # short kind for export, e.g. "agent", "start"
141
+ bg_color: Optional[str] = None # optional per-type background color (CSS/hex)
142
+
143
+ class NodeTypeRegistry:
144
+ """Registry for node type specifications. Extend/override in subclasses."""
145
+ def __init__(self):
146
+ self._types: Dict[str, NodeTypeSpec] = {}
147
+ self._install_default_types()
148
+
149
+ def register(self, spec: NodeTypeSpec):
150
+ self._types[spec.type_name] = spec
151
+
152
+ def types(self) -> List[str]:
153
+ return list(self._types.keys())
154
+
155
+ def get(self, type_name: str) -> Optional[NodeTypeSpec]:
156
+ return self._types.get(type_name)
157
+
158
+ def _install_default_types(self):
159
+ # Example/basic nodes kept intact
160
+ self.register(NodeTypeSpec(
161
+ type_name="Value/Float",
162
+ title="Float",
163
+ properties=[
164
+ PropertySpec(id="value", type="float", name="Value", editable=True, value=0.0,
165
+ allowed_inputs=0, allowed_outputs=1),
166
+ ]
167
+ ))
168
+ self.register(NodeTypeSpec(
169
+ type_name="Math/Add",
170
+ title="Add",
171
+ properties=[
172
+ PropertySpec(id="A", type="float", name="A", editable=True, value=0.0, allowed_inputs=1, allowed_outputs=0),
173
+ PropertySpec(id="B", type="float", name="B", editable=True, value=0.0, allowed_inputs=1, allowed_outputs=0),
174
+ PropertySpec(id="result", type="float", name="Result", editable=False, value=None, allowed_inputs=0, allowed_outputs=1),
175
+ ]
176
+ ))
177
+ # Tip: to allow multiple connections to an input or output, set allowed_inputs/allowed_outputs to -1.
178
+
179
+ # Agent-flow nodes
180
+ # Start
181
+ self.register(NodeTypeSpec(
182
+ type_name="Flow/Start",
183
+ title="Start",
184
+ base_id="start",
185
+ export_kind="start",
186
+ bg_color="#2D5A27",
187
+ properties=[
188
+ PropertySpec(id="output", type="flow", name="Output", editable=False, allowed_inputs=0, allowed_outputs=1),
189
+ # base_id will be auto-injected as read-only property at creation
190
+ ],
191
+ ))
192
+ # Agent
193
+ self.register(NodeTypeSpec(
194
+ type_name="Flow/Agent",
195
+ title="Agent",
196
+ base_id="agent",
197
+ export_kind="agent",
198
+ bg_color="#304A6E",
199
+ properties=[
200
+ PropertySpec(id="name", type="str", name="Name", editable=True, value=""),
201
+ PropertySpec(id="instruction", type="text", name="Instruction", editable=True, value=""),
202
+ PropertySpec(id="remote_tools", type="bool", name="Remote tools", editable=True, value=True),
203
+ PropertySpec(id="local_tools", type="bool", name="Local tools", editable=True, value=True),
204
+ PropertySpec(id="input", type="flow", name="Input", editable=False, allowed_inputs=-1, allowed_outputs=0),
205
+ PropertySpec(id="output", type="flow", name="Output", editable=False, allowed_inputs=0, allowed_outputs=1),
206
+ PropertySpec(id="memory", type="memory", name="Memory", editable=False, allowed_inputs=0, allowed_outputs=1),
207
+ ],
208
+ ))
209
+ # Memory
210
+ self.register(NodeTypeSpec(
211
+ type_name="Flow/Memory",
212
+ title="Memory",
213
+ base_id="mem",
214
+ export_kind="memory",
215
+ bg_color="#593E78",
216
+ properties=[
217
+ PropertySpec(id="name", type="str", name="Name", editable=True, value=""),
218
+ PropertySpec(id="input", type="memory", name="Input", editable=False, allowed_inputs=-1, allowed_outputs=0),
219
+ ],
220
+ ))
221
+ # End
222
+ self.register(NodeTypeSpec(
223
+ type_name="Flow/End",
224
+ title="End",
225
+ base_id="end",
226
+ export_kind="end",
227
+ bg_color="#6B2E2E",
228
+ properties=[
229
+ PropertySpec(id="input", type="flow", name="Input", editable=False, allowed_inputs=1, allowed_outputs=0),
230
+ ],
231
+ ))
232
+
233
+
234
+ # ------------------------ Graph (Qt QObject + signals) ------------------------
235
+
236
+ class NodeGraph(QObject):
237
+ """In-memory node graph with Qt signals, easily serializable."""
238
+ nodeAdded = Signal(object) # NodeModel
239
+ nodeRemoved = Signal(str) # node uuid
240
+ connectionAdded = Signal(object) # ConnectionModel
241
+ connectionRemoved = Signal(str) # connection uuid
242
+ cleared = Signal()
243
+ propertyValueChanged = Signal(str, str, object) # node_uuid, prop_id, new_value
244
+
245
+ def __init__(self, registry: Optional[NodeTypeRegistry] = None):
246
+ super().__init__()
247
+ self.registry = registry or NodeTypeRegistry()
248
+ self.nodes: Dict[str, NodeModel] = {}
249
+ self.connections: Dict[str, ConnectionModel] = {}
250
+ self._node_counter = 1
251
+ # Per-base_id counters for friendly IDs (persisted with layout)
252
+ self._id_counters: Dict[str, int] = {}
253
+
254
+ # -------- ID helpers (friendly unique IDs per base prefix) --------
255
+
256
+ @staticmethod
257
+ def _slug_from_type_name(type_name: str) -> str:
258
+ # fallback base id from type name: last segment lowercased, non-words to underscore
259
+ base = type_name.split("/")[-1].lower()
260
+ base = re.sub(r"\W+", "_", base).strip("_")
261
+ return base or "node"
262
+
263
+ def _next_id_for_base(self, base: str) -> str:
264
+ n = self._id_counters.get(base, 0) + 1
265
+ self._id_counters[base] = n
266
+ return f"{base}_{n}"
267
+
268
+ def _seed_counters_from_existing(self):
269
+ # Scan existing node ids like 'agent_12' and seed counters to max per base
270
+ for node in self.nodes.values():
271
+ m = re.match(r"^([a-zA-Z0-9]+)_(\d+)$", node.id)
272
+ if not m:
273
+ continue
274
+ base, num = m.group(1), int(m.group(2))
275
+ cur = self._id_counters.get(base, 0)
276
+ if num > cur:
277
+ self._id_counters[base] = num
278
+
279
+ # -------- Creation / mutation --------
280
+
281
+ def create_node_from_type(self, type_name: str, name: Optional[str] = None) -> NodeModel:
282
+ spec = self.registry.get(type_name)
283
+ if not spec:
284
+ raise ValueError(f"Unknown node type: {type_name}")
285
+
286
+ base_id = spec.base_id or self._slug_from_type_name(type_name)
287
+ # Generate friendly id if base configured; otherwise fallback to generic Node-#
288
+ if spec.base_id:
289
+ nid = self._next_id_for_base(base_id)
290
+ else:
291
+ nid = f"Node-{self._node_counter}"
292
+ self._node_counter += 1
293
+
294
+ props: Dict[str, PropertyModel] = {}
295
+ for ps in spec.properties:
296
+ props[ps.id] = PropertyModel(
297
+ uuid=gen_uuid(), id=ps.id, type=ps.type, name=ps.name or ps.id,
298
+ editable=ps.editable, value=ps.value,
299
+ allowed_inputs=ps.allowed_inputs, allowed_outputs=ps.allowed_outputs,
300
+ options=ps.options
301
+ )
302
+ # Auto inject read-only 'base_id' property for visibility if base_id defined and not present
303
+ if spec.base_id and "base_id" not in props:
304
+ props["base_id"] = PropertyModel(
305
+ uuid=gen_uuid(), id="base_id", type="str", name="Base ID",
306
+ editable=False, value=base_id, allowed_inputs=0, allowed_outputs=0
307
+ )
308
+
309
+ node = NodeModel(uuid=gen_uuid(), id=nid, name=name or spec.title or nid, type=type_name, properties=props)
310
+ return node
311
+
312
+ def add_node(self, node: NodeModel):
313
+ self.nodes[node.uuid] = node
314
+ # Ensure counters are aware of externally provided nodes
315
+ m = re.match(r"^([a-zA-Z0-9]+)_(\d+)$", node.id)
316
+ if m:
317
+ base, num = m.group(1), int(m.group(2))
318
+ if self._id_counters.get(base, 0) < num:
319
+ self._id_counters[base] = num
320
+ self.nodeAdded.emit(node)
321
+
322
+ def remove_node(self, node_uuid: str):
323
+ to_remove = [cid for cid, c in self.connections.items()
324
+ if c.src_node == node_uuid or c.dst_node == node_uuid]
325
+ for cid in to_remove:
326
+ self.remove_connection(cid)
327
+ if node_uuid in self.nodes:
328
+ del self.nodes[node_uuid]
329
+ self.nodeRemoved.emit(node_uuid)
330
+
331
+ def can_connect(self, src: Tuple[str, str], dst: Tuple[str, str]) -> Tuple[bool, str]:
332
+ src_node_uuid, src_prop_id = src
333
+ dst_node_uuid, dst_prop_id = dst
334
+ if src_node_uuid == dst_node_uuid and src_prop_id == dst_prop_id:
335
+ return False, "Cannot connect a port to itself."
336
+ src_node = self.nodes.get(src_node_uuid)
337
+ dst_node = self.nodes.get(dst_node_uuid)
338
+ if not src_node or not dst_node:
339
+ return False, "Node not found."
340
+ sp = src_node.properties.get(src_prop_id)
341
+ dp = dst_node.properties.get(dst_prop_id)
342
+ if not sp or not dp:
343
+ return False, "Property not found."
344
+ if sp.allowed_outputs == 0:
345
+ return False, "Source has no outputs."
346
+ if dp.allowed_inputs == 0:
347
+ return False, "Destination has no inputs."
348
+ if sp.type != dp.type:
349
+ return False, f"Type mismatch: {sp.type} -> {dp.type}"
350
+ if dp.allowed_inputs > 0:
351
+ count = sum(1 for c in self.connections.values()
352
+ if c.dst_node == dst_node_uuid and c.dst_prop == dst_prop_id)
353
+ if count >= dp.allowed_inputs:
354
+ return False, "Destination input limit reached."
355
+ if sp.allowed_outputs > 0:
356
+ count = sum(1 for c in self.connections.values()
357
+ if c.src_node == src_node_uuid and c.src_prop == src_prop_id)
358
+ if count >= sp.allowed_outputs:
359
+ return False, "Source output limit reached."
360
+ return True, ""
361
+
362
+ def add_connection(self, conn: ConnectionModel) -> Tuple[bool, str]:
363
+ ok, reason = self.can_connect((conn.src_node, conn.src_prop), (conn.dst_node, conn.dst_prop))
364
+ if not ok:
365
+ return False, reason
366
+ for c in self.connections.values():
367
+ if c.src_node == conn.src_node and c.src_prop == conn.src_prop and \
368
+ c.dst_node == conn.dst_node and c.dst_prop == conn.dst_prop:
369
+ return False, "Connection already exists."
370
+ self.connections[conn.uuid] = conn
371
+ self.connectionAdded.emit(conn)
372
+ return True, ""
373
+
374
+ def connect(self, src: Tuple[str, str], dst: Tuple[str, str]) -> Tuple[bool, str, Optional[ConnectionModel]]:
375
+ conn = ConnectionModel(uuid=gen_uuid(), src_node=src[0], src_prop=src[1], dst_node=dst[0], dst_prop=dst[1])
376
+ ok, reason = self.add_connection(conn)
377
+ return ok, reason, conn if ok else None
378
+
379
+ def remove_connection(self, conn_uuid: str):
380
+ if conn_uuid in self.connections:
381
+ del self.connections[conn_uuid]
382
+ self.connectionRemoved.emit(conn_uuid)
383
+
384
+ def set_property_value(self, node_uuid: str, prop_id: str, value: Any):
385
+ node = self.nodes.get(node_uuid)
386
+ if not node:
387
+ return
388
+ prop = node.properties.get(prop_id)
389
+ if not prop or not prop.editable:
390
+ return
391
+ prop.value = value
392
+ self.propertyValueChanged.emit(node_uuid, prop_id, value)
393
+
394
+ def to_dict(self) -> dict:
395
+ return {
396
+ "nodes": {nuuid: n.to_dict() for nuuid, n in self.nodes.items()},
397
+ "connections": {c.uuid: c.to_dict() for c in self.connections.values()},
398
+ "_node_counter": self._node_counter,
399
+ "_id_counters": dict(self._id_counters),
400
+ }
401
+
402
+ def to_schema(self) -> dict:
403
+ nodes_out: Dict[str, dict] = {}
404
+ for nuuid, n in self.nodes.items():
405
+ nodes_out[nuuid] = {
406
+ "type": n.type,
407
+ "id": n.id,
408
+ "name": n.name,
409
+ "values": {pid: p.value for pid, p in n.properties.items()},
410
+ }
411
+ conns_out = [{"src": [c.src_node, c.src_prop], "dst": [c.dst_node, c.dst_prop]}
412
+ for c in self.connections.values()]
413
+ return {"nodes": nodes_out, "connections": conns_out}
414
+
415
+ # --- Export to requested agent schema (list of nodes with slots/in-out) ---
416
+ def to_agent_schema(self) -> List[dict]:
417
+ # Build helper maps
418
+ uuid_to_node: Dict[str, NodeModel] = dict(self.nodes)
419
+ uuid_to_id: Dict[str, str] = {u: n.id for u, n in uuid_to_node.items()}
420
+ # Pre-index connections by (node_uuid, prop_id)
421
+ incoming: Dict[Tuple[str, str], List[str]] = {}
422
+ outgoing: Dict[Tuple[str, str], List[str]] = {}
423
+ for c in self.connections.values():
424
+ outgoing.setdefault((c.src_node, c.src_prop), []).append(uuid_to_id.get(c.dst_node, c.dst_node))
425
+ incoming.setdefault((c.dst_node, c.dst_prop), []).append(uuid_to_id.get(c.src_node, c.src_node))
426
+
427
+ result: List[dict] = []
428
+ for n in uuid_to_node.values():
429
+ spec = self.registry.get(n.type)
430
+ kind = spec.export_kind if spec and spec.export_kind else n.type.split("/")[-1].lower()
431
+ slots: Dict[str, Any] = {}
432
+ for pid, prop in n.properties.items():
433
+ is_port = (prop.allowed_inputs != 0) or (prop.allowed_outputs != 0)
434
+ if is_port:
435
+ slots[pid] = {
436
+ "in": list(incoming.get((n.uuid, pid), [])),
437
+ "out": list(outgoing.get((n.uuid, pid), [])),
438
+ }
439
+ else:
440
+ # Skip internal helper fields if needed
441
+ if pid == "base_id":
442
+ continue
443
+ slots[pid] = prop.value
444
+ result.append({
445
+ "type": kind,
446
+ "id": n.id,
447
+ "slots": slots,
448
+ })
449
+
450
+ # Stable order by id
451
+ result.sort(key=lambda d: d["id"])
452
+ return result
453
+
454
+ def from_dict(self, d: dict):
455
+ self.clear(silent=True)
456
+ nodes_d = d.get("nodes", {})
457
+ for nuuid, nd in nodes_d.items():
458
+ node = NodeModel.from_dict(nd)
459
+ self.nodes[node.uuid] = node
460
+ conns_d = d.get("connections", {})
461
+ for cid, cd in conns_d.items():
462
+ conn = ConnectionModel.from_dict(cd)
463
+ self.connections[conn.uuid] = conn
464
+ self._node_counter = d.get("_node_counter", len(self.nodes) + 1)
465
+ self._id_counters = dict(d.get("_id_counters", {}))
466
+ # Seed counters from existing node ids if counters were not present
467
+ if not self._id_counters:
468
+ self._seed_counters_from_existing()
469
+ for n in self.nodes.values():
470
+ self.nodeAdded.emit(n)
471
+ for c in self.connections.values():
472
+ self.connectionAdded.emit(c)
473
+
474
+ def clear(self, silent: bool = False):
475
+ self.nodes.clear()
476
+ self.connections.clear()
477
+ if not silent:
478
+ self.cleared.emit()
File without changes
pygpt_net/core/ctx/ctx.py CHANGED
@@ -727,9 +727,10 @@ class Ctx:
727
727
  :param id: ctx id
728
728
  :return: ctx meta object
729
729
  """
730
- self.load_tmp_meta(id)
731
730
  if id in self.meta:
732
731
  return self.meta[id]
732
+ else:
733
+ self.load_tmp_meta(id)
733
734
 
734
735
  def get_last(self) -> Optional[CtxItem]:
735
736
  """
File without changes
File without changes
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # ================================================== #
4
+ # This file is a part of PYGPT package #
5
+ # Website: https://pygpt.net #
6
+ # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
+ # MIT License #
8
+ # Created By : Marcin Szczygliński #
9
+ # Updated Date: 2025.09.19 00:00:00 #
10
+ # ================================================== #
11
+
12
+ class AgentBuilderDebug:
13
+ def __init__(self, window=None):
14
+ """
15
+ Agent debug
16
+
17
+ :param window: Window instance
18
+ """
19
+ self.window = window
20
+ self.id = 'agent_builder'
21
+
22
+ def update(self):
23
+ """Update debug window"""
24
+ debug = self.window.core.debug
25
+ editor = self.window.ui.editor["agent.builder"]
26
+
27
+ debug.begin(self.id)
28
+ debug.add(self.id, 'nodes', str(editor.debug_state()))
29
+ debug.end(self.id)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -383,12 +383,16 @@ class Renderer(BaseRenderer):
383
383
  :param meta: context meta
384
384
  """
385
385
  node = self.get_output_node(meta)
386
+ follow = getattr(node, "was_at_bottom", None)
387
+ follow = node.was_at_bottom() if callable(follow) else True
386
388
  cursor = node.textCursor()
387
389
  cursor.movePosition(QTextCursor.End)
388
390
  block_format = QTextBlockFormat()
389
391
  block_format.setIndent(0)
390
392
  cursor.insertBlock(block_format)
391
- node.setTextCursor(cursor)
393
+ if follow or (hasattr(node, "is_auto_scroll_enabled") and node.is_auto_scroll_enabled()):
394
+ node.setTextCursor(cursor)
395
+ node.ensureCursorVisible()
392
396
 
393
397
  def append_raw(
394
398
  self,
@@ -404,12 +408,16 @@ class Renderer(BaseRenderer):
404
408
  :param text: text to append
405
409
  """
406
410
  node = self.get_output_node(meta)
411
+ follow = getattr(node, "was_at_bottom", None)
412
+ follow = node.was_at_bottom() if callable(follow) else True
407
413
  cur = node.textCursor()
408
414
  cur.movePosition(QTextCursor.End)
409
415
  if not node.document().isEmpty():
410
416
  cur.insertText("\n\n")
411
417
  cur.insertText(text.strip())
412
- node.setTextCursor(cur)
418
+ if follow or (hasattr(node, "is_auto_scroll_enabled") and node.is_auto_scroll_enabled()):
419
+ node.setTextCursor(cur)
420
+ node.ensureCursorVisible()
413
421
 
414
422
  def append_chunk_start(self, meta: CtxMeta, ctx: CtxItem):
415
423
  """
@@ -419,9 +427,13 @@ class Renderer(BaseRenderer):
419
427
  :param ctx: context item
420
428
  """
421
429
  node = self.get_output_node(meta)
430
+ follow = getattr(node, "was_at_bottom", None)
431
+ follow = node.was_at_bottom() if callable(follow) else True
422
432
  cursor = node.textCursor()
423
433
  cursor.movePosition(QTextCursor.End)
424
- node.setTextCursor(cursor)
434
+ if follow or (hasattr(node, "is_auto_scroll_enabled") and node.is_auto_scroll_enabled()):
435
+ node.setTextCursor(cursor)
436
+ node.ensureCursorVisible()
425
437
 
426
438
  def append_context_item(
427
439
  self,
@@ -454,10 +466,14 @@ class Renderer(BaseRenderer):
454
466
  :param end: end of the line character
455
467
  """
456
468
  node = self.get_output_node(meta)
469
+ follow = getattr(node, "was_at_bottom", None)
470
+ follow = node.was_at_bottom() if callable(follow) else True
457
471
  cur = node.textCursor()
458
472
  cur.movePosition(QTextCursor.End)
459
473
  cur.insertText(f"{str(text)}{end}")
460
- node.setTextCursor(cur)
474
+ if follow or (hasattr(node, "is_auto_scroll_enabled") and node.is_auto_scroll_enabled()):
475
+ node.setTextCursor(cur)
476
+ node.ensureCursorVisible()
461
477
 
462
478
  def append_timestamp(
463
479
  self,
@@ -514,9 +530,15 @@ class Renderer(BaseRenderer):
514
530
  :param meta: context meta
515
531
  """
516
532
  node = self.get_output_node(meta)
533
+ was_bottom = getattr(node, "was_at_bottom", None)
534
+ was_bottom = node.was_at_bottom() if callable(was_bottom) else True
535
+ allow = was_bottom or (hasattr(node, "is_auto_scroll_enabled") and node.is_auto_scroll_enabled())
536
+ if not allow:
537
+ return
517
538
  cursor = node.textCursor()
518
539
  cursor.movePosition(QTextCursor.End)
519
540
  node.setTextCursor(cursor)
541
+ node.ensureCursorVisible()
520
542
 
521
543
  def is_timestamp_enabled(self) -> bool:
522
544
  """