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,292 @@
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 datetime import datetime
13
+ from typing import Dict
14
+
15
+ from PySide6 import QtCore
16
+ from PySide6.QtGui import QAction, QIcon
17
+
18
+ from pygpt_net.tools.base import BaseTool
19
+ from pygpt_net.utils import trans
20
+
21
+ from .ui.dialogs import Builder
22
+
23
+ class AgentBuilder(BaseTool):
24
+ def __init__(self, *args, **kwargs):
25
+ """
26
+ Agent builder (nodes editor)
27
+
28
+ :param window: Window instance
29
+ """
30
+ super(AgentBuilder, self).__init__(*args, **kwargs)
31
+ self.id = "agent_builder"
32
+ self.opened = False
33
+ self.dialog = None # dialog
34
+ self.initialized = False
35
+ self.current_agent = None # current agent ID
36
+
37
+ def setup(self):
38
+ """Setup controller"""
39
+ pass
40
+
41
+ def update(self):
42
+ """Update"""
43
+ pass
44
+
45
+ def save(self):
46
+ """Save layout to file"""
47
+ if "agent.builder" not in self.window.ui.editor:
48
+ return
49
+ custom = self.window.core.agents.custom
50
+ layout = self.window.ui.editor["agent.builder"].save_layout()
51
+ custom.update_layout(layout)
52
+ if self.current_agent:
53
+ custom.update_agent_layout(self.current_agent, layout)
54
+ custom.save()
55
+ self.window.update_status(f"Saved at: {datetime.now().strftime('%H:%M:%S')}")
56
+
57
+ def load(self):
58
+ """Load layout from file"""
59
+ self.restore()
60
+
61
+ def open(self):
62
+ """Open dialog"""
63
+ if not self.initialized:
64
+ self.dialog = Builder(self.window, tool=self)
65
+ self.dialog.setup()
66
+ self.restore()
67
+ self.initialized = True
68
+ self.window.ui.dialogs.open('agent.builder', width=900, height=600)
69
+ self.opened = True
70
+ self.update()
71
+
72
+ def close(self):
73
+ """Close dialog"""
74
+ self.window.ui.dialogs.close('agent.builder')
75
+ self.opened = False
76
+
77
+ def toggle(self):
78
+ """Toggle dialog window"""
79
+ if self.opened:
80
+ self.close()
81
+ else:
82
+ self.open()
83
+
84
+ def store_current(self):
85
+ """Store current to file"""
86
+ self.save()
87
+
88
+ def restore(self):
89
+ """Restore layout and agents from file"""
90
+ layout = self.window.core.agents.custom.get_layout()
91
+ if layout:
92
+ data = layout.data
93
+ if data:
94
+ self.window.ui.editor["agent.builder"].load_layout(data)
95
+ self.window.update_status(f"Loaded layout at: {datetime.now().strftime('%H:%M:%S')}")
96
+
97
+ self.update_list()
98
+
99
+ # select first agent on list
100
+ agents = self.window.core.agents.custom.get_agents()
101
+ if agents and len(agents) > 0:
102
+ first_agent_id = list(agents.keys())[0]
103
+ self.edit_agent(first_agent_id)
104
+
105
+ def show_hide(self, show: bool = True):
106
+ """
107
+ Show/hide dialog window
108
+
109
+ :param show: show/hide
110
+ """
111
+ if show:
112
+ self.open()
113
+ else:
114
+ self.close()
115
+
116
+ def on_close(self):
117
+ """On window close"""
118
+ self.opened = False
119
+ self.update()
120
+
121
+ def on_exit(self):
122
+ """On exit"""
123
+ self.store_current()
124
+
125
+ def clear(self, force: bool = False):
126
+ """
127
+ Clear layout
128
+
129
+ :param force: force clear
130
+ """
131
+ if not force:
132
+ self.window.ui.dialogs.confirm(
133
+ type='agent.builder.agent.clear',
134
+ id=0,
135
+ msg=trans('agent.builder.confirm.clear.msg'),
136
+ )
137
+ return
138
+ if self.window.ui.editor["agent.builder"].clear(ask_user=False):
139
+ self.save()
140
+
141
+ def add_agent(self, name: str = None):
142
+ """Add new agent"""
143
+ if name is None:
144
+ self.window.ui.dialog['create'].id = 'agent.builder.agent'
145
+ self.window.ui.dialog['create'].input.setText("")
146
+ self.window.ui.dialog['create'].current = ""
147
+ self.window.ui.dialog['create'].show()
148
+ self.window.ui.dialog['create'].input.setFocus()
149
+ return
150
+ uuid = self.window.core.agents.custom.new_agent(name)
151
+ if uuid:
152
+ self.update_list()
153
+ self.window.ui.editor["agent.builder"].clear(ask_user=False)
154
+ self.window.ui.dialogs.close('create')
155
+ self.edit_agent(uuid)
156
+
157
+ def rename_agent(self, agent_id: str, name: str = None):
158
+ """
159
+ Rename agent
160
+
161
+ :param agent_id: agent ID
162
+ :param name: new name
163
+ """
164
+ agent = self.window.core.agents.custom.get_agent(agent_id)
165
+ if not agent:
166
+ print("Agent not found:", agent_id)
167
+ return
168
+ current_name = agent.name
169
+ if name is None:
170
+ self.window.ui.dialog['rename'].id = 'agent.builder.agent'
171
+ self.window.ui.dialog['rename'].input.setText(current_name)
172
+ self.window.ui.dialog['rename'].current =agent_id
173
+ self.window.ui.dialog['rename'].show()
174
+ self.window.ui.dialog['rename'].input.setFocus()
175
+ return
176
+ if agent:
177
+ agent.name = name
178
+ self.window.core.agents.custom.save()
179
+ self.update_list()
180
+ self.window.ui.dialogs.close('rename')
181
+
182
+ def edit_agent(self, agent_id: str):
183
+ """
184
+ Edit agent
185
+
186
+ :param agent_id: agent ID
187
+ """
188
+ self.save()
189
+ self.current_agent = agent_id
190
+ agent = self.window.core.agents.custom.get_agent(agent_id)
191
+ if agent:
192
+ layout = agent.layout
193
+ if layout:
194
+ self.window.ui.editor["agent.builder"].load_layout(layout)
195
+ else:
196
+ self.window.ui.editor["agent.builder"].clear(ask_user=False)
197
+ self.select_on_list(agent_id)
198
+
199
+ def duplicate_agent(self, agent_id: str):
200
+ """
201
+ Duplicate agent
202
+
203
+ :param agent_id: agent ID
204
+ """
205
+ agent = self.window.core.agents.custom.get_agent(agent_id)
206
+ if agent:
207
+ new_name = f"{agent.name} (copy)"
208
+ self.window.core.agents.custom.duplicate_agent(agent_id, new_name)
209
+ self.update_list()
210
+
211
+ def delete_agent(self, agent_id: str, force: bool = False):
212
+ """
213
+ Delete agent
214
+
215
+ :param agent_id: agent ID
216
+ :param force: force delete without confirmation
217
+ """
218
+ if not force:
219
+ self.window.ui.dialogs.confirm(
220
+ type='agent.builder.agent.delete',
221
+ id=agent_id,
222
+ msg=trans('agent.builder.confirm.delete.msg'),
223
+ )
224
+ return
225
+ self.window.core.agents.custom.delete_agent(agent_id)
226
+ self.update_list()
227
+ if self.current_agent == agent_id:
228
+ self.current_agent = None
229
+ self.window.ui.editor["agent.builder"].clear(ask_user=False)
230
+
231
+ def update_list(self):
232
+ """Update agents list"""
233
+ data = self.window.core.agents.custom.get_agents()
234
+ self.window.ui.nodes["agent.builder.list"].update_list(data)
235
+
236
+ def select_on_list(self, agent_id: str):
237
+ """
238
+ Select agent on list
239
+
240
+ :param agent_id: agent ID
241
+ """
242
+ nodes = self.window.ui.nodes
243
+ models = self.window.ui.models
244
+
245
+ agents_list = nodes["agent.builder.list"].list
246
+ model = models.get("agent.builder.list")
247
+
248
+ if model is None:
249
+ return
250
+ for row in range(model.rowCount()):
251
+ idx = model.index(row, 0)
252
+ if str(model.data(idx, QtCore.Qt.UserRole)) == str(agent_id):
253
+ agents_list.setCurrentIndex(idx)
254
+ sm = agents_list.selectionModel()
255
+ if sm:
256
+ sm.select(idx, QtCore.QItemSelectionModel.ClearAndSelect)
257
+ agents_list.scrollTo(idx)
258
+ break
259
+
260
+ def setup_menu(self) -> Dict[str, QAction]:
261
+ """
262
+ Setup main menu
263
+
264
+ :return dict with menu actions
265
+ """
266
+ actions = {}
267
+ actions["agent.builder"] = QAction(
268
+ QIcon(":/icons/robot.svg"),
269
+ trans("menu.tools.agent.builder"),
270
+ self.window,
271
+ checkable=False,
272
+ )
273
+ actions["agent.builder"].triggered.connect(
274
+ lambda: self.toggle()
275
+ )
276
+ return actions
277
+
278
+ def setup_dialogs(self):
279
+ """Setup dialogs (static)"""
280
+ pass
281
+
282
+ def get_lang_mappings(self) -> Dict[str, Dict]:
283
+ """
284
+ Get language mappings
285
+
286
+ :return: dict with language mappings
287
+ """
288
+ return {
289
+ 'menu.text': {
290
+ 'tools.agent.builder': 'menu.tools.agent.builder',
291
+ }
292
+ }
File without changes
@@ -0,0 +1,152 @@
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 PySide6.QtCore import Qt
13
+ from PySide6.QtGui import QAction, QIcon
14
+ from PySide6.QtWidgets import QVBoxLayout, QMenuBar, QSplitter
15
+
16
+ from pygpt_net.tools.agent_builder.ui.list import AgentsWidget
17
+ from pygpt_net.ui.widget.builder.editor import NodeEditor
18
+ from pygpt_net.ui.widget.dialog.base import BaseDialog
19
+ from pygpt_net.utils import trans
20
+
21
+
22
+ class Builder:
23
+
24
+ def __init__(self, window=None, tool=None):
25
+ """
26
+ Builder dialog
27
+
28
+ :param window: Window instance
29
+ """
30
+ self.window = window
31
+ self.tool = tool
32
+ self.menu_bar = None
33
+ self.file_menu = None
34
+ self.actions = {}
35
+
36
+ def setup_menu(self, parent=None) -> QMenuBar:
37
+ """Setup audio agent_builder dialog menu"""
38
+ self.menu_bar = QMenuBar(parent)
39
+ self.file_menu = self.menu_bar.addMenu(trans("menu.file"))
40
+ t = self.tool
41
+
42
+ self.actions["open"] = QAction(QIcon(":/icons/folder.svg"), trans("action.open"), self.menu_bar)
43
+ self.actions["open"].triggered.connect(lambda checked=False, t=t: t.load())
44
+
45
+ self.actions["save"] = QAction(QIcon(":/icons/save.svg"), trans("action.save"), self.menu_bar)
46
+ self.actions["save"].triggered.connect(lambda checked=False, t=t: t.save())
47
+
48
+ self.actions["clear"] = QAction(QIcon(":/icons/clear.svg"), trans("action.clear"), self.menu_bar)
49
+ self.actions["clear"].triggered.connect(lambda checked=False, t=t: t.clear())
50
+
51
+ self.file_menu.addAction(self.actions["open"])
52
+ self.file_menu.addAction(self.actions["save"])
53
+ self.file_menu.addAction(self.actions["clear"])
54
+ return self.menu_bar
55
+
56
+ def setup(self):
57
+ """Setup agent_builder dialog"""
58
+ id = 'agent.builder'
59
+ u = self.window.ui
60
+
61
+ u.dialog['agent.builder'] = BuilderDialog(self.window)
62
+ dlg = u.dialog['agent.builder']
63
+
64
+ editor = NodeEditor(dlg) # parent == dialog
65
+ editor.setStyleSheet("""
66
+ NodeEditor {
67
+ qproperty-gridBackColor: #242629;
68
+ qproperty-gridPenColor: #3b3f46;
69
+
70
+ qproperty-nodeBackgroundColor: #2d2f34;
71
+ qproperty-nodeBorderColor: #4b4f57;
72
+ qproperty-nodeSelectionColor: #ff9900;
73
+ qproperty-nodeTitleColor: #3a3d44;
74
+
75
+ qproperty-portInputColor: #66b2ff;
76
+ qproperty-portOutputColor: #70e070;
77
+ qproperty-portConnectedColor: #ffd166;
78
+
79
+ qproperty-edgeColor: #c0c0c0;
80
+ qproperty-edgeSelectedColor: #ff8a5c;
81
+ }
82
+ """)
83
+
84
+ # Demo: add a couple of nodes
85
+ #editor.add_node("Value/Float", QPointF(100, 120))
86
+ #editor.add_node("Value/Float", QPointF(100, 240))
87
+ #editor.add_node("Math/Add", QPointF(420, 180))
88
+ editor.on_clear = self.tool.clear
89
+
90
+ u.editor[id] = editor
91
+
92
+ layout = QVBoxLayout()
93
+ layout.setMenuBar(self.setup_menu(dlg))
94
+
95
+ agents_list = AgentsWidget(self.window, tool=self.tool)
96
+ list_widget = agents_list.setup()
97
+ list_widget.setFixedWidth(250)
98
+ center_splitter = QSplitter(Qt.Horizontal)
99
+ center_splitter.addWidget(list_widget)
100
+ center_splitter.addWidget(u.editor[id])
101
+ center_splitter.setStretchFactor(0, 1)
102
+ center_splitter.setStretchFactor(1, 8)
103
+ layout.addWidget(center_splitter)
104
+
105
+ u.nodes["agent.builder.list"] = agents_list
106
+
107
+ dlg.setLayout(layout)
108
+ dlg.setWindowTitle(trans("agent.builder.title"))
109
+
110
+ def clear(self):
111
+ """Clear transcribe dialog"""
112
+ pass
113
+
114
+
115
+ class BuilderDialog(BaseDialog):
116
+ def __init__(self, window=None, id=None):
117
+ """
118
+ BuilderDialog
119
+
120
+ :param window: main window
121
+ :param id: configurator id
122
+ """
123
+ super(BuilderDialog, self).__init__(window, id)
124
+ self.window = window
125
+ self.id = id # id
126
+
127
+ def closeEvent(self, event):
128
+ """
129
+ Close event
130
+
131
+ :param event: close event
132
+ """
133
+ self.cleanup()
134
+ super(BuilderDialog, self).closeEvent(event)
135
+
136
+ def keyPressEvent(self, event):
137
+ """
138
+ Key press event
139
+
140
+ :param event: key press event
141
+ """
142
+ if event.key() == Qt.Key_Escape:
143
+ self.cleanup()
144
+ self.close()
145
+ else:
146
+ super(BuilderDialog, self).keyPressEvent(event)
147
+
148
+ def cleanup(self):
149
+ """
150
+ Cleanup on close
151
+ """
152
+ self.window.tools.get("agent_builder").on_close()
@@ -0,0 +1,228 @@
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.08.24 23:00:00 #
10
+ # ================================================== #
11
+
12
+ from PySide6 import QtCore
13
+ from PySide6.QtCore import QPoint
14
+ from PySide6.QtGui import QAction, QIcon, Qt, QStandardItemModel
15
+ from PySide6.QtWidgets import QMenu, QVBoxLayout, QPushButton, QWidget
16
+
17
+ from pygpt_net.ui.widget.lists.base import BaseList
18
+ from pygpt_net.utils import trans
19
+
20
+
21
+ class AgentsWidget:
22
+ def __init__(self, window=None, tool=None):
23
+ """
24
+ Agents select widget
25
+
26
+ :param window: main window
27
+ :param tool: tool instance
28
+ """
29
+ self.window = window
30
+ self.tool = tool
31
+ self.id = "agent.builder.list"
32
+ self.list = None
33
+
34
+ def setup(self):
35
+ """
36
+ Setup agents list widget
37
+
38
+ :return: QWidget
39
+ """
40
+ new_btn = QPushButton(QIcon(":/icons/add.svg"), "")
41
+ new_btn.clicked.connect(self.action_new)
42
+
43
+ self.list = AgentsList(self.window, tool=self.tool, id=self.id)
44
+ layout = QVBoxLayout()
45
+ layout.addWidget(new_btn)
46
+ layout.addWidget(self.list)
47
+
48
+ self.window.ui.models[self.id] = self.create_model(self.window)
49
+ self.list.setModel(self.window.ui.models[self.id])
50
+
51
+ widget = QWidget()
52
+ widget.setLayout(layout)
53
+ return widget
54
+
55
+ def action_new(self):
56
+ """
57
+ New agent action
58
+ """
59
+ self.tool.add_agent()
60
+
61
+ def create_model(self, parent) -> QStandardItemModel:
62
+ """
63
+ Create list model
64
+ :param parent: parent widget
65
+ :return: QStandardItemModel
66
+ """
67
+ return QStandardItemModel(0, 1, parent)
68
+
69
+ def update_list(self, data):
70
+ """
71
+ Update presets list
72
+
73
+ :param data: Data to update
74
+ """
75
+ nodes = self.window.ui.nodes
76
+ models = self.window.ui.models
77
+
78
+ view = nodes[self.id]
79
+ model = models.get(self.id)
80
+
81
+ if model is None:
82
+ model = self.create_model(self.window)
83
+ models[self.id] = model
84
+ view.setModel(model)
85
+ try:
86
+ if not data:
87
+ model.setRowCount(0)
88
+ else:
89
+ count = len(data)
90
+ model.setRowCount(count)
91
+ index_fn = model.index
92
+ set_item_data = model.setItemData
93
+ display_role = QtCore.Qt.DisplayRole
94
+
95
+ for i, (key, item) in enumerate(data.items()):
96
+ agent_id = item.id # <---------- from this
97
+ name = item.name
98
+ idx = index_fn(i, 0)
99
+ set_item_data(idx, {
100
+ display_role: name,
101
+ QtCore.Qt.UserRole: agent_id,
102
+ })
103
+ finally:
104
+ pass
105
+
106
+ class AgentsList(BaseList):
107
+ _ICO_EDIT = QIcon(":/icons/edit.svg")
108
+ _ICO_COPY = QIcon(":/icons/copy.svg")
109
+ _ICO_UNDO = QIcon(":/icons/undo.svg")
110
+ _ICO_DELETE = QIcon(":/icons/delete.svg")
111
+ _ICO_CHECK = QIcon(":/icons/check.svg")
112
+ _ICO_CLOSE = QIcon(":/icons/close.svg")
113
+
114
+ def __init__(self, window=None, tool=None, id=None):
115
+ """
116
+ Agents select menu
117
+
118
+ :param window: main window
119
+ :param id: input id
120
+ """
121
+ super(AgentsList, self).__init__(window)
122
+ self.window = window
123
+ self.id = id
124
+ self.tool = tool
125
+ self.doubleClicked.connect(self.dblclick)
126
+ self.setContextMenuPolicy(Qt.CustomContextMenu)
127
+ self.customContextMenuRequested.connect(self.show_context_menu)
128
+
129
+ def click(self, item):
130
+ idx = item.row()
131
+ if idx >= 0:
132
+ model = self.model()
133
+ agent_id = model.data(model.index(idx, 0), QtCore.Qt.UserRole)
134
+ if agent_id is not None:
135
+ self.tool.edit_agent(agent_id)
136
+
137
+ def dblclick(self, val):
138
+ """
139
+ Double click event
140
+
141
+ :param val: double click event
142
+ """
143
+ pass
144
+
145
+ def show_context_menu(self, pos: QPoint):
146
+ """
147
+ Context menu event
148
+
149
+ :param pos: QPoint
150
+ """
151
+ global_pos = self.viewport().mapToGlobal(pos)
152
+ index = self.indexAt(pos)
153
+ if not index.isValid():
154
+ return
155
+
156
+ menu = QMenu(self)
157
+
158
+ edit_act = QAction(self._ICO_EDIT, trans('preset.action.edit'), menu)
159
+ edit_act.triggered.connect(lambda checked=False, it=index: self.action_edit(it))
160
+ menu.addAction(edit_act)
161
+
162
+ duplicate_act = QAction(self._ICO_COPY, trans('preset.action.duplicate'), menu)
163
+ duplicate_act.triggered.connect(lambda checked=False, it=index: self.action_duplicate(it))
164
+ menu.addAction(duplicate_act)
165
+
166
+ delete_act = QAction(self._ICO_DELETE, trans('preset.action.delete'), menu)
167
+ delete_act.triggered.connect(lambda checked=False, it=index: self.action_delete(it))
168
+ menu.addAction(delete_act)
169
+
170
+ menu.exec_(global_pos)
171
+
172
+ def action_edit(self, item):
173
+ """
174
+ Edit action handler
175
+
176
+ :param item: list item
177
+ """
178
+ idx = item.row()
179
+ if idx >= 0:
180
+ model = self.model()
181
+ agent_id = model.data(model.index(idx, 0), QtCore.Qt.UserRole)
182
+ if agent_id is not None:
183
+ self.tool.rename_agent(agent_id)
184
+
185
+ def action_duplicate(self, item):
186
+ """
187
+ Duplicate action handler
188
+
189
+ :param item: list item
190
+ """
191
+ idx = item.row()
192
+ if idx >= 0:
193
+ model = self.model()
194
+ agent_id = model.data(model.index(idx, 0), QtCore.Qt.UserRole)
195
+ if agent_id is not None:
196
+ self.tool.duplicate_agent(agent_id)
197
+
198
+ def action_delete(self, item):
199
+ """
200
+ Delete action handler
201
+
202
+ :param item: list item
203
+ """
204
+ idx = item.row()
205
+ if idx >= 0:
206
+ model = self.model()
207
+ agent_id = model.data(model.index(idx, 0), QtCore.Qt.UserRole)
208
+ if agent_id is not None:
209
+ self.tool.delete_agent(agent_id)
210
+
211
+ def mousePressEvent(self, event):
212
+ if event.button() == Qt.LeftButton:
213
+ index = self.indexAt(event.pos())
214
+ if not index.isValid():
215
+ return
216
+ super().mousePressEvent(event)
217
+ elif event.button() == Qt.RightButton:
218
+ event.accept()
219
+ else:
220
+ super().mousePressEvent(event)
221
+
222
+ def selectionCommand(self, index, event=None):
223
+ """
224
+ Selection command
225
+ :param index: Index
226
+ :param event: Event
227
+ """
228
+ return super().selectionCommand(index, event)
File without changes
File without changes