dtSpark 1.1.0a2__py3-none-any.whl → 1.1.0a6__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 (56) hide show
  1. dtSpark/_version.txt +1 -1
  2. dtSpark/aws/authentication.py +1 -1
  3. dtSpark/aws/bedrock.py +238 -239
  4. dtSpark/aws/costs.py +9 -5
  5. dtSpark/aws/pricing.py +25 -21
  6. dtSpark/cli_interface.py +69 -62
  7. dtSpark/conversation_manager.py +54 -47
  8. dtSpark/core/application.py +151 -111
  9. dtSpark/core/context_compaction.py +241 -226
  10. dtSpark/daemon/__init__.py +36 -22
  11. dtSpark/daemon/action_monitor.py +46 -17
  12. dtSpark/daemon/daemon_app.py +126 -104
  13. dtSpark/daemon/daemon_manager.py +59 -23
  14. dtSpark/daemon/pid_file.py +3 -2
  15. dtSpark/database/autonomous_actions.py +3 -0
  16. dtSpark/database/credential_prompt.py +52 -54
  17. dtSpark/files/manager.py +6 -12
  18. dtSpark/limits/__init__.py +1 -1
  19. dtSpark/limits/tokens.py +2 -2
  20. dtSpark/llm/anthropic_direct.py +246 -141
  21. dtSpark/llm/ollama.py +3 -1
  22. dtSpark/mcp_integration/manager.py +4 -4
  23. dtSpark/mcp_integration/tool_selector.py +83 -77
  24. dtSpark/resources/config.yaml.template +10 -0
  25. dtSpark/safety/patterns.py +45 -46
  26. dtSpark/safety/prompt_inspector.py +8 -1
  27. dtSpark/scheduler/creation_tools.py +273 -181
  28. dtSpark/scheduler/executor.py +503 -221
  29. dtSpark/tools/builtin.py +70 -53
  30. dtSpark/web/endpoints/autonomous_actions.py +12 -9
  31. dtSpark/web/endpoints/chat.py +18 -6
  32. dtSpark/web/endpoints/conversations.py +57 -17
  33. dtSpark/web/endpoints/main_menu.py +132 -105
  34. dtSpark/web/endpoints/streaming.py +2 -2
  35. dtSpark/web/server.py +65 -5
  36. dtSpark/web/ssl_utils.py +3 -3
  37. dtSpark/web/static/css/dark-theme.css +8 -29
  38. dtSpark/web/static/js/actions.js +2 -1
  39. dtSpark/web/static/js/chat.js +6 -8
  40. dtSpark/web/static/js/main.js +8 -8
  41. dtSpark/web/static/js/sse-client.js +130 -122
  42. dtSpark/web/templates/actions.html +5 -5
  43. dtSpark/web/templates/base.html +13 -0
  44. dtSpark/web/templates/chat.html +52 -50
  45. dtSpark/web/templates/conversations.html +50 -22
  46. dtSpark/web/templates/goodbye.html +2 -2
  47. dtSpark/web/templates/main_menu.html +17 -17
  48. dtSpark/web/templates/new_conversation.html +51 -20
  49. dtSpark/web/web_interface.py +2 -2
  50. {dtspark-1.1.0a2.dist-info → dtspark-1.1.0a6.dist-info}/METADATA +9 -2
  51. dtspark-1.1.0a6.dist-info/RECORD +96 -0
  52. dtspark-1.1.0a2.dist-info/RECORD +0 -96
  53. {dtspark-1.1.0a2.dist-info → dtspark-1.1.0a6.dist-info}/WHEEL +0 -0
  54. {dtspark-1.1.0a2.dist-info → dtspark-1.1.0a6.dist-info}/entry_points.txt +0 -0
  55. {dtspark-1.1.0a2.dist-info → dtspark-1.1.0a6.dist-info}/licenses/LICENSE +0 -0
  56. {dtspark-1.1.0a2.dist-info → dtspark-1.1.0a6.dist-info}/top_level.txt +0 -0
@@ -21,9 +21,9 @@
21
21
  <div class="card-body overflow-auto" id="chat-messages">
22
22
  <!-- Messages will be appended here -->
23
23
  <div class="text-center text-muted">
24
- <div class="spinner-border spinner-border-sm" role="status">
24
+ <output class="spinner-border spinner-border-sm">
25
25
  <span class="visually-hidden">Loading...</span>
26
- </div>
26
+ </output>
27
27
  <span class="ms-2">Loading chat history...</span>
28
28
  </div>
29
29
  </div>
@@ -48,14 +48,14 @@
48
48
  ></textarea>
49
49
  </div>
50
50
  <div class="d-flex justify-content-between align-items-center">
51
- <div class="btn-group" role="group">
51
+ <fieldset class="btn-group">
52
52
  <button type="button" class="btn btn-outline-secondary btn-sm" onclick="showCommandMenu()">
53
53
  <i class="bi bi-terminal"></i> Commands
54
54
  </button>
55
55
  <button type="button" class="btn btn-outline-secondary btn-sm" onclick="attachFiles()">
56
56
  <i class="bi bi-paperclip"></i> Attach
57
57
  </button>
58
- </div>
58
+ </fieldset>
59
59
  <button type="submit" class="btn btn-primary" id="send-btn">
60
60
  <i class="bi bi-send-fill"></i> Send
61
61
  </button>
@@ -76,9 +76,9 @@
76
76
  </div>
77
77
  <div class="modal-body" id="info-content">
78
78
  <div class="text-center">
79
- <div class="spinner-border spinner-border-sm" role="status">
79
+ <output class="spinner-border spinner-border-sm">
80
80
  <span class="visually-hidden">Loading...</span>
81
- </div>
81
+ </output>
82
82
  </div>
83
83
  </div>
84
84
  </div>
@@ -324,70 +324,72 @@ async function performExport() {
324
324
 
325
325
  // Change model
326
326
  async function showChangeModelModal() {
327
- const modalHTML = `
328
- <div class="modal fade" id="changeModelModal" tabindex="-1">
329
- <div class="modal-dialog">
330
- <div class="modal-content">
331
- <div class="modal-header">
332
- <h5 class="modal-title"><i class="bi bi-arrow-repeat"></i> Change Model</h5>
333
- <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
334
- </div>
335
- <div class="modal-body">
336
- <div class="mb-3">
337
- <label class="form-label">Select New Model</label>
338
- <select class="form-select" id="new-model-select">
339
- <option value="">Loading models...</option>
340
- </select>
327
+ // Check if model is locked first
328
+ try {
329
+ const configResponse = await fetch('/api/models');
330
+ const configData = await configResponse.json();
331
+
332
+ if (configData.model_locked) {
333
+ showToast(`Model changing is disabled - model is locked to '${configData.mandatory_model}' via configuration`, 'error');
334
+ return;
335
+ }
336
+
337
+ const models = configData.models || configData;
338
+
339
+ const modalHTML = `
340
+ <div class="modal fade" id="changeModelModal" tabindex="-1">
341
+ <div class="modal-dialog">
342
+ <div class="modal-content">
343
+ <div class="modal-header">
344
+ <h5 class="modal-title"><i class="bi bi-arrow-repeat"></i> Change Model</h5>
345
+ <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
346
+ </div>
347
+ <div class="modal-body">
348
+ <div class="mb-3">
349
+ <label class="form-label">Select New Model</label>
350
+ <select class="form-select" id="new-model-select">
351
+ <option value="">Select a model...</option>
352
+ </select>
353
+ </div>
354
+ </div>
355
+ <div class="modal-footer">
356
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
357
+ <button type="button" class="btn btn-primary" onclick="performChangeModel()">
358
+ <i class="bi bi-check-circle-fill"></i> Change Model
359
+ </button>
341
360
  </div>
342
- </div>
343
- <div class="modal-footer">
344
- <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
345
- <button type="button" class="btn btn-primary" onclick="performChangeModel()">
346
- <i class="bi bi-check-circle-fill"></i> Change Model
347
- </button>
348
361
  </div>
349
362
  </div>
350
363
  </div>
351
- </div>
352
- `;
353
-
354
- // Remove old modal if exists
355
- const oldModal = document.getElementById('changeModelModal');
356
- if (oldModal) oldModal.remove();
364
+ `;
357
365
 
358
- document.body.insertAdjacentHTML('beforeend', modalHTML);
366
+ // Remove old modal if exists
367
+ const oldModal = document.getElementById('changeModelModal');
368
+ if (oldModal) oldModal.remove();
359
369
 
360
- // Load models
361
- try {
362
- const response = await fetch('/api/models');
363
- const models = await response.json();
370
+ document.body.insertAdjacentHTML('beforeend', modalHTML);
364
371
 
365
372
  const select = document.getElementById('new-model-select');
366
- select.innerHTML = '<option value="">Select a model...</option>';
367
-
368
373
  models.forEach(model => {
369
374
  const option = document.createElement('option');
370
375
  option.value = model.id;
371
376
 
372
- // Show service provider and optionally model maker
373
377
  let displayText = model.name;
374
378
  if (model.model_maker && model.provider !== model.model_maker) {
375
- // Show both: "Model Name [Model Maker via Service Provider]"
376
379
  displayText += ` [${model.model_maker} via ${model.provider}]`;
377
380
  } else {
378
- // Show service only: "Model Name [Service Provider]"
379
381
  displayText += ` [${model.provider}]`;
380
382
  }
381
383
 
382
384
  option.textContent = displayText;
383
385
  select.appendChild(option);
384
386
  });
387
+
388
+ const modal = new bootstrap.Modal(document.getElementById('changeModelModal'));
389
+ modal.show();
385
390
  } catch (error) {
386
- document.getElementById('new-model-select').innerHTML = '<option value="">Failed to load models</option>';
391
+ showToast('Failed to load models', 'error');
387
392
  }
388
-
389
- const modal = new bootstrap.Modal(document.getElementById('changeModelModal'));
390
- modal.show();
391
393
  }
392
394
 
393
395
  async function performChangeModel() {
@@ -430,7 +432,7 @@ async function showMCPAuditModal() {
430
432
  </div>
431
433
  <div class="modal-body" id="mcp-audit-content">
432
434
  <div class="text-center">
433
- <div class="spinner-border spinner-border-sm" role="status"></div>
435
+ <output class="spinner-border spinner-border-sm"></output>
434
436
  </div>
435
437
  </div>
436
438
  </div>
@@ -515,7 +517,7 @@ async function showMCPServersModal() {
515
517
  </div>
516
518
  <div class="modal-body" id="mcp-servers-content">
517
519
  <div class="text-center">
518
- <div class="spinner-border spinner-border-sm" role="status"></div>
520
+ <output class="spinner-border spinner-border-sm"></output>
519
521
  </div>
520
522
  </div>
521
523
  </div>
@@ -609,9 +611,9 @@ async function loadConversationInfo() {
609
611
  try {
610
612
  document.getElementById('info-content').innerHTML = `
611
613
  <div class="text-center">
612
- <div class="spinner-border spinner-border-sm" role="status">
614
+ <output class="spinner-border spinner-border-sm">
613
615
  <span class="visually-hidden">Loading...</span>
614
- </div>
616
+ </output>
615
617
  </div>
616
618
  `;
617
619
 
@@ -32,9 +32,9 @@
32
32
  <div class="card">
33
33
  <div class="card-body" id="conversations-list">
34
34
  <div class="text-center">
35
- <div class="spinner-border text-primary" role="status">
35
+ <output class="spinner-border text-primary">
36
36
  <span class="visually-hidden">Loading...</span>
37
- </div>
37
+ </output>
38
38
  <p class="mt-2">Loading conversations...</p>
39
39
  </div>
40
40
  </div>
@@ -226,28 +226,49 @@ async function showNewConversationModal() {
226
226
  async function loadModels() {
227
227
  try {
228
228
  const response = await fetch('/api/models');
229
- const models = await response.json();
229
+ const data = await response.json();
230
+
231
+ const models = data.models || data;
232
+ const modelLocked = data.model_locked || false;
230
233
 
231
234
  const select = document.getElementById('model-select');
232
- select.innerHTML = '<option value="">Select a model...</option>';
233
-
234
- models.forEach(model => {
235
- const option = document.createElement('option');
236
- option.value = model.id;
237
-
238
- // Show service provider and optionally model maker
239
- let displayText = model.name;
240
- if (model.model_maker && model.provider !== model.model_maker) {
241
- // Show both: "Model Name [Model Maker via Service Provider]"
242
- displayText += ` [${model.model_maker} via ${model.provider}]`;
243
- } else {
244
- // Show service only: "Model Name [Service Provider]"
245
- displayText += ` [${model.provider}]`;
246
- }
247
-
248
- option.textContent = displayText;
249
- select.appendChild(option);
250
- });
235
+
236
+ if (modelLocked) {
237
+ select.innerHTML = '';
238
+ models.forEach(model => {
239
+ const option = document.createElement('option');
240
+ option.value = model.id;
241
+ let displayText = model.name;
242
+ if (model.provider) {
243
+ displayText += ` [${model.provider}]`;
244
+ }
245
+ option.textContent = displayText;
246
+ option.selected = true;
247
+ select.appendChild(option);
248
+ });
249
+ select.disabled = true;
250
+
251
+ const infoDiv = document.createElement('div');
252
+ infoDiv.className = 'form-text text-info';
253
+ infoDiv.innerHTML = '<i class="bi bi-lock-fill"></i> Model is locked via configuration';
254
+ select.parentNode.appendChild(infoDiv);
255
+ } else {
256
+ select.innerHTML = '<option value="">Select a model...</option>';
257
+ models.forEach(model => {
258
+ const option = document.createElement('option');
259
+ option.value = model.id;
260
+
261
+ let displayText = model.name;
262
+ if (model.model_maker && model.provider !== model.model_maker) {
263
+ displayText += ` [${model.model_maker} via ${model.provider}]`;
264
+ } else {
265
+ displayText += ` [${model.provider}]`;
266
+ }
267
+
268
+ option.textContent = displayText;
269
+ select.appendChild(option);
270
+ });
271
+ }
251
272
 
252
273
  } catch (error) {
253
274
  document.getElementById('model-select').innerHTML = `
@@ -259,6 +280,13 @@ async function loadModels() {
259
280
  // Create conversation
260
281
  async function createConversation() {
261
282
  const form = document.getElementById('new-conversation-form');
283
+
284
+ // Re-enable disabled select so its value is included in form data
285
+ const modelSelect = document.getElementById('model-select');
286
+ if (modelSelect.disabled) {
287
+ modelSelect.disabled = false;
288
+ }
289
+
262
290
  const formData = new FormData(form);
263
291
 
264
292
  try {
@@ -27,9 +27,9 @@
27
27
  <div class="alert alert-info">
28
28
  <i class="bi bi-info-circle-fill"></i> The web server is shutting down...
29
29
  <div class="mt-2">
30
- <div class="spinner-border spinner-border-sm" role="status">
30
+ <output class="spinner-border spinner-border-sm">
31
31
  <span class="visually-hidden">Shutting down...</span>
32
- </div>
32
+ </output>
33
33
  <span class="ms-2">Please wait</span>
34
34
  </div>
35
35
  </div>
@@ -166,28 +166,28 @@
166
166
  </div>
167
167
 
168
168
  <!-- Tab Navigation -->
169
- <ul class="nav nav-tabs mb-4" id="mainTabs" role="tablist">
170
- <li class="nav-item" role="presentation">
169
+ <div class="nav nav-tabs mb-4" id="mainTabs" role="tablist">
170
+ <div class="nav-item">
171
171
  <button class="nav-link active" id="overview-tab" data-bs-toggle="tab" data-bs-target="#overview" type="button" role="tab">
172
172
  <i class="bi bi-speedometer2"></i> Overview
173
173
  </button>
174
- </li>
175
- <li class="nav-item" role="presentation">
174
+ </div>
175
+ <div class="nav-item">
176
176
  <button class="nav-link" id="llms-tab" data-bs-toggle="tab" data-bs-target="#llms" type="button" role="tab">
177
177
  <i class="bi bi-cpu"></i> LLMs
178
178
  </button>
179
- </li>
180
- <li class="nav-item" role="presentation">
179
+ </div>
180
+ <div class="nav-item">
181
181
  <button class="nav-link" id="integrations-tab" data-bs-toggle="tab" data-bs-target="#integrations" type="button" role="tab">
182
182
  <i class="bi bi-plug"></i> Integrations
183
183
  </button>
184
- </li>
185
- <li class="nav-item" role="presentation">
184
+ </div>
185
+ <div class="nav-item">
186
186
  <button class="nav-link" id="system-tab" data-bs-toggle="tab" data-bs-target="#system" type="button" role="tab">
187
187
  <i class="bi bi-gear"></i> System
188
188
  </button>
189
- </li>
190
- </ul>
189
+ </div>
190
+ </div>
191
191
 
192
192
  <!-- Tab Content -->
193
193
  <div class="tab-content" id="mainTabContent">
@@ -202,7 +202,7 @@
202
202
  <h5 class="card-title mb-3"><i class="bi bi-cpu"></i> LLM Providers</h5>
203
203
  <div id="llm-providers-overview" class="d-flex justify-content-around flex-wrap gap-2">
204
204
  <div class="text-center py-3">
205
- <div class="spinner-border spinner-border-sm text-primary" role="status"></div>
205
+ <output class="spinner-border spinner-border-sm text-primary"></output>
206
206
  <span class="ms-2">Loading providers...</span>
207
207
  </div>
208
208
  </div>
@@ -258,7 +258,7 @@
258
258
  <!-- Provider Selector Icons -->
259
259
  <div class="provider-selector" id="provider-selector">
260
260
  <div class="text-center py-3 w-100">
261
- <div class="spinner-border spinner-border-sm text-primary" role="status"></div>
261
+ <output class="spinner-border spinner-border-sm text-primary"></output>
262
262
  <span class="ms-2">Loading providers...</span>
263
263
  </div>
264
264
  </div>
@@ -283,7 +283,7 @@
283
283
  </div>
284
284
  <div class="card-body p-0" id="tool-sources-list">
285
285
  <div class="text-center py-4">
286
- <div class="spinner-border spinner-border-sm text-primary" role="status"></div>
286
+ <output class="spinner-border spinner-border-sm text-primary"></output>
287
287
  <span class="ms-2">Loading tools...</span>
288
288
  </div>
289
289
  </div>
@@ -317,7 +317,7 @@
317
317
  </div>
318
318
  <div class="card-body" id="user-identity">
319
319
  <div class="text-center py-3">
320
- <div class="spinner-border spinner-border-sm text-primary" role="status"></div>
320
+ <output class="spinner-border spinner-border-sm text-primary"></output>
321
321
  <span class="ms-2">Loading user identity...</span>
322
322
  </div>
323
323
  </div>
@@ -642,7 +642,7 @@ function selectProvider(providerType) {
642
642
  </div>
643
643
  <div class="card-body" id="costs-info">
644
644
  <div class="text-center py-3">
645
- <div class="spinner-border spinner-border-sm text-primary" role="status"></div>
645
+ <output class="spinner-border spinner-border-sm text-primary"></output>
646
646
  <span class="ms-2">Loading costs...</span>
647
647
  </div>
648
648
  </div>
@@ -799,7 +799,7 @@ async function selectToolSource(source, event) {
799
799
  headerEl.innerHTML = '<i class="bi bi-box-fill"></i> Embedded Tools';
800
800
  contentEl.innerHTML = `
801
801
  <div class="text-center py-4">
802
- <div class="spinner-border spinner-border-sm text-primary" role="status"></div>
802
+ <output class="spinner-border spinner-border-sm text-primary"></output>
803
803
  <span class="ms-2">Loading embedded tools...</span>
804
804
  </div>
805
805
  `;
@@ -890,7 +890,7 @@ async function selectToolSource(source, event) {
890
890
  // Fetch tools from API
891
891
  contentEl.innerHTML = `
892
892
  <div class="text-center py-4">
893
- <div class="spinner-border spinner-border-sm text-primary" role="status"></div>
893
+ <output class="spinner-border spinner-border-sm text-primary"></output>
894
894
  <span class="ms-2">Loading tools...</span>
895
895
  </div>
896
896
  `;
@@ -92,28 +92,53 @@
92
92
  async function loadModels() {
93
93
  try {
94
94
  const response = await fetch('/api/models');
95
- const models = await response.json();
95
+ const data = await response.json();
96
+
97
+ const models = data.models || data;
98
+ const modelLocked = data.model_locked || false;
96
99
 
97
100
  const select = document.getElementById('model-select');
98
- select.innerHTML = '<option value="">Select a model...</option>';
99
-
100
- models.forEach(model => {
101
- const option = document.createElement('option');
102
- option.value = model.id;
103
-
104
- // Show service provider and optionally model maker
105
- let displayText = model.name;
106
- if (model.model_maker && model.provider !== model.model_maker) {
107
- // Show both: "Model Name [Model Maker via Service Provider]"
108
- displayText += ` [${model.model_maker} via ${model.provider}]`;
109
- } else {
110
- // Show service only: "Model Name [Service Provider]"
111
- displayText += ` [${model.provider}]`;
112
- }
113
-
114
- option.textContent = displayText;
115
- select.appendChild(option);
116
- });
101
+
102
+ if (modelLocked) {
103
+ // Model is locked - show only the mandatory model and disable selection
104
+ select.innerHTML = '';
105
+ models.forEach(model => {
106
+ const option = document.createElement('option');
107
+ option.value = model.id;
108
+
109
+ let displayText = model.name;
110
+ if (model.provider) {
111
+ displayText += ` [${model.provider}]`;
112
+ }
113
+ option.textContent = displayText;
114
+ option.selected = true;
115
+ select.appendChild(option);
116
+ });
117
+ select.disabled = true;
118
+
119
+ // Add info message below the select
120
+ const infoDiv = document.createElement('div');
121
+ infoDiv.className = 'form-text text-info';
122
+ infoDiv.innerHTML = '<i class="bi bi-lock-fill"></i> Model is locked via configuration';
123
+ select.parentNode.appendChild(infoDiv);
124
+ } else {
125
+ select.innerHTML = '<option value="">Select a model...</option>';
126
+ models.forEach(model => {
127
+ const option = document.createElement('option');
128
+ option.value = model.id;
129
+
130
+ // Show service provider and optionally model maker
131
+ let displayText = model.name;
132
+ if (model.model_maker && model.provider !== model.model_maker) {
133
+ displayText += ` [${model.model_maker} via ${model.provider}]`;
134
+ } else {
135
+ displayText += ` [${model.provider}]`;
136
+ }
137
+
138
+ option.textContent = displayText;
139
+ select.appendChild(option);
140
+ });
141
+ }
117
142
  } catch (error) {
118
143
  console.error('Error loading models:', error);
119
144
  showToast('Failed to load models', 'error');
@@ -146,6 +171,12 @@ function showToast(message, type = 'info') {
146
171
  document.getElementById('new-conversation-form').addEventListener('submit', async (e) => {
147
172
  e.preventDefault();
148
173
 
174
+ // Re-enable disabled select so its value is included in form data
175
+ const modelSelect = document.getElementById('model-select');
176
+ if (modelSelect.disabled) {
177
+ modelSelect.disabled = false;
178
+ }
179
+
149
180
  const formData = new FormData(e.target);
150
181
 
151
182
  try {
@@ -124,7 +124,7 @@ class WebInterface:
124
124
  True if response was accepted, False if request not found
125
125
  """
126
126
  if request_id not in self._permission_requests:
127
- logger.warning(f"Permission response submitted for unknown request: {request_id}")
127
+ logger.warning("Permission response submitted for unknown request")
128
128
  return False
129
129
 
130
130
  # Store the response
@@ -133,5 +133,5 @@ class WebInterface:
133
133
  # Update request status
134
134
  self._permission_requests[request_id]['status'] = 'responded'
135
135
 
136
- logger.info(f"Permission response submitted for {request_id}: {response}")
136
+ logger.info("Permission response submitted and recorded")
137
137
  return True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dtSpark
3
- Version: 1.1.0a2
3
+ Version: 1.1.0a6
4
4
  Summary: Secure Personal AI Research Kit - Multi-provider LLM CLI/Web interface with MCP tool integration
5
5
  Home-page: https://github.com/digital-thought/dtSpark
6
6
  Author: Matthew Westwood-Hill
@@ -42,7 +42,7 @@ Requires-Dist: httpx>=0.24.0
42
42
  Requires-Dist: aiohttp>=3.8.0
43
43
  Requires-Dist: mcp>=0.9.0
44
44
  Requires-Dist: pyyaml>=6.0
45
- Requires-Dist: dtPyAppFramework>=4.0.3
45
+ Requires-Dist: dtPyAppFramework>=4.1.2
46
46
  Requires-Dist: tiktoken>=0.5.0
47
47
  Requires-Dist: ollama>=0.2.0
48
48
  Requires-Dist: cryptography>=41.0.0
@@ -83,6 +83,13 @@ Dynamic: requires-python
83
83
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
84
84
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
85
85
 
86
+ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Digital-Thought_dtSpark&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=Digital-Thought_dtSpark)
87
+ [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=Digital-Thought_dtSpark&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=Digital-Thought_dtSpark)
88
+ [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=Digital-Thought_dtSpark&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=Digital-Thought_dtSpark)
89
+ [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=Digital-Thought_dtSpark&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=Digital-Thought_dtSpark)
90
+ [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=Digital-Thought_dtSpark&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=Digital-Thought_dtSpark)
91
+ [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=Digital-Thought_dtSpark&metric=bugs)](https://sonarcloud.io/summary/new_code?id=Digital-Thought_dtSpark)
92
+
86
93
  **Spark** is a powerful, multi-provider LLM interface for conversational AI with integrated tool support. It supports AWS Bedrock, Anthropic Direct API, and Ollama local models through both CLI and Web interfaces.
87
94
 
88
95
  ## Key Features
@@ -0,0 +1,96 @@
1
+ dtSpark/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ dtSpark/_description.txt,sha256=4OTFeEBVY3q0IbKbSdmi7lQ9bT5aeFHl9mUmQ7qluSg,209
3
+ dtSpark/_full_name.txt,sha256=wsMYXtT12WMrY9gT1JHiKdE4k7H59psECS6cSD07giQ,31
4
+ dtSpark/_licence.txt,sha256=Mvt5wkOkst8VGlk48vwN3CgHwMHLfmplKSPOUEbTfOw,1071
5
+ dtSpark/_metadata.yaml,sha256=h3PQd2QsY5yUBzS2b6EueTwkmd57svsbAKcwDVVEfIo,188
6
+ dtSpark/_name.txt,sha256=kDZC5_a3iMKIPOUvtLXl0C9N5DiOfgUCsecwTUnkJhs,7
7
+ dtSpark/_version.txt,sha256=gjNl3xINivNOurU564CJITfMDtfS5cMPFUF0a2kFUEM,7
8
+ dtSpark/cli_interface.py,sha256=Aae-vQ-aIaOiON-salTw-eDFo2eGI1-f_EJI6wmOYCo,97412
9
+ dtSpark/conversation_manager.py,sha256=VcfZSwrRuuUbVZa8kQVJjHwG4un5HA0nqYuajsUovoI,132593
10
+ dtSpark/launch.py,sha256=j8XYpmDswWUIzhpMc32E0Fhbhk_qhOQUAwJSpqh37f0,892
11
+ dtSpark/aws/__init__.py,sha256=tVuUKO69R3ZOkHQNQo81ukGTdU0OAyYVxkH0DgtwaTM,261
12
+ dtSpark/aws/authentication.py,sha256=dgYxrwtZHoGVhFb3HCsP7zA8tnM7qSsVUYHDqVkJbzY,11287
13
+ dtSpark/aws/bedrock.py,sha256=CK0fFYeMv1U0pnkkIFmNqIctBCOqhqHiYkJrYdNFqbA,23177
14
+ dtSpark/aws/costs.py,sha256=D8fnAL1NGCngA40rHqvdarf9g2TbrP5WxmehkIV5-uQ,12066
15
+ dtSpark/aws/pricing.py,sha256=y0SBRJoFDq1uXr9v0IYPxCnsHVivI77CD2f28i84d1E,23286
16
+ dtSpark/core/__init__.py,sha256=kORX-9C7L91WxMTMUHXr3Yc09rb6oJNzEH5_KDRdgqM,477
17
+ dtSpark/core/application.py,sha256=NBbxrr7RW0Y_jJjXzgPWN6VJIvRpnfh6ePxkyYtbm0E,171801
18
+ dtSpark/core/context_compaction.py,sha256=D-2OlnhHReOcgxIRX80Dnc1SPu-RfiyGgQ-2vQ0XneA,31474
19
+ dtSpark/daemon/__init__.py,sha256=Dw4lvbnKm7GngU_Iy_F_J4CBFDUZFaVZRXb-bAPd8HY,3495
20
+ dtSpark/daemon/__main__.py,sha256=sRNG4RJ-Ejvd-f7OAU5slPOtxVpCoC2OfazdTJro69Q,170
21
+ dtSpark/daemon/action_monitor.py,sha256=FYwPOrDN2_Q4zwvc2zrU4PVaZTw1gaC0fCFc2LcVvEk,8618
22
+ dtSpark/daemon/daemon_app.py,sha256=g6WhFOWGOdtB15-0Ctk24htiRDdRNB_mAqUOZX1rjiM,28900
23
+ dtSpark/daemon/daemon_manager.py,sha256=dPV9ISY2IopETH6-nJ1dk2X2KXi6XB0mYBbaZ2Tnclo,10057
24
+ dtSpark/daemon/execution_coordinator.py,sha256=ykZ2iKe6XaoD3JCOjhnEbiD8q12d7opg9ZafZFiW7lQ,5869
25
+ dtSpark/daemon/pid_file.py,sha256=Nm0rmjisr5a2YRAOwMkqpFpAXLjJ3V0IB-E6t4ZnAWA,4687
26
+ dtSpark/database/__init__.py,sha256=NaNZ-06nPUaXrq1C4W_YHdUWvcfMUAD8qdJOhPJSYco,25950
27
+ dtSpark/database/autonomous_actions.py,sha256=FCpxhzpM5Mjnt6dCTYxK2-iqC-Y5iNuWEFSGPZYnH_8,36143
28
+ dtSpark/database/backends.py,sha256=HAskNCI5QsF5QeYVD596XHn4ITlfqJkJW2jEkJUpYl0,9347
29
+ dtSpark/database/connection.py,sha256=egEGhp7gb7beoEZCYUUflY2YMAC5gdDs_XTWuB0CwiM,3672
30
+ dtSpark/database/conversations.py,sha256=kldbkVe1UMz52FSrX8RyCYNeAPE7P6pfpIGWHDsijpU,18338
31
+ dtSpark/database/credential_prompt.py,sha256=hRvYfZyOi1rqwHz-bmgVAuBR9zubS7Yvn3QE2UWGSM8,6789
32
+ dtSpark/database/files.py,sha256=WDOE_aShfzlDvEQcwx9bZKPFz1unrIoBDQqpjG8UBdA,7006
33
+ dtSpark/database/mcp_ops.py,sha256=jgc8Ig1iogvrbOV8cUcSlmFRuhp14x1K8sgicPl2Neg,12706
34
+ dtSpark/database/messages.py,sha256=h2iVIWFzashtNlbg-8ln37H12yeKTOofRVXgDR1yPtY,5296
35
+ dtSpark/database/schema.py,sha256=j7Av9Ag9Q60pz99d26wjqvaHvQ4OZh8zAd5HX9_6Rjw,23336
36
+ dtSpark/database/tool_permissions.py,sha256=6NjYmU82BAq2lFsyhgzkudVoOpWAw-R-l2AV1_Z0KC4,6227
37
+ dtSpark/database/usage.py,sha256=6DwKvQTxx8F-P7cNU7dPjqCinIp9cst6OiUgJkY008o,5368
38
+ dtSpark/files/__init__.py,sha256=BTSp2hvW4NI6GSka3eKoNCfvzcxUPPWJOiqbY5gXe4I,90
39
+ dtSpark/files/manager.py,sha256=7JzBGhvzSNT6BjGuAg6X9AifBprNIaNUqQiEkl8gDVQ,10627
40
+ dtSpark/limits/__init__.py,sha256=vCqYQvR8Ss6Q64ySUj-Vx_8cWUFLGUH9z330Wd4dNBg,262
41
+ dtSpark/limits/costs.py,sha256=YpPTQ3uqCkrOr4xpVOkIEml_vdLbzIAak_rV__2-wxg,10213
42
+ dtSpark/limits/tokens.py,sha256=UF5razY6qxFUA0HrxBMJ-zVJ5VhOauitcrZrJx66bJ0,13590
43
+ dtSpark/llm/__init__.py,sha256=Govebgc3ukJFyu7eyIwTeUcsBwpUTeWkF4xIstW9kQk,608
44
+ dtSpark/llm/anthropic_direct.py,sha256=AexKSBOALVMLmnIOMTZr4wPLLooKFNY22o3jVESYK6A,20241
45
+ dtSpark/llm/base.py,sha256=M8DaC_uZSa7UNt7Cx_EUBZcx6dbHCeEQBTSYGgBbphM,4217
46
+ dtSpark/llm/context_limits.py,sha256=YnyPpG7f6esS7KcS1hUrKLijYWL25crmQsWA_DeIhco,16627
47
+ dtSpark/llm/manager.py,sha256=Qg9glX5ZhepWaRnb8ILZiPoiwqzC8Y318JgwuJf9m58,5837
48
+ dtSpark/llm/ollama.py,sha256=BQOS6j8nRipoHzPv6gxwzpjucdJ-HLQ3ixNvTEPROKM,20897
49
+ dtSpark/mcp_integration/__init__.py,sha256=pFw-yTSSJ1yx_ksTe94eq8pBrwDD-5Z-UqSM3VO4deQ,157
50
+ dtSpark/mcp_integration/manager.py,sha256=yfSymFPXAN-80Rl0M5D-Upb3vIvRq_tvGAI5wVR-IdQ,25241
51
+ dtSpark/mcp_integration/tool_selector.py,sha256=GHH1pEyi5E2QA2JdfrWFGkZlVucuhSIh4jBJOb54TjU,11029
52
+ dtSpark/resources/config.yaml.template,sha256=8N3zeXHSafIlU-UO8IGztrYcTbNwZyrkspVqC_PclGM,27346
53
+ dtSpark/safety/__init__.py,sha256=fdcZ4qNbYhH7Un9iKLwNe2GDr_doUmpSgtv-oNS8qPE,460
54
+ dtSpark/safety/llm_service.py,sha256=N2J9_Od-fGGvk9BkddD6CFd81PrJ03sMjSz6egBDYr4,3820
55
+ dtSpark/safety/patterns.py,sha256=ZeHuLHrtunZhOHIo3ZG0r9b2e1f9Dp9X_FtJMf8gefE,8467
56
+ dtSpark/safety/prompt_inspector.py,sha256=c5vIvIRyj-TC9rS-V07KpVNvw4xwHdbKSlPW7N3NBhA,16440
57
+ dtSpark/safety/violation_logger.py,sha256=HCWKOWuhIe4_BIx9Ccb_mcdW-14fWRMGH6YqFc-3o8c,11769
58
+ dtSpark/scheduler/__init__.py,sha256=DkhER25jUoqFU1c4xTDZyoJhMJ-wFS6yZqvsp3cr0zo,494
59
+ dtSpark/scheduler/creation_tools.py,sha256=rhIf0naBn-8_8Bp_wGbBdPH8MP5uQQLHOfYX0XoScfs,23342
60
+ dtSpark/scheduler/execution_queue.py,sha256=7_yXnGxO-arZTl0qPbyE-kDhZDVXQKT2z9zIKj9s1SA,4954
61
+ dtSpark/scheduler/executor.py,sha256=s_-6WKdTYEK1-xjYJNXGcAj6vdN27Cf6TI9zNYPSsk0,51371
62
+ dtSpark/scheduler/manager.py,sha256=vwtmQadqf3cv1QzdZJzFqC0l3bBzIplGZ79BUjfsh4o,12846
63
+ dtSpark/tools/__init__.py,sha256=TPK-c8CmXheEkoiFzL9PMP8ve0hTpw9iIV2xlGLTsMc,147
64
+ dtSpark/tools/builtin.py,sha256=oTdOsxK8x4-DR4wDOYZdBNdZZ7MlqgplM5GLV6OaWQQ,88941
65
+ dtSpark/web/__init__.py,sha256=5OrzA2yIR9NBf9mlTPnrQ0afMJTBuEgnzxq4QmIYe54,428
66
+ dtSpark/web/auth.py,sha256=uSIHwJOiklkjZSpLcznwOL1pVQktKeWifZygt068M9Y,4384
67
+ dtSpark/web/dependencies.py,sha256=ku54-Vb8wYvGVQ8Kluzxj8zm2Re3wDgU5LzFJ0NVIsI,874
68
+ dtSpark/web/server.py,sha256=J27-tMSRYhB24vf03e56o3wPVhLCo7QFVbLUn88iGdM,23500
69
+ dtSpark/web/session.py,sha256=yoz4yKGqUiYtxc5qoKtyBxNH0JrITSUyzgfu5iTo_Lw,4972
70
+ dtSpark/web/ssl_utils.py,sha256=PcZazlLeZTqIWeLY3N4xrk7CcxBNQXMcDJ6ou4r6-F4,6652
71
+ dtSpark/web/web_interface.py,sha256=vLGfinZpQqqVq6E8Xfb4GvpQ4lR6c26R9on94tT_LAk,4681
72
+ dtSpark/web/endpoints/__init__.py,sha256=uOTiOKx6IDZ2kc0-2GS2hqZD2qX6KtwAhMMZQbS7pWc,356
73
+ dtSpark/web/endpoints/autonomous_actions.py,sha256=U0YY2sjgS9C3OhmUUKg7kaW4aNWCeFq9amGtkXYrO6k,36727
74
+ dtSpark/web/endpoints/chat.py,sha256=c5MWZE-SY26Hr0X3DIFU_LQ15m1E-fFZ7hnQbmzXd1w,26041
75
+ dtSpark/web/endpoints/conversations.py,sha256=ADEsoZlN9roa_uoazvFMSw_w-gFpXHKd6tJyZuxop2w,13248
76
+ dtSpark/web/endpoints/main_menu.py,sha256=shAP7F5zREbs2A7BmZAIzt5LpR83tZHrNXiFdWgsmFg,20621
77
+ dtSpark/web/endpoints/streaming.py,sha256=qo0ugUWYvJJF5QvvLpuIvFIlVWgOpfPyUK59HeoRgdY,14603
78
+ dtSpark/web/static/css/dark-theme.css,sha256=vMHtvATXuPFYCKlcwexa5ttq15IIffUWiBchxDqxwvo,7673
79
+ dtSpark/web/static/js/actions.js,sha256=EI-ur3eNV97flgpUcM4M5YOQtn_VPS1o4aFiPvthx3U,37463
80
+ dtSpark/web/static/js/chat.js,sha256=JE1v7i-Bn6arcMQbbLvV1u-bzlRrjPoJwkuTXTsa84o,21737
81
+ dtSpark/web/static/js/main.js,sha256=0JUuRtVlWxpRgCZoHwM4_tRxyBrNKwTPQmN_meKEI4M,16133
82
+ dtSpark/web/static/js/sse-client.js,sha256=JZnLDar6j8m7TxuHJ9JQDl7E3LqUiWSbQHt6yMaskPI,9104
83
+ dtSpark/web/templates/actions.html,sha256=08Pk8aqmNEr3uEQTzmnFklETqd1hUcE8PCtUZVMZJso,18875
84
+ dtSpark/web/templates/base.html,sha256=Om8MLeJPAB27CGOELUx63I3ZVtKpTlnrEvKaUsZQImU,4221
85
+ dtSpark/web/templates/chat.html,sha256=QuyIJOrfKbsLgGH7ELGLBJe_JBnuF73_Sx6EFuMflcc,45104
86
+ dtSpark/web/templates/conversations.html,sha256=JFDvjDUyRkO60KwRsO-F3Dzvtyb9Q4wOHSxiibakTJE,13997
87
+ dtSpark/web/templates/goodbye.html,sha256=ZdEzgP9MD4kMPrLHkg_3wAod2Hfr9hSTRyBq9fB9DV4,2817
88
+ dtSpark/web/templates/login.html,sha256=OkLf_uzMYhl_o9ER1RQZc8ch6-bCaiOokEhKbeEl8E8,3274
89
+ dtSpark/web/templates/main_menu.html,sha256=80NUCu-nzvpMLHGz4gvabjLVmdASldesYtKjvm38Hv0,39120
90
+ dtSpark/web/templates/new_conversation.html,sha256=wL9ZZbn3M8ktEoX7H5n4r6XKSEImtO2aXnuNKsB-pEw,8047
91
+ dtspark-1.1.0a6.dist-info/licenses/LICENSE,sha256=jIuWlmbirwQabTwxfzE7SXT1LpCG-y_GRQ3VnoRTKgo,1101
92
+ dtspark-1.1.0a6.dist-info/METADATA,sha256=t2IBA-ybdErR_JSrTwcM7Gh6fqrnk7r5UZ1EMHdWpC8,7410
93
+ dtspark-1.1.0a6.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
94
+ dtspark-1.1.0a6.dist-info/entry_points.txt,sha256=IpIwa_a6XY8Z2w7DtgYAhpFHHEbha-zhLkyttWd3zpw,76
95
+ dtspark-1.1.0a6.dist-info/top_level.txt,sha256=x-6lMA6vNuxyDNJGNOKI4dyy7L0kOb9V98I5z46bJVY,8
96
+ dtspark-1.1.0a6.dist-info/RECORD,,