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.
- pygpt_net/CHANGELOG.txt +11 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +26 -22
- pygpt_net/controller/audio/audio.py +0 -0
- pygpt_net/controller/calendar/calendar.py +0 -0
- pygpt_net/controller/calendar/note.py +0 -0
- pygpt_net/controller/chat/chat.py +0 -0
- pygpt_net/controller/chat/handler/openai_stream.py +2 -1
- pygpt_net/controller/chat/handler/worker.py +0 -0
- pygpt_net/controller/chat/remote_tools.py +0 -0
- pygpt_net/controller/chat/render.py +0 -0
- pygpt_net/controller/chat/text.py +0 -0
- pygpt_net/controller/ctx/common.py +0 -0
- pygpt_net/controller/debug/debug.py +26 -2
- pygpt_net/controller/debug/fixtures.py +1 -1
- pygpt_net/controller/dialogs/confirm.py +15 -1
- pygpt_net/controller/dialogs/debug.py +2 -0
- pygpt_net/controller/lang/mapping.py +0 -0
- pygpt_net/controller/launcher/launcher.py +0 -0
- pygpt_net/controller/mode/mode.py +0 -0
- pygpt_net/controller/presets/presets.py +0 -0
- pygpt_net/controller/realtime/realtime.py +0 -0
- pygpt_net/controller/theme/theme.py +0 -0
- pygpt_net/controller/ui/mode.py +0 -0
- pygpt_net/controller/ui/tabs.py +0 -0
- pygpt_net/core/agents/agents.py +3 -1
- pygpt_net/core/agents/custom.py +150 -0
- pygpt_net/core/agents/provider.py +0 -0
- pygpt_net/core/builder/__init__.py +12 -0
- pygpt_net/core/builder/graph.py +478 -0
- pygpt_net/core/calendar/calendar.py +0 -0
- pygpt_net/core/ctx/ctx.py +2 -1
- pygpt_net/core/ctx/output.py +0 -0
- pygpt_net/core/debug/agent.py +0 -0
- pygpt_net/core/debug/agent_builder.py +29 -0
- pygpt_net/core/debug/console/console.py +0 -0
- pygpt_net/core/debug/db.py +0 -0
- pygpt_net/core/debug/debug.py +0 -0
- pygpt_net/core/debug/events.py +0 -0
- pygpt_net/core/debug/indexes.py +0 -0
- pygpt_net/core/debug/kernel.py +0 -0
- pygpt_net/core/debug/tabs.py +0 -0
- pygpt_net/core/filesystem/filesystem.py +0 -0
- pygpt_net/core/fixtures/__init__ +0 -0
- pygpt_net/core/fixtures/stream/__init__.py +0 -0
- pygpt_net/core/fixtures/stream/generator.py +0 -0
- pygpt_net/core/models/models.py +0 -0
- pygpt_net/core/render/plain/pid.py +0 -0
- pygpt_net/core/render/plain/renderer.py +26 -4
- pygpt_net/core/render/web/body.py +46 -4
- pygpt_net/core/render/web/debug.py +0 -0
- pygpt_net/core/render/web/helpers.py +0 -0
- pygpt_net/core/render/web/pid.py +0 -0
- pygpt_net/core/render/web/renderer.py +15 -20
- pygpt_net/core/tabs/tab.py +0 -0
- pygpt_net/core/tabs/tabs.py +0 -0
- pygpt_net/core/text/utils.py +0 -0
- pygpt_net/css.qrc +0 -0
- pygpt_net/css_rc.py +0 -0
- pygpt_net/data/config/config.json +7 -7
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/css/web-blocks.css +9 -0
- pygpt_net/data/css/web-blocks.dark.css +6 -0
- pygpt_net/data/css/web-blocks.darkest.css +6 -0
- pygpt_net/data/css/web-chatgpt.css +14 -6
- pygpt_net/data/css/web-chatgpt.dark.css +6 -0
- pygpt_net/data/css/web-chatgpt.darkest.css +6 -0
- pygpt_net/data/css/web-chatgpt.light.css +6 -0
- pygpt_net/data/css/web-chatgpt_wide.css +14 -6
- pygpt_net/data/css/web-chatgpt_wide.dark.css +6 -0
- pygpt_net/data/css/web-chatgpt_wide.darkest.css +6 -0
- pygpt_net/data/css/web-chatgpt_wide.light.css +6 -0
- pygpt_net/data/fixtures/fake_stream.txt +14 -1
- pygpt_net/data/icons/case.svg +0 -0
- pygpt_net/data/icons/chat1.svg +0 -0
- pygpt_net/data/icons/chat2.svg +0 -0
- pygpt_net/data/icons/chat3.svg +0 -0
- pygpt_net/data/icons/chat4.svg +0 -0
- pygpt_net/data/icons/fit.svg +0 -0
- pygpt_net/data/icons/note1.svg +0 -0
- pygpt_net/data/icons/note2.svg +0 -0
- pygpt_net/data/icons/note3.svg +0 -0
- pygpt_net/data/icons/stt.svg +0 -0
- pygpt_net/data/icons/translate.svg +0 -0
- pygpt_net/data/icons/tts.svg +0 -0
- pygpt_net/data/icons/url.svg +0 -0
- pygpt_net/data/icons/vision.svg +0 -0
- pygpt_net/data/icons/web_off.svg +0 -0
- pygpt_net/data/icons/web_on.svg +0 -0
- pygpt_net/data/js/app/async.js +166 -0
- pygpt_net/data/js/app/bridge.js +88 -0
- pygpt_net/data/js/app/common.js +212 -0
- pygpt_net/data/js/app/config.js +223 -0
- pygpt_net/data/js/app/custom.js +961 -0
- pygpt_net/data/js/app/data.js +84 -0
- pygpt_net/data/js/app/dom.js +322 -0
- pygpt_net/data/js/app/events.js +400 -0
- pygpt_net/data/js/app/highlight.js +542 -0
- pygpt_net/data/js/app/logger.js +305 -0
- pygpt_net/data/js/app/markdown.js +1137 -0
- pygpt_net/data/js/app/math.js +167 -0
- pygpt_net/data/js/app/nodes.js +395 -0
- pygpt_net/data/js/app/queue.js +260 -0
- pygpt_net/data/js/app/raf.js +250 -0
- pygpt_net/data/js/app/runtime.js +582 -0
- pygpt_net/data/js/app/scroll.js +433 -0
- pygpt_net/data/js/app/stream.js +2708 -0
- pygpt_net/data/js/app/template.js +287 -0
- pygpt_net/data/js/app/tool.js +87 -0
- pygpt_net/data/js/app/ui.js +86 -0
- pygpt_net/data/js/app/user.js +380 -0
- pygpt_net/data/js/app/utils.js +64 -0
- pygpt_net/data/js/app.min.js +880 -0
- pygpt_net/data/js/markdown-it/markdown-it-katex.min.js +1 -1
- pygpt_net/data/js/markdown-it/markdown-it.min.js +0 -0
- pygpt_net/data/locale/locale.de.ini +0 -0
- pygpt_net/data/locale/locale.en.ini +7 -0
- pygpt_net/data/locale/locale.es.ini +0 -0
- pygpt_net/data/locale/locale.fr.ini +0 -0
- pygpt_net/data/locale/locale.it.ini +0 -0
- pygpt_net/data/locale/locale.pl.ini +0 -0
- pygpt_net/data/locale/locale.uk.ini +0 -0
- pygpt_net/data/locale/locale.zh.ini +0 -0
- pygpt_net/data/locale/plugin.agent.de.ini +0 -0
- pygpt_net/data/locale/plugin.agent.en.ini +0 -0
- pygpt_net/data/locale/plugin.agent.es.ini +0 -0
- pygpt_net/data/locale/plugin.agent.fr.ini +0 -0
- pygpt_net/data/locale/plugin.agent.it.ini +0 -0
- pygpt_net/data/locale/plugin.agent.pl.ini +0 -0
- pygpt_net/data/locale/plugin.agent.uk.ini +0 -0
- pygpt_net/data/locale/plugin.agent.zh.ini +0 -0
- pygpt_net/data/locale/plugin.audio_input.de.ini +0 -0
- pygpt_net/data/locale/plugin.audio_input.en.ini +0 -0
- pygpt_net/data/locale/plugin.audio_input.es.ini +0 -0
- pygpt_net/data/locale/plugin.audio_input.fr.ini +0 -0
- pygpt_net/data/locale/plugin.audio_input.it.ini +0 -0
- pygpt_net/data/locale/plugin.audio_input.pl.ini +0 -0
- pygpt_net/data/locale/plugin.audio_input.uk.ini +0 -0
- pygpt_net/data/locale/plugin.audio_input.zh.ini +0 -0
- pygpt_net/data/locale/plugin.audio_output.de.ini +0 -0
- pygpt_net/data/locale/plugin.audio_output.en.ini +0 -0
- pygpt_net/data/locale/plugin.audio_output.es.ini +0 -0
- pygpt_net/data/locale/plugin.audio_output.fr.ini +0 -0
- pygpt_net/data/locale/plugin.audio_output.it.ini +0 -0
- pygpt_net/data/locale/plugin.audio_output.pl.ini +0 -0
- pygpt_net/data/locale/plugin.audio_output.uk.ini +0 -0
- pygpt_net/data/locale/plugin.audio_output.zh.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_api.de.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_api.en.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_api.es.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_api.fr.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_api.it.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_api.pl.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_api.uk.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_api.zh.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.de.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.en.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.es.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.fr.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.it.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.pl.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.uk.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.zh.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_custom.de.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_custom.en.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_custom.es.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_custom.fr.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_custom.it.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_custom.pl.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_custom.uk.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_custom.zh.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_files.de.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_files.en.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_files.es.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_files.fr.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_files.it.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_files.pl.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_files.uk.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_files.zh.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_history.de.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_history.en.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_history.es.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_history.fr.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_history.it.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_history.pl.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_history.uk.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_history.zh.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_mouse_control.de.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_mouse_control.en.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_mouse_control.es.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_mouse_control.fr.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_mouse_control.it.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_mouse_control.pl.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_mouse_control.uk.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_mouse_control.zh.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_serial.de.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_serial.en.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_serial.es.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_serial.fr.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_serial.it.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_serial.pl.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_serial.uk.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_serial.zh.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_system.de.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_system.en.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_system.es.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_system.fr.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_system.it.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_system.pl.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_system.uk.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_system.zh.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_web.de.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_web.en.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_web.es.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_web.fr.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_web.it.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_web.pl.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_web.uk.ini +0 -0
- pygpt_net/data/locale/plugin.cmd_web.zh.ini +0 -0
- pygpt_net/data/locale/plugin.crontab.de.ini +0 -0
- pygpt_net/data/locale/plugin.crontab.en.ini +0 -0
- pygpt_net/data/locale/plugin.crontab.es.ini +0 -0
- pygpt_net/data/locale/plugin.crontab.fr.ini +0 -0
- pygpt_net/data/locale/plugin.crontab.it.ini +0 -0
- pygpt_net/data/locale/plugin.crontab.pl.ini +0 -0
- pygpt_net/data/locale/plugin.crontab.uk.ini +0 -0
- pygpt_net/data/locale/plugin.crontab.zh.ini +0 -0
- pygpt_net/data/locale/plugin.experts.de.ini +0 -0
- pygpt_net/data/locale/plugin.experts.en.ini +0 -0
- pygpt_net/data/locale/plugin.experts.es.ini +0 -0
- pygpt_net/data/locale/plugin.experts.fr.ini +0 -0
- pygpt_net/data/locale/plugin.experts.it.ini +0 -0
- pygpt_net/data/locale/plugin.experts.pl.ini +0 -0
- pygpt_net/data/locale/plugin.experts.uk.ini +0 -0
- pygpt_net/data/locale/plugin.experts.zh.ini +0 -0
- pygpt_net/data/locale/plugin.extra_prompt.de.ini +0 -0
- pygpt_net/data/locale/plugin.extra_prompt.en.ini +0 -0
- pygpt_net/data/locale/plugin.extra_prompt.es.ini +0 -0
- pygpt_net/data/locale/plugin.extra_prompt.fr.ini +0 -0
- pygpt_net/data/locale/plugin.extra_prompt.it.ini +0 -0
- pygpt_net/data/locale/plugin.extra_prompt.pl.ini +0 -0
- pygpt_net/data/locale/plugin.extra_prompt.uk.ini +0 -0
- pygpt_net/data/locale/plugin.extra_prompt.zh.ini +0 -0
- pygpt_net/data/locale/plugin.idx_llama_index.de.ini +0 -0
- pygpt_net/data/locale/plugin.idx_llama_index.en.ini +0 -0
- pygpt_net/data/locale/plugin.idx_llama_index.es.ini +0 -0
- pygpt_net/data/locale/plugin.idx_llama_index.fr.ini +0 -0
- pygpt_net/data/locale/plugin.idx_llama_index.it.ini +0 -0
- pygpt_net/data/locale/plugin.idx_llama_index.pl.ini +0 -0
- pygpt_net/data/locale/plugin.idx_llama_index.uk.ini +0 -0
- pygpt_net/data/locale/plugin.idx_llama_index.zh.ini +0 -0
- pygpt_net/data/locale/plugin.mailer.en.ini +0 -0
- pygpt_net/data/locale/plugin.mcp.en.ini +0 -0
- pygpt_net/data/locale/plugin.openai_dalle.de.ini +0 -0
- pygpt_net/data/locale/plugin.openai_dalle.en.ini +0 -0
- pygpt_net/data/locale/plugin.openai_dalle.es.ini +0 -0
- pygpt_net/data/locale/plugin.openai_dalle.fr.ini +0 -0
- pygpt_net/data/locale/plugin.openai_dalle.it.ini +0 -0
- pygpt_net/data/locale/plugin.openai_dalle.pl.ini +0 -0
- pygpt_net/data/locale/plugin.openai_dalle.uk.ini +0 -0
- pygpt_net/data/locale/plugin.openai_dalle.zh.ini +0 -0
- pygpt_net/data/locale/plugin.openai_vision.de.ini +0 -0
- pygpt_net/data/locale/plugin.openai_vision.en.ini +0 -0
- pygpt_net/data/locale/plugin.openai_vision.es.ini +0 -0
- pygpt_net/data/locale/plugin.openai_vision.fr.ini +0 -0
- pygpt_net/data/locale/plugin.openai_vision.it.ini +0 -0
- pygpt_net/data/locale/plugin.openai_vision.pl.ini +0 -0
- pygpt_net/data/locale/plugin.openai_vision.uk.ini +0 -0
- pygpt_net/data/locale/plugin.openai_vision.zh.ini +0 -0
- pygpt_net/data/locale/plugin.osm.en.ini +0 -0
- pygpt_net/data/locale/plugin.real_time.de.ini +0 -0
- pygpt_net/data/locale/plugin.real_time.en.ini +0 -0
- pygpt_net/data/locale/plugin.real_time.es.ini +0 -0
- pygpt_net/data/locale/plugin.real_time.fr.ini +0 -0
- pygpt_net/data/locale/plugin.real_time.it.ini +0 -0
- pygpt_net/data/locale/plugin.real_time.pl.ini +0 -0
- pygpt_net/data/locale/plugin.real_time.uk.ini +0 -0
- pygpt_net/data/locale/plugin.real_time.zh.ini +0 -0
- pygpt_net/data/locale/plugin.voice_control.de.ini +0 -0
- pygpt_net/data/locale/plugin.voice_control.en.ini +0 -0
- pygpt_net/data/locale/plugin.voice_control.es.ini +0 -0
- pygpt_net/data/locale/plugin.voice_control.fr.ini +0 -0
- pygpt_net/data/locale/plugin.voice_control.it.ini +0 -0
- pygpt_net/data/locale/plugin.voice_control.pl.ini +0 -0
- pygpt_net/data/locale/plugin.voice_control.uk.ini +0 -0
- pygpt_net/data/locale/plugin.voice_control.zh.ini +0 -0
- pygpt_net/data/locale/plugin.wolfram.en.ini +0 -0
- pygpt_net/fonts.qrc +0 -0
- pygpt_net/fonts_rc.py +0 -0
- pygpt_net/icons.qrc +0 -0
- pygpt_net/icons_rc.py +0 -0
- pygpt_net/item/agent.py +62 -0
- pygpt_net/item/builder_layout.py +62 -0
- pygpt_net/js.qrc +24 -1
- pygpt_net/js_rc.py +51394 -33687
- pygpt_net/plugin/base/worker.py +0 -0
- pygpt_net/plugin/mcp/__init__.py +0 -0
- pygpt_net/plugin/mcp/config.py +0 -0
- pygpt_net/plugin/mcp/plugin.py +0 -0
- pygpt_net/plugin/mcp/worker.py +0 -0
- pygpt_net/plugin/osm/__init__.py +0 -0
- pygpt_net/plugin/osm/config.py +0 -0
- pygpt_net/plugin/osm/plugin.py +0 -0
- pygpt_net/plugin/osm/worker.py +0 -0
- pygpt_net/plugin/wolfram/__init__.py +0 -0
- pygpt_net/plugin/wolfram/config.py +0 -0
- pygpt_net/plugin/wolfram/plugin.py +0 -0
- pygpt_net/plugin/wolfram/worker.py +0 -0
- pygpt_net/provider/api/anthropic/tools.py +0 -0
- pygpt_net/provider/api/google/__init__.py +0 -0
- pygpt_net/provider/api/google/video.py +0 -0
- pygpt_net/provider/api/openai/agents/experts.py +0 -0
- pygpt_net/provider/api/openai/agents/remote_tools.py +0 -0
- pygpt_net/provider/api/openai/remote_tools.py +0 -0
- pygpt_net/provider/api/openai/responses.py +0 -0
- pygpt_net/provider/api/x_ai/__init__.py +0 -0
- pygpt_net/provider/api/x_ai/remote.py +0 -0
- pygpt_net/provider/core/agent/__init__.py +10 -0
- pygpt_net/provider/core/agent/base.py +51 -0
- pygpt_net/provider/core/agent/json_file.py +200 -0
- pygpt_net/provider/core/config/patch.py +18 -0
- pygpt_net/provider/core/config/patches/__init__.py +0 -0
- pygpt_net/provider/core/config/patches/patch_before_2_6_42.py +0 -0
- pygpt_net/provider/core/ctx/db_sqlite/storage.py +0 -0
- pygpt_net/provider/core/model/patches/__init__.py +0 -0
- pygpt_net/provider/core/model/patches/patch_before_2_6_42.py +0 -0
- pygpt_net/provider/core/preset/patch.py +0 -0
- pygpt_net/provider/core/preset/patches/__init__.py +0 -0
- pygpt_net/provider/core/preset/patches/patch_before_2_6_42.py +0 -0
- pygpt_net/provider/llms/base.py +0 -0
- pygpt_net/provider/llms/deepseek_api.py +0 -0
- pygpt_net/provider/llms/google.py +0 -0
- pygpt_net/provider/llms/hugging_face_api.py +0 -0
- pygpt_net/provider/llms/hugging_face_embedding.py +0 -0
- pygpt_net/provider/llms/hugging_face_router.py +0 -0
- pygpt_net/provider/llms/local.py +0 -0
- pygpt_net/provider/llms/mistral.py +0 -0
- pygpt_net/provider/llms/open_router.py +0 -0
- pygpt_net/provider/llms/perplexity.py +0 -0
- pygpt_net/provider/llms/utils.py +0 -0
- pygpt_net/provider/llms/voyage.py +0 -0
- pygpt_net/provider/llms/x_ai.py +0 -0
- pygpt_net/tools/agent_builder/__init__.py +12 -0
- pygpt_net/tools/agent_builder/tool.py +292 -0
- pygpt_net/tools/agent_builder/ui/__init__.py +0 -0
- pygpt_net/tools/agent_builder/ui/dialogs.py +152 -0
- pygpt_net/tools/agent_builder/ui/list.py +228 -0
- pygpt_net/tools/code_interpreter/ui/html.py +0 -0
- pygpt_net/tools/code_interpreter/ui/widgets.py +0 -0
- pygpt_net/tools/html_canvas/tool.py +23 -6
- pygpt_net/tools/html_canvas/ui/widgets.py +224 -2
- pygpt_net/ui/layout/chat/chat.py +0 -0
- pygpt_net/ui/main.py +10 -9
- pygpt_net/ui/menu/debug.py +39 -1
- pygpt_net/ui/widget/builder/__init__.py +12 -0
- pygpt_net/ui/widget/builder/editor.py +2001 -0
- pygpt_net/ui/widget/draw/painter.py +0 -0
- pygpt_net/ui/widget/element/labels.py +9 -4
- pygpt_net/ui/widget/lists/db.py +0 -0
- pygpt_net/ui/widget/lists/debug.py +0 -0
- pygpt_net/ui/widget/tabs/body.py +0 -0
- pygpt_net/ui/widget/textarea/input.py +17 -8
- pygpt_net/ui/widget/textarea/output.py +21 -1
- pygpt_net/ui/widget/textarea/web.py +29 -2
- pygpt_net/utils.py +40 -0
- {pygpt_net-2.6.54.dist-info → pygpt_net-2.6.56.dist-info}/METADATA +13 -2
- {pygpt_net-2.6.54.dist-info → pygpt_net-2.6.56.dist-info}/RECORD +86 -47
- pygpt_net/data/js/app.js +0 -5869
- {pygpt_net-2.6.54.dist-info → pygpt_net-2.6.56.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.54.dist-info → pygpt_net-2.6.56.dist-info}/WHEEL +0 -0
- {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
pygpt_net/core/ctx/output.py
CHANGED
|
File without changes
|
pygpt_net/core/debug/agent.py
CHANGED
|
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
|
pygpt_net/core/debug/db.py
CHANGED
|
File without changes
|
pygpt_net/core/debug/debug.py
CHANGED
|
File without changes
|
pygpt_net/core/debug/events.py
CHANGED
|
File without changes
|
pygpt_net/core/debug/indexes.py
CHANGED
|
File without changes
|
pygpt_net/core/debug/kernel.py
CHANGED
|
File without changes
|
pygpt_net/core/debug/tabs.py
CHANGED
|
File without changes
|
|
File without changes
|
pygpt_net/core/fixtures/__init__
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
pygpt_net/core/models/models.py
CHANGED
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
"""
|