llms-py 3.0.1__tar.gz → 3.0.3__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.1 → llms_py-3.0.3}/PKG-INFO +1 -1
- llms_py-3.0.1/llms/extensions/app/db_manager.py → llms_py-3.0.3/llms/db.py +180 -16
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/app/__init__.py +96 -29
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/app/db.py +16 -124
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/app/ui/threadStore.mjs +23 -2
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/__init__.py +37 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/gallery/__init__.py +15 -13
- llms_py-3.0.3/llms/extensions/gallery/db.py +243 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/gallery/ui/index.mjs +1 -1
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/providers/__init__.py +3 -1
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/providers/anthropic.py +7 -3
- llms_py-3.0.3/llms/extensions/providers/cerebras.py +37 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/providers/chutes.py +1 -1
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/providers/google.py +131 -28
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/providers/nvidia.py +2 -2
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/providers/openai.py +2 -2
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/providers/openrouter.py +4 -2
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/llms.json +3 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/main.py +83 -34
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/providers.json +1 -1
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/ai.mjs +1 -1
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/app.css +106 -3
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/ctx.mjs +34 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/index.mjs +2 -0
- llms_py-3.0.3/llms/ui/modules/chat/ChatBody.mjs +688 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/modules/chat/index.mjs +93 -2
- llms_py-3.0.3/llms/ui/modules/icons.mjs +46 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/modules/layout.mjs +28 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/modules/model-selector.mjs +0 -40
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/tailwind.input.css +1 -1
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/utils.mjs +9 -1
- {llms_py-3.0.1 → llms_py-3.0.3}/llms_py.egg-info/PKG-INFO +1 -1
- {llms_py-3.0.1 → llms_py-3.0.3}/llms_py.egg-info/SOURCES.txt +4 -1
- {llms_py-3.0.1 → llms_py-3.0.3}/pyproject.toml +1 -1
- {llms_py-3.0.1 → llms_py-3.0.3}/setup.py +1 -1
- llms_py-3.0.3/tests/test_gemini_upload.py +71 -0
- llms_py-3.0.1/llms/extensions/gallery/db.py +0 -298
- llms_py-3.0.1/llms/ui/modules/chat/ChatBody.mjs +0 -691
- {llms_py-3.0.1 → llms_py-3.0.3}/LICENSE +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/MANIFEST.in +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/README.md +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/__init__.py +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/__main__.py +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/analytics/ui/index.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/app/README.md +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/app/ui/Recents.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/app/ui/index.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/CALCULATOR.md +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/addon/edit/closebrackets.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/addon/edit/closetag.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/addon/edit/continuelist.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/addon/edit/matchbrackets.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/addon/edit/matchtags.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/addon/edit/trailingspace.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/addon/selection/active-line.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/addon/selection/mark-selection.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/addon/selection/selection-pointer.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/doc/docs.css +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/doc/source_sans.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/mode/clike/clike.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/mode/javascript/index.html +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/mode/javascript/javascript.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/mode/javascript/typescript.html +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/mode/python/python.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/theme/dracula.css +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/codemirror/theme/mocha.css +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/core_tools/ui/index.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/gallery/README.md +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/README.md +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/__init__.py +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/README.md +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/contrib/auto-render.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/contrib/auto-render.min.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/contrib/auto-render.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/contrib/copy-tex.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/contrib/copy-tex.min.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/contrib/copy-tex.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/contrib/mathtex-script-type.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/contrib/mathtex-script-type.min.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/contrib/mathtex-script-type.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/contrib/mhchem.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/contrib/mhchem.min.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/contrib/mhchem.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/contrib/render-a11y-string.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/contrib/render-a11y-string.min.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/contrib/render-a11y-string.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.woff +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/index.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/katex-swap.css +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/katex-swap.min.css +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/katex.css +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/katex.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/katex.min.css +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/katex.min.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/katex.min.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/katex/ui/katex.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/system_prompts/README.md +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/system_prompts/__init__.py +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/system_prompts/ui/index.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/system_prompts/ui/prompts.json +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/tools/__init__.py +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/extensions/tools/ui/index.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/index.html +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/providers-extra.json +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/App.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/fav.svg +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/lib/chart.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/lib/charts.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/lib/color.js +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/lib/highlight.min.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/lib/idb.min.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/lib/marked.min.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/lib/servicestack-client.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/lib/servicestack-vue.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/lib/vue-router.min.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/lib/vue.min.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/lib/vue.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/markdown.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/modules/chat/SettingsDialog.mjs +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms/ui/typography.css +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms_py.egg-info/dependency_links.txt +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms_py.egg-info/entry_points.txt +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms_py.egg-info/not-zip-safe +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms_py.egg-info/requires.txt +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/llms_py.egg-info/top_level.txt +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/requirements.txt +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/setup.cfg +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/tests/test_async.py +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/tests/test_config.py +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/tests/test_extensions.py +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/tests/test_integration.py +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/tests/test_provider_checks.py +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/tests/test_provider_config.py +0 -0
- {llms_py-3.0.1 → llms_py-3.0.3}/tests/test_utils.py +0 -0
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import os
|
|
2
3
|
import sqlite3
|
|
4
|
+
import threading
|
|
3
5
|
from queue import Empty, Queue
|
|
4
6
|
from threading import Event, Thread
|
|
5
7
|
|
|
8
|
+
POOL = os.getenv("LLMS_POOL", "1") == "1"
|
|
9
|
+
|
|
6
10
|
|
|
7
11
|
def create_reader_connection(db_path):
|
|
8
|
-
|
|
12
|
+
# isolation_level=None leaves the connection in autocommit mode
|
|
13
|
+
conn = sqlite3.connect(
|
|
14
|
+
db_path, timeout=1.0, check_same_thread=False, isolation_level=None
|
|
15
|
+
) # Lower - reads should be fast
|
|
9
16
|
conn.execute("PRAGMA query_only=1") # Read-only optimization
|
|
10
17
|
return conn
|
|
11
18
|
|
|
@@ -33,7 +40,7 @@ def writer_thread(ctx, db_path, task_queue, stop_event):
|
|
|
33
40
|
sql, args, callback = task # Optional callback for results
|
|
34
41
|
|
|
35
42
|
try:
|
|
36
|
-
ctx.dbg("SQL>" + ("\n" if "\n" in sql else " ") + sql)
|
|
43
|
+
ctx.dbg("SQL>" + ("\n" if "\n" in sql else " ") + sql + ("\n" if args else " ") + str(args))
|
|
37
44
|
cursor = conn.execute(sql, args)
|
|
38
45
|
conn.commit()
|
|
39
46
|
ctx.dbg(f"lastrowid {cursor.lastrowid}, rowcount {cursor.rowcount}")
|
|
@@ -53,17 +60,79 @@ def writer_thread(ctx, db_path, task_queue, stop_event):
|
|
|
53
60
|
conn.close()
|
|
54
61
|
|
|
55
62
|
|
|
63
|
+
def to_dto(ctx, row, json_columns):
|
|
64
|
+
# as=column -> [0,1,2]
|
|
65
|
+
if not isinstance(row, dict):
|
|
66
|
+
return row
|
|
67
|
+
|
|
68
|
+
to = {}
|
|
69
|
+
for k, v in row.items():
|
|
70
|
+
if k in json_columns and v is not None and isinstance(v, str):
|
|
71
|
+
try:
|
|
72
|
+
to[k] = json.loads(v)
|
|
73
|
+
except Exception as e:
|
|
74
|
+
print(f"Failed to parse JSON for {k}: {v} ({type(v)})", e)
|
|
75
|
+
to[k] = v
|
|
76
|
+
else:
|
|
77
|
+
to[k] = v
|
|
78
|
+
return to
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def valid_columns(all_columns, fields):
|
|
82
|
+
if fields:
|
|
83
|
+
if not isinstance(fields, list):
|
|
84
|
+
fields = fields.split(",")
|
|
85
|
+
cols = []
|
|
86
|
+
for k in fields:
|
|
87
|
+
k = k.strip()
|
|
88
|
+
if k in all_columns:
|
|
89
|
+
cols.append(k)
|
|
90
|
+
return cols
|
|
91
|
+
return []
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def table_columns(all_columns, fields):
|
|
95
|
+
cols = valid_columns(all_columns, fields)
|
|
96
|
+
return ", ".join(cols) if len(cols) > 0 else ", ".join(all_columns)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def select_columns(all_columns, fields, select=None):
|
|
100
|
+
columns = table_columns(all_columns, fields)
|
|
101
|
+
if select == "distinct":
|
|
102
|
+
return f"SELECT DISTINCT {columns}"
|
|
103
|
+
return f"SELECT {columns}"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def order_by(all_columns, sort):
|
|
107
|
+
cols = []
|
|
108
|
+
for k in sort.split(","):
|
|
109
|
+
k = k.strip()
|
|
110
|
+
by = ""
|
|
111
|
+
if k[0] == "-":
|
|
112
|
+
by = " DESC"
|
|
113
|
+
k = k[1:]
|
|
114
|
+
if k in all_columns:
|
|
115
|
+
cols.append(f"{k}{by}")
|
|
116
|
+
return f"ORDER BY {', '.join(cols)} " if len(cols) > 0 else ""
|
|
117
|
+
|
|
118
|
+
|
|
56
119
|
class DbManager:
|
|
57
|
-
def __init__(self, ctx, db_path):
|
|
120
|
+
def __init__(self, ctx, db_path, clone=None):
|
|
58
121
|
if db_path is None:
|
|
59
122
|
raise ValueError("db_path is required")
|
|
60
123
|
self.ctx = ctx
|
|
61
124
|
self.db_path = db_path
|
|
62
|
-
self.task_queue = Queue()
|
|
63
|
-
self.stop_event = Event()
|
|
64
|
-
self.writer_thread = Thread(target=writer_thread, args=(ctx, db_path, self.task_queue, self.stop_event))
|
|
65
|
-
self.writer_thread.start()
|
|
66
125
|
self.read_only_pool = Queue()
|
|
126
|
+
if not clone:
|
|
127
|
+
self.task_queue = Queue()
|
|
128
|
+
self.stop_event = Event()
|
|
129
|
+
self.writer_thread = Thread(target=writer_thread, args=(ctx, db_path, self.task_queue, self.stop_event))
|
|
130
|
+
self.writer_thread.start()
|
|
131
|
+
else:
|
|
132
|
+
# share singleton writer thread in clones
|
|
133
|
+
self.task_queue = clone.task_queue
|
|
134
|
+
self.stop_event = clone.stop_event
|
|
135
|
+
self.writer_thread = clone.writer_thread
|
|
67
136
|
|
|
68
137
|
def create_reader_connection(self):
|
|
69
138
|
return create_reader_connection(self.db_path)
|
|
@@ -72,11 +141,21 @@ class DbManager:
|
|
|
72
141
|
return create_writer_connection(self.db_path)
|
|
73
142
|
|
|
74
143
|
def resolve_connection(self):
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
144
|
+
if POOL:
|
|
145
|
+
try:
|
|
146
|
+
return self.read_only_pool.get_nowait()
|
|
147
|
+
except Empty:
|
|
148
|
+
return self.create_reader_connection()
|
|
149
|
+
else:
|
|
78
150
|
return self.create_reader_connection()
|
|
79
151
|
|
|
152
|
+
def release_connection(self, conn):
|
|
153
|
+
if POOL:
|
|
154
|
+
conn.rollback()
|
|
155
|
+
self.read_only_pool.put(conn)
|
|
156
|
+
else:
|
|
157
|
+
conn.close()
|
|
158
|
+
|
|
80
159
|
def write(self, query, args=None, callback=None):
|
|
81
160
|
"""
|
|
82
161
|
Execute a write operation asynchronously.
|
|
@@ -94,13 +173,18 @@ class DbManager:
|
|
|
94
173
|
|
|
95
174
|
def log_sql(self, sql, parameters=None):
|
|
96
175
|
if self.ctx.debug:
|
|
97
|
-
self.ctx.dbg(
|
|
176
|
+
self.ctx.dbg(
|
|
177
|
+
"SQL>" + ("\n" if "\n" in sql else " ") + sql + ("\n" if parameters else " ") + str(parameters)
|
|
178
|
+
)
|
|
98
179
|
|
|
99
180
|
def exec(self, connection, sql, parameters=None):
|
|
100
181
|
self.log_sql(sql, parameters)
|
|
101
182
|
return connection.execute(sql, parameters or ())
|
|
102
183
|
|
|
103
184
|
def all(self, sql, parameters=None, connection=None):
|
|
185
|
+
"""
|
|
186
|
+
Execute a query and return all rows as a list of dictionaries.
|
|
187
|
+
"""
|
|
104
188
|
conn = self.resolve_connection() if connection is None else connection
|
|
105
189
|
|
|
106
190
|
try:
|
|
@@ -112,9 +196,12 @@ class DbManager:
|
|
|
112
196
|
finally:
|
|
113
197
|
if connection is None:
|
|
114
198
|
conn.row_factory = None
|
|
115
|
-
self.
|
|
199
|
+
self.release_connection(conn)
|
|
116
200
|
|
|
117
201
|
def one(self, sql, parameters=None, connection=None):
|
|
202
|
+
"""
|
|
203
|
+
Execute a query and return the first row as a dictionary.
|
|
204
|
+
"""
|
|
118
205
|
conn = self.resolve_connection() if connection is None else connection
|
|
119
206
|
|
|
120
207
|
try:
|
|
@@ -126,9 +213,12 @@ class DbManager:
|
|
|
126
213
|
finally:
|
|
127
214
|
if connection is None:
|
|
128
215
|
conn.row_factory = None
|
|
129
|
-
self.
|
|
216
|
+
self.release_connection(conn)
|
|
130
217
|
|
|
131
218
|
def scalar(self, sql, parameters=None, connection=None):
|
|
219
|
+
"""
|
|
220
|
+
Execute a scalar query and return the first column of the first row.
|
|
221
|
+
"""
|
|
132
222
|
conn = self.resolve_connection() if connection is None else connection
|
|
133
223
|
|
|
134
224
|
try:
|
|
@@ -140,7 +230,7 @@ class DbManager:
|
|
|
140
230
|
finally:
|
|
141
231
|
if connection is None:
|
|
142
232
|
conn.row_factory = None
|
|
143
|
-
self.
|
|
233
|
+
self.release_connection(conn)
|
|
144
234
|
|
|
145
235
|
def column(self, sql, parameters=None, connection=None):
|
|
146
236
|
"""
|
|
@@ -154,7 +244,7 @@ class DbManager:
|
|
|
154
244
|
return [row[0] for row in cursor.fetchall()]
|
|
155
245
|
finally:
|
|
156
246
|
if connection is None:
|
|
157
|
-
self.
|
|
247
|
+
self.release_connection(conn)
|
|
158
248
|
|
|
159
249
|
def dict(self, sql, parameters=None, connection=None):
|
|
160
250
|
"""
|
|
@@ -171,7 +261,7 @@ class DbManager:
|
|
|
171
261
|
finally:
|
|
172
262
|
if connection is None:
|
|
173
263
|
conn.row_factory = None
|
|
174
|
-
self.
|
|
264
|
+
self.release_connection(conn)
|
|
175
265
|
|
|
176
266
|
# Helper to safely dump JSON if value exists
|
|
177
267
|
def value(self, val):
|
|
@@ -181,6 +271,80 @@ class DbManager:
|
|
|
181
271
|
return json.dumps(val)
|
|
182
272
|
return val
|
|
183
273
|
|
|
274
|
+
def insert(self, table, columns, info, callback=None):
|
|
275
|
+
if not info:
|
|
276
|
+
raise Exception("info is required")
|
|
277
|
+
|
|
278
|
+
args = {}
|
|
279
|
+
known_columns = columns.keys()
|
|
280
|
+
for k, val in info.items():
|
|
281
|
+
if k in known_columns and k != "id":
|
|
282
|
+
args[k] = self.value(val)
|
|
283
|
+
|
|
284
|
+
insert_keys = list(args.keys())
|
|
285
|
+
insert_body = ", ".join(insert_keys)
|
|
286
|
+
insert_values = ", ".join(["?" for _ in insert_keys])
|
|
287
|
+
|
|
288
|
+
sql = f"INSERT INTO {table} ({insert_body}) VALUES ({insert_values})"
|
|
289
|
+
|
|
290
|
+
self.write(sql, tuple(args[k] for k in insert_keys), callback)
|
|
291
|
+
|
|
292
|
+
async def insert_async(self, table, columns, info):
|
|
293
|
+
event = threading.Event()
|
|
294
|
+
|
|
295
|
+
ret = [None, None]
|
|
296
|
+
|
|
297
|
+
def cb(lastrowid, rowcount, error=None):
|
|
298
|
+
nonlocal ret
|
|
299
|
+
if error:
|
|
300
|
+
ret[1] = error
|
|
301
|
+
else:
|
|
302
|
+
ret[0] = lastrowid
|
|
303
|
+
event.set()
|
|
304
|
+
|
|
305
|
+
self.insert(table, columns, info, cb)
|
|
306
|
+
event.wait()
|
|
307
|
+
if ret[1]:
|
|
308
|
+
raise ret[1]
|
|
309
|
+
return ret[0]
|
|
310
|
+
|
|
311
|
+
def update(self, table, columns, info, callback=None):
|
|
312
|
+
if not info:
|
|
313
|
+
raise Exception("info is required")
|
|
314
|
+
|
|
315
|
+
args = {}
|
|
316
|
+
known_columns = columns.keys()
|
|
317
|
+
for k, val in info.items():
|
|
318
|
+
if k in known_columns and k != "id":
|
|
319
|
+
args[k] = self.value(val)
|
|
320
|
+
|
|
321
|
+
update_keys = list(args.keys())
|
|
322
|
+
update_body = ", ".join([f"{k} = :{k}" for k in update_keys])
|
|
323
|
+
|
|
324
|
+
args["id"] = info["id"]
|
|
325
|
+
sql = f"UPDATE {table} SET {update_body} WHERE id = :id"
|
|
326
|
+
|
|
327
|
+
self.write(sql, args, callback)
|
|
328
|
+
|
|
329
|
+
async def update_async(self, table, columns, info):
|
|
330
|
+
event = threading.Event()
|
|
331
|
+
|
|
332
|
+
ret = [None, None]
|
|
333
|
+
|
|
334
|
+
def cb(lastrowid, rowcount, error=None):
|
|
335
|
+
nonlocal ret
|
|
336
|
+
if error:
|
|
337
|
+
ret[1] = error
|
|
338
|
+
else:
|
|
339
|
+
ret[0] = rowcount
|
|
340
|
+
event.set()
|
|
341
|
+
|
|
342
|
+
self.update(table, columns, info, cb)
|
|
343
|
+
event.wait()
|
|
344
|
+
if ret[1]:
|
|
345
|
+
raise ret[1]
|
|
346
|
+
return ret[0]
|
|
347
|
+
|
|
184
348
|
def close(self):
|
|
185
349
|
self.ctx.dbg("Closing database")
|
|
186
350
|
self.stop_event.set()
|
|
@@ -7,13 +7,9 @@ from typing import Any
|
|
|
7
7
|
|
|
8
8
|
from aiohttp import web
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
from .db import AppDB
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
from llms.extensions.app.db import AppDB
|
|
14
|
-
except ImportError as e:
|
|
15
|
-
print(f"Failed to import AppDB: {e}")
|
|
16
|
-
AppDB = None
|
|
12
|
+
g_db = None
|
|
17
13
|
|
|
18
14
|
|
|
19
15
|
def install(ctx):
|
|
@@ -32,28 +28,50 @@ def install(ctx):
|
|
|
32
28
|
if not get_db():
|
|
33
29
|
return
|
|
34
30
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
31
|
+
thread_fields = [
|
|
32
|
+
"id",
|
|
33
|
+
"threadId",
|
|
34
|
+
"createdAt",
|
|
35
|
+
"updatedAt",
|
|
36
|
+
"title",
|
|
37
|
+
"model",
|
|
38
|
+
"modelInfo",
|
|
39
|
+
"modalities",
|
|
40
|
+
"messages",
|
|
41
|
+
"tools",
|
|
42
|
+
"args",
|
|
43
|
+
"cost",
|
|
44
|
+
"inputTokens",
|
|
45
|
+
"outputTokens",
|
|
46
|
+
"stats",
|
|
47
|
+
"provider",
|
|
48
|
+
"providerModel",
|
|
49
|
+
"publishedAt",
|
|
50
|
+
"startedAt",
|
|
51
|
+
"completedAt",
|
|
52
|
+
"metadata",
|
|
53
|
+
"error",
|
|
54
|
+
"ref",
|
|
55
|
+
]
|
|
51
56
|
|
|
52
57
|
def thread_dto(row):
|
|
53
|
-
return row and to_dto(
|
|
58
|
+
return row and g_db.to_dto(
|
|
59
|
+
row,
|
|
60
|
+
[
|
|
61
|
+
"messages",
|
|
62
|
+
"tools",
|
|
63
|
+
"toolHistory",
|
|
64
|
+
"modalities",
|
|
65
|
+
"args",
|
|
66
|
+
"modelInfo",
|
|
67
|
+
"stats",
|
|
68
|
+
"metadata",
|
|
69
|
+
"providerResponse",
|
|
70
|
+
],
|
|
71
|
+
)
|
|
54
72
|
|
|
55
73
|
def request_dto(row):
|
|
56
|
-
return row and to_dto(row, ["usage"])
|
|
74
|
+
return row and g_db.to_dto(row, ["usage"])
|
|
57
75
|
|
|
58
76
|
def prompt_to_title(prompt):
|
|
59
77
|
return prompt[:100] + ("..." if len(prompt) > 100 else "") if prompt else None
|
|
@@ -67,7 +85,10 @@ def install(ctx):
|
|
|
67
85
|
return messages
|
|
68
86
|
|
|
69
87
|
async def query_threads(request):
|
|
70
|
-
|
|
88
|
+
query = request.query.copy()
|
|
89
|
+
if "fields" not in query:
|
|
90
|
+
query["fields"] = thread_fields
|
|
91
|
+
rows = g_db.query_threads(query, user=ctx.get_username(request))
|
|
71
92
|
dtos = [thread_dto(row) for row in rows]
|
|
72
93
|
return web.json_response(dtos)
|
|
73
94
|
|
|
@@ -81,6 +102,13 @@ def install(ctx):
|
|
|
81
102
|
|
|
82
103
|
ctx.add_post("threads", create_thread)
|
|
83
104
|
|
|
105
|
+
async def get_thread(request):
|
|
106
|
+
id = request.match_info["id"]
|
|
107
|
+
row = g_db.get_thread(id, user=ctx.get_username(request))
|
|
108
|
+
return web.json_response(thread_dto(row) if row else "")
|
|
109
|
+
|
|
110
|
+
ctx.add_get("threads/{id}", get_thread)
|
|
111
|
+
|
|
84
112
|
async def update_thread(request):
|
|
85
113
|
thread = await request.json()
|
|
86
114
|
id = request.match_info["id"]
|
|
@@ -119,8 +147,10 @@ def install(ctx):
|
|
|
119
147
|
if not thread:
|
|
120
148
|
raise Exception("Thread not found")
|
|
121
149
|
|
|
150
|
+
tools = chat.get("tools", thread.get("tools", []))
|
|
122
151
|
update_thread = {
|
|
123
152
|
"messages": messages,
|
|
153
|
+
"tools": tools,
|
|
124
154
|
"startedAt": datetime.now(),
|
|
125
155
|
"completedAt": None,
|
|
126
156
|
"error": None,
|
|
@@ -164,24 +194,28 @@ def install(ctx):
|
|
|
164
194
|
if not thread:
|
|
165
195
|
raise Exception("Thread not found")
|
|
166
196
|
|
|
167
|
-
metadata = thread.get("metadata"
|
|
197
|
+
metadata = thread.get("metadata") or {}
|
|
168
198
|
chat = {
|
|
169
199
|
"model": thread.get("model"),
|
|
170
200
|
"messages": thread.get("messages"),
|
|
171
201
|
"modalities": thread.get("modalities"),
|
|
172
202
|
"systemPrompt": thread.get("systemPrompt"),
|
|
203
|
+
"tools": thread.get("tools"), # tools request
|
|
173
204
|
"metadata": metadata,
|
|
174
205
|
}
|
|
175
|
-
|
|
206
|
+
args = thread.get("args") or {}
|
|
207
|
+
for k, v in args.items():
|
|
176
208
|
if k in ctx.request_args:
|
|
177
209
|
chat[k] = v
|
|
178
210
|
|
|
211
|
+
ctx.dbg("CHAT\n" + json.dumps(chat, indent=2))
|
|
212
|
+
|
|
179
213
|
context = {
|
|
180
214
|
"chat": chat,
|
|
181
215
|
"user": user,
|
|
182
216
|
"threadId": id,
|
|
183
217
|
"metadata": metadata,
|
|
184
|
-
"tools": metadata.get("tools", "all"),
|
|
218
|
+
"tools": metadata.get("tools", "all"), # only tools: all|none|<tool1>,<tool2>,...
|
|
185
219
|
}
|
|
186
220
|
|
|
187
221
|
# execute chat in background thread
|
|
@@ -295,6 +329,7 @@ def install(ctx):
|
|
|
295
329
|
metadata = chat.get("metadata", {})
|
|
296
330
|
model = chat.get("model", None)
|
|
297
331
|
messages = timestamp_messages(chat.get("messages", []))
|
|
332
|
+
tools = chat.get("tools", [])
|
|
298
333
|
title = context.get("title") or prompt_to_title(ctx.last_user_prompt(chat) if chat else None)
|
|
299
334
|
started_at = context.get("startedAt")
|
|
300
335
|
if not started_at:
|
|
@@ -307,6 +342,7 @@ def install(ctx):
|
|
|
307
342
|
"modelInfo": model_info,
|
|
308
343
|
"title": title,
|
|
309
344
|
"messages": messages,
|
|
345
|
+
"tools": tools,
|
|
310
346
|
"systemPrompt": ctx.chat_to_system_prompt(chat),
|
|
311
347
|
"modalities": chat.get("modalities", ["text"]),
|
|
312
348
|
"startedAt": started_at,
|
|
@@ -321,6 +357,7 @@ def install(ctx):
|
|
|
321
357
|
"modelInfo": model_info,
|
|
322
358
|
"startedAt": started_at,
|
|
323
359
|
"messages": messages,
|
|
360
|
+
"tools": tools,
|
|
324
361
|
"completedAt": None,
|
|
325
362
|
"error": None,
|
|
326
363
|
"metadata": metadata,
|
|
@@ -355,6 +392,29 @@ def install(ctx):
|
|
|
355
392
|
|
|
356
393
|
ctx.register_chat_tool_filter(tool_request)
|
|
357
394
|
|
|
395
|
+
def truncate_long_strings(obj, max_length=10000):
|
|
396
|
+
"""
|
|
397
|
+
Recursively traverse a dictionary/list structure and replace
|
|
398
|
+
string values longer than max_length with their length indicator.
|
|
399
|
+
|
|
400
|
+
Args:
|
|
401
|
+
obj: The object to process (dict, list, or other value)
|
|
402
|
+
max_length: Maximum string length before truncation (default 10000)
|
|
403
|
+
|
|
404
|
+
Returns:
|
|
405
|
+
A new object with long strings replaced by "({length})"
|
|
406
|
+
"""
|
|
407
|
+
if isinstance(obj, dict):
|
|
408
|
+
return {key: truncate_long_strings(value, max_length) for key, value in obj.items()}
|
|
409
|
+
elif isinstance(obj, list):
|
|
410
|
+
return [truncate_long_strings(item, max_length) for item in obj]
|
|
411
|
+
elif isinstance(obj, str):
|
|
412
|
+
if len(obj) > max_length:
|
|
413
|
+
return f"({len(obj)})"
|
|
414
|
+
return obj
|
|
415
|
+
else:
|
|
416
|
+
return obj
|
|
417
|
+
|
|
358
418
|
async def chat_response(openai_response, context):
|
|
359
419
|
ctx.dbg("create_response")
|
|
360
420
|
o = openai_response
|
|
@@ -406,7 +466,6 @@ def install(ctx):
|
|
|
406
466
|
"totalTokens": total_tokens,
|
|
407
467
|
"usage": usage,
|
|
408
468
|
"completedAt": completed_at,
|
|
409
|
-
"toolHistory": o.get("tool_history", None),
|
|
410
469
|
"ref": o.get("id", None),
|
|
411
470
|
}
|
|
412
471
|
tasks.append(g_db.create_request_async(request, user=user))
|
|
@@ -436,15 +495,23 @@ def install(ctx):
|
|
|
436
495
|
}
|
|
437
496
|
messages.append(assistant_message)
|
|
438
497
|
|
|
498
|
+
tools = chat.get("tools", [])
|
|
439
499
|
update_thread = {
|
|
440
500
|
"model": model,
|
|
441
501
|
"providerModel": o.get("model"),
|
|
442
502
|
"modelInfo": model_info,
|
|
443
503
|
"messages": messages,
|
|
504
|
+
"tools": tools,
|
|
444
505
|
"completedAt": completed_at,
|
|
445
506
|
}
|
|
507
|
+
tool_history = o.get("tool_history", None)
|
|
508
|
+
if tool_history:
|
|
509
|
+
update_thread["toolHistory"] = tool_history
|
|
446
510
|
if "error" in metadata:
|
|
447
511
|
update_thread["error"] = metadata["error"]
|
|
512
|
+
provider_response = context.get("providerResponse", None)
|
|
513
|
+
if provider_response:
|
|
514
|
+
update_thread["providerResponse"] = truncate_long_strings(provider_response)
|
|
448
515
|
tasks.append(g_db.update_thread_async(thread_id, update_thread, user=user))
|
|
449
516
|
else:
|
|
450
517
|
ctx.dbg("Missing thread_id")
|