llms-py 3.0.10__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.
Files changed (41) hide show
  1. llms/extensions/app/__init__.py +0 -1
  2. llms/extensions/app/db.py +7 -3
  3. llms/extensions/app/ui/threadStore.mjs +10 -3
  4. llms/extensions/computer/README.md +96 -0
  5. llms/extensions/computer/__init__.py +59 -0
  6. llms/extensions/computer/base.py +80 -0
  7. llms/extensions/computer/bash.py +185 -0
  8. llms/extensions/computer/computer.py +523 -0
  9. llms/extensions/computer/edit.py +299 -0
  10. llms/extensions/computer/filesystem.py +542 -0
  11. llms/extensions/computer/platform.py +461 -0
  12. llms/extensions/computer/run.py +37 -0
  13. llms/extensions/core_tools/__init__.py +0 -38
  14. llms/extensions/providers/anthropic.py +28 -1
  15. llms/extensions/providers/cerebras.py +0 -1
  16. llms/extensions/providers/google.py +112 -34
  17. llms/extensions/skills/LICENSE +202 -0
  18. llms/extensions/skills/__init__.py +130 -0
  19. llms/extensions/skills/errors.py +25 -0
  20. llms/extensions/skills/models.py +39 -0
  21. llms/extensions/skills/parser.py +178 -0
  22. llms/extensions/skills/ui/index.mjs +376 -0
  23. llms/extensions/skills/ui/skills/create-plan/SKILL.md +74 -0
  24. llms/extensions/skills/validator.py +177 -0
  25. llms/extensions/system_prompts/ui/index.mjs +6 -10
  26. llms/extensions/tools/__init__.py +5 -82
  27. llms/extensions/tools/ui/index.mjs +194 -63
  28. llms/main.py +502 -146
  29. llms/ui/ai.mjs +1 -1
  30. llms/ui/app.css +530 -0
  31. llms/ui/ctx.mjs +53 -6
  32. llms/ui/modules/chat/ChatBody.mjs +200 -20
  33. llms/ui/modules/chat/index.mjs +108 -104
  34. llms/ui/tailwind.input.css +10 -0
  35. llms/ui/utils.mjs +25 -1
  36. {llms_py-3.0.10.dist-info → llms_py-3.0.18.dist-info}/METADATA +2 -2
  37. {llms_py-3.0.10.dist-info → llms_py-3.0.18.dist-info}/RECORD +41 -24
  38. {llms_py-3.0.10.dist-info → llms_py-3.0.18.dist-info}/WHEEL +1 -1
  39. {llms_py-3.0.10.dist-info → llms_py-3.0.18.dist-info}/entry_points.txt +0 -0
  40. {llms_py-3.0.10.dist-info → llms_py-3.0.18.dist-info}/licenses/LICENSE +0 -0
  41. {llms_py-3.0.10.dist-info → llms_py-3.0.18.dist-info}/top_level.txt +0 -0
@@ -2,6 +2,86 @@ import { inject, computed, ref, onMounted } from "vue"
2
2
 
3
3
  let ext
4
4
 
5
+ function useTools(ctx) {
6
+
7
+ const availableTools = computed(() => ctx.state.tool.definitions.filter(x => x.function))
8
+ const toolPageHeaders = {}
9
+
10
+ function setToolPageHeaders(components) {
11
+ Object.assign(toolPageHeaders, components)
12
+ }
13
+
14
+ function selectTool({ group, tool }) {
15
+ ext.setPrefs({ selectedGroup: group, selectedTool: tool })
16
+ }
17
+
18
+ function getToolDefinition(name) {
19
+ return ctx.state.tool.definitions.find(d => d.function?.name === name)
20
+ }
21
+
22
+ function isToolEnabled(name) {
23
+ const toolDef = getToolDefinition(name)
24
+ if (!toolDef) return false
25
+ const onlyTools = ctx.prefs.onlyTools
26
+ if (onlyTools == null) return true
27
+ return Array.isArray(onlyTools) && onlyTools.includes(name)
28
+ }
29
+
30
+ function enableTool(name) {
31
+ let onlyTools = ctx.prefs.onlyTools
32
+ if (onlyTools == null) return // All tools are enabled
33
+
34
+ if (!Array.isArray(onlyTools)) {
35
+ onlyTools = [onlyTools]
36
+ }
37
+ else if (!onlyTools.includes(name)) {
38
+ onlyTools.push(name)
39
+ } else {
40
+ return // Already enabled
41
+ }
42
+ ctx.setPrefs({ onlyTools })
43
+ }
44
+
45
+ function disableTool(name) {
46
+ let onlyTools = ctx.prefs.onlyTools
47
+ if (onlyTools == null) {
48
+ // If currently 'All', clicking a tool means we enter custom mode with all OTHER tools selected
49
+ onlyTools = availableTools.value.map(t => t.function.name).filter(t => t !== name)
50
+ } else if (!Array.isArray(onlyTools)) {
51
+ onlyTools = []
52
+ } else {
53
+ onlyTools = onlyTools.filter(t => t !== name)
54
+ }
55
+ ctx.setPrefs({ onlyTools })
56
+ }
57
+
58
+ function toggleTool(name, enable = null) {
59
+ if (enable == null) {
60
+ enable = !isToolEnabled(name)
61
+ }
62
+ if (enable) {
63
+ enableTool(name)
64
+ } else {
65
+ disableTool(name)
66
+ }
67
+ }
68
+
69
+ return {
70
+ availableTools,
71
+ toolPageHeaders,
72
+ setToolPageHeaders,
73
+ selectTool,
74
+ getToolDefinition,
75
+ isToolEnabled,
76
+ enableTool,
77
+ disableTool,
78
+ toggleTool,
79
+ get selectedGroup() { return ext.prefs.selectedGroup },
80
+ get selectedTool() { return ext.prefs.selectedTool },
81
+ }
82
+ }
83
+
84
+
5
85
  const ToolResult = {
6
86
  template: `
7
87
  <div>
@@ -18,10 +98,10 @@ const ToolResult = {
18
98
  preview
19
99
  </span>
20
100
  </div>
21
- <div class="not-prose px-3 py-2">
101
+ <div class="not-prose py-2">
22
102
  <pre v-if="ext.prefs.toolFormat !== 'preview'" class="tool-output">{{ origResult }}</pre>
23
103
  <div v-else>
24
- <ViewTypes v-if="Array.isArray(result)" :results="result" />
104
+ <ViewTypes v-if="Array.isArray(result) && result[0]?.type" :results="result" />
25
105
  <ViewType v-else :result="result" />
26
106
  </div>
27
107
  </div>
@@ -76,10 +156,92 @@ const ToolResult = {
76
156
  }
77
157
  }
78
158
 
79
- const Tools = {
80
- components: {
81
- ToolResult
159
+ const JsonInput = {
160
+ template: `
161
+ <div class="flex flex-col gap-1">
162
+ <div class="relative">
163
+ <textarea
164
+ v-model="localJson"
165
+ @input="validate"
166
+ rows="5"
167
+ class="w-full p-2 font-mono text-xs border rounded-md resize-y focus:outline-none focus:ring-2 transition-colors"
168
+ :class="error
169
+ ? 'border-red-300 dark:border-red-700 bg-red-50 dark:bg-red-900/10 focus:ring-red-500'
170
+ : 'border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 focus:ring-blue-500'"
171
+ spellcheck="false"
172
+ ></textarea>
173
+ <div v-if="isValid" class="absolute bottom-2 right-2 text-green-500 bg-white dark:bg-gray-800 rounded-full p-1 shadow-sm">
174
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
175
+ <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
176
+ </svg>
177
+ </div>
178
+ </div>
179
+ <div v-if="error" class="text-xs text-red-600 dark:text-red-400 font-medium px-1">
180
+ {{ error }}
181
+ </div>
182
+ </div>
183
+ `,
184
+ props: {
185
+ modelValue: {
186
+ required: true
187
+ }
82
188
  },
189
+ emits: ['update:modelValue'],
190
+ setup(props, { emit }) {
191
+ // Initialize with formatted JSON
192
+ const localJson = ref(
193
+ props.modelValue !== undefined
194
+ ? JSON.stringify(props.modelValue, null, 4)
195
+ : ''
196
+ )
197
+ const error = ref(null)
198
+ const isValid = ref(true)
199
+
200
+ function validate() {
201
+ try {
202
+ if (!localJson.value.trim()) {
203
+ // Decide if empty string is valid object/array or undefined
204
+ // For now, let's say empty is NOT valid if the prop expects object
205
+ // But maybe we can treat it as valid undefined/null?
206
+ // Let's enforce valid JSON.
207
+ if (localJson.value === '') {
208
+ error.value = null
209
+ isValid.value = true
210
+ emit('update:modelValue', undefined)
211
+ return
212
+ }
213
+ }
214
+
215
+ const parsed = JSON.parse(localJson.value)
216
+ error.value = null
217
+ isValid.value = true
218
+ emit('update:modelValue', parsed)
219
+ } catch (e) {
220
+ error.value = e.message
221
+ isValid.value = false
222
+ // Do not emit invalid values
223
+ }
224
+ }
225
+
226
+ // Watch external changes only if they differ significantly from local
227
+ /*
228
+ Note: two-way binding with text representation is tricky.
229
+ If we watch props.modelValue, we might re-format user's in-progress typing if we aren't careful.
230
+ Usually better to only update localJson if the prop changes "from outside".
231
+ For this simple tool, initial value is likely enough, or we can watch with a deep compare check.
232
+ For now, let's stick to initial + internal validation.
233
+ */
234
+
235
+ return {
236
+ localJson,
237
+ error,
238
+ isValid,
239
+ validate
240
+ }
241
+ }
242
+ }
243
+
244
+ const Tools = {
83
245
  template: `
84
246
  <div class="p-4 md:p-6 max-w-7xl mx-auto w-full relative">
85
247
  <div v-if="Object.keys($ctx.tools.toolPageHeaders).length">
@@ -153,6 +315,10 @@ const Tools = {
153
315
  </select>
154
316
  </div>
155
317
 
318
+ <div v-else-if="prop.type === 'object' || prop.type === 'array'">
319
+ <JsonInput v-model="execForm[name]" />
320
+ </div>
321
+
156
322
  <div v-else>
157
323
  <input :type="prop.type === 'integer' || prop.type === 'number' ? 'number' : 'text'"
158
324
  v-model="execForm[name]"
@@ -191,7 +357,7 @@ const Tools = {
191
357
  </div>
192
358
 
193
359
  <div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
194
- <div v-for="tool in filteredTools" :key="tool.function.name"
360
+ <div v-for="tool in filteredTools" :key="tool.function.name" :id="'tool-' + tool.function.name"
195
361
  class="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden flex flex-col">
196
362
 
197
363
  <div class="p-4 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50 flex justify-between items-center">
@@ -262,7 +428,6 @@ const Tools = {
262
428
  const ctx = inject('ctx')
263
429
 
264
430
  // Execution State
265
- const executingTool = ref(null)
266
431
  const execForm = ref({})
267
432
  const execResult = ref(null)
268
433
  const execError = ref(null)
@@ -270,6 +435,12 @@ const Tools = {
270
435
  const refForm = ref()
271
436
  const refTop = ref()
272
437
 
438
+ const executingTool = computed(() => {
439
+ const tool = ext.prefs.selectedTool
440
+ if (!tool) return null
441
+ return ctx.state.tool.definitions.find(x => x.function.name === tool)
442
+ })
443
+
273
444
  // UI State
274
445
  const expandedDescriptions = ref({})
275
446
 
@@ -284,7 +455,7 @@ const Tools = {
284
455
  })
285
456
 
286
457
  function startExec(tool) {
287
- executingTool.value = tool
458
+ ext.setPrefs({ selectedTool: tool.function.name })
288
459
  execForm.value = {}
289
460
  execResult.value = null
290
461
  execError.value = null
@@ -309,7 +480,7 @@ const Tools = {
309
480
  }
310
481
 
311
482
  function closeExec() {
312
- executingTool.value = null
483
+ ext.setPrefs({ selectedTool: null })
313
484
  execForm.value = {}
314
485
  execResult.value = null
315
486
  execError.value = null
@@ -396,14 +567,14 @@ const ToolSelector = {
396
567
  <div class="flex items-center gap-2">
397
568
  <button @click="$ctx.setPrefs({ onlyTools: null })"
398
569
  class="px-3 py-1 rounded-md text-xs font-medium border transition-colors select-none"
399
- :class="$prefs.onlyTools == null
570
+ :class="prefs.onlyTools == null
400
571
  ? 'bg-green-100 dark:bg-green-900/40 text-green-800 dark:text-green-300 border-green-300 dark:border-green-800'
401
572
  : 'cursor-pointer bg-white dark:bg-gray-800 text-gray-600 dark:text-gray-400 border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600'">
402
573
  All Tools
403
574
  </button>
404
575
  <button @click="$ctx.setPrefs({ onlyTools:[] })"
405
576
  class="px-3 py-1 rounded-md text-xs font-medium border transition-colors select-none"
406
- :class="$prefs.onlyTools?.length === 0
577
+ :class="prefs.onlyTools?.length === 0
407
578
  ? 'bg-fuchsia-100 dark:bg-fuchsia-900/40 text-fuchsia-800 dark:text-fuchsia-300 border-fuchsia-200 dark:border-fuchsia-800'
408
579
  : 'cursor-pointer bg-white dark:bg-gray-800 text-gray-600 dark:text-gray-400 border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600'">
409
580
  No Tools
@@ -456,10 +627,10 @@ const ToolSelector = {
456
627
  <div v-show="!isCollapsed(group.name)" class="p-3 bg-white dark:bg-gray-900 border-t border-gray-100 dark:border-gray-800">
457
628
  <div class="flex flex-wrap gap-2">
458
629
  <button v-for="tool in group.tools" :key="tool.function.name" type="button"
459
- @click="toggleTool(tool.function.name)"
630
+ @click="$tools.toggleTool(tool.function.name)"
460
631
  :title="tool.function.description"
461
632
  class="px-2.5 py-1 rounded-full text-xs font-medium border transition-colors select-none text-left truncate max-w-[200px]"
462
- :class="isToolActive(tool.function.name)
633
+ :class="$tools.isToolEnabled(tool.function.name)
463
634
  ? 'bg-blue-100 dark:bg-blue-900/40 text-blue-800 dark:text-blue-300 border-blue-200 dark:border-blue-800'
464
635
  : 'bg-gray-50 dark:bg-gray-800 text-gray-600 dark:text-gray-400 border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600'">
465
636
  {{ tool.function.name }}
@@ -474,10 +645,10 @@ const ToolSelector = {
474
645
  const ctx = inject('ctx')
475
646
  const collapsedState = ref({})
476
647
 
477
- const availableTools = computed(() => ctx.state.tool.definitions.filter(x => x.function))
648
+ const prefs = computed(() => ctx.prefs)
478
649
 
479
650
  const toolGroups = computed(() => {
480
- const defs = availableTools.value
651
+ const defs = ctx.tools.availableTools.value
481
652
  const groups = ctx.state.tool.groups || {}
482
653
 
483
654
  const definedGroups = []
@@ -500,33 +671,6 @@ const ToolSelector = {
500
671
  return definedGroups
501
672
  })
502
673
 
503
- function isToolActive(name) {
504
- const only = ctx.prefs.onlyTools
505
- if (only == null) return true
506
- if (Array.isArray(only)) {
507
- return only.includes(name)
508
- }
509
- return false
510
- }
511
-
512
- function toggleTool(name) {
513
- let onlyTools = ctx.prefs.onlyTools
514
-
515
- // If currently 'All', clicking a tool means we enter custom mode with all OTHER tools selected (deselecting clicked)
516
- if (onlyTools == null) {
517
- onlyTools = availableTools.value.map(t => t.function.name).filter(t => t !== name)
518
- } else {
519
- // Currently Custom or None
520
- if (onlyTools.includes(name)) {
521
- onlyTools = onlyTools.filter(t => t !== name)
522
- } else {
523
- onlyTools = [...onlyTools, name]
524
- }
525
- }
526
-
527
- ctx.setPrefs({ onlyTools })
528
- }
529
-
530
674
  function toggleCollapse(groupName) {
531
675
  const key = groupName || '_other_'
532
676
  collapsedState.value[key] = !collapsedState.value[key]
@@ -539,19 +683,19 @@ const ToolSelector = {
539
683
 
540
684
  function setGroupTools(group, enable) {
541
685
  const groupToolNames = group.tools.map(t => t.function.name)
542
- let onlyTools = ctx.prefs.onlyTools
686
+ let onlyTools = prefs.value.onlyTools
543
687
 
544
688
  if (enable) {
545
689
  if (onlyTools == null) return
546
690
  const newSet = new Set(onlyTools)
547
691
  groupToolNames.forEach(n => newSet.add(n))
548
692
  onlyTools = Array.from(newSet)
549
- if (onlyTools.length === availableTools.value.length) {
693
+ if (onlyTools.length === ctx.tools.availableTools.value.length) {
550
694
  onlyTools = null
551
695
  }
552
696
  } else {
553
697
  if (onlyTools == null) {
554
- onlyTools = availableTools.value
698
+ onlyTools = ctx.tools.availableTools.value
555
699
  .map(t => t.function.name)
556
700
  .filter(n => !groupToolNames.includes(n))
557
701
  } else {
@@ -563,16 +707,14 @@ const ToolSelector = {
563
707
  }
564
708
 
565
709
  function getActiveCount(group) {
566
- const onlyTools = ctx.prefs.onlyTools
710
+ const onlyTools = prefs.value.onlyTools
567
711
  if (onlyTools == null) return group.tools.length
568
712
  return group.tools.filter(t => onlyTools.includes(t.function.name)).length
569
713
  }
570
714
 
571
715
  return {
572
- availableTools,
716
+ prefs,
573
717
  toolGroups,
574
- isToolActive,
575
- toggleTool,
576
718
  toggleCollapse,
577
719
  isCollapsed,
578
720
  setGroupTools,
@@ -581,19 +723,6 @@ const ToolSelector = {
581
723
  }
582
724
  }
583
725
 
584
- function useTools(ctx) {
585
- const toolPageHeaders = {}
586
-
587
- function setToolPageHeaders(components) {
588
- Object.assign(toolPageHeaders, components)
589
- }
590
-
591
- return {
592
- toolPageHeaders,
593
- setToolPageHeaders,
594
- }
595
- }
596
-
597
726
  export default {
598
727
  order: 10 - 100,
599
728
 
@@ -603,6 +732,8 @@ export default {
603
732
  ctx.components({
604
733
  Tools,
605
734
  ToolSelector,
735
+ ToolResult,
736
+ JsonInput,
606
737
  })
607
738
 
608
739
  ctx.setGlobals({
@@ -644,7 +775,7 @@ export default {
644
775
  }
645
776
  })
646
777
 
647
- ctx.chatRequestFilters.push(({ request, thread }) => {
778
+ ctx.chatRequestFilters.push(({ request, thread, context }) => {
648
779
  // Tool Preferences
649
780
  const prefs = ctx.prefs
650
781
  if (prefs.onlyTools != null) {