dtSpark 1.1.0a1__py3-none-any.whl → 1.1.0a3__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.
dtSpark/_version.txt CHANGED
@@ -1 +1 @@
1
- 1.1.0a1
1
+ 1.1.0a3
@@ -328,34 +328,6 @@ class AWSBedrockCLI(AbstractApp):
328
328
 
329
329
  logging.info('Initialising application components')
330
330
 
331
- # Debug: Diagnose settings loading for llm_providers
332
- # Try different access patterns to understand how Settings class works
333
- logging.info("=== Settings Diagnostics ===")
334
-
335
- # Try accessing the whole llm_providers section
336
- llm_providers_raw = self.settings.get('llm_providers', None)
337
- logging.info(f"settings.get('llm_providers'): {llm_providers_raw} (type: {type(llm_providers_raw).__name__ if llm_providers_raw else 'None'})")
338
-
339
- # Try accessing aws_bedrock under llm_providers
340
- aws_bedrock_raw = self.settings.get('llm_providers.aws_bedrock', None)
341
- logging.info(f"settings.get('llm_providers.aws_bedrock'): {aws_bedrock_raw} (type: {type(aws_bedrock_raw).__name__ if aws_bedrock_raw else 'None'})")
342
-
343
- # If llm_providers is a dict, try to access nested values directly
344
- if isinstance(llm_providers_raw, dict):
345
- logging.info(f"llm_providers keys: {list(llm_providers_raw.keys())}")
346
- aws_bedrock_dict = llm_providers_raw.get('aws_bedrock', {})
347
- logging.info(f"llm_providers['aws_bedrock']: {aws_bedrock_dict}")
348
- if isinstance(aws_bedrock_dict, dict):
349
- logging.info(f"aws_bedrock['enabled']: {aws_bedrock_dict.get('enabled', 'NOT_FOUND')}")
350
-
351
- # Check if settings has a _settings or similar internal dict
352
- if hasattr(self.settings, '_settings'):
353
- logging.info(f"settings._settings type: {type(self.settings._settings)}")
354
- if hasattr(self.settings, 'settings'):
355
- logging.info(f"settings.settings type: {type(self.settings.settings)}")
356
-
357
- logging.info("=== End Settings Diagnostics ===")
358
-
359
331
  # Initialise CLI interface
360
332
  self.cli = CLIInterface()
361
333
 
@@ -1044,8 +1016,9 @@ class AWSBedrockCLI(AbstractApp):
1044
1016
  logging.debug("Predefined conversations not enabled in config")
1045
1017
  return
1046
1018
 
1047
- # Get the mandatory model setting
1019
+ # Get the mandatory model and provider settings
1048
1020
  mandatory_model = self._get_nested_setting('llm_providers.mandatory_model', None)
1021
+ mandatory_provider = self._get_nested_setting('llm_providers.mandatory_provider', None)
1049
1022
 
1050
1023
  # Get list of predefined conversations
1051
1024
  predefined_convs = self.settings.get('predefined_conversations.conversations', [])
@@ -1163,27 +1136,45 @@ class AWSBedrockCLI(AbstractApp):
1163
1136
  if not source or not source.strip():
1164
1137
  return source
1165
1138
 
1166
- # Try ResourceManager first
1167
- try:
1168
- resource_content = ResourceManager().load_resource(source)
1169
- if resource_content is not None:
1170
- logging.info(f"Loaded {description} via ResourceManager from: {source}")
1171
- return resource_content
1172
- except Exception as e:
1173
- logging.debug(f"ResourceManager could not load {description} from '{source}': {e}")
1139
+ import os
1174
1140
 
1175
- # Try direct file path
1176
- try:
1177
- import os
1178
- if os.path.isfile(source):
1179
- with open(source, 'r', encoding='utf-8') as f:
1180
- content = f.read()
1181
- logging.info(f"Loaded {description} from file path: {source}")
1182
- return content
1183
- except Exception as e:
1184
- logging.debug(f"Could not load {description} from file path '{source}': {e}")
1141
+ # Determine if source looks like a file path or resource name
1142
+ # (contains path separators, has a file extension, or doesn't contain spaces)
1143
+ looks_like_path = (
1144
+ os.sep in source
1145
+ or '/' in source
1146
+ or '\\' in source
1147
+ or (
1148
+ '.' in source
1149
+ and not source.strip().endswith('.')
1150
+ and ' ' not in source.strip()
1151
+ )
1152
+ )
1153
+
1154
+ if looks_like_path:
1155
+ # Try ResourceManager first (for package resources)
1156
+ try:
1157
+ resource_content = ResourceManager().load_resource(source)
1158
+ if resource_content is not None:
1159
+ logging.info(f"Loaded {description} via ResourceManager from: {source}")
1160
+ return resource_content
1161
+ except Exception as e:
1162
+ logging.debug(f"ResourceManager could not load {description} from '{source}': {e}")
1163
+
1164
+ # Try direct file path
1165
+ try:
1166
+ if os.path.isfile(source):
1167
+ with open(source, 'r', encoding='utf-8') as f:
1168
+ content = f.read()
1169
+ logging.info(f"Loaded {description} from file path: {source}")
1170
+ return content
1171
+ except Exception as e:
1172
+ logging.debug(f"Could not load {description} from file path '{source}': {e}")
1173
+
1174
+ # Path-like source but couldn't load - log warning and return as-is
1175
+ logging.warning(f"Could not load {description} from path '{source}', using as inline text")
1185
1176
 
1186
- # If both methods fail, assume it's inline text
1177
+ # Treat as inline text
1187
1178
  logging.debug(f"Using inline text for {description}")
1188
1179
  return source
1189
1180
 
dtSpark/tools/builtin.py CHANGED
@@ -1630,6 +1630,17 @@ def _execute_create_word_document(tool_input: Dict[str, Any],
1630
1630
  if content.get('title'):
1631
1631
  doc.add_heading(content['title'], 0)
1632
1632
 
1633
+ # Define valid built-in styles that python-docx supports
1634
+ valid_styles = {
1635
+ 'Normal', 'Title', 'Subtitle', 'Quote', 'Intense Quote',
1636
+ 'List Paragraph', 'List Bullet', 'List Number',
1637
+ 'Heading 1', 'Heading 2', 'Heading 3', 'Heading 4',
1638
+ 'Heading 5', 'Heading 6', 'Heading 7', 'Heading 8', 'Heading 9',
1639
+ 'Body Text', 'Body Text 2', 'Body Text 3',
1640
+ 'Caption', 'Macro Text', 'No Spacing'
1641
+ }
1642
+ invalid_styles_used = set()
1643
+
1633
1644
  # Add paragraphs
1634
1645
  for para_data in content.get('paragraphs', []):
1635
1646
  text = para_data.get('text', '')
@@ -1638,8 +1649,15 @@ def _execute_create_word_document(tool_input: Dict[str, Any],
1638
1649
  level = int(style.split()[-1]) if style.split()[-1].isdigit() else 1
1639
1650
  doc.add_heading(text, level)
1640
1651
  else:
1652
+ # Validate style - fall back to Normal if invalid
1653
+ if style not in valid_styles:
1654
+ invalid_styles_used.add(style)
1655
+ style = 'Normal'
1641
1656
  doc.add_paragraph(text, style=style)
1642
1657
 
1658
+ if invalid_styles_used:
1659
+ logging.warning(f"Invalid styles replaced with 'Normal': {', '.join(sorted(invalid_styles_used))}")
1660
+
1643
1661
  doc.save(str(full_path))
1644
1662
 
1645
1663
  result = {
@@ -448,6 +448,16 @@ async def command_change_model(
448
448
  try:
449
449
  app_instance = request.app.state.app_instance
450
450
 
451
+ # Check if model is locked via configuration
452
+ mandatory_model = getattr(app_instance, 'configured_model_id', None)
453
+ if mandatory_model:
454
+ return CommandResponse(
455
+ command="changemodel",
456
+ status="error",
457
+ message=f"Model changing is disabled - model is locked to '{mandatory_model}' via configuration",
458
+ data=None,
459
+ )
460
+
451
461
  # Load conversation
452
462
  app_instance.conversation_manager.load_conversation(conversation_id)
453
463
 
@@ -179,6 +179,14 @@ async def create_conversation(
179
179
  database = app_instance.database
180
180
  conversation_manager = app_instance.conversation_manager
181
181
 
182
+ # Enforce mandatory model if configured
183
+ mandatory_model = getattr(app_instance, 'configured_model_id', None)
184
+ mandatory_provider = getattr(app_instance, 'configured_provider', None)
185
+ if mandatory_model:
186
+ model_id = mandatory_model
187
+ logger.info(f"Mandatory model enforced: {model_id}"
188
+ f"{f' via {mandatory_provider}' if mandatory_provider else ''}")
189
+
182
190
  # Create conversation in database
183
191
  conversation_id = database.create_conversation(
184
192
  name=name,
@@ -190,7 +198,7 @@ async def create_conversation(
190
198
  conversation_manager.load_conversation(conversation_id)
191
199
 
192
200
  # Set the model from the conversation and update service references
193
- app_instance.llm_manager.set_model(model_id)
201
+ app_instance.llm_manager.set_model(model_id, mandatory_provider)
194
202
  app_instance.bedrock_service = app_instance.llm_manager.get_active_service()
195
203
  conversation_manager.update_service(app_instance.bedrock_service)
196
204
 
@@ -325,29 +333,59 @@ async def delete_conversation(
325
333
  async def list_models(
326
334
  request: Request,
327
335
  session_id: str = Depends(get_current_session),
328
- ) -> List[dict]:
336
+ ) -> dict:
329
337
  """
330
- Get available models.
338
+ Get available models and mandatory model configuration.
331
339
 
332
340
  Returns:
333
- List of available models with their IDs and names
341
+ Dictionary with models list and mandatory model info
334
342
  """
335
343
  try:
336
344
  app_instance = request.app.state.app_instance
337
345
 
346
+ mandatory_model = getattr(app_instance, 'configured_model_id', None)
347
+ mandatory_provider = getattr(app_instance, 'configured_provider', None)
348
+
338
349
  # Get available models from LLM manager
339
- models = app_instance.llm_manager.list_all_models()
350
+ all_models = app_instance.llm_manager.list_all_models()
340
351
 
341
- return [
352
+ models = [
342
353
  {
343
354
  "id": model.get('id', model.get('name', 'unknown')),
344
355
  "name": model.get('name', 'Unknown'),
345
356
  "provider": model.get('provider', 'Unknown'),
346
- "model_maker": model.get('model_maker'), # Optional: model creator (for Bedrock models)
357
+ "model_maker": model.get('model_maker'),
347
358
  }
348
- for model in models
359
+ for model in all_models
349
360
  ]
350
361
 
362
+ # If mandatory model is set, filter to matching models only
363
+ if mandatory_model:
364
+ filtered = [
365
+ m for m in models
366
+ if m['id'] == mandatory_model
367
+ or m['name'] == mandatory_model
368
+ ]
369
+
370
+ # Further filter by provider if mandatory_provider is set
371
+ if mandatory_provider and filtered:
372
+ provider_filtered = [
373
+ m for m in filtered
374
+ if m['provider'] == mandatory_provider
375
+ ]
376
+ if provider_filtered:
377
+ filtered = provider_filtered
378
+
379
+ if filtered:
380
+ models = filtered
381
+
382
+ return {
383
+ "models": models,
384
+ "mandatory_model": mandatory_model,
385
+ "mandatory_provider": mandatory_provider,
386
+ "model_locked": mandatory_model is not None,
387
+ }
388
+
351
389
  except Exception as e:
352
390
  logger.error(f"Error listing models: {e}")
353
391
  raise HTTPException(status_code=500, detail=str(e))
@@ -624,7 +624,8 @@ async function loadModels() {
624
624
  const response = await fetch('/api/models');
625
625
  if (!response.ok) throw new Error('Failed to load models');
626
626
 
627
- availableModels = await response.json();
627
+ const data = await response.json();
628
+ availableModels = data.models || data;
628
629
 
629
630
  const select = document.getElementById('actionModel');
630
631
  select.innerHTML = '<option value="">Select a model...</option>';
@@ -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() {
@@ -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 {
@@ -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 {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dtSpark
3
- Version: 1.1.0a1
3
+ Version: 1.1.0a3
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
@@ -4,7 +4,7 @@ dtSpark/_full_name.txt,sha256=wsMYXtT12WMrY9gT1JHiKdE4k7H59psECS6cSD07giQ,31
4
4
  dtSpark/_licence.txt,sha256=Mvt5wkOkst8VGlk48vwN3CgHwMHLfmplKSPOUEbTfOw,1071
5
5
  dtSpark/_metadata.yaml,sha256=h3PQd2QsY5yUBzS2b6EueTwkmd57svsbAKcwDVVEfIo,188
6
6
  dtSpark/_name.txt,sha256=kDZC5_a3iMKIPOUvtLXl0C9N5DiOfgUCsecwTUnkJhs,7
7
- dtSpark/_version.txt,sha256=hfp31eFAhdQ4qbzp72MNun0WOiS5Gps8p-hsIiWM7Ig,8
7
+ dtSpark/_version.txt,sha256=rkv-UB4slhPYzKCJ5ps5yjDjs2Ssz1_PYfaD_F6tqvA,7
8
8
  dtSpark/cli_interface.py,sha256=aB-rFAh6o8GOwwecx-rSHEj3W4bmQHp51OPEBtC2CEw,96911
9
9
  dtSpark/conversation_manager.py,sha256=e1aTJpUjxV96G9xrssJl1ujPJMZZwtfufQ8ZDb1WyAI,132270
10
10
  dtSpark/launch.py,sha256=j8XYpmDswWUIzhpMc32E0Fhbhk_qhOQUAwJSpqh37f0,892
@@ -14,7 +14,7 @@ dtSpark/aws/bedrock.py,sha256=j1OknN76LehIMRmoqzx8G3DUSqk2IsO3Fiy5AxQp7Fw,24250
14
14
  dtSpark/aws/costs.py,sha256=eyjigH_Yef7g5cKqhR2QUx_7y4E6-NsLd9-WL52I2vM,11931
15
15
  dtSpark/aws/pricing.py,sha256=pk85e--C5Iz0Y-6iWv_VfENAnrcWQ_9XK0fJQSlk5Xk,23388
16
16
  dtSpark/core/__init__.py,sha256=kORX-9C7L91WxMTMUHXr3Yc09rb6oJNzEH5_KDRdgqM,477
17
- dtSpark/core/application.py,sha256=tYAfP0QGuvRnqxT4gBcRqqIf0NPwkjIVRucBIYOK5SQ,171425
17
+ dtSpark/core/application.py,sha256=UnIHCt0vZ0tNkZoaRyITw7cP83qlbmzxow-EH5pfz68,170589
18
18
  dtSpark/core/context_compaction.py,sha256=FWN352EW8n-eWv0MzbOiWIiKcooRxeIAb7611eN-kdY,31898
19
19
  dtSpark/daemon/__init__.py,sha256=xdKEyMsNXgIv6nNerpDcwf94c80n-BFoJFaucWxVF64,3300
20
20
  dtSpark/daemon/__main__.py,sha256=sRNG4RJ-Ejvd-f7OAU5slPOtxVpCoC2OfazdTJro69Q,170
@@ -61,7 +61,7 @@ dtSpark/scheduler/execution_queue.py,sha256=7_yXnGxO-arZTl0qPbyE-kDhZDVXQKT2z9zI
61
61
  dtSpark/scheduler/executor.py,sha256=n42MGNyZOoQohpYh1QFenZzFsv560S0h-o_-7FajkJc,43709
62
62
  dtSpark/scheduler/manager.py,sha256=vwtmQadqf3cv1QzdZJzFqC0l3bBzIplGZ79BUjfsh4o,12846
63
63
  dtSpark/tools/__init__.py,sha256=TPK-c8CmXheEkoiFzL9PMP8ve0hTpw9iIV2xlGLTsMc,147
64
- dtSpark/tools/builtin.py,sha256=4Jw6F9i1RbJ772J3PX-SirSsbAKcTuvrgqYueHS3MIo,87762
64
+ dtSpark/tools/builtin.py,sha256=F2QxhLc7i4nloyAohNnzbX6ry4QLPMGAc5nSew2F-_A,88683
65
65
  dtSpark/web/__init__.py,sha256=5OrzA2yIR9NBf9mlTPnrQ0afMJTBuEgnzxq4QmIYe54,428
66
66
  dtSpark/web/auth.py,sha256=uSIHwJOiklkjZSpLcznwOL1pVQktKeWifZygt068M9Y,4384
67
67
  dtSpark/web/dependencies.py,sha256=ku54-Vb8wYvGVQ8Kluzxj8zm2Re3wDgU5LzFJ0NVIsI,874
@@ -71,26 +71,26 @@ dtSpark/web/ssl_utils.py,sha256=keDhLzEbc9REUGSdMls0vxBV3yPunR490u4j6EvB8dg,6624
71
71
  dtSpark/web/web_interface.py,sha256=Jl50HxTatj6yzKFBvOxp51jlhNe3CqOqnBjT1uL8HEw,4713
72
72
  dtSpark/web/endpoints/__init__.py,sha256=uOTiOKx6IDZ2kc0-2GS2hqZD2qX6KtwAhMMZQbS7pWc,356
73
73
  dtSpark/web/endpoints/autonomous_actions.py,sha256=tHJtFvJJtpr34LujQu-udZvT4vY5TpJB3Sn0WPJ8giM,36588
74
- dtSpark/web/endpoints/chat.py,sha256=Xb8FOsmHvw2S3ju1wpET1XOAOR0P5pC1qGoYMhNG0xg,25560
75
- dtSpark/web/endpoints/conversations.py,sha256=uFNpd_9DF1jqTEKFd9qRWK-uffXyTwz4Px9JIur_128,11728
74
+ dtSpark/web/endpoints/chat.py,sha256=_UBPAZy4rdYsNZZ8TY3Jpz5lp-KyNJ7hYJHId7g2dtI,25981
75
+ dtSpark/web/endpoints/conversations.py,sha256=tdI8Pqd89b7VNrirqwssSc19quYRPtGc3uoXW1DATIE,13227
76
76
  dtSpark/web/endpoints/main_menu.py,sha256=54KYz86-jj9KXeBLbqEq-OOuxg2Cs4Hbnd_Z48MdB9M,20363
77
77
  dtSpark/web/endpoints/streaming.py,sha256=vhpLefhc1PUDlmZ3Lx4IXizZfHy45zPgv5POhb-TdFU,14581
78
78
  dtSpark/web/static/css/dark-theme.css,sha256=K2q2C1s5kjqi_O1xAF86HTVFsI6sEfwPAPhVEfmT02M,8117
79
- dtSpark/web/static/js/actions.js,sha256=NC9nLFfKEwffE88yBoaaGosmi4q9RoSVOPnziTD08GQ,37421
79
+ dtSpark/web/static/js/actions.js,sha256=EI-ur3eNV97flgpUcM4M5YOQtn_VPS1o4aFiPvthx3U,37463
80
80
  dtSpark/web/static/js/chat.js,sha256=s-TeeFgpRAsz0npeQHKPhQCgQawe03LBwLQYa7bjM84,21863
81
81
  dtSpark/web/static/js/main.js,sha256=A5m_VDyEzMcfCL9nnId2oCtFecvWRlpedzzPbt34QGY,16235
82
82
  dtSpark/web/static/js/sse-client.js,sha256=-YyRXNzSoQWrNLDvT8xGXtbgll_1JiP8p398OtQU7H8,8438
83
83
  dtSpark/web/templates/actions.html,sha256=KHJ552XjwPCCOrz0WUkehRzNwuBkS7qVpsAoCx1lGZI,18852
84
84
  dtSpark/web/templates/base.html,sha256=ne7kY8mnT5GpGDcxokQhNsn6H4tVksBE9BsXcJAsdmI,3765
85
- dtSpark/web/templates/chat.html,sha256=wMDna_73e9kulTR8OKzg-uSotkp9EXP4zIJh0bDe9o0,45073
86
- dtSpark/web/templates/conversations.html,sha256=URJX3W5-MjUjuUAXixziY1yFG-T6Ho5_u9Up7FcH70E,13004
85
+ dtSpark/web/templates/chat.html,sha256=lP_bkRjcAWxFqdByCkU-q9fddpf4k2u1NKmSR6xjk9s,45147
86
+ dtSpark/web/templates/conversations.html,sha256=wH71Jon9xgmyO_eOIvAk1uZIwgRhf0K-2TJ7SNj_A_k,14005
87
87
  dtSpark/web/templates/goodbye.html,sha256=4VnUgq6gHCMeJuty51qq8SZuTtpEMMUOsgTBut37Mc8,2825
88
88
  dtSpark/web/templates/login.html,sha256=OkLf_uzMYhl_o9ER1RQZc8ch6-bCaiOokEhKbeEl8E8,3274
89
89
  dtSpark/web/templates/main_menu.html,sha256=_tK5QBLzSmJY_j2qHFHk0c1fz9YyRr3i4ZLIhTzNEUU,39246
90
- dtSpark/web/templates/new_conversation.html,sha256=hoiQ4Ew3lpFWHTsYza0JiBqqWJs7St7jTusKDnxRR8w,6844
91
- dtspark-1.1.0a1.dist-info/licenses/LICENSE,sha256=jIuWlmbirwQabTwxfzE7SXT1LpCG-y_GRQ3VnoRTKgo,1101
92
- dtspark-1.1.0a1.dist-info/METADATA,sha256=maCoXtYpyuo_aFSScJQ94rZWy-cMwVQMTnCciwA6efo,6262
93
- dtspark-1.1.0a1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
94
- dtspark-1.1.0a1.dist-info/entry_points.txt,sha256=IpIwa_a6XY8Z2w7DtgYAhpFHHEbha-zhLkyttWd3zpw,76
95
- dtspark-1.1.0a1.dist-info/top_level.txt,sha256=x-6lMA6vNuxyDNJGNOKI4dyy7L0kOb9V98I5z46bJVY,8
96
- dtspark-1.1.0a1.dist-info/RECORD,,
90
+ dtSpark/web/templates/new_conversation.html,sha256=wL9ZZbn3M8ktEoX7H5n4r6XKSEImtO2aXnuNKsB-pEw,8047
91
+ dtspark-1.1.0a3.dist-info/licenses/LICENSE,sha256=jIuWlmbirwQabTwxfzE7SXT1LpCG-y_GRQ3VnoRTKgo,1101
92
+ dtspark-1.1.0a3.dist-info/METADATA,sha256=mjY7XU8Q5KLdAYhhkodKjMtfc80-WZ0rYXn0nej4dbc,6262
93
+ dtspark-1.1.0a3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
94
+ dtspark-1.1.0a3.dist-info/entry_points.txt,sha256=IpIwa_a6XY8Z2w7DtgYAhpFHHEbha-zhLkyttWd3zpw,76
95
+ dtspark-1.1.0a3.dist-info/top_level.txt,sha256=x-6lMA6vNuxyDNJGNOKI4dyy7L0kOb9V98I5z46bJVY,8
96
+ dtspark-1.1.0a3.dist-info/RECORD,,