pygpt-net 2.6.55__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 +6 -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 +0 -0
- 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 +9 -7
- 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.55.dist-info → pygpt_net-2.6.56.dist-info}/METADATA +8 -2
- {pygpt_net-2.6.55.dist-info → pygpt_net-2.6.56.dist-info}/RECORD +85 -46
- pygpt_net/data/js/app.js +0 -5869
- {pygpt_net-2.6.55.dist-info → pygpt_net-2.6.56.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.55.dist-info → pygpt_net-2.6.56.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.55.dist-info → pygpt_net-2.6.56.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// Math renderer (async, chunked)
|
|
3
|
+
// ==========================================================================
|
|
4
|
+
|
|
5
|
+
class MathRenderer {
|
|
6
|
+
|
|
7
|
+
// Math renderer for LaTeX formulas.
|
|
8
|
+
constructor(cfg, raf, asyncer) {
|
|
9
|
+
this.cfg = cfg;
|
|
10
|
+
this.raf = raf;
|
|
11
|
+
this.asyncer = asyncer;
|
|
12
|
+
this.scheduled = false;
|
|
13
|
+
|
|
14
|
+
// rAF key used by the central pump (do not change – API compatibility).
|
|
15
|
+
this.rafKey = {
|
|
16
|
+
t: 'Math:render'
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Pending roots aggregation: if document-level render is requested, it supersedes others.
|
|
20
|
+
this._pendingRoots = new Set();
|
|
21
|
+
this._pendingDoc = false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Async, cooperative KaTeX rendering to avoid long blocking on many formulas.
|
|
25
|
+
async renderAsync(root) {
|
|
26
|
+
if (typeof katex === 'undefined') return;
|
|
27
|
+
const scope = root || document;
|
|
28
|
+
const scripts = Array.from(scope.querySelectorAll('script[type^="math/tex"]'));
|
|
29
|
+
const useToString = (typeof katex.renderToString === 'function');
|
|
30
|
+
|
|
31
|
+
const batchFn = async (script) => {
|
|
32
|
+
if (!script || !script.isConnected) return;
|
|
33
|
+
// Only render math in bot messages
|
|
34
|
+
if (!script.closest('.msg-box.msg-bot')) return;
|
|
35
|
+
const t = script.getAttribute('type') || '';
|
|
36
|
+
const displayMode = t.indexOf('mode=display') > -1;
|
|
37
|
+
// avoid innerText (it may trigger layout). textContent is sufficient here.
|
|
38
|
+
const mathContent = script.textContent || '';
|
|
39
|
+
const parent = script.parentNode;
|
|
40
|
+
if (!parent) return;
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
if (useToString) {
|
|
44
|
+
let html = '';
|
|
45
|
+
try {
|
|
46
|
+
html = katex.renderToString(mathContent, {
|
|
47
|
+
displayMode,
|
|
48
|
+
throwOnError: false
|
|
49
|
+
});
|
|
50
|
+
} catch (_) {
|
|
51
|
+
const fb = displayMode ? `\\[${mathContent}\\]` : `\\(${mathContent}\\)`;
|
|
52
|
+
html = (displayMode ? `<div>${Utils.escapeHtml(fb)}</div>` : `<span>${Utils.escapeHtml(fb)}</span>`);
|
|
53
|
+
}
|
|
54
|
+
const host = document.createElement(displayMode ? 'div' : 'span');
|
|
55
|
+
host.innerHTML = html;
|
|
56
|
+
const el = host.firstElementChild || host;
|
|
57
|
+
if (parent.classList && parent.classList.contains('math-pending')) parent.replaceWith(el);
|
|
58
|
+
else parent.replaceChild(el, script);
|
|
59
|
+
} else {
|
|
60
|
+
const el = document.createElement(displayMode ? 'div' : 'span');
|
|
61
|
+
try {
|
|
62
|
+
katex.render(mathContent, el, {
|
|
63
|
+
displayMode,
|
|
64
|
+
throwOnError: false
|
|
65
|
+
});
|
|
66
|
+
} catch (_) {
|
|
67
|
+
el.textContent = (displayMode ? `\\[${mathContent}\\]` : `\\(${mathContent}\\)`);
|
|
68
|
+
}
|
|
69
|
+
if (parent.classList && parent.classList.contains('math-pending')) parent.replaceWith(el);
|
|
70
|
+
else parent.replaceChild(el, script);
|
|
71
|
+
}
|
|
72
|
+
} catch (_) {
|
|
73
|
+
// Keep fallback text intact on any error
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Process formulas cooperatively (rAF yields).
|
|
78
|
+
await this.asyncer.forEachChunk(scripts, batchFn, 'MathRenderer');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Schedule math rendering for a root. Coalesces multiple calls.
|
|
82
|
+
schedule(root, _delayIgnored = 0, forceNow = false) {
|
|
83
|
+
// If KaTeX is not available, honor no-op. API stays intact.
|
|
84
|
+
if (typeof katex === 'undefined') return;
|
|
85
|
+
|
|
86
|
+
// Normalize root (default to whole document).
|
|
87
|
+
const targetRoot = root || document;
|
|
88
|
+
|
|
89
|
+
// Fast existence check to avoid arming rAF when nothing to do, but still
|
|
90
|
+
// keep aggregation semantics: if a job is already scheduled we can still
|
|
91
|
+
// merge new roots into the pending set when they actually contain math.
|
|
92
|
+
let hasMath = true;
|
|
93
|
+
if (!forceNow) {
|
|
94
|
+
try {
|
|
95
|
+
hasMath = !!(targetRoot && targetRoot.querySelector && targetRoot.querySelector('script[type^="math/tex"]'));
|
|
96
|
+
} catch (_) {
|
|
97
|
+
hasMath = false;
|
|
98
|
+
}
|
|
99
|
+
if (!hasMath) return; // nothing to render for this root; safe early exit
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Aggregate roots so nothing is lost while one job is already scheduled.
|
|
103
|
+
if (targetRoot === document || targetRoot === document.documentElement || targetRoot === document.body) {
|
|
104
|
+
this._pendingDoc = true; // promote to a full-document sweep
|
|
105
|
+
this._pendingRoots.clear(); // small optimization (document covers all)
|
|
106
|
+
} else if (!this._pendingDoc) {
|
|
107
|
+
this._pendingRoots.add(targetRoot);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// If a task is already scheduled, do not arm another – coalescing will take care of it.
|
|
111
|
+
if (this.scheduled && this.raf && typeof this.raf.isScheduled === 'function' && this.raf.isScheduled(this.rafKey)) return;
|
|
112
|
+
|
|
113
|
+
this.scheduled = true;
|
|
114
|
+
const priority = forceNow ? 0 : 2;
|
|
115
|
+
|
|
116
|
+
// Single rAF job drains all pending roots; renderAsync remains public and unchanged.
|
|
117
|
+
this.raf.schedule(this.rafKey, () => {
|
|
118
|
+
this.scheduled = false;
|
|
119
|
+
|
|
120
|
+
const useDoc = this._pendingDoc;
|
|
121
|
+
const roots = [];
|
|
122
|
+
|
|
123
|
+
if (useDoc) {
|
|
124
|
+
roots.push(document);
|
|
125
|
+
} else {
|
|
126
|
+
this._pendingRoots.forEach((r) => {
|
|
127
|
+
// Only keep connected elements to avoid useless work.
|
|
128
|
+
try {
|
|
129
|
+
if (r && (r.isConnected === undefined || r.isConnected)) roots.push(r);
|
|
130
|
+
} catch (_) {
|
|
131
|
+
// Conservative: keep the root; renderAsync guards internally.
|
|
132
|
+
roots.push(r);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Reset aggregation state before running (new calls can aggregate afresh).
|
|
138
|
+
this._pendingDoc = false;
|
|
139
|
+
this._pendingRoots.clear();
|
|
140
|
+
|
|
141
|
+
// Fire-and-forget async drain; keep renderAsync API intact.
|
|
142
|
+
(async () => {
|
|
143
|
+
for (let i = 0; i < roots.length; i++) {
|
|
144
|
+
try {
|
|
145
|
+
await this.renderAsync(roots[i]);
|
|
146
|
+
} catch (_) {
|
|
147
|
+
/* swallow – resilient */
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
})();
|
|
151
|
+
}, 'Math', priority);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Cleanup pending work and state.
|
|
155
|
+
cleanup() {
|
|
156
|
+
try {
|
|
157
|
+
this.raf.cancelGroup('Math');
|
|
158
|
+
} catch (_) {}
|
|
159
|
+
this.scheduled = false;
|
|
160
|
+
|
|
161
|
+
// Ensure pending state is fully cleared on cleanup.
|
|
162
|
+
try {
|
|
163
|
+
this._pendingRoots.clear();
|
|
164
|
+
} catch (_) {}
|
|
165
|
+
this._pendingDoc = false;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// Nodes manager
|
|
3
|
+
// ==========================================================================
|
|
4
|
+
|
|
5
|
+
class NodesManager {
|
|
6
|
+
|
|
7
|
+
// Nodes manager for handling message nodes.
|
|
8
|
+
constructor(dom, renderer, highlighter, math) {
|
|
9
|
+
this.dom = dom;
|
|
10
|
+
this.renderer = renderer;
|
|
11
|
+
this.highlighter = highlighter;
|
|
12
|
+
this.math = math;
|
|
13
|
+
// User message collapse manager
|
|
14
|
+
this._userCollapse = new UserCollapseManager(this.renderer.cfg);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Check if HTML contains only user messages without any markdown or code features.
|
|
18
|
+
_isUserOnlyContent(html) {
|
|
19
|
+
try {
|
|
20
|
+
const tmp = document.createElement('div');
|
|
21
|
+
tmp.innerHTML = html;
|
|
22
|
+
const hasBot = !!tmp.querySelector('.msg-box.msg-bot');
|
|
23
|
+
const hasUser = !!tmp.querySelector('.msg-box.msg-user');
|
|
24
|
+
const hasMD64 = !!tmp.querySelector('[data-md64]');
|
|
25
|
+
const hasMDNative = !!tmp.querySelector('[md-block-markdown]');
|
|
26
|
+
const hasCode = !!tmp.querySelector('pre code');
|
|
27
|
+
const hasMath = !!tmp.querySelector('script[type^="math/tex"]');
|
|
28
|
+
return hasUser && !hasBot && !hasMD64 && !hasMDNative && !hasCode && !hasMath;
|
|
29
|
+
} catch (_) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Convert user markdown placeholders into plain text nodes.
|
|
35
|
+
_materializeUserMdAsPlainText(scopeEl) {
|
|
36
|
+
try {
|
|
37
|
+
const nodes = scopeEl.querySelectorAll('.msg-box.msg-user [data-md64], .msg-box.msg-user [md-block-markdown]');
|
|
38
|
+
nodes.forEach(el => {
|
|
39
|
+
let txt = '';
|
|
40
|
+
if (el.hasAttribute('data-md64')) {
|
|
41
|
+
const b64 = el.getAttribute('data-md64') || '';
|
|
42
|
+
el.removeAttribute('data-md64');
|
|
43
|
+
try {
|
|
44
|
+
txt = this.renderer.b64ToUtf8(b64);
|
|
45
|
+
} catch (_) {
|
|
46
|
+
txt = '';
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
// Native Markdown block in user message: keep as plain text (no markdown-it)
|
|
50
|
+
try {
|
|
51
|
+
txt = el.textContent || '';
|
|
52
|
+
} catch (_) {
|
|
53
|
+
txt = '';
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
el.removeAttribute('md-block-markdown');
|
|
57
|
+
} catch (_) {}
|
|
58
|
+
}
|
|
59
|
+
const span = document.createElement('span');
|
|
60
|
+
span.textContent = txt;
|
|
61
|
+
el.replaceWith(span);
|
|
62
|
+
});
|
|
63
|
+
} catch (_) {}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Ensure user copy icon exists inside each user message (.msg) under root.
|
|
67
|
+
_ensureUserCopyIcons(root) {
|
|
68
|
+
try {
|
|
69
|
+
const scope = root || document;
|
|
70
|
+
const cfg = (this.renderer && this.renderer.cfg) || {};
|
|
71
|
+
const I = cfg.ICONS || {};
|
|
72
|
+
const L = cfg.LOCALE || {};
|
|
73
|
+
const copyIcon = I.CODE_COPY || '';
|
|
74
|
+
const copyTitle = L.COPY || 'Copy';
|
|
75
|
+
|
|
76
|
+
const list = scope.querySelectorAll('.msg-box.msg-user .msg');
|
|
77
|
+
for (let i = 0; i < list.length; i++) {
|
|
78
|
+
const msg = list[i];
|
|
79
|
+
if (!msg || !msg.isConnected) continue;
|
|
80
|
+
|
|
81
|
+
// If exists but sits inside .uc-content, move it up to .msg for stable absolute positioning.
|
|
82
|
+
const existing = msg.querySelector('.msg-copy-btn');
|
|
83
|
+
if (existing) {
|
|
84
|
+
try {
|
|
85
|
+
const p = existing.parentElement;
|
|
86
|
+
if (p && p.classList && p.classList.contains('uc-content')) {
|
|
87
|
+
msg.insertAdjacentElement('afterbegin', existing);
|
|
88
|
+
}
|
|
89
|
+
} catch (_) {}
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const a = document.createElement('a');
|
|
94
|
+
a.href = 'empty:0';
|
|
95
|
+
a.className = 'msg-copy-btn';
|
|
96
|
+
a.setAttribute('role', 'button');
|
|
97
|
+
a.setAttribute('title', copyTitle);
|
|
98
|
+
a.setAttribute('aria-label', copyTitle);
|
|
99
|
+
a.setAttribute('data-tip', copyTitle);
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const box = msg.closest('.msg-box.msg-user');
|
|
103
|
+
if (box && box.id && box.id.startsWith('msg-user-')) {
|
|
104
|
+
const id = box.id.slice('msg-user-'.length);
|
|
105
|
+
a.setAttribute('data-id', id);
|
|
106
|
+
}
|
|
107
|
+
} catch (_) {}
|
|
108
|
+
|
|
109
|
+
const img = document.createElement('img');
|
|
110
|
+
img.className = 'copy-img';
|
|
111
|
+
img.src = copyIcon;
|
|
112
|
+
img.alt = copyTitle;
|
|
113
|
+
|
|
114
|
+
a.appendChild(img);
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
msg.insertAdjacentElement('afterbegin', a);
|
|
118
|
+
} catch (_) {
|
|
119
|
+
try {
|
|
120
|
+
msg.appendChild(a);
|
|
121
|
+
} catch (__) {}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
} catch (_) {}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Append HTML/text into the message input container.
|
|
128
|
+
// If plain text is provided, wrap it into a minimal msg-user box to keep layout consistent.
|
|
129
|
+
appendToInput(content) {
|
|
130
|
+
const el = this.dom.get('_append_input_');
|
|
131
|
+
if (!el) return;
|
|
132
|
+
|
|
133
|
+
let html = String(content || '');
|
|
134
|
+
const trimmed = html.trim();
|
|
135
|
+
|
|
136
|
+
// If already a full msg-user wrapper, append as-is; otherwise wrap the plain text.
|
|
137
|
+
const isWrapped = (trimmed.startsWith('<div') && /class=["']msg-box msg-user["']/.test(trimmed));
|
|
138
|
+
if (!isWrapped) {
|
|
139
|
+
// Treat incoming payload as plain text (escape + convert newlines to <br>).
|
|
140
|
+
const safe = (typeof Utils !== 'undefined' && Utils.escapeHtml) ?
|
|
141
|
+
Utils.escapeHtml(html) :
|
|
142
|
+
String(html).replace(/[&<>"']/g, m => ({
|
|
143
|
+
'&': '&',
|
|
144
|
+
'<': '<',
|
|
145
|
+
'>': '>',
|
|
146
|
+
'"': '"',
|
|
147
|
+
"'": '''
|
|
148
|
+
} [m]));
|
|
149
|
+
const body = safe.replace(/\r?\n/g, '<br>');
|
|
150
|
+
// Minimal, margin-less user message (no empty msg-extra to avoid extra spacing).
|
|
151
|
+
html = `<div class="msg-box msg-user"><div class="msg"><p style="margin:0">${body}</p></div></div>`;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Synchronous DOM update.
|
|
155
|
+
el.insertAdjacentHTML('beforeend', html);
|
|
156
|
+
|
|
157
|
+
// Apply collapse to any user messages in input area (now or later).
|
|
158
|
+
try {
|
|
159
|
+
this._userCollapse.apply(el);
|
|
160
|
+
} catch (_) {}
|
|
161
|
+
|
|
162
|
+
// Ensure copy icons exist (inject or reposition outside uc-content).
|
|
163
|
+
try {
|
|
164
|
+
this._ensureUserCopyIcons(el);
|
|
165
|
+
} catch (_) {}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Append nodes into messages list and perform post-processing (markdown, code, math).
|
|
169
|
+
appendNode(content, scrollMgr) {
|
|
170
|
+
// Keep scroll behavior consistent with existing logic
|
|
171
|
+
scrollMgr.userInteracted = false;
|
|
172
|
+
scrollMgr.prevScroll = 0;
|
|
173
|
+
this.dom.clearStreamBefore();
|
|
174
|
+
|
|
175
|
+
const el = this.dom.get('_nodes_');
|
|
176
|
+
if (!el) return;
|
|
177
|
+
el.classList.remove('empty_list');
|
|
178
|
+
|
|
179
|
+
const userOnly = this._isUserOnlyContent(content);
|
|
180
|
+
if (userOnly) {
|
|
181
|
+
el.insertAdjacentHTML('beforeend', content);
|
|
182
|
+
this._materializeUserMdAsPlainText(el);
|
|
183
|
+
// Collapse before scrolling to ensure final height is used for scroll computations.
|
|
184
|
+
try {
|
|
185
|
+
this._userCollapse.apply(el);
|
|
186
|
+
} catch (_) {}
|
|
187
|
+
// Ensure copy icons exist for user messages.
|
|
188
|
+
try {
|
|
189
|
+
this._ensureUserCopyIcons(el);
|
|
190
|
+
} catch (_) {}
|
|
191
|
+
|
|
192
|
+
scrollMgr.scrollToBottom(false);
|
|
193
|
+
scrollMgr.scheduleScrollFabUpdate();
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
el.insertAdjacentHTML('beforeend', content);
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
// Defer post-processing (highlight/math/collapse) and perform scroll AFTER collapse.
|
|
201
|
+
const maybePromise = this.renderer.renderPendingMarkdown(el);
|
|
202
|
+
const post = () => {
|
|
203
|
+
// Viewport highlight scheduling
|
|
204
|
+
try {
|
|
205
|
+
this.highlighter.scheduleScanVisibleCodes(null);
|
|
206
|
+
} catch (_) {}
|
|
207
|
+
|
|
208
|
+
// In finalize-only mode we must explicitly schedule KaTeX
|
|
209
|
+
try {
|
|
210
|
+
if (getMathMode() === 'finalize-only') this.math.schedule(el, 0, true);
|
|
211
|
+
} catch (_) {}
|
|
212
|
+
|
|
213
|
+
// Collapse user messages now that DOM is materialized (ensures correct height).
|
|
214
|
+
try {
|
|
215
|
+
this._userCollapse.apply(el);
|
|
216
|
+
} catch (_) {}
|
|
217
|
+
|
|
218
|
+
// Ensure copy icons exist for user messages.
|
|
219
|
+
try {
|
|
220
|
+
this._ensureUserCopyIcons(el);
|
|
221
|
+
} catch (_) {}
|
|
222
|
+
|
|
223
|
+
// Only now scroll to bottom and update FAB – uses post-collapse heights.
|
|
224
|
+
scrollMgr.scrollToBottom(false);
|
|
225
|
+
scrollMgr.scheduleScrollFabUpdate();
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
if (maybePromise && typeof maybePromise.then === 'function') {
|
|
229
|
+
maybePromise.then(post);
|
|
230
|
+
} else {
|
|
231
|
+
post();
|
|
232
|
+
}
|
|
233
|
+
} catch (_) {
|
|
234
|
+
// In case of error, do a conservative scroll to keep UX responsive.
|
|
235
|
+
scrollMgr.scrollToBottom(false);
|
|
236
|
+
scrollMgr.scheduleScrollFabUpdate();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Replace messages list content entirely and re-run post-processing.
|
|
241
|
+
replaceNodes(content, scrollMgr) {
|
|
242
|
+
// Same semantics as appendNode, but using a hard clone reset
|
|
243
|
+
scrollMgr.userInteracted = false;
|
|
244
|
+
scrollMgr.prevScroll = 0;
|
|
245
|
+
this.dom.clearStreamBefore();
|
|
246
|
+
|
|
247
|
+
const el = this.dom.hardReplaceByClone('_nodes_');
|
|
248
|
+
if (!el) return;
|
|
249
|
+
el.classList.remove('empty_list');
|
|
250
|
+
|
|
251
|
+
const userOnly = this._isUserOnlyContent(content);
|
|
252
|
+
if (userOnly) {
|
|
253
|
+
el.insertAdjacentHTML('beforeend', content);
|
|
254
|
+
this._materializeUserMdAsPlainText(el);
|
|
255
|
+
// Collapse before scrolling to ensure final height is used for scroll computations.
|
|
256
|
+
try {
|
|
257
|
+
this._userCollapse.apply(el);
|
|
258
|
+
} catch (_) {}
|
|
259
|
+
// Ensure copy icons exist for user messages.
|
|
260
|
+
try {
|
|
261
|
+
this._ensureUserCopyIcons(el);
|
|
262
|
+
} catch (_) {}
|
|
263
|
+
|
|
264
|
+
scrollMgr.scrollToBottom(false, true);
|
|
265
|
+
scrollMgr.scheduleScrollFabUpdate();
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
el.insertAdjacentHTML('beforeend', content);
|
|
270
|
+
|
|
271
|
+
try {
|
|
272
|
+
// Defer KaTeX schedule to post-Markdown to avoid races and collapse before scroll.
|
|
273
|
+
const maybePromise = this.renderer.renderPendingMarkdown(el);
|
|
274
|
+
const post = () => {
|
|
275
|
+
try {
|
|
276
|
+
this.highlighter.scheduleScanVisibleCodes(null);
|
|
277
|
+
} catch (_) {}
|
|
278
|
+
try {
|
|
279
|
+
if (getMathMode() === 'finalize-only') this.math.schedule(el, 0, true);
|
|
280
|
+
} catch (_) {}
|
|
281
|
+
|
|
282
|
+
// Collapse after materialization to compute final heights correctly.
|
|
283
|
+
try {
|
|
284
|
+
this._userCollapse.apply(el);
|
|
285
|
+
} catch (_) {}
|
|
286
|
+
|
|
287
|
+
// Ensure copy icons exist for user messages.
|
|
288
|
+
try {
|
|
289
|
+
this._ensureUserCopyIcons(el);
|
|
290
|
+
} catch (_) {}
|
|
291
|
+
|
|
292
|
+
// Now scroll and update FAB using the collapsed layout.
|
|
293
|
+
scrollMgr.scrollToBottom(false, true);
|
|
294
|
+
scrollMgr.scheduleScrollFabUpdate();
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
if (maybePromise && typeof maybePromise.then === 'function') {
|
|
298
|
+
maybePromise.then(post);
|
|
299
|
+
} else {
|
|
300
|
+
post();
|
|
301
|
+
}
|
|
302
|
+
} catch (_) {
|
|
303
|
+
scrollMgr.scrollToBottom(false, true);
|
|
304
|
+
scrollMgr.scheduleScrollFabUpdate();
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Append "extra" content into a specific bot message and post-process locally.
|
|
309
|
+
appendExtra(id, content, scrollMgr) {
|
|
310
|
+
const el = document.getElementById('msg-bot-' + id);
|
|
311
|
+
if (!el) return;
|
|
312
|
+
const extra = el.querySelector('.msg-extra');
|
|
313
|
+
if (!extra) return;
|
|
314
|
+
|
|
315
|
+
extra.insertAdjacentHTML('beforeend', content);
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
const maybePromise = this.renderer.renderPendingMarkdown(extra);
|
|
319
|
+
|
|
320
|
+
const post = () => {
|
|
321
|
+
const activeCode = (typeof runtime !== 'undefined' && runtime.stream) ? runtime.stream.activeCode : null;
|
|
322
|
+
|
|
323
|
+
// Attach observers after Markdown produced the nodes
|
|
324
|
+
try {
|
|
325
|
+
this.highlighter.observeNewCode(extra, {
|
|
326
|
+
deferLastIfStreaming: true,
|
|
327
|
+
minLinesForLast: this.renderer.cfg.PROFILE_CODE.minLinesForHL,
|
|
328
|
+
minCharsForLast: this.renderer.cfg.PROFILE_CODE.minCharsForHL
|
|
329
|
+
}, activeCode);
|
|
330
|
+
this.highlighter.observeMsgBoxes(extra, (box) => this._onBox(box));
|
|
331
|
+
} catch (_) {}
|
|
332
|
+
|
|
333
|
+
// KaTeX: honor stream mode; in finalize-only force immediate schedule
|
|
334
|
+
try {
|
|
335
|
+
const mm = getMathMode();
|
|
336
|
+
if (mm === 'finalize-only') this.math.schedule(extra, 0, true);
|
|
337
|
+
else this.math.schedule(extra);
|
|
338
|
+
} catch (_) {}
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
if (maybePromise && typeof maybePromise.then === 'function') {
|
|
342
|
+
maybePromise.then(post);
|
|
343
|
+
} else {
|
|
344
|
+
post();
|
|
345
|
+
}
|
|
346
|
+
} catch (_) {
|
|
347
|
+
/* swallow */
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
scrollMgr.scheduleScroll(true);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// When a new message box appears, hook up code/highlight handlers.
|
|
354
|
+
_onBox(box) {
|
|
355
|
+
const activeCode = (typeof runtime !== 'undefined' && runtime.stream) ? runtime.stream.activeCode : null;
|
|
356
|
+
this.highlighter.observeNewCode(box, {
|
|
357
|
+
deferLastIfStreaming: true,
|
|
358
|
+
minLinesForLast: this.renderer.cfg.PROFILE_CODE.minLinesForHL,
|
|
359
|
+
minCharsForLast: this.renderer.cfg.PROFILE_CODE.minCharsForHL
|
|
360
|
+
}, activeCode);
|
|
361
|
+
this.renderer.hooks.codeScrollInit(box);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Remove message by id and keep scroll consistent.
|
|
365
|
+
removeNode(id, scrollMgr) {
|
|
366
|
+
scrollMgr.prevScroll = 0;
|
|
367
|
+
let el = document.getElementById('msg-user-' + id);
|
|
368
|
+
if (el) el.remove();
|
|
369
|
+
el = document.getElementById('msg-bot-' + id);
|
|
370
|
+
if (el) el.remove();
|
|
371
|
+
this.dom.resetEphemeral();
|
|
372
|
+
try {
|
|
373
|
+
this.renderer.renderPendingMarkdown();
|
|
374
|
+
} catch (_) {}
|
|
375
|
+
scrollMgr.scheduleScroll(true);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Remove all messages from (and including) a given message id.
|
|
379
|
+
removeNodesFromId(id, scrollMgr) {
|
|
380
|
+
scrollMgr.prevScroll = 0;
|
|
381
|
+
const container = this.dom.get('_nodes_');
|
|
382
|
+
if (!container) return;
|
|
383
|
+
const elements = container.querySelectorAll('.msg-box');
|
|
384
|
+
let remove = false;
|
|
385
|
+
elements.forEach((element) => {
|
|
386
|
+
if (element.id && element.id.endsWith('-' + id)) remove = true;
|
|
387
|
+
if (remove) element.remove();
|
|
388
|
+
});
|
|
389
|
+
this.dom.resetEphemeral();
|
|
390
|
+
try {
|
|
391
|
+
this.renderer.renderPendingMarkdown(container);
|
|
392
|
+
} catch (_) {}
|
|
393
|
+
scrollMgr.scheduleScroll(true);
|
|
394
|
+
}
|
|
395
|
+
}
|