llms-py 2.0.16__tar.gz → 2.0.18__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.
Files changed (65) hide show
  1. {llms_py-2.0.16/llms_py.egg-info → llms_py-2.0.18}/PKG-INFO +1 -1
  2. {llms_py-2.0.16 → llms_py-2.0.18}/llms/__pycache__/main.cpython-314.pyc +0 -0
  3. {llms_py-2.0.16 → llms_py-2.0.18}/llms/llms.json +20 -22
  4. {llms_py-2.0.16 → llms_py-2.0.18}/llms/main.py +1 -1
  5. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/Analytics.mjs +35 -1
  6. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/Main.mjs +2 -2
  7. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/ai.mjs +1 -1
  8. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/threadStore.mjs +1 -1
  9. {llms_py-2.0.16 → llms_py-2.0.18/llms_py.egg-info}/PKG-INFO +1 -1
  10. {llms_py-2.0.16 → llms_py-2.0.18}/pyproject.toml +1 -1
  11. {llms_py-2.0.16 → llms_py-2.0.18}/setup.py +1 -1
  12. {llms_py-2.0.16 → llms_py-2.0.18}/LICENSE +0 -0
  13. {llms_py-2.0.16 → llms_py-2.0.18}/MANIFEST.in +0 -0
  14. {llms_py-2.0.16 → llms_py-2.0.18}/README.md +0 -0
  15. {llms_py-2.0.16 → llms_py-2.0.18}/llms/__init__.py +0 -0
  16. {llms_py-2.0.16 → llms_py-2.0.18}/llms/__main__.py +0 -0
  17. {llms_py-2.0.16 → llms_py-2.0.18}/llms/__pycache__/__init__.cpython-312.pyc +0 -0
  18. {llms_py-2.0.16 → llms_py-2.0.18}/llms/__pycache__/__init__.cpython-313.pyc +0 -0
  19. {llms_py-2.0.16 → llms_py-2.0.18}/llms/__pycache__/__init__.cpython-314.pyc +0 -0
  20. {llms_py-2.0.16 → llms_py-2.0.18}/llms/__pycache__/__main__.cpython-312.pyc +0 -0
  21. {llms_py-2.0.16 → llms_py-2.0.18}/llms/__pycache__/__main__.cpython-314.pyc +0 -0
  22. {llms_py-2.0.16 → llms_py-2.0.18}/llms/__pycache__/llms.cpython-312.pyc +0 -0
  23. {llms_py-2.0.16 → llms_py-2.0.18}/llms/__pycache__/main.cpython-312.pyc +0 -0
  24. {llms_py-2.0.16 → llms_py-2.0.18}/llms/__pycache__/main.cpython-313.pyc +0 -0
  25. {llms_py-2.0.16 → llms_py-2.0.18}/llms/index.html +0 -0
  26. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/App.mjs +0 -0
  27. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/Avatar.mjs +0 -0
  28. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/Brand.mjs +0 -0
  29. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/ChatPrompt.mjs +0 -0
  30. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/ModelSelector.mjs +0 -0
  31. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/ProviderIcon.mjs +0 -0
  32. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/ProviderStatus.mjs +0 -0
  33. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/Recents.mjs +0 -0
  34. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/SettingsDialog.mjs +0 -0
  35. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/Sidebar.mjs +0 -0
  36. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/SignIn.mjs +0 -0
  37. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/SystemPromptEditor.mjs +0 -0
  38. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/SystemPromptSelector.mjs +0 -0
  39. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/Welcome.mjs +0 -0
  40. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/app.css +0 -0
  41. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/fav.svg +0 -0
  42. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/lib/chart.js +0 -0
  43. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/lib/charts.mjs +0 -0
  44. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/lib/color.js +0 -0
  45. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/lib/highlight.min.mjs +0 -0
  46. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/lib/idb.min.mjs +0 -0
  47. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/lib/marked.min.mjs +0 -0
  48. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/lib/servicestack-client.mjs +0 -0
  49. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/lib/servicestack-vue.mjs +0 -0
  50. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/lib/vue-router.min.mjs +0 -0
  51. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/lib/vue.min.mjs +0 -0
  52. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/lib/vue.mjs +0 -0
  53. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/markdown.mjs +0 -0
  54. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/tailwind.input.css +0 -0
  55. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/typography.css +0 -0
  56. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui/utils.mjs +0 -0
  57. {llms_py-2.0.16 → llms_py-2.0.18}/llms/ui.json +0 -0
  58. {llms_py-2.0.16 → llms_py-2.0.18}/llms_py.egg-info/SOURCES.txt +0 -0
  59. {llms_py-2.0.16 → llms_py-2.0.18}/llms_py.egg-info/dependency_links.txt +0 -0
  60. {llms_py-2.0.16 → llms_py-2.0.18}/llms_py.egg-info/entry_points.txt +0 -0
  61. {llms_py-2.0.16 → llms_py-2.0.18}/llms_py.egg-info/not-zip-safe +0 -0
  62. {llms_py-2.0.16 → llms_py-2.0.18}/llms_py.egg-info/requires.txt +0 -0
  63. {llms_py-2.0.16 → llms_py-2.0.18}/llms_py.egg-info/top_level.txt +0 -0
  64. {llms_py-2.0.16 → llms_py-2.0.18}/requirements.txt +0 -0
  65. {llms_py-2.0.16 → llms_py-2.0.18}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llms-py
3
- Version: 2.0.16
3
+ Version: 2.0.18
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
@@ -93,10 +93,6 @@
93
93
  }
94
94
  ],
95
95
  "max_completion_tokens": 16,
96
- "reasoning": {
97
- "max_tokens": 16,
98
- "reasoning_effort": "low"
99
- },
100
96
  "stream": false
101
97
  }
102
98
  },
@@ -147,7 +143,6 @@
147
143
  "api_key": "$GROQ_API_KEY",
148
144
  "models": {
149
145
  "allam-2-7b": "allam-2-7b",
150
- "gemma2:9b": "gemma2-9b-it",
151
146
  "compound": "groq/compound",
152
147
  "compound-mini": "groq/compound-mini",
153
148
  "llama3.1:8b": "llama-3.1-8b-instant",
@@ -168,7 +163,7 @@
168
163
  }
169
164
  },
170
165
  "google_free": {
171
- "enabled": true,
166
+ "enabled": false,
172
167
  "type": "GoogleProvider",
173
168
  "api_key": "$GOOGLE_FREE_API_KEY",
174
169
  "models": {
@@ -599,7 +594,6 @@
599
594
  "base_url": "https://api.anthropic.com",
600
595
  "api_key": "$ANTHROPIC_API_KEY",
601
596
  "models": {
602
- "claude-opus-4-1": "claude-opus-4-1",
603
597
  "claude-sonnet-4-5": "claude-sonnet-4-5",
604
598
  "claude-sonnet-4-0": "claude-sonnet-4-0",
605
599
  "claude-3-7-sonnet": "claude-3-7-sonnet-latest",
@@ -640,6 +634,25 @@
640
634
  "input": "0.00000025",
641
635
  "output": "0.00000125"
642
636
  }
637
+ },
638
+ "check": {
639
+ "messages": [
640
+ {
641
+ "role": "user",
642
+ "content": [
643
+ {
644
+ "type": "text",
645
+ "text": "1+1="
646
+ }
647
+ ]
648
+ }
649
+ ],
650
+ "max_completion_tokens": 512,
651
+ "reasoning": {
652
+ "max_tokens": 128,
653
+ "reasoning_effort": "low"
654
+ },
655
+ "stream": false
643
656
  }
644
657
  },
645
658
  "openai": {
@@ -735,21 +748,6 @@
735
748
  "input": "0.000003",
736
749
  "output": "0.000006"
737
750
  }
738
- },
739
- "check": {
740
- "messages": [
741
- {
742
- "role": "user",
743
- "content": [
744
- {
745
- "type": "text",
746
- "text": "1+1="
747
- }
748
- ]
749
- }
750
- ],
751
- "max_completion_tokens": 16,
752
- "stream": false
753
751
  }
754
752
  },
755
753
  "grok": {
@@ -22,7 +22,7 @@ from aiohttp import web
22
22
  from pathlib import Path
23
23
  from importlib import resources # Py≥3.9 (pip install importlib_resources for 3.7/3.8)
24
24
 
25
- VERSION = "2.0.16"
25
+ VERSION = "2.0.18"
26
26
  _ROOT = None
27
27
  g_config_path = None
28
28
  g_ui_path = None
@@ -380,7 +380,7 @@ export default {
380
380
  </div>
381
381
  </div>
382
382
  <div class="flex flex-col gap-2">
383
- <button type="button" v-if="request.threadId" @click="openThread(request.threadId)" class="flex-shrink-0 px-4 py-2 text-sm font-medium text-blue-600 hover:text-blue-800 border border-blue-300 rounded hover:bg-blue-50 transition-colors whitespace-nowrap">
383
+ <button type="button" v-if="threadExists(request.threadId)" @click="openThread(request.threadId)" class="flex-shrink-0 px-4 py-2 text-sm font-medium text-blue-600 hover:text-blue-800 border border-blue-300 rounded hover:bg-blue-50 transition-colors whitespace-nowrap">
384
384
  View<span class="hidden lg:inline"> Thread</span>
385
385
  </button>
386
386
  <button type="button" @click="deleteRequestLog(request.id)" class="flex-shrink-0 px-4 py-2 text-sm font-medium text-red-600 hover:text-red-800 border border-red-300 rounded hover:bg-red-50 transition-colors whitespace-nowrap">
@@ -525,6 +525,7 @@ export default {
525
525
  const activityHasMore = ref(true)
526
526
  const activityOffset = ref(0)
527
527
  const activityPageSize = 20
528
+ const existingThreadIds = ref(new Set())
528
529
 
529
530
  const selectedModel = ref('')
530
531
  const selectedProvider = ref('')
@@ -1234,11 +1235,43 @@ export default {
1234
1235
  }
1235
1236
  }
1236
1237
 
1238
+ const loadExistingThreadIds = async () => {
1239
+ try {
1240
+ // Calculate date range for selected month/year
1241
+ const startDate = new Date(selectedYear.value, selectedMonth.value - 1, 1)
1242
+ const endDate = new Date(selectedYear.value, selectedMonth.value, 0, 23, 59, 59)
1243
+
1244
+ // Convert to timestamp strings (threadId format)
1245
+ const startThreadId = startDate.getTime().toString()
1246
+ const endThreadId = endDate.getTime().toString()
1247
+
1248
+ const db = await initDB()
1249
+ const tx = db.transaction(['threads'], 'readonly')
1250
+ const store = tx.objectStore('threads')
1251
+
1252
+ // Use IDBKeyRange to only load threads within the month's timestamp range
1253
+ const range = IDBKeyRange.bound(startThreadId, endThreadId)
1254
+ const monthThreads = await store.getAll(range)
1255
+
1256
+ // Create a Set of existing thread IDs for the month
1257
+ existingThreadIds.value = new Set(monthThreads.map(thread => thread.id))
1258
+ } catch (error) {
1259
+ console.error('Failed to load existing thread IDs:', error)
1260
+ existingThreadIds.value = new Set()
1261
+ }
1262
+ }
1263
+
1264
+ const threadExists = (threadId) => {
1265
+ return threadId ? existingThreadIds.value.has(threadId) : false
1266
+ }
1267
+
1237
1268
  const loadActivityRequests = async (reset = false) => {
1238
1269
  if (reset) {
1239
1270
  activityOffset.value = 0
1240
1271
  activityRequests.value = []
1241
1272
  isActivityLoading.value = true
1273
+ // Load all existing thread IDs once when resetting
1274
+ await loadExistingThreadIds()
1242
1275
  } else {
1243
1276
  isActivityLoadingMore.value = true
1244
1277
  }
@@ -1474,6 +1507,7 @@ export default {
1474
1507
  onActivityScroll,
1475
1508
  clearActivityFilters,
1476
1509
  formatActivityDate,
1510
+ threadExists,
1477
1511
  openThread,
1478
1512
  deleteRequestLog,
1479
1513
  loadActivityFilterOptions,
@@ -187,7 +187,7 @@ export default {
187
187
  <!-- Edit and Redo buttons (shown on hover for user messages, outside bubble) -->
188
188
  <div v-if="message.role === 'user'" class="flex flex-col gap-2 opacity-0 group-hover:opacity-100 transition-opacity mt-1">
189
189
  <button type="button" @click.stop="editMessage(message)"
190
- class="text-xs px-2 py-1 rounded text-gray-400 hover:text-green-600 hover:bg-green-50 transition-all"
190
+ class="whitespace-nowrap text-xs px-2 py-1 rounded text-gray-400 hover:text-green-600 hover:bg-green-50 transition-all"
191
191
  title="Edit message">
192
192
  <svg class="size-4 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
193
193
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>
@@ -195,7 +195,7 @@ export default {
195
195
  Edit
196
196
  </button>
197
197
  <button type="button" @click.stop="redoMessage(message)"
198
- class="text-xs px-2 py-1 rounded text-gray-400 hover:text-blue-600 hover:bg-blue-50 transition-all"
198
+ class="whitespace-nowrap text-xs px-2 py-1 rounded text-gray-400 hover:text-blue-600 hover:bg-blue-50 transition-all"
199
199
  title="Redo message (clears all responses after this message and re-runs it)">
200
200
  <svg class="size-4 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
201
201
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
@@ -6,7 +6,7 @@ const headers = { 'Accept': 'application/json' }
6
6
  const prefsKey = 'llms.prefs'
7
7
 
8
8
  export const o = {
9
- version: '2.0.16',
9
+ version: '2.0.18',
10
10
  base,
11
11
  prefsKey,
12
12
  welcome: 'Welcome to llms.py',
@@ -89,7 +89,7 @@ async function logRequest(threadId, model, request, response) {
89
89
  outputPrice,
90
90
  cost: (parseFloat(inputPrice) * inputTokens) + (parseFloat(outputPrice) * outputTokens),
91
91
  duration: metadata.duration ?? 0,
92
- created: subtractDays(response.created ?? Math.floor(Date.now() / 1000), 1),
92
+ created: response.created ?? Math.floor(Date.now() / 1000),
93
93
  finishReason,
94
94
  providerRef: response.provider,
95
95
  ref: response.id || undefined,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llms-py
3
- Version: 2.0.16
3
+ Version: 2.0.18
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "llms-py"
7
- version = "2.0.16"
7
+ version = "2.0.18"
8
8
  description = "A lightweight CLI tool and OpenAI-compatible server for querying multiple Large Language Model (LLM) providers"
9
9
  readme = "README.md"
10
10
  license = "BSD-3-Clause"
@@ -16,7 +16,7 @@ with open(os.path.join(this_directory, "requirements.txt"), encoding="utf-8") as
16
16
 
17
17
  setup(
18
18
  name="llms-py",
19
- version="2.0.16",
19
+ version="2.0.18",
20
20
  author="ServiceStack",
21
21
  author_email="team@servicestack.net",
22
22
  description="A lightweight CLI tool and OpenAI-compatible server for querying multiple Large Language Model (LLM) providers",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes