llms-py 3.0.12__py3-none-any.whl → 3.0.14__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/main.py CHANGED
@@ -26,11 +26,24 @@ import sys
26
26
  import time
27
27
  import traceback
28
28
  from datetime import datetime
29
- from enum import IntEnum
29
+ from enum import Enum, IntEnum
30
30
  from importlib import resources # Py≥3.9 (pip install importlib_resources for 3.7/3.8)
31
31
  from io import BytesIO
32
32
  from pathlib import Path
33
- from typing import Any, Callable, Dict, List, Optional, Tuple, Union, get_type_hints
33
+ from typing import (
34
+ Annotated,
35
+ Any,
36
+ Callable,
37
+ Dict,
38
+ List,
39
+ Literal,
40
+ Optional,
41
+ Tuple,
42
+ Union,
43
+ get_args,
44
+ get_origin,
45
+ get_type_hints,
46
+ )
34
47
  from urllib.parse import parse_qs, urlencode, urljoin
35
48
 
36
49
  import aiohttp
@@ -43,7 +56,7 @@ try:
43
56
  except ImportError:
44
57
  HAS_PIL = False
45
58
 
46
- VERSION = "3.0.12"
59
+ VERSION = "3.0.14"
47
60
  _ROOT = None
48
61
  DEBUG = os.getenv("DEBUG") == "1"
49
62
  MOCK = os.getenv("MOCK") == "1"
@@ -348,22 +361,75 @@ def to_content(result):
348
361
  return str(result)
349
362
 
350
363
 
364
+ def get_literal_values(typ):
365
+ """Recursively extract values from Literal and Union types."""
366
+ origin = get_origin(typ)
367
+ if origin is Literal:
368
+ return list(get_args(typ))
369
+ elif origin is Union:
370
+ values = []
371
+ for arg in get_args(typ):
372
+ # Recurse for nested Unions or Literals
373
+ nested_values = get_literal_values(arg)
374
+ if nested_values:
375
+ for v in nested_values:
376
+ if v not in values:
377
+ values.append(v)
378
+ return values
379
+ return None
380
+
381
+
351
382
  def function_to_tool_definition(func):
352
- type_hints = get_type_hints(func)
383
+ type_hints = get_type_hints(func, include_extras=True)
353
384
  signature = inspect.signature(func)
354
385
  parameters = {"type": "object", "properties": {}, "required": []}
355
386
 
356
387
  for name, param in signature.parameters.items():
357
388
  param_type = type_hints.get(name, str)
358
389
  param_type_name = "string"
359
- if param_type is int:
390
+ enum_values = None
391
+ description = None
392
+
393
+ # Check for Annotated (for description)
394
+ if get_origin(param_type) is Annotated:
395
+ args = get_args(param_type)
396
+ param_type = args[0]
397
+ for arg in args[1:]:
398
+ if isinstance(arg, str):
399
+ description = arg
400
+ break
401
+
402
+ # Check for Enum
403
+ if inspect.isclass(param_type) and issubclass(param_type, Enum):
404
+ enum_values = [e.value for e in param_type]
405
+ else:
406
+ # Check for Literal / Union[Literal]
407
+ enum_values = get_literal_values(param_type)
408
+
409
+ if enum_values:
410
+ # Infer type from the first value
411
+ value_type = type(enum_values[0])
412
+ if value_type is int:
413
+ param_type_name = "integer"
414
+ elif value_type is float:
415
+ param_type_name = "number"
416
+ elif value_type is bool:
417
+ param_type_name = "boolean"
418
+
419
+ elif param_type is int:
360
420
  param_type_name = "integer"
361
421
  elif param_type is float:
362
422
  param_type_name = "number"
363
423
  elif param_type is bool:
364
424
  param_type_name = "boolean"
365
425
 
366
- parameters["properties"][name] = {"type": param_type_name}
426
+ prop = {"type": param_type_name}
427
+ if description:
428
+ prop["description"] = description
429
+ if enum_values:
430
+ prop["enum"] = enum_values
431
+ parameters["properties"][name] = prop
432
+
367
433
  if param.default == inspect.Parameter.empty:
368
434
  parameters["required"].append(name)
369
435
 
@@ -371,7 +437,7 @@ def function_to_tool_definition(func):
371
437
  "type": "function",
372
438
  "function": {
373
439
  "name": func.__name__,
374
- "description": func.__doc__ or "",
440
+ "description": (func.__doc__ or "").strip(),
375
441
  "parameters": parameters,
376
442
  },
377
443
  }
@@ -1513,6 +1579,7 @@ def g_tool_result(result, function_name: Optional[str] = None, function_args: Op
1513
1579
  content = []
1514
1580
  resources = []
1515
1581
  args = function_args or {}
1582
+ _dbg(f"{function_name} tool result type: {type(result)}")
1516
1583
  if isinstance(result, dict):
1517
1584
  text, res = tool_result_part(result, function_name, args)
1518
1585
  if text:
@@ -1555,7 +1622,7 @@ def group_resources(resources: list):
1555
1622
  {"images": [{"type": "image_url", "image_url": {"url": "/image.jpg"}}] }
1556
1623
  """
1557
1624
  grouped = {}
1558
- for res in resources:
1625
+ for res in resources or []:
1559
1626
  type = res.get("type")
1560
1627
  if not type:
1561
1628
  continue
@@ -1584,6 +1651,9 @@ async def g_chat_completion(chat, context=None):
1584
1651
  if context is None:
1585
1652
  context = {"chat": chat, "tools": "all"}
1586
1653
 
1654
+ if "request_id" not in context:
1655
+ context["request_id"] = str(int(time.time() * 1000))
1656
+
1587
1657
  # get first provider that has the model
1588
1658
  candidate_providers = [name for name, provider in g_handlers.items() if provider.provider_model(model)]
1589
1659
  if len(candidate_providers) == 0:
@@ -1735,7 +1805,9 @@ async def g_chat_completion(chat, context=None):
1735
1805
  continue
1736
1806
 
1737
1807
  # If we get here, all providers failed
1738
- raise first_exception
1808
+ if first_exception:
1809
+ raise first_exception
1810
+ raise Exception("All providers failed")
1739
1811
 
1740
1812
 
1741
1813
  async def cli_chat(chat, tools=None, image=None, audio=None, file=None, args=None, raw=False):
@@ -2917,6 +2989,9 @@ class ExtensionContext:
2917
2989
  def add_index_footer(self, html: str):
2918
2990
  self.app.index_footers.append(html)
2919
2991
 
2992
+ def get_home_path(self, name: str = "") -> str:
2993
+ return home_llms_path(name)
2994
+
2920
2995
  def get_config(self) -> Optional[Dict[str, Any]]:
2921
2996
  return g_config
2922
2997
 
llms/ui/ai.mjs CHANGED
@@ -6,7 +6,7 @@ const headers = { 'Accept': 'application/json' }
6
6
  const prefsKey = 'llms.prefs'
7
7
 
8
8
  export const o = {
9
- version: '3.0.12',
9
+ version: '3.0.14',
10
10
  base,
11
11
  prefsKey,
12
12
  welcome: 'Welcome to llms.py',
llms/ui/app.css CHANGED
@@ -424,9 +424,15 @@
424
424
  .right-0 {
425
425
  right: calc(var(--spacing) * 0);
426
426
  }
427
+ .right-1 {
428
+ right: calc(var(--spacing) * 1);
429
+ }
427
430
  .right-2 {
428
431
  right: calc(var(--spacing) * 2);
429
432
  }
433
+ .right-3 {
434
+ right: calc(var(--spacing) * 3);
435
+ }
430
436
  .right-4 {
431
437
  right: calc(var(--spacing) * 4);
432
438
  }
@@ -556,6 +562,9 @@
556
562
  .-mt-1 {
557
563
  margin-top: calc(var(--spacing) * -1);
558
564
  }
565
+ .-mt-2 {
566
+ margin-top: calc(var(--spacing) * -2);
567
+ }
559
568
  .-mt-8 {
560
569
  margin-top: calc(var(--spacing) * -8);
561
570
  }
@@ -821,6 +830,15 @@
821
830
  .h-screen {
822
831
  height: 100vh;
823
832
  }
833
+ .max-h-10 {
834
+ max-height: calc(var(--spacing) * 10);
835
+ }
836
+ .max-h-20 {
837
+ max-height: calc(var(--spacing) * 20);
838
+ }
839
+ .max-h-50 {
840
+ max-height: calc(var(--spacing) * 50);
841
+ }
824
842
  .max-h-60 {
825
843
  max-height: calc(var(--spacing) * 60);
826
844
  }
@@ -2933,6 +2951,13 @@
2933
2951
  }
2934
2952
  }
2935
2953
  }
2954
+ .group-hover\:opacity-50 {
2955
+ &:is(:where(.group):hover *) {
2956
+ @media (hover: hover) {
2957
+ opacity: 50%;
2958
+ }
2959
+ }
2960
+ }
2936
2961
  .group-hover\:opacity-75 {
2937
2962
  &:is(:where(.group):hover *) {
2938
2963
  @media (hover: hover) {
@@ -55,8 +55,8 @@ function embedHtml(html) {
55
55
 
56
56
  export const TypeText = {
57
57
  template: `
58
- <div v-if="text.type === 'text'">
59
- <div v-html="html"></div>
58
+ <div data-type="text" v-if="text.type === 'text'">
59
+ <div v-html="html?.trim()" class="whitespace-pre-wrap"></div>
60
60
  </div>
61
61
  `,
62
62
  props: {
@@ -72,7 +72,7 @@ export const TypeText = {
72
72
  return ctx.fmt.markdown(props.text.text)
73
73
  } catch (e) {
74
74
  console.error('TypeText: markdown', e)
75
- return `<div class="whitespace-pre-wrap">${props.text.text}</div>`
75
+ return `<div>${props.text.text}</div>`
76
76
  }
77
77
  })
78
78
  return { html }
@@ -161,7 +161,7 @@ export const LightboxImage = {
161
161
 
162
162
  export const TypeImage = {
163
163
  template: `
164
- <div v-if="image.type === 'image_url'">
164
+ <div data-type="image" v-if="image.type === 'image_url'">
165
165
  <LightboxImage :src="$ctx.resolveUrl(image.image_url.url)" />
166
166
  </div>
167
167
  `,
@@ -175,7 +175,7 @@ export const TypeImage = {
175
175
 
176
176
  export const TypeAudio = {
177
177
  template: `
178
- <div v-if="audio.type === 'audio_url'">
178
+ <div data-type="audio" v-if="audio.type === 'audio_url'">
179
179
  <slot></slot>
180
180
  <audio controls :src="$ctx.resolveUrl(audio.audio_url.url)" class="h-8 w-64"></audio>
181
181
  </div>
@@ -190,7 +190,7 @@ export const TypeAudio = {
190
190
 
191
191
  export const TypeFile = {
192
192
  template: `
193
- <a v-if="file.type === 'file'" :href="$ctx.resolveUrl(file.file.file_data)" target="_blank"
193
+ <a data-type="file" v-if="file.type === 'file'" :href="$ctx.resolveUrl(file.file.file_data)" target="_blank"
194
194
  class="flex items-center gap-2 px-3 py-2 rounded-lg border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors text-sm text-blue-600 dark:text-blue-400 hover:underline">
195
195
  <svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline></svg>
196
196
  <span class="max-w-xs truncate">{{ file.file.filename || 'Attachment' }}</span>
@@ -211,7 +211,7 @@ export const ViewType = {
211
211
  <TypeImage v-else-if="result.type === 'image_url'" :image="result" />
212
212
  <TypeAudio v-else-if="result.type === 'audio_url'" :audio="result" />
213
213
  <TypeFile v-else-if="result.type === 'file'" :file="result" />
214
- <div v-else>
214
+ <div data-type="other" v-else>
215
215
  <HtmlFormat :value="result" :classes="$utils.htmlFormatClasses" />
216
216
  </div>
217
217
  </div>
@@ -352,11 +352,27 @@ export const ToolArguments = {
352
352
  <div class="prose html-format">
353
353
  <table class="table-object border-none">
354
354
  <tr v-for="(v, k) in dict" :key="k">
355
- <td class="align-top py-2 px-4 text-left text-sm font-medium tracking-wider whitespace-nowrap lowercase">{{ k }}</td>
356
- <td v-if="$utils.isHtml(v)" style="margin:0;padding:0;width:100%">
355
+ <td data-arg="name" class="align-top py-2 px-4 text-left text-sm font-medium tracking-wider whitespace-nowrap lowercase">{{ k }}</td>
356
+ <td data-arg="html" v-if="$utils.isHtml(v)" style="margin:0;padding:0;width:100%">
357
357
  <div v-html="embedHtml(v)" class="w-full h-full"></div>
358
358
  </td>
359
- <td v-else class="align-top py-2 px-4 text-sm whitespace-pre-wrap">
359
+ <td data-arg="string" v-else-if="typeof v === 'string'" class="align-top py-2 px-4 text-sm whitespace-pre-wrap">
360
+ <div v-if="v.length > 200" class="relative">
361
+ <button type="button" @click="maximized[k] = !maximized[k]" class="absolute top-0 right-3 opacity-0 group-hover:opacity-50 transition-opacity duration-200 rounded focus:outline-none focus:ring-0">
362
+ <div class="flex items-center space-x-1">
363
+ <span class="text-xs text-gray-600 dark:text-gray-400" :title="v.length + ' characters'">{{ $fmt.humanifyNumber(v.length) }}</span>
364
+ <svg class="size-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
365
+ <path v-if="maximized[k]" fill="currentColor" d="M9 9H3V7h4V3h2zm0 6H3v2h4v4h2zm12 0h-6v6h2v-4h4zm-6-6h6V7h-4V3h-2z"/>
366
+ <path v-else fill="currentColor" d="M3 3h6v2H5v4H3zm0 18h6v-2H5v-4H3zm12 0h6v-6h-2v4h-4zm6-18h-6v2h4v4h2z"/>
367
+ </svg>
368
+ </div>
369
+ </button>
370
+ <div v-if="!maximized[k]" class="max-h-60 overflow-y-auto">{{ v }}</div>
371
+ <div v-else class="w-full h-full">{{ v }}</div>
372
+ </div>
373
+ <div v-else>{{ v }}</div>
374
+ </td>
375
+ <td data-arg="value" v-else class="align-top py-2 px-4 text-sm whitespace-pre-wrap">
360
376
  <HtmlFormat :value="v" :classes="$utils.htmlFormatClasses" />
361
377
  </td>
362
378
  </tr>
@@ -373,6 +389,7 @@ export const ToolArguments = {
373
389
  },
374
390
  setup(props) {
375
391
  const refArgs = ref()
392
+ const maximized = ref({})
376
393
  const dict = computed(() => {
377
394
  if (isEmpty(props.value)) return null
378
395
  const ret = tryParseJson(props.value)
@@ -409,6 +426,7 @@ export const ToolArguments = {
409
426
 
410
427
  return {
411
428
  refArgs,
429
+ maximized,
412
430
  dict,
413
431
  list,
414
432
  isEmpty,
@@ -524,7 +542,7 @@ export const ChatBody = {
524
542
  : 'bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-gray-100 border border-gray-200 dark:border-gray-700'"
525
543
  >
526
544
  <!-- Copy button in top right corner -->
527
- <button
545
+ <button v-if="message.content"
528
546
  type="button"
529
547
  @click="copyMessageContent(message)"
530
548
  class="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity duration-200 p-1 rounded hover:bg-black/10 dark:hover:bg-white/10 focus:outline-none focus:ring-0"
@@ -950,7 +950,7 @@ export default {
950
950
  ctx.setLeftIcons({
951
951
  chat: {
952
952
  component: {
953
- template: `<svg @click="$ctx.togglePath('/')" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" d="M8 2.19c3.13 0 5.68 2.25 5.68 5s-2.55 5-5.68 5a5.7 5.7 0 0 1-1.89-.29l-.75-.26l-.56.56a14 14 0 0 1-2 1.55a.13.13 0 0 1-.07 0v-.06a6.58 6.58 0 0 0 .15-4.29a5.25 5.25 0 0 1-.55-2.16c0-2.77 2.55-5 5.68-5M8 .94c-3.83 0-6.93 2.81-6.93 6.27a6.4 6.4 0 0 0 .64 2.64a5.53 5.53 0 0 1-.18 3.48a1.32 1.32 0 0 0 2 1.5a15 15 0 0 0 2.16-1.71a6.8 6.8 0 0 0 2.31.36c3.83 0 6.93-2.81 6.93-6.27S11.83.94 8 .94"/><ellipse cx="5.2" cy="7.7" fill="currentColor" rx=".8" ry=".75"/><ellipse cx="8" cy="7.7" fill="currentColor" rx=".8" ry=".75"/><ellipse cx="10.8" cy="7.7" fill="currentColor" rx=".8" ry=".75"/></svg>`,
953
+ template: `<svg @click="$ctx.togglePath($ctx.layout.path?.startsWith('/c/') ? $ctx.layout.path : '/')" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" d="M8 2.19c3.13 0 5.68 2.25 5.68 5s-2.55 5-5.68 5a5.7 5.7 0 0 1-1.89-.29l-.75-.26l-.56.56a14 14 0 0 1-2 1.55a.13.13 0 0 1-.07 0v-.06a6.58 6.58 0 0 0 .15-4.29a5.25 5.25 0 0 1-.55-2.16c0-2.77 2.55-5 5.68-5M8 .94c-3.83 0-6.93 2.81-6.93 6.27a6.4 6.4 0 0 0 .64 2.64a5.53 5.53 0 0 1-.18 3.48a1.32 1.32 0 0 0 2 1.5a15 15 0 0 0 2.16-1.71a6.8 6.8 0 0 0 2.31.36c3.83 0 6.93-2.81 6.93-6.27S11.83.94 8 .94"/><ellipse cx="5.2" cy="7.7" fill="currentColor" rx=".8" ry=".75"/><ellipse cx="8" cy="7.7" fill="currentColor" rx=".8" ry=".75"/><ellipse cx="10.8" cy="7.7" fill="currentColor" rx=".8" ry=".75"/></svg>`,
954
954
  },
955
955
  isActive({ path }) {
956
956
  return path === '/' || path.startsWith('/c/')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llms-py
3
- Version: 3.0.12
3
+ Version: 3.0.14
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
@@ -3,7 +3,7 @@ llms/__main__.py,sha256=hrBulHIt3lmPm1BCyAEVtB6DQ0Hvc3gnIddhHCmJasg,151
3
3
  llms/db.py,sha256=oozp5I5lECVO8oZEFwcZl3ES5mARqWeR1BkoqG5kSqM,11687
4
4
  llms/index.html,sha256=nGk1Djtn9p7l6LuKp4Kg0JIB9fCzxtTWXFfmDb4ggpc,1658
5
5
  llms/llms.json,sha256=NEr9kJRkUGZ2YZHbWC-haGPlVVL2Qtnx4kKZENGH1wk,11494
6
- llms/main.py,sha256=HgQ_nS0OSqu8BRq_k4a1vpPhGzNiIgvIg-fxs7O6G44,174163
6
+ llms/main.py,sha256=GNivNxCaKGzVrFGZ2vqr0RcRRafZBmI9asUgzCGerqk,176342
7
7
  llms/providers-extra.json,sha256=_6DmGBiQY9LM6_Y0zOiObYn7ba4g3akSNQfmHcYlENc,11101
8
8
  llms/providers.json,sha256=yjhDurlwo70xqfV0HNLiZaCpw3WvtIgkjoLahQIKX2w,282530
9
9
  llms/extensions/analytics/ui/index.mjs,sha256=m1XwaqYCLwK267JAUCAltkN_nOXep0GxfpvGNS5i4_w,69547
@@ -13,6 +13,13 @@ llms/extensions/app/db.py,sha256=DU8YZ25yFsBI-O6msxh2GgzbwaqKqXkAHJLwQKcmFPI,215
13
13
  llms/extensions/app/ui/Recents.mjs,sha256=2ypAKUp9_Oqcive1nUWZ8I2PQTBomBg_Pkjygi4oPgs,9261
14
14
  llms/extensions/app/ui/index.mjs,sha256=sB9176LLNuKFsZ28yL-tROA6J4xePNtvxtSrzFcinRo,13271
15
15
  llms/extensions/app/ui/threadStore.mjs,sha256=CLlD-1HBO1yhZBHLfL0ZdA4quT4R07qr1JW4a8igVNc,12287
16
+ llms/extensions/computer_use/__init__.py,sha256=YOMJnMFsIi6vdZ8BpI7_uWubIwiWHAJoLpHflGC9BI0,715
17
+ llms/extensions/computer_use/base.py,sha256=Igio5R6kPQOxIbmpaA7X6j6eC4cpF3jwTTR8rURfp5E,2386
18
+ llms/extensions/computer_use/bash.py,sha256=5s_oYqRGnE1xIICe6qVsfUMJFIbp79Ac0X5NVkSrn_c,5929
19
+ llms/extensions/computer_use/computer.py,sha256=wehwcrYwi9usCRcziE_loMhWDbVgfjLk_T4_4TZa4W4,19642
20
+ llms/extensions/computer_use/edit.py,sha256=fEMylXnS07Ql3ZoQPG_l98fKrBHIHOWJzn_yp3D5XXI,12784
21
+ llms/extensions/computer_use/platform.py,sha256=w5ECar8lM4Lag7rTYUQmU7wEWaqCeejNXwwM3CB8ulQ,14866
22
+ llms/extensions/computer_use/run.py,sha256=ZIcoYyy2cc3IKR_T4yJgx6IUHu2m7UusIJi9Dx1s7dA,1566
16
23
  llms/extensions/core_tools/CALCULATOR.md,sha256=pJRtCVF01BgxFrSNh2Ys_lrRi3SFwLgJzAX93AGh93Q,1944
17
24
  llms/extensions/core_tools/__init__.py,sha256=Y5ZlcSg5yVXxIGX_FVbDcHyeXx3ex_rzRQ2hli6Nk38,23280
18
25
  llms/extensions/core_tools/ui/index.mjs,sha256=KycJ2FcQ6BieBY7fjWGxVBGHN6WuFx712OFrO6flXww,31770
@@ -128,7 +135,7 @@ llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.ttf,sha256=8B8-h9nGphwMC
128
135
  llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.woff,sha256=4U_tArGrp86fWv1YRLXQMhsiNR_rxyDg3ouHI1J2Cfc,16028
129
136
  llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.woff2,sha256=cdUX1ngneHz6vfGGkUzDNY7aU543kxlB8rL9SiH2jAs,13568
130
137
  llms/extensions/providers/__init__.py,sha256=C5zOBQEOB2L96rAZdjV42fPVk_dZxSh2Dv30Kb1w3lE,534
131
- llms/extensions/providers/anthropic.py,sha256=V9mechnhyoX-5Z5AkwyQ-UzLax6cqG7j7GLvGTZF9no,10941
138
+ llms/extensions/providers/anthropic.py,sha256=ey3G9D3drhjzaNTKC8SS_XVSjdi3K7uqYTskmf26Aic,12011
132
139
  llms/extensions/providers/cerebras.py,sha256=HaeFW0GwbD6V6Zrrwqyv78kQb0VXg9oHmykvJfIOOYE,1417
133
140
  llms/extensions/providers/chutes.py,sha256=5ZrfbqoOhgzKLQy_qULcp4jlvW5WXPR0jP9kN2Jzb9g,6229
134
141
  llms/extensions/providers/google.py,sha256=oCCTE2KAw-WWE2v14XpKzgAMdFIWbjTBoa6GWuqT4dw,26215
@@ -141,10 +148,10 @@ llms/extensions/system_prompts/__init__.py,sha256=TZy1CS2dPkBNBA_Ovf9BlVetZqTt2N
141
148
  llms/extensions/system_prompts/ui/index.mjs,sha256=_pVCreAebSzE9dzcHF2kiYODwP-fDHCqtUQB-X5Io9Q,12107
142
149
  llms/extensions/system_prompts/ui/prompts.json,sha256=t5DD3bird-87wFa4OlW-bC2wdoYDrVzfyc8TO5OaotI,128489
143
150
  llms/extensions/tools/__init__.py,sha256=u76604Cn_sRFQRqeA_pkVEty27V688Mt9Z7Kh63yDr8,4825
144
- llms/extensions/tools/ui/index.mjs,sha256=IbGB2FQJ5VL4a8arwoR9C79vUCNrz8VIyQnHZ4vxU9o,34486
151
+ llms/extensions/tools/ui/index.mjs,sha256=-Rby2y1Rx83JFcqYqn86uYZjVd_WlF4wSajZ1M31LWg,34997
145
152
  llms/ui/App.mjs,sha256=CoUzO9mV__-jV19NKHYIbwHsjWMnO11jyNSbnJhe1gQ,7486
146
- llms/ui/ai.mjs,sha256=S-LmypGGmTrAteH9By37md6gRJw2ILbjXf36Glho5EY,6541
147
- llms/ui/app.css,sha256=vfXErYVdVlE3pL8oZ-2G_OC-_reJzmaL0p91EVv48uo,186490
153
+ llms/ui/ai.mjs,sha256=gE3WAMzTEu2m67l1Gh3pn4dsog9xSGDYPLQw9TbG67w,6541
154
+ llms/ui/app.css,sha256=ZxdHeOSiZYKQvkP_ydTdrW1Zo8lrD4c_amtj4kOtgzA,186973
148
155
  llms/ui/ctx.mjs,sha256=X4scgXEQ9bMUfQl36sM4A3o2Ufad3LRwItxfmSu1xwc,12838
149
156
  llms/ui/fav.svg,sha256=_R6MFeXl6wBFT0lqcUxYQIDWgm246YH_3hSTW0oO8qw,734
150
157
  llms/ui/index.mjs,sha256=7GMbFyG3L4k6dxSrQYQ0BLzqL976xw5HeaqKco0THHA,4296
@@ -166,12 +173,12 @@ llms/ui/lib/vue.mjs,sha256=75FuLhUTPk19sncwNIrm0BGEL0_Qw298-_v01fPWYoI,542872
166
173
  llms/ui/modules/icons.mjs,sha256=LGcH0ys0QLS2ZKCO42qHpwPYbBV_EssoWLezU4XZEzU,27751
167
174
  llms/ui/modules/layout.mjs,sha256=8pAxs8bedQI3b3eRA9nrfpLZznLmrpp4BZvigYAQjpQ,12572
168
175
  llms/ui/modules/model-selector.mjs,sha256=6U4rAZ7vmQELFRQGWk4YEtq02v3lyHdMq6yUOp-ArXg,43184
169
- llms/ui/modules/chat/ChatBody.mjs,sha256=5yWjo6tWmcKidDpRvKFeHqx3lXO3DB-3rTyXY72gB4U,49122
176
+ llms/ui/modules/chat/ChatBody.mjs,sha256=l6ANTkOMb6GJSg9-vUBhClndO2pI2RJr8NascPjvMJY,50904
170
177
  llms/ui/modules/chat/SettingsDialog.mjs,sha256=HMBJTwrapKrRIAstIIqp0QlJL5O-ho4hzgvfagPfsX8,19930
171
- llms/ui/modules/chat/index.mjs,sha256=lfSbERMaM3bLsKhdJJPWwL4-FGr8U_ftlvqW5vC3T1s,39762
172
- llms_py-3.0.12.dist-info/licenses/LICENSE,sha256=bus9cuAOWeYqBk2OuhSABVV1P4z7hgrEFISpyda_H5w,1532
173
- llms_py-3.0.12.dist-info/METADATA,sha256=KVDU66mm6L_mF4uwzhWhSbPHqqydeOKSuuKHf0IRJ_w,2195
174
- llms_py-3.0.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
175
- llms_py-3.0.12.dist-info/entry_points.txt,sha256=WswyE7PfnkZMIxboC-MS6flBD6wm-CYU7JSUnMhqMfM,40
176
- llms_py-3.0.12.dist-info/top_level.txt,sha256=gC7hk9BKSeog8gyg-EM_g2gxm1mKHwFRfK-10BxOsa4,5
177
- llms_py-3.0.12.dist-info/RECORD,,
178
+ llms/ui/modules/chat/index.mjs,sha256=FZ0fJ53JXQnTDiSOFhyGp3J5OMuEDQ2YZJGKC5VwS0E,39819
179
+ llms_py-3.0.14.dist-info/licenses/LICENSE,sha256=bus9cuAOWeYqBk2OuhSABVV1P4z7hgrEFISpyda_H5w,1532
180
+ llms_py-3.0.14.dist-info/METADATA,sha256=bLramlKkA30HvkQwaGmAl9Z_r1Q75UZ0gP3FXv5451s,2195
181
+ llms_py-3.0.14.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
182
+ llms_py-3.0.14.dist-info/entry_points.txt,sha256=WswyE7PfnkZMIxboC-MS6flBD6wm-CYU7JSUnMhqMfM,40
183
+ llms_py-3.0.14.dist-info/top_level.txt,sha256=gC7hk9BKSeog8gyg-EM_g2gxm1mKHwFRfK-10BxOsa4,5
184
+ llms_py-3.0.14.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5