llms-py 2.0.20__py3-none-any.whl → 3.0.18__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.
- llms/__init__.py +3 -1
- llms/db.py +359 -0
- llms/{ui/Analytics.mjs → extensions/analytics/ui/index.mjs} +254 -327
- llms/extensions/app/README.md +20 -0
- llms/extensions/app/__init__.py +588 -0
- llms/extensions/app/db.py +540 -0
- llms/{ui → extensions/app/ui}/Recents.mjs +99 -73
- llms/{ui/Sidebar.mjs → extensions/app/ui/index.mjs} +139 -68
- llms/extensions/app/ui/threadStore.mjs +440 -0
- llms/extensions/computer/README.md +96 -0
- llms/extensions/computer/__init__.py +59 -0
- llms/extensions/computer/base.py +80 -0
- llms/extensions/computer/bash.py +185 -0
- llms/extensions/computer/computer.py +523 -0
- llms/extensions/computer/edit.py +299 -0
- llms/extensions/computer/filesystem.py +542 -0
- llms/extensions/computer/platform.py +461 -0
- llms/extensions/computer/run.py +37 -0
- llms/extensions/core_tools/CALCULATOR.md +32 -0
- llms/extensions/core_tools/__init__.py +599 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/closebrackets.js +201 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/closetag.js +185 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/continuelist.js +101 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/matchbrackets.js +160 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/matchtags.js +66 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/trailingspace.js +27 -0
- llms/extensions/core_tools/ui/codemirror/addon/selection/active-line.js +72 -0
- llms/extensions/core_tools/ui/codemirror/addon/selection/mark-selection.js +119 -0
- llms/extensions/core_tools/ui/codemirror/addon/selection/selection-pointer.js +98 -0
- llms/extensions/core_tools/ui/codemirror/codemirror.css +344 -0
- llms/extensions/core_tools/ui/codemirror/codemirror.js +9884 -0
- llms/extensions/core_tools/ui/codemirror/doc/docs.css +225 -0
- llms/extensions/core_tools/ui/codemirror/doc/source_sans.woff +0 -0
- llms/extensions/core_tools/ui/codemirror/mode/clike/clike.js +942 -0
- llms/extensions/core_tools/ui/codemirror/mode/javascript/index.html +118 -0
- llms/extensions/core_tools/ui/codemirror/mode/javascript/javascript.js +962 -0
- llms/extensions/core_tools/ui/codemirror/mode/javascript/typescript.html +62 -0
- llms/extensions/core_tools/ui/codemirror/mode/python/python.js +402 -0
- llms/extensions/core_tools/ui/codemirror/theme/dracula.css +40 -0
- llms/extensions/core_tools/ui/codemirror/theme/mocha.css +135 -0
- llms/extensions/core_tools/ui/index.mjs +650 -0
- llms/extensions/gallery/README.md +61 -0
- llms/extensions/gallery/__init__.py +63 -0
- llms/extensions/gallery/db.py +243 -0
- llms/extensions/gallery/ui/index.mjs +482 -0
- llms/extensions/katex/README.md +39 -0
- llms/extensions/katex/__init__.py +6 -0
- llms/extensions/katex/ui/README.md +125 -0
- llms/extensions/katex/ui/contrib/auto-render.js +338 -0
- llms/extensions/katex/ui/contrib/auto-render.min.js +1 -0
- llms/extensions/katex/ui/contrib/auto-render.mjs +244 -0
- llms/extensions/katex/ui/contrib/copy-tex.js +127 -0
- llms/extensions/katex/ui/contrib/copy-tex.min.js +1 -0
- llms/extensions/katex/ui/contrib/copy-tex.mjs +105 -0
- llms/extensions/katex/ui/contrib/mathtex-script-type.js +109 -0
- llms/extensions/katex/ui/contrib/mathtex-script-type.min.js +1 -0
- llms/extensions/katex/ui/contrib/mathtex-script-type.mjs +24 -0
- llms/extensions/katex/ui/contrib/mhchem.js +3213 -0
- llms/extensions/katex/ui/contrib/mhchem.min.js +1 -0
- llms/extensions/katex/ui/contrib/mhchem.mjs +3109 -0
- llms/extensions/katex/ui/contrib/render-a11y-string.js +887 -0
- llms/extensions/katex/ui/contrib/render-a11y-string.min.js +1 -0
- llms/extensions/katex/ui/contrib/render-a11y-string.mjs +800 -0
- llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- llms/extensions/katex/ui/index.mjs +92 -0
- llms/extensions/katex/ui/katex-swap.css +1230 -0
- llms/extensions/katex/ui/katex-swap.min.css +1 -0
- llms/extensions/katex/ui/katex.css +1230 -0
- llms/extensions/katex/ui/katex.js +19080 -0
- llms/extensions/katex/ui/katex.min.css +1 -0
- llms/extensions/katex/ui/katex.min.js +1 -0
- llms/extensions/katex/ui/katex.min.mjs +1 -0
- llms/extensions/katex/ui/katex.mjs +18547 -0
- llms/extensions/providers/__init__.py +22 -0
- llms/extensions/providers/anthropic.py +260 -0
- llms/extensions/providers/cerebras.py +36 -0
- llms/extensions/providers/chutes.py +153 -0
- llms/extensions/providers/google.py +559 -0
- llms/extensions/providers/nvidia.py +103 -0
- llms/extensions/providers/openai.py +154 -0
- llms/extensions/providers/openrouter.py +74 -0
- llms/extensions/providers/zai.py +182 -0
- llms/extensions/skills/LICENSE +202 -0
- llms/extensions/skills/__init__.py +130 -0
- llms/extensions/skills/errors.py +25 -0
- llms/extensions/skills/models.py +39 -0
- llms/extensions/skills/parser.py +178 -0
- llms/extensions/skills/ui/index.mjs +376 -0
- llms/extensions/skills/ui/skills/create-plan/SKILL.md +74 -0
- llms/extensions/skills/validator.py +177 -0
- llms/extensions/system_prompts/README.md +22 -0
- llms/extensions/system_prompts/__init__.py +45 -0
- llms/extensions/system_prompts/ui/index.mjs +276 -0
- llms/extensions/system_prompts/ui/prompts.json +1067 -0
- llms/extensions/tools/__init__.py +67 -0
- llms/extensions/tools/ui/index.mjs +837 -0
- llms/index.html +36 -62
- llms/llms.json +180 -879
- llms/main.py +4009 -912
- llms/providers-extra.json +394 -0
- llms/providers.json +1 -0
- llms/ui/App.mjs +176 -8
- llms/ui/ai.mjs +156 -20
- llms/ui/app.css +3768 -321
- llms/ui/ctx.mjs +459 -0
- llms/ui/index.mjs +131 -0
- llms/ui/lib/chart.js +14 -0
- llms/ui/lib/charts.mjs +16 -0
- llms/ui/lib/color.js +14 -0
- llms/ui/lib/highlight.min.mjs +1243 -0
- llms/ui/lib/idb.min.mjs +8 -0
- llms/ui/lib/marked.min.mjs +8 -0
- llms/ui/lib/servicestack-client.mjs +1 -0
- llms/ui/lib/servicestack-vue.mjs +37 -0
- llms/ui/lib/vue-router.min.mjs +6 -0
- llms/ui/lib/vue.min.mjs +13 -0
- llms/ui/lib/vue.mjs +18530 -0
- llms/ui/markdown.mjs +25 -14
- llms/ui/modules/chat/ChatBody.mjs +1156 -0
- llms/ui/{SettingsDialog.mjs → modules/chat/SettingsDialog.mjs} +74 -74
- llms/ui/modules/chat/index.mjs +995 -0
- llms/ui/modules/icons.mjs +46 -0
- llms/ui/modules/layout.mjs +271 -0
- llms/ui/modules/model-selector.mjs +811 -0
- llms/ui/tailwind.input.css +560 -78
- llms/ui/typography.css +54 -36
- llms/ui/utils.mjs +221 -92
- llms_py-3.0.18.dist-info/METADATA +49 -0
- llms_py-3.0.18.dist-info/RECORD +194 -0
- {llms_py-2.0.20.dist-info → llms_py-3.0.18.dist-info}/WHEEL +1 -1
- {llms_py-2.0.20.dist-info → llms_py-3.0.18.dist-info}/licenses/LICENSE +1 -2
- llms/ui/Avatar.mjs +0 -28
- llms/ui/Brand.mjs +0 -34
- llms/ui/ChatPrompt.mjs +0 -443
- llms/ui/Main.mjs +0 -740
- llms/ui/ModelSelector.mjs +0 -60
- llms/ui/ProviderIcon.mjs +0 -29
- llms/ui/ProviderStatus.mjs +0 -105
- llms/ui/SignIn.mjs +0 -64
- llms/ui/SystemPromptEditor.mjs +0 -31
- llms/ui/SystemPromptSelector.mjs +0 -36
- llms/ui/Welcome.mjs +0 -8
- llms/ui/threadStore.mjs +0 -524
- llms/ui.json +0 -1069
- llms_py-2.0.20.dist-info/METADATA +0 -931
- llms_py-2.0.20.dist-info/RECORD +0 -36
- {llms_py-2.0.20.dist-info → llms_py-3.0.18.dist-info}/entry_points.txt +0 -0
- {llms_py-2.0.20.dist-info → llms_py-3.0.18.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from aiohttp import web
|
|
5
|
+
|
|
6
|
+
default_prompts = [
|
|
7
|
+
{"name": "Helpful Assistant", "prompt": "You are a helpful assistant."},
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# runs after providers are configured but before server is run
|
|
12
|
+
def install(ctx):
|
|
13
|
+
# helper to get user or default prompts
|
|
14
|
+
def get_user_prompts(request):
|
|
15
|
+
candidate_paths = []
|
|
16
|
+
# check if user is signed in
|
|
17
|
+
username = ctx.get_username(request)
|
|
18
|
+
if username:
|
|
19
|
+
# if signed in (Github OAuth), return the prompts for this user if exists
|
|
20
|
+
candidate_paths.append(os.path.join(ctx.get_user_path(username), "system_prompts", "prompts.json"))
|
|
21
|
+
# return default prompts for all users if exists
|
|
22
|
+
candidate_paths.append(os.path.join(ctx.get_user_path(), "system_prompts", "prompts.json"))
|
|
23
|
+
# otherwise return the default prompts from this repo
|
|
24
|
+
candidate_paths.append(os.path.join(ctx.path, "ui", "prompts.json"))
|
|
25
|
+
|
|
26
|
+
# iterate all candidate paths and when exists return its json
|
|
27
|
+
for path in candidate_paths:
|
|
28
|
+
if os.path.exists(path):
|
|
29
|
+
with open(path, encoding="utf-8") as f:
|
|
30
|
+
txt = f.read()
|
|
31
|
+
return json.loads(txt)
|
|
32
|
+
return default_prompts
|
|
33
|
+
|
|
34
|
+
# API Handler to get prompts
|
|
35
|
+
async def get_prompts(request):
|
|
36
|
+
prompts_json = get_user_prompts(request)
|
|
37
|
+
return web.json_response(prompts_json)
|
|
38
|
+
|
|
39
|
+
ctx.add_get("prompts.json", get_prompts)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# register install extension handler
|
|
43
|
+
__install__ = install
|
|
44
|
+
|
|
45
|
+
__order__ = -10
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { ref, computed, inject, watch, onMounted, onUnmounted, nextTick } from "vue"
|
|
2
|
+
import { AppContext } from "ctx.mjs"
|
|
3
|
+
|
|
4
|
+
let ext
|
|
5
|
+
|
|
6
|
+
const PromptFinder = {
|
|
7
|
+
template: `
|
|
8
|
+
<div v-if="modelValue" class="absolute right-0 top-full z-10 mt-1 origin-top-right rounded-md bg-white dark:bg-gray-900 shadow-lg border border-gray-300 dark:border-gray-600 focus:outline-none"
|
|
9
|
+
style="width:400px"
|
|
10
|
+
role="menu" aria-orientation="vertical" aria-labelledby="menu-button" tabindex="-1">
|
|
11
|
+
<div class="p-2" role="none">
|
|
12
|
+
<div class="relative mb-2">
|
|
13
|
+
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
|
14
|
+
<svg class="h-4 w-4 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
15
|
+
<path fill-rule="evenodd" d="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z" clip-rule="evenodd" />
|
|
16
|
+
</svg>
|
|
17
|
+
</div>
|
|
18
|
+
<input type="text"
|
|
19
|
+
ref="searchInput"
|
|
20
|
+
v-model="searchQuery"
|
|
21
|
+
@keydown="onKeydown"
|
|
22
|
+
class="block w-full rounded-md border-0 py-1.5 pl-10 text-gray-900 dark:text-gray-100 shadow-sm ring-1 ring-inset ring-gray-300 dark:ring-gray-600 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-xs sm:leading-6 bg-transparent"
|
|
23
|
+
placeholder="Search prompts...">
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div class="max-h-80 overflow-y-auto" ref="resultsList">
|
|
27
|
+
<div v-if="filteredPrompts.length === 0" class="p-4 text-center text-xs text-gray-500">
|
|
28
|
+
No prompts found
|
|
29
|
+
</div>
|
|
30
|
+
<div v-for="(prompt, index) in filteredPrompts" :key="prompt.id"
|
|
31
|
+
@click="selectPrompt(prompt)"
|
|
32
|
+
:class="['group relative flex gap-x-2 rounded-md p-2 cursor-pointer border-b border-gray-100 dark:border-gray-800 last:border-0',
|
|
33
|
+
selectedIndex === index ? 'bg-blue-50 dark:bg-blue-900/20' : 'hover:bg-gray-50 dark:hover:bg-gray-800']"
|
|
34
|
+
:data-index="index">
|
|
35
|
+
<div class="flex-auto">
|
|
36
|
+
<div class="flex items-center justify-between">
|
|
37
|
+
<h4 :class="['font-semibold text-sm', selectedIndex === index ? 'text-blue-700 dark:text-blue-300' : 'text-gray-900 dark:text-gray-100']">
|
|
38
|
+
{{ prompt.name }}
|
|
39
|
+
</h4>
|
|
40
|
+
</div>
|
|
41
|
+
<p class="text-xs leading-4 text-gray-500 dark:text-gray-400 line-clamp-2 mt-0.5">{{ prompt.value }}</p>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
`,
|
|
48
|
+
props: {
|
|
49
|
+
modelValue: Boolean, // controls visibility
|
|
50
|
+
prompts: {
|
|
51
|
+
type: Array,
|
|
52
|
+
default: () => []
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
emits: ['update:modelValue', 'select'],
|
|
56
|
+
setup(props, { emit }) {
|
|
57
|
+
const searchQuery = ref('')
|
|
58
|
+
const searchInput = ref(null)
|
|
59
|
+
const resultsList = ref(null)
|
|
60
|
+
const selectedIndex = ref(-1)
|
|
61
|
+
|
|
62
|
+
const filteredPrompts = computed(() => {
|
|
63
|
+
if (!searchQuery.value) return props.prompts
|
|
64
|
+
const q = searchQuery.value.toLowerCase()
|
|
65
|
+
return props.prompts.filter(p =>
|
|
66
|
+
p.name.toLowerCase().includes(q) ||
|
|
67
|
+
p.value.toLowerCase().includes(q) ||
|
|
68
|
+
p.id.toLowerCase().includes(q)
|
|
69
|
+
)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
function selectPrompt(prompt) {
|
|
73
|
+
emit('select', prompt)
|
|
74
|
+
emit('update:modelValue', false)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function scrollToSelected() {
|
|
78
|
+
nextTick(() => {
|
|
79
|
+
if (!resultsList.value) return
|
|
80
|
+
const el = resultsList.value.querySelector(`[data-index="${selectedIndex.value}"]`)
|
|
81
|
+
if (el) {
|
|
82
|
+
el.scrollIntoView({ block: 'nearest' })
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function onKeydown(e) {
|
|
88
|
+
if (filteredPrompts.value.length === 0) return
|
|
89
|
+
|
|
90
|
+
if (e.key === 'ArrowDown') {
|
|
91
|
+
e.preventDefault()
|
|
92
|
+
selectedIndex.value = (selectedIndex.value + 1) % filteredPrompts.value.length
|
|
93
|
+
scrollToSelected()
|
|
94
|
+
} else if (e.key === 'ArrowUp') {
|
|
95
|
+
e.preventDefault()
|
|
96
|
+
selectedIndex.value = (selectedIndex.value - 1 + filteredPrompts.value.length) % filteredPrompts.value.length
|
|
97
|
+
scrollToSelected()
|
|
98
|
+
} else if (e.key === 'Enter') {
|
|
99
|
+
e.preventDefault()
|
|
100
|
+
if (selectedIndex.value >= 0 && selectedIndex.value < filteredPrompts.value.length) {
|
|
101
|
+
selectPrompt(filteredPrompts.value[selectedIndex.value])
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
watch(() => props.modelValue, (isOpen) => {
|
|
107
|
+
if (isOpen) {
|
|
108
|
+
// Focus search input when modal opens
|
|
109
|
+
nextTick(() => {
|
|
110
|
+
if (searchInput.value) {
|
|
111
|
+
searchInput.value.focus()
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
selectedIndex.value = -1
|
|
115
|
+
} else {
|
|
116
|
+
searchQuery.value = ''
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
watch(searchQuery, () => {
|
|
121
|
+
selectedIndex.value = 0 // Select first result on search
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
searchQuery,
|
|
126
|
+
searchInput,
|
|
127
|
+
resultsList,
|
|
128
|
+
filteredPrompts,
|
|
129
|
+
selectedIndex,
|
|
130
|
+
selectPrompt,
|
|
131
|
+
onKeydown
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const SystemPromptEditor = {
|
|
137
|
+
template: `
|
|
138
|
+
<div class="border-b border-gray-200 dark:border-gray-700 px-6 pb-4">
|
|
139
|
+
<div class="max-w-6xl mx-auto">
|
|
140
|
+
<div class="mt-2 h-10 flex justify-between items-center">
|
|
141
|
+
<label class="select-none block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
142
|
+
System Prompt
|
|
143
|
+
</label>
|
|
144
|
+
<div v-if="hasMessages" class="text-sm text-gray-500 dark:text-gray-400">
|
|
145
|
+
{{ !ext.prefs.systemPrompt ? '' : prompts.find(x => x.value === ext.prefs.systemPrompt)?.name || 'Custom' }}
|
|
146
|
+
</div>
|
|
147
|
+
<div v-else class="mb-2 relative" ref="containerRef">
|
|
148
|
+
<div class="flex items-center gap-2">
|
|
149
|
+
<span v-if="selected" class="text-sm text-gray-500 dark:text-gray-400">
|
|
150
|
+
{{ selected.name }}
|
|
151
|
+
</span>
|
|
152
|
+
<button v-if="modelValue" type="button" title="Clear System Prompt" @click="$emit('update:modelValue', null)"
|
|
153
|
+
class="rounded-full p-1 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors">
|
|
154
|
+
<svg class="size-4 text-gray-500 dark:text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12z"/></svg>
|
|
155
|
+
</button>
|
|
156
|
+
<button type="button"
|
|
157
|
+
@click="ext.setPrefs({ showFinder: !ext.prefs.showFinder })"
|
|
158
|
+
class="inline-flex items-center gap-x-1.5 rounded-md bg-white dark:bg-gray-900 px-2.5 py-1.5 text-sm font-medium text-gray-700 dark:text-gray-300 shadow-sm border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-800">
|
|
159
|
+
Explore Prompts
|
|
160
|
+
</button>
|
|
161
|
+
</div>
|
|
162
|
+
<PromptFinder v-model="ext.prefs.showFinder" :prompts="prompts" @select="onSelect" />
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
<div v-if="hasMessages" class="w-full rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 px-3 py-2 text-sm">
|
|
166
|
+
<TextViewer prefsName="systemPrompt" :text="$threads.getCurrentThreadSystemPrompt() || 'No System Prompt was used'" />
|
|
167
|
+
</div>
|
|
168
|
+
<div v-else>
|
|
169
|
+
<textarea
|
|
170
|
+
:value="modelValue" @input="$emit('update:modelValue', $event.target.value)"
|
|
171
|
+
placeholder="Enter a system prompt to guide AI's behavior..."
|
|
172
|
+
rows="6"
|
|
173
|
+
class="block w-full resize-vertical rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 px-3 py-2 text-sm placeholder-gray-500 dark:placeholder-gray-400 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
|
|
174
|
+
></textarea>
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
`,
|
|
179
|
+
emits: ['update:modelValue'],
|
|
180
|
+
props: {
|
|
181
|
+
prompts: Array,
|
|
182
|
+
selected: Object,
|
|
183
|
+
modelValue: String,
|
|
184
|
+
},
|
|
185
|
+
setup(props, { emit }) {
|
|
186
|
+
/**@type {AppContext} */
|
|
187
|
+
const ctx = inject('ctx')
|
|
188
|
+
const containerRef = ref()
|
|
189
|
+
const hasMessages = computed(() => ctx.threads.currentThread.value?.messages?.length > 0)
|
|
190
|
+
const selected = computed(() =>
|
|
191
|
+
props.prompts.find(x => x.value === props.modelValue) ?? { name: "Custom", value: props.modelValue })
|
|
192
|
+
|
|
193
|
+
function onSelect(prompt) {
|
|
194
|
+
ext.setPrefs({ prompt: prompt }) // {"id","name","value"}
|
|
195
|
+
emit('update:modelValue', prompt.value)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function closeFinder(e) {
|
|
199
|
+
if (ext.prefs.showFinder && containerRef.value && !containerRef.value.contains(e.target)) {
|
|
200
|
+
ext.setPrefs({ showFinder: false })
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
watch(() => props.modelValue, systemPrompt => {
|
|
205
|
+
ext.setPrefs({ systemPrompt })
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
onMounted(() => {
|
|
209
|
+
document.addEventListener('click', closeFinder)
|
|
210
|
+
if (ext.prefs.prompt) {
|
|
211
|
+
emit('update:modelValue', ext.prefs.prompt)
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
onUnmounted(() => {
|
|
215
|
+
document.removeEventListener('click', closeFinder)
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
ext,
|
|
220
|
+
hasMessages,
|
|
221
|
+
selected,
|
|
222
|
+
containerRef,
|
|
223
|
+
onSelect,
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export default {
|
|
229
|
+
order: 30 - 100,
|
|
230
|
+
|
|
231
|
+
install(ctx) {
|
|
232
|
+
ext = ctx.scope('system_prompts')
|
|
233
|
+
ctx.components({
|
|
234
|
+
PromptFinder,
|
|
235
|
+
SystemPromptEditor,
|
|
236
|
+
SystemPromptsPanel: {
|
|
237
|
+
template: `<SystemPromptEditor :prompts="ext.state.prompts" v-model="ext.prefs.prompt" />`,
|
|
238
|
+
setup() {
|
|
239
|
+
return { ext }
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
})
|
|
243
|
+
ext.setPrefs({ systemPrompt: '' })
|
|
244
|
+
|
|
245
|
+
ctx.setTopIcons({
|
|
246
|
+
system_prompts: {
|
|
247
|
+
component: {
|
|
248
|
+
template: `<svg @click="$ctx.toggleTop('SystemPromptsPanel')" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m5 7l5 5l-5 5m8 0h6"/></svg>`,
|
|
249
|
+
},
|
|
250
|
+
isActive({ top }) { return top === 'SystemPromptsPanel' }
|
|
251
|
+
}
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
ctx.chatRequestFilters.push(({ request, thread, context }) => {
|
|
255
|
+
|
|
256
|
+
const hasSystemPrompt = !!context.systemPrompt
|
|
257
|
+
console.log('system_prompts chatRequestFilters', hasSystemPrompt)
|
|
258
|
+
if (hasSystemPrompt) {
|
|
259
|
+
console.log('Already has system prompt', hasSystemPrompt.content)
|
|
260
|
+
return
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (ext.prefs.systemPrompt) {
|
|
264
|
+
context.systemPrompt = ext.prefs.systemPrompt
|
|
265
|
+
}
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
ctx.setState({ prompts: [] })
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
async load(ctx) {
|
|
272
|
+
const api = await ext.getJson(`/prompts.json`)
|
|
273
|
+
const prompts = api.response || []
|
|
274
|
+
ext.setState({ prompts })
|
|
275
|
+
}
|
|
276
|
+
}
|