llms-py 2.0.35__py3-none-any.whl → 3.0.0b1__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/ui/markdown.mjs CHANGED
@@ -5,7 +5,7 @@ export const marked = (() => {
5
5
  const aliases = {
6
6
  vue: 'html',
7
7
  }
8
-
8
+
9
9
  const ret = new Marked(
10
10
  markedHighlight({
11
11
  langPrefix: 'hljs language-',
@@ -18,18 +18,21 @@ export const marked = (() => {
18
18
  }
19
19
  })
20
20
  )
21
- ret.use({ extensions:[thinkTag()] })
21
+ ret.use({ extensions: [thinkTag()] })
22
22
  //ret.use({ extensions: [divExtension()] })
23
23
  return ret
24
24
  })();
25
25
 
26
26
  export function renderMarkdown(content) {
27
+ if (Array.isArray(content)) {
28
+ content = content.filter(c => c.type === 'text').map(c => c.text).join('\n')
29
+ }
27
30
  if (content) {
28
31
  content = content
29
- .replaceAll(`\\[ \\boxed{`,'\n<span class="inline-block text-xl text-blue-500 bg-blue-50 dark:text-blue-400 dark:bg-blue-950 px-3 py-1 rounded">')
30
- .replaceAll('} \\]','</span>\n')
32
+ .replaceAll(`\\[ \\boxed{`, '\n<span class="inline-block text-xl text-blue-500 bg-blue-50 dark:text-blue-400 dark:bg-blue-950 px-3 py-1 rounded">')
33
+ .replaceAll('} \\]', '</span>\n')
31
34
  }
32
- return marked.parse(content)
35
+ return marked.parse(content || '')
33
36
  }
34
37
 
35
38
  // export async function renderMarkdown(body) {
llms/ui/threadStore.mjs CHANGED
@@ -12,7 +12,7 @@ let db = null
12
12
  // Initialize IndexedDB
13
13
  async function initDB() {
14
14
  if (db) return db
15
-
15
+
16
16
  db = await openDB('LlmsThreads', 3, {
17
17
  upgrade(db, _oldVersion, _newVersion, transaction) {
18
18
  if (!db.objectStoreNames.contains('threads')) {
@@ -44,7 +44,7 @@ async function initDB() {
44
44
  }
45
45
  }
46
46
  })
47
-
47
+
48
48
  return db
49
49
  }
50
50
 
@@ -59,8 +59,8 @@ async function logRequest(threadId, model, request, response) {
59
59
  const usage = response.usage || {}
60
60
  const [inputPrice, outputPrice] = metadata.pricing ? metadata.pricing.split('/') : [0, 0]
61
61
  const lastUserContent = request.messages?.slice().reverse().find(m => m.role === 'user')?.content
62
- const content = Array.isArray(lastUserContent)
63
- ? lastUserContent.filter(c => c?.text).map(c => c.text).join(' ')
62
+ const content = Array.isArray(lastUserContent)
63
+ ? lastUserContent.filter(c => c?.text).map(c => c.text).join(' ')
64
64
  : lastUserContent
65
65
  const title = content.slice(0, 100) + (content.length > 100 ? '...' : '')
66
66
  const inputTokens = usage?.prompt_tokens ?? 0
@@ -87,7 +87,7 @@ async function logRequest(threadId, model, request, response) {
87
87
  totalTokens: usage.total_tokens ?? (inputTokens + outputTokens),
88
88
  inputPrice,
89
89
  outputPrice,
90
- cost: (parseFloat(inputPrice) * inputTokens) + (parseFloat(outputPrice) * outputTokens),
90
+ cost: (parseFloat(inputPrice) * inputTokens / 1_000_000) + (parseFloat(outputPrice) * outputTokens / 1_000_000),
91
91
  duration: parseInt(metadata.duration) || 0,
92
92
  created: response.created ?? Math.floor(Date.now() / 1000),
93
93
  finishReason,
@@ -116,13 +116,18 @@ async function createThread(title = 'New Chat', model = null, systemPrompt = '')
116
116
  createdAt: new Date().toISOString(),
117
117
  updatedAt: new Date().toISOString()
118
118
  }
119
-
120
- const tx = db.transaction(['threads'], 'readwrite')
121
- await tx.objectStore('threads').add(thread)
122
- await tx.complete
123
-
124
- threads.value.unshift(thread)
125
- // Note: currentThread will be set by router navigation
119
+
120
+ try {
121
+ const tx = db.transaction(['threads'], 'readwrite')
122
+ await tx.objectStore('threads').add(thread)
123
+ await tx.complete
124
+
125
+ threads.value.unshift(thread)
126
+ // Note: currentThread will be set by router navigation
127
+
128
+ } catch (e) {
129
+ console.error('Error creating thread', e, thread)
130
+ }
126
131
 
127
132
  return thread
128
133
  }
@@ -130,56 +135,56 @@ async function createThread(title = 'New Chat', model = null, systemPrompt = '')
130
135
  // Update thread
131
136
  async function updateThread(threadId, updates) {
132
137
  await initDB()
133
-
138
+
134
139
  const tx = db.transaction(['threads'], 'readwrite')
135
140
  const store = tx.objectStore('threads')
136
-
141
+
137
142
  const thread = await store.get(threadId)
138
143
  if (!thread) throw new Error('Thread not found')
139
-
144
+
140
145
  const updatedThread = {
141
146
  ...thread,
142
147
  ...updates,
143
148
  updatedAt: new Date().toISOString()
144
149
  }
145
-
150
+
146
151
  await store.put(updatedThread)
147
152
  await tx.complete
148
-
153
+
149
154
  // Update in memory
150
155
  const index = threads.value.findIndex(t => t.id === threadId)
151
156
  if (index !== -1) {
152
157
  threads.value[index] = updatedThread
153
158
  }
154
-
159
+
155
160
  if (currentThread.value?.id === threadId) {
156
161
  currentThread.value = updatedThread
157
162
  }
158
-
163
+
159
164
  return updatedThread
160
165
  }
161
166
 
162
167
  async function calculateThreadStats(threadId) {
163
168
  await initDB()
164
-
169
+
165
170
  const tx = db.transaction(['requests'], 'readonly')
166
171
  const store = tx.objectStore('requests')
167
172
  const index = store.index('threadId')
168
-
173
+
169
174
  const requests = await index.getAll(threadId)
170
-
175
+
171
176
  let inputTokens = 0
172
177
  let outputTokens = 0
173
178
  let cost = 0.0
174
179
  let duration = 0
175
-
180
+
176
181
  requests.forEach(req => {
177
182
  inputTokens += req.inputTokens || 0
178
183
  outputTokens += req.outputTokens || 0
179
184
  cost += req.cost || 0.0
180
185
  duration += req.duration || 0
181
186
  })
182
-
187
+
183
188
  return {
184
189
  inputTokens,
185
190
  outputTokens,
@@ -193,13 +198,13 @@ async function calculateThreadStats(threadId) {
193
198
  async function addMessageToThread(threadId, message, usage) {
194
199
  const thread = await getThread(threadId)
195
200
  if (!thread) throw new Error('Thread not found')
196
-
201
+
197
202
  const newMessage = {
198
203
  id: nextId(),
199
204
  timestamp: new Date().toISOString(),
200
205
  ...message
201
206
  }
202
-
207
+
203
208
  // Add input and output token usage to previous 'input' message
204
209
  if (usage?.prompt_tokens != null) {
205
210
  const lastMessage = thread.messages[thread.messages.length - 1]
@@ -219,21 +224,25 @@ async function addMessageToThread(threadId, message, usage) {
219
224
  }
220
225
 
221
226
  const updatedMessages = [...thread.messages, newMessage]
222
-
227
+
223
228
  // Auto-generate title from first user message if still "New Chat"
224
229
  let title = thread.title
225
230
  if (title === 'New Chat' && message.role === 'user' && updatedMessages.length <= 2) {
226
- title = message.content.slice(0, 200) + (message.content.length > 200 ? '...' : '')
231
+ let contentText = message.content
232
+ if (Array.isArray(contentText)) {
233
+ contentText = contentText.filter(c => c.type === 'text').map(c => c.text).join(' ')
234
+ }
235
+ title = contentText.slice(0, 200) + (contentText.length > 200 ? '...' : '')
227
236
  }
228
237
 
229
238
  const stats = await calculateThreadStats(threadId)
230
-
239
+
231
240
  await updateThread(threadId, {
232
241
  messages: updatedMessages,
233
242
  title: title,
234
243
  stats,
235
244
  })
236
-
245
+
237
246
  return newMessage
238
247
  }
239
248
 
@@ -279,15 +288,15 @@ async function redoMessageFromThread(threadId, messageId) {
279
288
  async function loadThreads() {
280
289
  await initDB()
281
290
  isLoading.value = true
282
-
291
+
283
292
  try {
284
293
  const tx = db.transaction(['threads'], 'readonly')
285
294
  const store = tx.objectStore('threads')
286
295
  const index = store.index('updatedAt')
287
-
296
+
288
297
  const allThreads = await index.getAll()
289
298
  threads.value = allThreads.reverse() // Most recent first
290
-
299
+
291
300
  return threads.value
292
301
  } finally {
293
302
  isLoading.value = false
@@ -297,23 +306,23 @@ async function loadThreads() {
297
306
  // Get single thread
298
307
  async function getThread(threadId) {
299
308
  await initDB()
300
-
309
+
301
310
  const tx = db.transaction(['threads'], 'readonly')
302
311
  const thread = await tx.objectStore('threads').get(threadId)
303
-
312
+
304
313
  return thread
305
314
  }
306
315
 
307
316
  // Delete thread
308
317
  async function deleteThread(threadId) {
309
318
  await initDB()
310
-
319
+
311
320
  const tx = db.transaction(['threads'], 'readwrite')
312
321
  await tx.objectStore('threads').delete(threadId)
313
322
  await tx.complete
314
-
323
+
315
324
  threads.value = threads.value.filter(t => t.id !== threadId)
316
-
325
+
317
326
  if (currentThread.value?.id === threadId) {
318
327
  currentThread.value = null
319
328
  }
@@ -359,19 +368,19 @@ function getGroupedThreads(total) {
359
368
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())
360
369
  const lastWeek = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000)
361
370
  const lastMonth = new Date(today.getTime() - 30 * 24 * 60 * 60 * 1000)
362
-
371
+
363
372
  const groups = {
364
373
  today: [],
365
374
  lastWeek: [],
366
375
  lastMonth: [],
367
376
  older: {}
368
377
  }
369
-
378
+
370
379
  const takeThreads = threads.value.slice(0, total)
371
380
 
372
381
  takeThreads.forEach(thread => {
373
382
  const threadDate = new Date(thread.updatedAt)
374
-
383
+
375
384
  if (threadDate >= today) {
376
385
  groups.today.push(thread)
377
386
  } else if (threadDate >= lastWeek) {
@@ -382,14 +391,14 @@ function getGroupedThreads(total) {
382
391
  const year = threadDate.getFullYear()
383
392
  const month = threadDate.toLocaleString('default', { month: 'long' })
384
393
  const key = `${month} ${year}`
385
-
394
+
386
395
  if (!groups.older[key]) {
387
396
  groups.older[key] = []
388
397
  }
389
398
  groups.older[key].push(thread)
390
399
  }
391
400
  })
392
-
401
+
393
402
  return groups
394
403
  }
395
404
 
@@ -416,7 +425,7 @@ async function getRequest(requestId) {
416
425
 
417
426
  async function getAllRequestIds() {
418
427
  await initDB()
419
-
428
+
420
429
  const tx = db.transaction(['requests'], 'readonly')
421
430
  const store = tx.objectStore('requests')
422
431
  const ids = await store.getAllKeys()
@@ -428,7 +437,7 @@ async function getAllThreadIds() {
428
437
  const tx = db.transaction(['threads'], 'readonly')
429
438
  const store = tx.objectStore('threads')
430
439
  const ids = await store.getAllKeys()
431
- return ids
440
+ return ids
432
441
  }
433
442
 
434
443
  // Query requests with pagination and filtering
llms/ui/utils.mjs CHANGED
@@ -1,4 +1,37 @@
1
- import { $$, createElement, rightPart } from "@servicestack/client"
1
+ import { $$, createElement, rightPart, pick } from "@servicestack/client"
2
+
3
+ const cacheUrlInfo = {}
4
+
5
+ export function getCacheInfo(url) {
6
+ return cacheUrlInfo[url]
7
+ }
8
+ export async function fetchCacheInfos(urls) {
9
+ const infos = {}
10
+ const fetchInfos = []
11
+ for (const url of urls) {
12
+ const info = getCacheInfo(url)
13
+ if (info) {
14
+ infos[url] = info
15
+ } else {
16
+ fetchInfos.push(fetch(url + "?info"))
17
+ }
18
+ }
19
+ const responses = await Promise.all(fetchInfos)
20
+ for (let i = 0; i < urls.length; i++) {
21
+ try {
22
+ const info = await responses[i].json()
23
+ setCacheInfo(urls[i], info)
24
+ infos[urls[i]] = info
25
+ } catch (e) {
26
+ console.error('Failed to fetch info for', urls[i], e)
27
+ }
28
+ }
29
+ return infos
30
+ }
31
+
32
+ export function setCacheInfo(url, info) {
33
+ cacheUrlInfo[url] = info
34
+ }
2
35
 
3
36
  export function toJsonArray(json) {
4
37
  try {
@@ -30,36 +63,75 @@ export function storageObject(key, save) {
30
63
  return toJsonObject(localStorage.getItem(key)) ?? {}
31
64
  }
32
65
 
33
- export function deepClone(obj) {
34
- return JSON.parse(JSON.stringify(obj))
66
+ export function fileToBase64(file) {
67
+ return new Promise((resolve, reject) => {
68
+ const reader = new FileReader()
69
+ reader.readAsDataURL(file) //= "data:…;base64,…"
70
+ reader.onload = () => {
71
+ resolve(rightPart(reader.result, ',')) // strip prefix
72
+ }
73
+ reader.onerror = err => reject(err)
74
+ })
35
75
  }
36
76
 
37
- export function fileToBase64(file) {
38
- return new Promise((resolve, reject) => {
39
- const reader = new FileReader()
40
- reader.readAsDataURL(file) //= "data:…;base64,…"
41
- reader.onload = () => {
42
- resolve(rightPart(reader.result, ',')) // strip prefix
77
+ export function fileToDataUri(file) {
78
+ return new Promise((resolve, reject) => {
79
+ const reader = new FileReader()
80
+ reader.readAsDataURL(file) //= "data:…;base64,…"
81
+ reader.onload = () => resolve(reader.result)
82
+ reader.onerror = err => reject(err)
83
+ })
84
+ }
85
+
86
+ export async function uploadFile(file) {
87
+ const formData = new FormData()
88
+ formData.append('file', file)
89
+ const response = await fetch('/upload', {
90
+ method: 'POST',
91
+ body: formData
92
+ })
93
+ if (!response.ok) {
94
+ throw new Error(`Upload failed: ${response.statusText}`)
43
95
  }
44
- reader.onerror = err => reject(err)
45
- })
96
+ return response.json()
46
97
  }
47
98
 
48
- export function fileToDataUri(file) {
49
- return new Promise((resolve, reject) => {
50
- const reader = new FileReader()
51
- reader.readAsDataURL(file) //= "data:…;base64,…"
52
- reader.onload = () => resolve(reader.result)
53
- reader.onerror = err => reject(err)
54
- })
99
+ export function serializedClone(obj) {
100
+ try {
101
+ return JSON.parse(JSON.stringify(obj))
102
+ } catch (e) {
103
+ console.warn('Deep cloning failed, returning original value:', e)
104
+ return obj
105
+ }
106
+ }
107
+
108
+ export function deepClone(o) {
109
+ if (o === null || typeof o !== 'object') return o
110
+
111
+ // Handle Array objects
112
+ if (Array.isArray(o)) {
113
+ return o.map(x => deepClone(x))
114
+ }
115
+
116
+ if (typeof structuredClone === 'function') { // available (modern browsers, Node.js 17+)
117
+ try {
118
+ return structuredClone(o)
119
+ } catch (e) {
120
+ console.warn('structuredClone failed, falling back to JSON:', e)
121
+ }
122
+ }
123
+
124
+ // Fallback to JSON stringify/parse for older environments
125
+ return serializedClone(o)
55
126
  }
56
127
 
57
128
  export function toModelInfo(model) {
58
129
  if (!model) return undefined
59
- return Object.assign({}, model, { pricing: Object.assign({}, model.pricing) || undefined })
130
+ const { id, name, provider, cost, modalities } = model
131
+ return deepClone({ id, name, provider, cost, modalities })
60
132
  }
61
133
 
62
- const numFmt = new Intl.NumberFormat(undefined,{style:'currency',currency:'USD', maximumFractionDigits:6})
134
+ const numFmt = new Intl.NumberFormat(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 6 })
63
135
  export function tokenCost(price) {
64
136
  if (!price) return ''
65
137
  var ret = numFmt.format(parseFloat(price))
@@ -123,8 +195,8 @@ export function addCopyButtonToCodeBlocks(sel) {
123
195
  if (pre.classList.contains('group')) return
124
196
  pre.classList.add('relative', 'group')
125
197
 
126
- const div = createElement('div', {attrs: {className: 'opacity-0 group-hover:opacity-100 transition-opacity duration-100 flex absolute right-2 -mt-1 select-none'}})
127
- const label = createElement('div', {attrs: {className: 'hidden font-sans p-1 px-2 mr-1 rounded-md border border-gray-600 bg-gray-700 text-gray-400'}})
198
+ const div = createElement('div', { attrs: { className: 'opacity-0 group-hover:opacity-100 transition-opacity duration-100 flex absolute right-2 -mt-1 select-none' } })
199
+ const label = createElement('div', { attrs: { className: 'hidden font-sans p-1 px-2 mr-1 rounded-md border border-gray-600 bg-gray-700 text-gray-400' } })
128
200
  const btn = createElement('button', {
129
201
  attrs: {
130
202
  type: 'button',
@@ -147,10 +219,10 @@ export function addCopyButtons() {
147
219
  * Returns an ever-increasing unique integer id.
148
220
  */
149
221
  export const nextId = (() => {
150
- let last = 0 // cache of the last id that was handed out
151
- return () => {
152
- const now = Date.now() // current millisecond timestamp
153
- last = (now > last) ? now : last + 1
154
- return last
155
- }
222
+ let last = 0 // cache of the last id that was handed out
223
+ return () => {
224
+ const now = Date.now() // current millisecond timestamp
225
+ last = (now > last) ? now : last + 1
226
+ return last
227
+ }
156
228
  })();
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llms-py
3
- Version: 2.0.35
3
+ Version: 3.0.0b1
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
@@ -1,19 +1,20 @@
1
1
  llms/__init__.py,sha256=DKwTZDsyYL_wHe7yvLw49Nf8PSgPSyWaeVdotUqSvrQ,84
2
2
  llms/__main__.py,sha256=hrBulHIt3lmPm1BCyAEVtB6DQ0Hvc3gnIddhHCmJasg,151
3
3
  llms/index.html,sha256=_pkjdzCX95HTf19LgE4gMh6tLittcnf7M_jL2hSEbbM,3250
4
- llms/llms.json,sha256=E-nDAPJYf4jauEfbUYy5MrIBtvEI4SYeBz7ZoyEovW0,35105
5
- llms/main.py,sha256=JC3CGhHfmQbEGDaaSbkSWqCSFDMp3Ww0GFwt4DCKWSU,91160
4
+ llms/llms.json,sha256=Y_J3Usw0tt96fc7Dp_fY41wjHrIRKbx0gS0-gk2Uoqk,9697
5
+ llms/main.py,sha256=knAHWd0WZO_nSLrAqDVTziPa0CjQfS8Ahsk9vuw510M,117476
6
+ llms/providers.json,sha256=meE6G2vyzfKYmwdml9-O8Pm_uGc520bj891SUjQmsLY,215127
6
7
  llms/ui.json,sha256=iBOmpNeD5-o8AgUa51ymS-KemovJ7bm9J1fnL0nf8jk,134025
7
8
  llms/ui/Analytics.mjs,sha256=LfWbUlpb__0EEYtHu6e4r8AeyhsNQeAxrg44RuNSR0M,73261
8
9
  llms/ui/App.mjs,sha256=L8Zn7b7YVqR5jgVQKvo_txijSd1T7jq6QOQEt7Q0eB0,3811
9
10
  llms/ui/Avatar.mjs,sha256=TgouwV9bN-Ou1Tf2zCDtVaRiUB21TXZZPFCTlFL-xxQ,3387
10
11
  llms/ui/Brand.mjs,sha256=JLN_lPirNXqS332g0B_WVOlFRVg3lNe1Q56TRnpj0zQ,3411
11
- llms/ui/ChatPrompt.mjs,sha256=7Bx2-ossJPm8F2n9M82vNt8J-ayHEXft3qctd9TeSdw,27147
12
- llms/ui/Main.mjs,sha256=SxItBoxJXf5vEVzfUYY6F7imJuwdm0By3EhrCfo4a1M,43016
13
- llms/ui/ModelSelector.mjs,sha256=0YuNXlyEeiD4YKyXtxtHu0rT7zIv_lnfljvB3hm7YE8,3198
12
+ llms/ui/ChatPrompt.mjs,sha256=vu05EC_mHdiEBYRHUNMJrmyupfhHVo-MZh4QgvNhrsM,26892
13
+ llms/ui/Main.mjs,sha256=Z5RQfFF7AaXZ-SSMHBnWeiKnXbZP6po1HY28mBGH9Ro,45867
14
+ llms/ui/ModelSelector.mjs,sha256=8WoPrlWXr_kSJN6TFJfGjk6M_GzoEm-trswvprDCwK0,37507
14
15
  llms/ui/OAuthSignIn.mjs,sha256=IdA9Tbswlh74a_-9e9YulOpqLfRpodRLGfCZ9sTZ5jU,4879
15
- llms/ui/ProviderIcon.mjs,sha256=uNIK1Ad9f8vc0d70rlwID9k3zuD_Y-WCIQrnwnCQDCc,9384
16
- llms/ui/ProviderStatus.mjs,sha256=v5_Qx5kX-JbnJHD6Or5THiePzcX3Wf9ODcS4Q-kfQbM,6084
16
+ llms/ui/ProviderIcon.mjs,sha256=XdEJRm90Zaeu7AlcxfLTXqh_jj2F5JvFkug0XexZeQc,22900
17
+ llms/ui/ProviderStatus.mjs,sha256=Dsr_kzjdYuXNLNIwpcQe3URB4nmBdEEFeU8DgOfWu20,6144
17
18
  llms/ui/Recents.mjs,sha256=sRoesSktUvBZ7UjfFJwp0btCQj5eQvnTDjSUDzN8ySU,8864
18
19
  llms/ui/SettingsDialog.mjs,sha256=vyqLOrACBICwT8qQ10oJAMOYeA1phrAyz93mZygn-9Y,19956
19
20
  llms/ui/Sidebar.mjs,sha256=93wCzrbY4F9VBFGiWujNIj5ynxP_9bmv5pJQOGdybIc,11183
@@ -21,14 +22,14 @@ llms/ui/SignIn.mjs,sha256=df3b-7L3ZIneDGbJWUk93K9RGo40gVeuR5StzT1ZH9g,2324
21
22
  llms/ui/SystemPromptEditor.mjs,sha256=PffkNPV6hGbm1QZBKPI7yvWPZSBL7qla0d-JEJ4mxYo,1466
22
23
  llms/ui/SystemPromptSelector.mjs,sha256=UgoeuscFes0B1oFkx74dFwC0JgRib37VM4Gy3-kCVDQ,3769
23
24
  llms/ui/Welcome.mjs,sha256=r9j7unF9CF3k7gEQBMRMVsa2oSjgHGNn46Oa5l5BwlY,950
24
- llms/ui/ai.mjs,sha256=KhMkKx2Q5LQmasMXPpZ7SZPxdsTbgdOPE20JPBnKL6k,4849
25
- llms/ui/app.css,sha256=m6wR6XCzJWbUs0K_MDyGbcnxsWOu2Q58nGpAL646kio,111026
25
+ llms/ui/ai.mjs,sha256=GpYD7np2mFb4FX49dzHZCUUrB9-Aj676zf_1ejVp4tA,4839
26
+ llms/ui/app.css,sha256=WrCjd6lJTS6DWuQKUMGPwmrIYCTfauDS_m-ghkoR2qA,119287
26
27
  llms/ui/fav.svg,sha256=_R6MFeXl6wBFT0lqcUxYQIDWgm246YH_3hSTW0oO8qw,734
27
- llms/ui/markdown.mjs,sha256=uWSyBZZ8a76Dkt53q6CJzxg7Gkx7uayX089td3Srv8w,6388
28
+ llms/ui/markdown.mjs,sha256=0LUF2Tyvpv88ic-MjdUjAAdd1Rt8LYA_d7VRA-kBFuM,6518
28
29
  llms/ui/tailwind.input.css,sha256=QInTVDpCR89OTzRo9AePdAa-MX3i66RkhNOfa4_7UAg,12086
29
- llms/ui/threadStore.mjs,sha256=Z5FT3jRs-e9e8BI1oaxfh929JwqHMPO_sH-Qv5RL7vI,16553
30
+ llms/ui/threadStore.mjs,sha256=CL-dTxnMJsk9ORDiN80FSgdsdDQEmKsZDKI5fAGCr-o,16706
30
31
  llms/ui/typography.css,sha256=6o7pbMIamRVlm2GfzSStpcOG4T5eFCK_WcQ3RIHKAsU,19587
31
- llms/ui/utils.mjs,sha256=cYrP17JwpQk7lLqTWNgVTOD_ZZAovbWnx2QSvKzeB24,5333
32
+ llms/ui/utils.mjs,sha256=dzBBhltx8bUPasFAM3VRsobbDOesBd2M3mjuYdwAExA,7283
32
33
  llms/ui/lib/chart.js,sha256=dx8FdDX0Rv6OZtZjr9FQh5h-twFsKjfnb-FvFlQ--cU,196176
33
34
  llms/ui/lib/charts.mjs,sha256=MNym9qE_2eoH6M7_8Gj9i6e6-Y3b7zw9UQWCUHRF6x0,1088
34
35
  llms/ui/lib/color.js,sha256=DDG7Pr-qzJHTPISZNSqP_qJR8UflKHEc_56n6xrBugQ,8273
@@ -40,9 +41,9 @@ llms/ui/lib/servicestack-vue.mjs,sha256=unTA8lM0tKy2PwZiJ8UEvrTuGmei8jNZnmmuQ5MK
40
41
  llms/ui/lib/vue-router.min.mjs,sha256=fR30GHoXI1u81zyZ26YEU105pZgbbAKSXbpnzFKIxls,30418
41
42
  llms/ui/lib/vue.min.mjs,sha256=iXh97m5hotl0eFllb3aoasQTImvp7mQoRJ_0HoxmZkw,163811
42
43
  llms/ui/lib/vue.mjs,sha256=dS8LKOG01t9CvZ04i0tbFXHqFXOO_Ha4NmM3BytjQAs,537071
43
- llms_py-2.0.35.dist-info/licenses/LICENSE,sha256=bus9cuAOWeYqBk2OuhSABVV1P4z7hgrEFISpyda_H5w,1532
44
- llms_py-2.0.35.dist-info/METADATA,sha256=DHJx2uG45fMrH4CpJ4oV61bjCSlg45u2dpcyRBgjTc4,2192
45
- llms_py-2.0.35.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
46
- llms_py-2.0.35.dist-info/entry_points.txt,sha256=WswyE7PfnkZMIxboC-MS6flBD6wm-CYU7JSUnMhqMfM,40
47
- llms_py-2.0.35.dist-info/top_level.txt,sha256=gC7hk9BKSeog8gyg-EM_g2gxm1mKHwFRfK-10BxOsa4,5
48
- llms_py-2.0.35.dist-info/RECORD,,
44
+ llms_py-3.0.0b1.dist-info/licenses/LICENSE,sha256=bus9cuAOWeYqBk2OuhSABVV1P4z7hgrEFISpyda_H5w,1532
45
+ llms_py-3.0.0b1.dist-info/METADATA,sha256=jS7M9B8ThKrqFC_Uzuk_fYmbzo3eNNDqiAj6aJY7cZw,2193
46
+ llms_py-3.0.0b1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
47
+ llms_py-3.0.0b1.dist-info/entry_points.txt,sha256=WswyE7PfnkZMIxboC-MS6flBD6wm-CYU7JSUnMhqMfM,40
48
+ llms_py-3.0.0b1.dist-info/top_level.txt,sha256=gC7hk9BKSeog8gyg-EM_g2gxm1mKHwFRfK-10BxOsa4,5
49
+ llms_py-3.0.0b1.dist-info/RECORD,,