llms-py 3.0.0b8__tar.gz → 3.0.0b10__tar.gz
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.
- {llms_py-3.0.0b8/llms_py.egg-info → llms_py-3.0.0b10}/PKG-INFO +1 -1
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/__pycache__/main.cpython-314.pyc +0 -0
- llms_py-3.0.0b10/llms/extensions/app/README.md +20 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/app/__init__.py +16 -5
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/app/__pycache__/__init__.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/app/__pycache__/db.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/app/__pycache__/db_manager.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/app/db.py +12 -9
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/app/ui/index.mjs +1 -1
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/app/ui/threadStore.mjs +21 -17
- llms_py-3.0.0b10/llms/extensions/core_tools/CALCULATOR.md +32 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/__init__.py +1 -1
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/__pycache__/__init__.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/index.mjs +4 -4
- llms_py-3.0.0b10/llms/extensions/gallery/README.md +61 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/gallery/ui/index.mjs +1 -0
- llms_py-3.0.0b10/llms/extensions/katex/README.md +39 -0
- llms_py-3.0.0b10/llms/extensions/system_prompts/README.md +22 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/llms.json +9 -12
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/main.py +25 -5
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/ai.mjs +20 -5
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/app.css +114 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/ctx.mjs +22 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/modules/chat/ChatBody.mjs +43 -27
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/modules/chat/index.mjs +17 -29
- {llms_py-3.0.0b8 → llms_py-3.0.0b10/llms_py.egg-info}/PKG-INFO +1 -1
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms_py.egg-info/SOURCES.txt +5 -1
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/pyproject.toml +1 -1
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/setup.py +1 -1
- llms_py-3.0.0b8/llms/ui/modules/chat/HomeTools.mjs +0 -12
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/LICENSE +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/MANIFEST.in +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/README.md +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/__init__.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/__main__.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/__pycache__/__init__.cpython-312.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/__pycache__/__init__.cpython-313.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/__pycache__/__init__.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/__pycache__/__main__.cpython-312.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/__pycache__/__main__.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/__pycache__/llms.cpython-312.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/__pycache__/main.cpython-312.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/__pycache__/main.cpython-313.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/__pycache__/plugins.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/analytics/ui/index.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/app/db_manager.py +1 -1
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/app/requests.json +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/app/threads.json +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/app/ui/Recents.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/addon/edit/closebrackets.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/addon/edit/closetag.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/addon/edit/continuelist.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/addon/edit/matchbrackets.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/addon/edit/matchtags.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/addon/edit/trailingspace.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/addon/selection/active-line.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/addon/selection/mark-selection.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/addon/selection/selection-pointer.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/doc/docs.css +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/doc/source_sans.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/lib/codemirror.css +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/lib/codemirror.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/mode/clike/clike.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/mode/javascript/index.html +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/mode/javascript/javascript.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/mode/javascript/typescript.html +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/mode/python/python.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/theme/dracula.css +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/ui/codemirror/theme/mocha.css +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/gallery/__init__.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/gallery/__pycache__/__init__.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/gallery/__pycache__/db.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/gallery/db.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/__init__.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/__pycache__/__init__.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/README.md +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/contrib/auto-render.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/contrib/auto-render.min.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/contrib/auto-render.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/contrib/copy-tex.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/contrib/copy-tex.min.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/contrib/copy-tex.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/contrib/mathtex-script-type.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/contrib/mathtex-script-type.min.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/contrib/mathtex-script-type.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/contrib/mhchem.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/contrib/mhchem.min.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/contrib/mhchem.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/contrib/render-a11y-string.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/contrib/render-a11y-string.min.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/contrib/render-a11y-string.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.woff +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/index.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/katex-swap.css +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/katex-swap.min.css +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/katex.css +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/katex.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/katex.min.css +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/katex.min.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/katex.min.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/katex/ui/katex.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/providers/__init__.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/providers/__pycache__/__init__.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/providers/__pycache__/anthropic.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/providers/__pycache__/chutes.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/providers/__pycache__/google.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/providers/__pycache__/nvidia.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/providers/__pycache__/openai.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/providers/__pycache__/openrouter.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/providers/anthropic.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/providers/chutes.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/providers/google.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/providers/nvidia.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/providers/openai.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/providers/openrouter.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/system_prompts/__init__.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/system_prompts/__pycache__/__init__.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/system_prompts/ui/index.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/system_prompts/ui/prompts.json +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/tools/__init__.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/tools/__pycache__/__init__.cpython-314.pyc +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/tools/ui/index.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/index.html +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/providers-extra.json +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/providers.json +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/App.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/fav.svg +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/index.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/lib/chart.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/lib/charts.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/lib/color.js +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/lib/highlight.min.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/lib/idb.min.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/lib/marked.min.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/lib/servicestack-client.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/lib/servicestack-vue.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/lib/vue-router.min.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/lib/vue.min.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/lib/vue.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/markdown.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/modules/chat/SettingsDialog.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/modules/layout.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/modules/model-selector.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/tailwind.input.css +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/typography.css +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/ui/utils.mjs +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms_py.egg-info/dependency_links.txt +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms_py.egg-info/entry_points.txt +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms_py.egg-info/not-zip-safe +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms_py.egg-info/requires.txt +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms_py.egg-info/top_level.txt +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/requirements.txt +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/setup.cfg +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/tests/test_async.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/tests/test_config.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/tests/test_extensions.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/tests/test_integration.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/tests/test_provider_checks.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/tests/test_provider_config.py +0 -0
- {llms_py-3.0.0b8 → llms_py-3.0.0b10}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: llms-py
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.0b10
|
|
4
4
|
Summary: A lightweight CLI tool and OpenAI-compatible server for querying multiple Large Language Model (LLM) providers
|
|
5
5
|
Home-page: https://github.com/ServiceStack/llms
|
|
6
6
|
Author: ServiceStack
|
|
Binary file
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# App Extension
|
|
2
|
+
|
|
3
|
+
This extension provides the core application logic and data persistence for the LLMs platform.
|
|
4
|
+
|
|
5
|
+
## Data Storage & Architecture
|
|
6
|
+
|
|
7
|
+
### Server-Side SQLite Migration
|
|
8
|
+
The application has migrated from client-side IndexedDB storage to a robust server-side SQLite solution. This architectural shift ensures better data consistency, improved performance, and enables multi-device access to your chat history.
|
|
9
|
+
|
|
10
|
+
### Asset Management
|
|
11
|
+
To keep the database efficient and portable, binary assets (images, audio, etc.) are not stored directly in the SQLite database. Instead:
|
|
12
|
+
- All generated assets are stored in the local file system cache at `~/.llms/cache`.
|
|
13
|
+
- The database stores only **relative URLs** pointing to these assets.
|
|
14
|
+
- This approach allows for efficient caching and serving of static media.
|
|
15
|
+
|
|
16
|
+
### Concurrency Model
|
|
17
|
+
To ensure data integrity and high performance without complex locking mechanisms, the system utilizes a **single background thread** for managing all write operations to the database. This design improves concurrency handling and eliminates database locking issues during high-load scenarios.
|
|
18
|
+
|
|
19
|
+
### Multi-Tenancy & Security
|
|
20
|
+
When authentication is enabled, data isolation is automatically enforced. All core tables, including `threads` and `requests`, are scoped to the authenticated user, ensuring that users can only access their own data.
|
|
@@ -60,7 +60,7 @@ def install(ctx):
|
|
|
60
60
|
return to
|
|
61
61
|
|
|
62
62
|
def thread_dto(row):
|
|
63
|
-
return row and to_dto(row, ["messages", "modalities", "args", "modelInfo", "stats"])
|
|
63
|
+
return row and to_dto(row, ["messages", "modalities", "args", "modelInfo", "stats", "metadata"])
|
|
64
64
|
|
|
65
65
|
def request_dto(row):
|
|
66
66
|
return row and to_dto(row, ["usage"])
|
|
@@ -174,12 +174,13 @@ def install(ctx):
|
|
|
174
174
|
if not thread:
|
|
175
175
|
raise Exception("Thread not found")
|
|
176
176
|
|
|
177
|
+
metadata = thread.get("metadata", {})
|
|
177
178
|
chat = {
|
|
178
179
|
"model": thread.get("model"),
|
|
179
180
|
"messages": thread.get("messages"),
|
|
180
181
|
"modalities": thread.get("modalities"),
|
|
181
182
|
"systemPrompt": thread.get("systemPrompt"),
|
|
182
|
-
"metadata":
|
|
183
|
+
"metadata": metadata,
|
|
183
184
|
}
|
|
184
185
|
for k, v in thread.get("args", {}).items():
|
|
185
186
|
if k in ctx.request_args:
|
|
@@ -189,7 +190,8 @@ def install(ctx):
|
|
|
189
190
|
"chat": chat,
|
|
190
191
|
"user": user,
|
|
191
192
|
"threadId": id,
|
|
192
|
-
"
|
|
193
|
+
"metadata": metadata,
|
|
194
|
+
"tools": metadata.get("tools", "all"),
|
|
193
195
|
}
|
|
194
196
|
|
|
195
197
|
# execute chat in background thread
|
|
@@ -341,13 +343,22 @@ def install(ctx):
|
|
|
341
343
|
|
|
342
344
|
ctx.register_chat_request_filter(chat_request)
|
|
343
345
|
|
|
344
|
-
async def tool_request(
|
|
345
|
-
|
|
346
|
+
async def tool_request(chat_request, context):
|
|
347
|
+
messages = chat_request.get("messages", [])
|
|
348
|
+
ctx.dbg(f"tool_request: messages {len(messages)}")
|
|
346
349
|
thread_id = context.get("threadId", None)
|
|
347
350
|
if not thread_id:
|
|
348
351
|
ctx.dbg("Missing threadId")
|
|
349
352
|
return
|
|
350
353
|
user = context.get("user", None)
|
|
354
|
+
await g_db.update_thread_async(
|
|
355
|
+
thread_id,
|
|
356
|
+
{
|
|
357
|
+
"messages": messages,
|
|
358
|
+
},
|
|
359
|
+
user=user,
|
|
360
|
+
)
|
|
361
|
+
|
|
351
362
|
completed_at = g_db.get_thread_column(thread_id, "completedAt", user=user)
|
|
352
363
|
if completed_at:
|
|
353
364
|
context["completed"] = True
|
{llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/app/__pycache__/__init__.cpython-314.pyc
RENAMED
|
Binary file
|
|
Binary file
|
{llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/app/__pycache__/db_manager.cpython-314.pyc
RENAMED
|
Binary file
|
|
@@ -62,6 +62,11 @@ class AppDB:
|
|
|
62
62
|
|
|
63
63
|
self.ctx = ctx
|
|
64
64
|
self.db_path = str(db_path)
|
|
65
|
+
|
|
66
|
+
dirname = os.path.dirname(self.db_path)
|
|
67
|
+
if dirname:
|
|
68
|
+
os.makedirs(dirname, exist_ok=True)
|
|
69
|
+
|
|
65
70
|
self.db = DbManager(ctx, self.db_path)
|
|
66
71
|
self.columns = {
|
|
67
72
|
"thread": {
|
|
@@ -86,6 +91,7 @@ class AppDB:
|
|
|
86
91
|
"publishedAt": "TIMESTAMP",
|
|
87
92
|
"startedAt": "TIMESTAMP",
|
|
88
93
|
"completedAt": "TIMESTAMP",
|
|
94
|
+
"metadata": "JSON",
|
|
89
95
|
"error": "TEXT",
|
|
90
96
|
"ref": "TEXT",
|
|
91
97
|
},
|
|
@@ -142,9 +148,6 @@ class AppDB:
|
|
|
142
148
|
self.ctx.err(f"adding {table} column {col}", e)
|
|
143
149
|
|
|
144
150
|
def init_db(self, conn):
|
|
145
|
-
dirname = os.path.dirname(self.db_path)
|
|
146
|
-
if dirname:
|
|
147
|
-
os.makedirs(dirname, exist_ok=True)
|
|
148
151
|
# Create table with all columns
|
|
149
152
|
# Note: default SQLite timestamp has different tz to datetime.now()
|
|
150
153
|
overrides = {
|
|
@@ -442,7 +445,7 @@ class AppDB:
|
|
|
442
445
|
event.wait()
|
|
443
446
|
return ret[0]
|
|
444
447
|
|
|
445
|
-
def prepare_thread(self, thread, id=None):
|
|
448
|
+
def prepare_thread(self, thread, id=None, user=None):
|
|
446
449
|
now = datetime.now()
|
|
447
450
|
if id:
|
|
448
451
|
thread["id"] = id
|
|
@@ -452,19 +455,19 @@ class AppDB:
|
|
|
452
455
|
if "messages" in thread:
|
|
453
456
|
for m in thread["messages"]:
|
|
454
457
|
self.ctx.cache_message_inline_data(m)
|
|
455
|
-
return thread
|
|
458
|
+
return with_user(thread, user=user)
|
|
456
459
|
|
|
457
460
|
def create_thread(self, thread: Dict[str, Any], user=None):
|
|
458
|
-
return self.insert("thread",
|
|
461
|
+
return self.insert("thread", self.prepare_thread(thread, user=user))
|
|
459
462
|
|
|
460
463
|
async def create_thread_async(self, thread: Dict[str, Any], user=None):
|
|
461
|
-
return await self.insert_async("thread",
|
|
464
|
+
return await self.insert_async("thread", self.prepare_thread(thread, user=user))
|
|
462
465
|
|
|
463
466
|
def update_thread(self, id, thread: Dict[str, Any], user=None):
|
|
464
|
-
return self.update("thread",
|
|
467
|
+
return self.update("thread", self.prepare_thread(thread, id, user=user))
|
|
465
468
|
|
|
466
469
|
async def update_thread_async(self, id, thread: Dict[str, Any], user=None):
|
|
467
|
-
return await self.update_async("thread",
|
|
470
|
+
return await self.update_async("thread", self.prepare_thread(thread, id, user=user))
|
|
468
471
|
|
|
469
472
|
def delete_thread(self, id, user=None, callback=None):
|
|
470
473
|
sql_where, params = self.get_user_filter(user, {"id": id})
|
|
@@ -219,7 +219,7 @@ const ThreadsSidebar = {
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
const createNewThread = async () => {
|
|
222
|
-
ctx.threads.startNewThread({ title: 'New Chat', model: ctx.chat.getSelectedModel() })
|
|
222
|
+
ctx.threads.startNewThread({ title: 'New Chat', model: ctx.chat.getSelectedModel(), redirect: true })
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
const goToInitialState = () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ref, computed } from 'vue'
|
|
2
|
-
import { appendQueryString
|
|
2
|
+
import { appendQueryString } from '@servicestack/client'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Returns an ever-increasing unique integer id.
|
|
@@ -21,11 +21,6 @@ const isLoading = ref(false)
|
|
|
21
21
|
let ctx = null
|
|
22
22
|
let ext = null
|
|
23
23
|
|
|
24
|
-
// Generate unique thread ID
|
|
25
|
-
function generateThreadId() {
|
|
26
|
-
return Date.now().toString()
|
|
27
|
-
}
|
|
28
|
-
|
|
29
24
|
function setError(error, msg = null) {
|
|
30
25
|
ctx?.setError(error, msg)
|
|
31
26
|
}
|
|
@@ -170,7 +165,7 @@ async function redoMessageFromThread(threadId, timestamp) {
|
|
|
170
165
|
// Find the index of the message to redo
|
|
171
166
|
const messageIndex = thread.messages.findIndex(m => m.timestamp === timestamp)
|
|
172
167
|
if (messageIndex === -1) {
|
|
173
|
-
setError(
|
|
168
|
+
setError({ message: `Message not found for timestamp ${timestamp}` })
|
|
174
169
|
return
|
|
175
170
|
}
|
|
176
171
|
|
|
@@ -188,7 +183,8 @@ async function redoMessageFromThread(threadId, timestamp) {
|
|
|
188
183
|
const updatedMessages = thread.messages.slice(0, messageIndex + 1)
|
|
189
184
|
|
|
190
185
|
// Update the thread with the new messages
|
|
191
|
-
const
|
|
186
|
+
const request = { messages: updatedMessages }
|
|
187
|
+
const api = await queueChat({ request, thread })
|
|
192
188
|
if (api.response) {
|
|
193
189
|
replaceThread(api.response)
|
|
194
190
|
} else {
|
|
@@ -311,7 +307,7 @@ function getLatestCachedThread() {
|
|
|
311
307
|
return threads.value[0]
|
|
312
308
|
}
|
|
313
309
|
|
|
314
|
-
async function startNewThread({ title, model }) {
|
|
310
|
+
async function startNewThread({ title, model, redirect }) {
|
|
315
311
|
if (!model) {
|
|
316
312
|
console.error('No model selected')
|
|
317
313
|
return
|
|
@@ -337,8 +333,10 @@ async function startNewThread({ title, model }) {
|
|
|
337
333
|
})
|
|
338
334
|
|
|
339
335
|
console.log('newThread', newThread, model)
|
|
340
|
-
|
|
341
|
-
|
|
336
|
+
if (redirect) {
|
|
337
|
+
// Navigate to the new thread URL
|
|
338
|
+
ctx.to(`/c/${newThread.id}`)
|
|
339
|
+
}
|
|
342
340
|
|
|
343
341
|
// Get the thread to check for duplicates
|
|
344
342
|
let thread = await getThread(newThread.id)
|
|
@@ -346,12 +344,19 @@ async function startNewThread({ title, model }) {
|
|
|
346
344
|
return thread
|
|
347
345
|
}
|
|
348
346
|
|
|
349
|
-
async function queueChat(
|
|
350
|
-
|
|
347
|
+
async function queueChat(ctxRequest, options = {}) {
|
|
348
|
+
if (!ctxRequest.request) return ctx.createErrorResult({ message: 'No request provided' })
|
|
349
|
+
if (!ctxRequest.thread) return ctx.createErrorResult({ message: 'No thread provided' })
|
|
350
|
+
if (!ctxRequest.request.metadata) {
|
|
351
|
+
ctxRequest.request.metadata = {}
|
|
352
|
+
}
|
|
353
|
+
ctx.chatRequestFilters.forEach(f => f(ctxRequest))
|
|
354
|
+
const { thread, request } = ctxRequest
|
|
355
|
+
const api = await ctx.postJson(`/ext/app/threads/${thread.id}/chat`, {
|
|
351
356
|
...options,
|
|
352
|
-
body: typeof
|
|
353
|
-
?
|
|
354
|
-
: JSON.stringify(
|
|
357
|
+
body: typeof request == 'string'
|
|
358
|
+
? request
|
|
359
|
+
: JSON.stringify(request),
|
|
355
360
|
})
|
|
356
361
|
return api
|
|
357
362
|
}
|
|
@@ -380,7 +385,6 @@ export function useThreadStore() {
|
|
|
380
385
|
clearCurrentThread,
|
|
381
386
|
getGroupedThreads,
|
|
382
387
|
getLatestCachedThread,
|
|
383
|
-
generateThreadId,
|
|
384
388
|
startNewThread,
|
|
385
389
|
replaceThread,
|
|
386
390
|
queueChat,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Calculator
|
|
2
|
+
|
|
3
|
+
A powerful and safe mathematical expression evaluator with a rich web interface.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
### 🖥️ UX Friendly Interface
|
|
8
|
+
Experience a clean, modern interface designed for efficiency. The UI is fully responsive and supports dark mode, seamlessly integrating with the rest of the application.
|
|
9
|
+
|
|
10
|
+
### 💾 Persistent History
|
|
11
|
+
Never lose track of your calculations. The Calculator automatically saves your history to `localStorage`, ensuring your previous expressions and results are preserved between sessions.
|
|
12
|
+
|
|
13
|
+
### ⚡ 1-Click Interaction
|
|
14
|
+
Streamline your workflow with interactive history items:
|
|
15
|
+
- **Load & Copy**: Click on any past expression or answer to instantly load it into the input field and copy it to your clipboard.
|
|
16
|
+
- **Visual Feedback**: Temporary checkmarks confirm successful copy actions.
|
|
17
|
+
|
|
18
|
+
### ⌨️ Keyboard-Free Access
|
|
19
|
+
While full keyboard support is available, you can perform complex calculations entirely via the UI:
|
|
20
|
+
- **Numbers & Constants**: Quick access to digits and mathematical constants like `pi`, `e`, `inf`.
|
|
21
|
+
- **Operators**: Comprehensive set of buttons for arithmetic (`+`, `-`, `*`, `/`, `%`, `^`) and boolean logic (`and`, `or`, `not`).
|
|
22
|
+
- **Functions**: One-click insertion or wrapping of selection for all supported math functions.
|
|
23
|
+
|
|
24
|
+
### 🐍 Python Math Support
|
|
25
|
+
Unlock the power of Python's math library directly in the browser.
|
|
26
|
+
- **Math Functions**: Support for `sin`, `cos`, `tan`, `sqrt`, `log`, `factorial`, and many more.
|
|
27
|
+
- **Statistics**: Built-in functions for `mean`, `median`, `stdev`, and `variance`.
|
|
28
|
+
|
|
29
|
+
### 🛡️ Safe Evaluation
|
|
30
|
+
Security is a priority. Instead of using Python's unsafe `eval()`, the Calculator uses a robust **AST (Abstract Syntax Tree) evaluator**.
|
|
31
|
+
- **Restricted Environment**: Only allowed mathematical operations and functions are executed.
|
|
32
|
+
- **No Side Effects**: Prevents arbitrary code execution, making it safe to evaluate expressions from untrusted sources.
|
|
@@ -523,7 +523,7 @@ def install(ctx):
|
|
|
523
523
|
# Examples of registering tools using automatic definition generation
|
|
524
524
|
ctx.register_tool(memory_read)
|
|
525
525
|
ctx.register_tool(memory_write)
|
|
526
|
-
ctx.register_tool(semantic_search)
|
|
526
|
+
# ctx.register_tool(semantic_search) # TODO: implement
|
|
527
527
|
ctx.register_tool(read_file)
|
|
528
528
|
ctx.register_tool(write_file)
|
|
529
529
|
ctx.register_tool(list_directory)
|
{llms_py-3.0.0b8 → llms_py-3.0.0b10}/llms/extensions/core_tools/__pycache__/__init__.cpython-314.pyc
RENAMED
|
Binary file
|
|
@@ -381,7 +381,7 @@ const CalcPage = {
|
|
|
381
381
|
type="button"
|
|
382
382
|
@click="insert(num)"
|
|
383
383
|
class="px-3 py-1 bg-gray-100 dark:bg-gray-800 hover:bg-blue-100 dark:hover:bg-blue-900/30 text-gray-700 dark:text-gray-300 hover:text-blue-700 dark:hover:text-blue-300 border border-gray-200 dark:border-gray-700 rounded text-sm font-mono transition-colors"
|
|
384
|
-
title="
|
|
384
|
+
:title="'insert number ' + num"
|
|
385
385
|
>
|
|
386
386
|
{{ num }}
|
|
387
387
|
</button>
|
|
@@ -392,7 +392,7 @@ const CalcPage = {
|
|
|
392
392
|
type="button"
|
|
393
393
|
@click="insert(c)"
|
|
394
394
|
class="px-3 py-1 bg-gray-100 dark:bg-gray-800 hover:bg-blue-100 dark:hover:bg-blue-900/30 text-gray-700 dark:text-gray-300 hover:text-blue-700 dark:hover:text-blue-300 border border-gray-200 dark:border-gray-700 rounded text-sm font-mono transition-colors"
|
|
395
|
-
title="
|
|
395
|
+
:title="'insert constant ' + c"
|
|
396
396
|
>
|
|
397
397
|
{{ c }}
|
|
398
398
|
</button>
|
|
@@ -408,7 +408,7 @@ const CalcPage = {
|
|
|
408
408
|
type="button"
|
|
409
409
|
@click="insert(op)"
|
|
410
410
|
class="px-3 py-1 bg-gray-100 dark:bg-gray-800 hover:bg-blue-100 dark:hover:bg-blue-900/30 text-gray-700 dark:text-gray-300 hover:text-blue-700 dark:hover:text-blue-300 border border-gray-200 dark:border-gray-700 rounded text-sm font-mono transition-colors"
|
|
411
|
-
title="
|
|
411
|
+
:title="'insert operator ' + op"
|
|
412
412
|
>
|
|
413
413
|
{{ op }}
|
|
414
414
|
</button>
|
|
@@ -425,7 +425,7 @@ const CalcPage = {
|
|
|
425
425
|
type="button"
|
|
426
426
|
@click="wrapWithFunction(func)"
|
|
427
427
|
class="px-3 py-1 bg-gray-100 dark:bg-gray-800 hover:bg-purple-100 dark:hover:bg-purple-900/30 text-gray-700 dark:text-gray-300 hover:text-purple-700 dark:hover:text-purple-300 border border-gray-200 dark:border-gray-700 rounded text-sm font-mono transition-colors"
|
|
428
|
-
title="
|
|
428
|
+
:title="'use function ' + func"
|
|
429
429
|
>
|
|
430
430
|
{{ func }}
|
|
431
431
|
</button>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Gallery Extension
|
|
2
|
+
|
|
3
|
+
The Gallery extension intercepts all generated image, audio & file assets and uploaded files in `~/.llms/cache` file storage whose metadata is maintained in a SQLite database.
|
|
4
|
+
|
|
5
|
+
Dedicated UIs are available for quickly browsing and navigating or generated images / audio files with optimized UIs for viewing portrait, square and landscape images.
|
|
6
|
+
|
|
7
|
+
## Generated Asset Interception
|
|
8
|
+
|
|
9
|
+
The Gallery extension automatically monitors the creation of new cache entries. Whenever a file is saved to the LLMs cache (located at `~/.llms/cache`), the extension captures its metadata and stores it in the gallery database.
|
|
10
|
+
|
|
11
|
+
This includes:
|
|
12
|
+
- **Generated Images**: Images created by AI models (e.g., DALL-E, Stable Diffusion).
|
|
13
|
+
- **Generated Audio**: Audio files generated by text-to-speech or audio models.
|
|
14
|
+
- **Uploaded Files**: Any files uploaded through the UI.
|
|
15
|
+
|
|
16
|
+
All metadata is stored in a dedicated SQLite database located at `~/.llms/user/default/gallery/gallery.sqlite`, in the `media` table.
|
|
17
|
+
|
|
18
|
+
## User Interface
|
|
19
|
+
|
|
20
|
+
The Gallery UI provides a rich, interactive way to explore your generated assets. You can access it via the **Gallery** tab in the sidebar or by navigating to `/gallery`.
|
|
21
|
+
|
|
22
|
+
### Image Gallery
|
|
23
|
+
|
|
24
|
+
The image view offers a responsive grid layout optimized for different aspect ratios.
|
|
25
|
+
|
|
26
|
+
- **Filtering**:
|
|
27
|
+
- **By Format**: Easily switch between **Portrait**, **Square**, and **Landscape** views to see images in their best light.
|
|
28
|
+
- **Search**: Real-time search by prompt, model name, or other metadata.
|
|
29
|
+
- **Interactions**:
|
|
30
|
+
- **Lightbox**: Click any image to view it in full screen.
|
|
31
|
+
- **Details**: View comprehensive metadata including the prompt used, generation model, dimensions, file size, creation date, and generation cost.
|
|
32
|
+
- **Download**: extensive download options.
|
|
33
|
+
- **Remix**: Quickly re-use the prompt and settings of an existing image to generate a new one.
|
|
34
|
+
- **Delete**: Remove unwanted images from the gallery.
|
|
35
|
+
|
|
36
|
+
### Audio Gallery
|
|
37
|
+
|
|
38
|
+
The audio view presents a list layout designed for easy listening and management.
|
|
39
|
+
|
|
40
|
+
- **Playback**: Integrated audio player to preview generated sounds directly in the list.
|
|
41
|
+
- **Metadata**: Displays the caption/prompt, model, and creation time.
|
|
42
|
+
- **Actions**:
|
|
43
|
+
- **Remix**: Regenerate audio using the same prompt.
|
|
44
|
+
- **Delete**: Remove audio files.
|
|
45
|
+
|
|
46
|
+
## Storage Data model
|
|
47
|
+
|
|
48
|
+
The `media` table tracks extensive information about each asset to support the search and filtering capabilities:
|
|
49
|
+
|
|
50
|
+
| Column | Description |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `url` | Relative path to the file in `~/.llms/cache` |
|
|
53
|
+
| `type` | Asset type (image, audio, video) |
|
|
54
|
+
| `prompt` | The prompt used to generate the asset |
|
|
55
|
+
| `model` | The AI model used |
|
|
56
|
+
| `aspect_ratio` | Aspect ratio (e.g., "1:1", "16:9") |
|
|
57
|
+
| `cost` | Generation cost |
|
|
58
|
+
| `metadata` | Additional JSON metadata |
|
|
59
|
+
| `created` | Timestamp of creation |
|
|
60
|
+
|
|
61
|
+
This local database ensures your gallery remains fast and responsive, even with a large collection of generated assets.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# KaTeX Extension
|
|
2
|
+
|
|
3
|
+
This extension enables beautiful rendering of LaTeX math expressions in AI responses using [KaTeX](https://katex.org/). It integrates automatically with the markdown parser to render math equations in both inline and block formats.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Fast Rendering**: Uses KaTeX for high-performance rendering of math expressions.
|
|
8
|
+
- **Inline Math**: Renders math within text using `$` or `$$` delimiters.
|
|
9
|
+
- **Block Math**: Renders complex equations in their own block using `$` or `$$` delimiters across multiple lines.
|
|
10
|
+
- **Auto-Integration**: Automatically extends the `marked` parser used in the application.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
The extension supports standard LaTeX math syntax.
|
|
15
|
+
|
|
16
|
+
### Inline Math
|
|
17
|
+
|
|
18
|
+
Surround your LaTeX expression with single `$` (for inline style) or double `$$` (for display style) delimiters.
|
|
19
|
+
|
|
20
|
+
**Example:**
|
|
21
|
+
`The quadratic formula is $x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$.`
|
|
22
|
+
|
|
23
|
+
### Block Math
|
|
24
|
+
|
|
25
|
+
For larger equations or when you want the math to be displayed on its own line, use block syntax by placing the delimiters on separate lines. Standard usage is to use double `$$` delimiters.
|
|
26
|
+
|
|
27
|
+
**Example:**
|
|
28
|
+
```latex
|
|
29
|
+
$$
|
|
30
|
+
\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
|
|
31
|
+
$$
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Configuration
|
|
35
|
+
|
|
36
|
+
The extension automatically registers:
|
|
37
|
+
- **Import Maps**: Loads `katex.min.mjs` for the frontend.
|
|
38
|
+
- **CSS**: Injects `katex.min.css` for styling.
|
|
39
|
+
- **Markdown Extension**: Adds a custom tokenizer and renderer to `marked` to detect and render LaTeX patterns.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# System Prompts Extension
|
|
2
|
+
|
|
3
|
+
This extension configures AI requests with a library of **over 200+** awesome curated system prompts that can be selected from the UI.
|
|
4
|
+
|
|
5
|
+
## Custom System Prompts
|
|
6
|
+
|
|
7
|
+
You can also maintain your own library of system prompts which can be maintained for all anonymous users at:
|
|
8
|
+
`~/.llms/user/default/system-prompts.json`
|
|
9
|
+
|
|
10
|
+
Or for signed in users at:
|
|
11
|
+
`~/.llms/user/<github-user>/system-prompts.json`
|
|
12
|
+
|
|
13
|
+
The JSON file should contain an array of Prompt objects, e.g:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
[
|
|
17
|
+
{
|
|
18
|
+
"name": "Helpful Assistant",
|
|
19
|
+
"prompt": "You are a helpful assistant."
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
```
|
|
@@ -9,14 +9,11 @@
|
|
|
9
9
|
"restrict_to": "GITHUB_USERS"
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
|
-
"disable_extensions": [
|
|
13
|
-
"xmas",
|
|
14
|
-
"duckduckgo"
|
|
15
|
-
],
|
|
12
|
+
"disable_extensions": [],
|
|
16
13
|
"defaults": {
|
|
17
14
|
"headers": {
|
|
18
15
|
"Content-Type": "application/json",
|
|
19
|
-
"User-Agent": "llmspy.org/
|
|
16
|
+
"User-Agent": "llmspy.org/3.0"
|
|
20
17
|
},
|
|
21
18
|
"text": {
|
|
22
19
|
"model": "kimi-k2",
|
|
@@ -95,7 +92,7 @@
|
|
|
95
92
|
]
|
|
96
93
|
},
|
|
97
94
|
"out:image": {
|
|
98
|
-
"model": "
|
|
95
|
+
"model": "gemini-2.5-flash-image",
|
|
99
96
|
"messages": [
|
|
100
97
|
{
|
|
101
98
|
"role": "user",
|
|
@@ -202,10 +199,10 @@
|
|
|
202
199
|
}
|
|
203
200
|
},
|
|
204
201
|
"github-copilot": {
|
|
205
|
-
"enabled":
|
|
202
|
+
"enabled": true
|
|
206
203
|
},
|
|
207
204
|
"github-models": {
|
|
208
|
-
"enabled":
|
|
205
|
+
"enabled": true,
|
|
209
206
|
"check": {
|
|
210
207
|
"messages": [
|
|
211
208
|
{
|
|
@@ -230,13 +227,13 @@
|
|
|
230
227
|
"temperature": 1.0
|
|
231
228
|
},
|
|
232
229
|
"ollama": {
|
|
233
|
-
"enabled":
|
|
230
|
+
"enabled": false,
|
|
234
231
|
"id": "ollama",
|
|
235
232
|
"npm": "ollama",
|
|
236
233
|
"api": "http://localhost:11434"
|
|
237
234
|
},
|
|
238
235
|
"lmstudio": {
|
|
239
|
-
"enabled":
|
|
236
|
+
"enabled": false,
|
|
240
237
|
"npm": "lmstudio",
|
|
241
238
|
"api": "http://127.0.0.1:1234/v1",
|
|
242
239
|
"models": {}
|
|
@@ -351,7 +348,7 @@
|
|
|
351
348
|
"enabled": true
|
|
352
349
|
},
|
|
353
350
|
"moonshotai": {
|
|
354
|
-
"enabled":
|
|
351
|
+
"enabled": true
|
|
355
352
|
},
|
|
356
353
|
"nvidia": {
|
|
357
354
|
"enabled": true,
|
|
@@ -372,7 +369,7 @@
|
|
|
372
369
|
"enabled": true
|
|
373
370
|
},
|
|
374
371
|
"fireworks-ai": {
|
|
375
|
-
"enabled":
|
|
372
|
+
"enabled": true
|
|
376
373
|
},
|
|
377
374
|
"openrouter": {
|
|
378
375
|
"enabled": true,
|
|
@@ -29,7 +29,7 @@ from importlib import resources # Py≥3.9 (pip install importlib_resources fo
|
|
|
29
29
|
from io import BytesIO
|
|
30
30
|
from pathlib import Path
|
|
31
31
|
from typing import get_type_hints
|
|
32
|
-
from urllib.parse import parse_qs, urlencode
|
|
32
|
+
from urllib.parse import parse_qs, urlencode, urljoin
|
|
33
33
|
|
|
34
34
|
import aiohttp
|
|
35
35
|
from aiohttp import web
|
|
@@ -41,7 +41,7 @@ try:
|
|
|
41
41
|
except ImportError:
|
|
42
42
|
HAS_PIL = False
|
|
43
43
|
|
|
44
|
-
VERSION = "3.0.
|
|
44
|
+
VERSION = "3.0.0b10"
|
|
45
45
|
_ROOT = None
|
|
46
46
|
DEBUG = os.getenv("DEBUG") == "1"
|
|
47
47
|
MOCK = os.getenv("MOCK") == "1"
|
|
@@ -204,6 +204,12 @@ def id_to_name(id):
|
|
|
204
204
|
return id.replace("-", " ").title()
|
|
205
205
|
|
|
206
206
|
|
|
207
|
+
def pluralize(word, count):
|
|
208
|
+
if count == 1:
|
|
209
|
+
return word
|
|
210
|
+
return word + "s"
|
|
211
|
+
|
|
212
|
+
|
|
207
213
|
def get_file_mime_type(filename):
|
|
208
214
|
mime_type, _ = mimetypes.guess_type(filename)
|
|
209
215
|
return mime_type or "application/octet-stream"
|
|
@@ -368,6 +374,9 @@ async def process_chat(chat, provider_id=None):
|
|
|
368
374
|
raise Exception("No chat provided")
|
|
369
375
|
if "stream" not in chat:
|
|
370
376
|
chat["stream"] = False
|
|
377
|
+
# Some providers don't support empty tools
|
|
378
|
+
if "tools" in chat and len(chat["tools"]) == 0:
|
|
379
|
+
del chat["tools"]
|
|
371
380
|
if "messages" not in chat:
|
|
372
381
|
return chat
|
|
373
382
|
|
|
@@ -700,6 +709,7 @@ def save_image_to_cache(base64_data, filename, image_info, ignore_info=False):
|
|
|
700
709
|
async def response_json(response):
|
|
701
710
|
text = await response.text()
|
|
702
711
|
if response.status >= 400:
|
|
712
|
+
_dbg(f"HTTP {response.status} {response.reason}: {text}")
|
|
703
713
|
raise HTTPError(response.status, reason=response.reason, body=text, headers=dict(response.headers))
|
|
704
714
|
response.raise_for_status()
|
|
705
715
|
body = json.loads(text)
|
|
@@ -1427,6 +1437,8 @@ async def g_chat_completion(chat, context=None):
|
|
|
1427
1437
|
current_chat["messages"].append(message)
|
|
1428
1438
|
tool_history.append(message)
|
|
1429
1439
|
|
|
1440
|
+
await g_app.on_chat_tool(current_chat, context)
|
|
1441
|
+
|
|
1430
1442
|
for tool_call in tool_calls:
|
|
1431
1443
|
function_name = tool_call["function"]["name"]
|
|
1432
1444
|
try:
|
|
@@ -1450,8 +1462,7 @@ async def g_chat_completion(chat, context=None):
|
|
|
1450
1462
|
current_chat["messages"].append(tool_msg)
|
|
1451
1463
|
tool_history.append(tool_msg)
|
|
1452
1464
|
|
|
1453
|
-
|
|
1454
|
-
await filter_func(current_chat, context)
|
|
1465
|
+
await g_app.on_chat_tool(current_chat, context)
|
|
1455
1466
|
|
|
1456
1467
|
if should_cancel_thread(context):
|
|
1457
1468
|
return
|
|
@@ -1606,7 +1617,7 @@ async def cli_chat(chat, tools=None, image=None, audio=None, file=None, args=Non
|
|
|
1606
1617
|
for file in generated_files:
|
|
1607
1618
|
if file.startswith("/~cache"):
|
|
1608
1619
|
print(get_cache_path(file[8:]))
|
|
1609
|
-
print(
|
|
1620
|
+
print(urljoin("http://localhost:8000", file))
|
|
1610
1621
|
else:
|
|
1611
1622
|
print(file)
|
|
1612
1623
|
|
|
@@ -2443,6 +2454,15 @@ class AppExtensions:
|
|
|
2443
2454
|
except Exception as e:
|
|
2444
2455
|
_err("chat error filter failed", e)
|
|
2445
2456
|
|
|
2457
|
+
async def on_chat_tool(self, chat, context):
|
|
2458
|
+
m_len = len(chat.get("messages", []))
|
|
2459
|
+
t_len = len(self.chat_tool_filters)
|
|
2460
|
+
_dbg(
|
|
2461
|
+
f"on_tool_call for thread {context.get('threadId', None)} with {m_len} {pluralize('message', m_len)}, invoking {t_len} {pluralize('filter', t_len)}:"
|
|
2462
|
+
)
|
|
2463
|
+
for filter_func in self.chat_tool_filters:
|
|
2464
|
+
await filter_func(chat, context)
|
|
2465
|
+
|
|
2446
2466
|
def exit(self, exit_code=0):
|
|
2447
2467
|
if len(self.shutdown_handlers) > 0:
|
|
2448
2468
|
_dbg(f"running {len(self.shutdown_handlers)} shutdown handlers...")
|