dtSpark 1.1.0a3__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.
- dtSpark/_version.txt +1 -1
- dtSpark/aws/authentication.py +1 -1
- dtSpark/aws/bedrock.py +238 -239
- dtSpark/aws/costs.py +9 -5
- dtSpark/aws/pricing.py +25 -21
- dtSpark/cli_interface.py +69 -62
- dtSpark/conversation_manager.py +54 -47
- dtSpark/core/application.py +112 -91
- dtSpark/core/context_compaction.py +241 -226
- dtSpark/daemon/__init__.py +36 -22
- dtSpark/daemon/action_monitor.py +46 -17
- dtSpark/daemon/daemon_app.py +126 -104
- dtSpark/daemon/daemon_manager.py +59 -23
- dtSpark/daemon/pid_file.py +3 -2
- dtSpark/database/autonomous_actions.py +3 -0
- dtSpark/database/credential_prompt.py +52 -54
- dtSpark/files/manager.py +6 -12
- dtSpark/limits/__init__.py +1 -1
- dtSpark/limits/tokens.py +2 -2
- dtSpark/llm/anthropic_direct.py +246 -141
- dtSpark/llm/ollama.py +3 -1
- dtSpark/mcp_integration/manager.py +4 -4
- dtSpark/mcp_integration/tool_selector.py +83 -77
- dtSpark/resources/config.yaml.template +10 -0
- dtSpark/safety/patterns.py +45 -46
- dtSpark/safety/prompt_inspector.py +8 -1
- dtSpark/scheduler/creation_tools.py +273 -181
- dtSpark/scheduler/executor.py +503 -221
- dtSpark/tools/builtin.py +70 -53
- dtSpark/web/endpoints/autonomous_actions.py +12 -9
- dtSpark/web/endpoints/chat.py +8 -6
- dtSpark/web/endpoints/conversations.py +11 -9
- dtSpark/web/endpoints/main_menu.py +132 -105
- dtSpark/web/endpoints/streaming.py +2 -2
- dtSpark/web/server.py +65 -5
- dtSpark/web/ssl_utils.py +3 -3
- dtSpark/web/static/css/dark-theme.css +8 -29
- dtSpark/web/static/js/chat.js +6 -8
- dtSpark/web/static/js/main.js +8 -8
- dtSpark/web/static/js/sse-client.js +130 -122
- dtSpark/web/templates/actions.html +5 -5
- dtSpark/web/templates/base.html +13 -0
- dtSpark/web/templates/chat.html +10 -10
- dtSpark/web/templates/conversations.html +2 -2
- dtSpark/web/templates/goodbye.html +2 -2
- dtSpark/web/templates/main_menu.html +17 -17
- dtSpark/web/web_interface.py +2 -2
- {dtspark-1.1.0a3.dist-info → dtspark-1.1.0a6.dist-info}/METADATA +9 -2
- dtspark-1.1.0a6.dist-info/RECORD +96 -0
- dtspark-1.1.0a3.dist-info/RECORD +0 -96
- {dtspark-1.1.0a3.dist-info → dtspark-1.1.0a6.dist-info}/WHEEL +0 -0
- {dtspark-1.1.0a3.dist-info → dtspark-1.1.0a6.dist-info}/entry_points.txt +0 -0
- {dtspark-1.1.0a3.dist-info → dtspark-1.1.0a6.dist-info}/licenses/LICENSE +0 -0
- {dtspark-1.1.0a3.dist-info → dtspark-1.1.0a6.dist-info}/top_level.txt +0 -0
dtSpark/conversation_manager.py
CHANGED
|
@@ -22,6 +22,13 @@ from dtSpark.database.tool_permissions import PERMISSION_ALLOWED, PERMISSION_DEN
|
|
|
22
22
|
from dtSpark.llm.context_limits import ContextLimitResolver
|
|
23
23
|
from dtSpark.core.context_compaction import ContextCompactor, get_provider_from_model_id
|
|
24
24
|
|
|
25
|
+
# String constants to avoid duplication
|
|
26
|
+
_ERR_NO_ACTIVE_CONVERSATION = "No active conversation. Create or load a conversation first."
|
|
27
|
+
_TOOL_RESULTS_MARKER = '[TOOL_RESULTS]'
|
|
28
|
+
_SUMMARY_MARKER = '[Summary of previous conversation]'
|
|
29
|
+
_ERR_NO_CONVERSATION_TO_EXPORT = "No conversation loaded to export"
|
|
30
|
+
_LABEL_TOKEN_COUNT = 'Token Count'
|
|
31
|
+
|
|
25
32
|
|
|
26
33
|
class ConversationManager:
|
|
27
34
|
"""Manages conversation state and automatic rollup for token management."""
|
|
@@ -254,7 +261,7 @@ class ConversationManager:
|
|
|
254
261
|
Message ID
|
|
255
262
|
"""
|
|
256
263
|
if not self.current_conversation_id:
|
|
257
|
-
raise ValueError(
|
|
264
|
+
raise ValueError(_ERR_NO_ACTIVE_CONVERSATION)
|
|
258
265
|
|
|
259
266
|
token_count = self.bedrock_service.count_tokens(content)
|
|
260
267
|
message_id = self.database.add_message(
|
|
@@ -282,7 +289,7 @@ class ConversationManager:
|
|
|
282
289
|
Message ID
|
|
283
290
|
"""
|
|
284
291
|
if not self.current_conversation_id:
|
|
285
|
-
raise ValueError(
|
|
292
|
+
raise ValueError(_ERR_NO_ACTIVE_CONVERSATION)
|
|
286
293
|
|
|
287
294
|
token_count = self.bedrock_service.count_tokens(content)
|
|
288
295
|
message_id = self.database.add_message(
|
|
@@ -334,10 +341,10 @@ class ConversationManager:
|
|
|
334
341
|
except json.JSONDecodeError:
|
|
335
342
|
pass # Not JSON, treat as regular message
|
|
336
343
|
|
|
337
|
-
if msg['role'] == 'user' and content.startswith(
|
|
344
|
+
if msg['role'] == 'user' and content.startswith(_TOOL_RESULTS_MARKER):
|
|
338
345
|
# This is a tool results message
|
|
339
346
|
try:
|
|
340
|
-
tool_results_json = content.replace(
|
|
347
|
+
tool_results_json = content.replace(_TOOL_RESULTS_MARKER, '', 1)
|
|
341
348
|
tool_results = json.loads(tool_results_json)
|
|
342
349
|
formatted_messages.append({
|
|
343
350
|
'role': 'user',
|
|
@@ -472,12 +479,12 @@ class ConversationManager:
|
|
|
472
479
|
text_parts.append(block.get('text', ''))
|
|
473
480
|
if text_parts:
|
|
474
481
|
return '\n'.join(text_parts)
|
|
475
|
-
except
|
|
482
|
+
except ValueError:
|
|
476
483
|
# Not JSON, return as-is
|
|
477
484
|
pass
|
|
478
485
|
|
|
479
486
|
# Check if it's a rollup summary
|
|
480
|
-
if content.startswith(
|
|
487
|
+
if content.startswith(_SUMMARY_MARKER):
|
|
481
488
|
return content
|
|
482
489
|
|
|
483
490
|
# Regular assistant message
|
|
@@ -575,7 +582,7 @@ class ConversationManager:
|
|
|
575
582
|
while cutoff_index > 0:
|
|
576
583
|
cutoff_msg = messages[cutoff_index] if cutoff_index < len(messages) else None
|
|
577
584
|
|
|
578
|
-
if cutoff_msg and cutoff_msg['content'].startswith(
|
|
585
|
+
if cutoff_msg and cutoff_msg['content'].startswith(_TOOL_RESULTS_MARKER):
|
|
579
586
|
# This is a tool_result message, we need to keep the preceding tool_use
|
|
580
587
|
# Move cutoff back one more message
|
|
581
588
|
cutoff_index -= 1
|
|
@@ -595,7 +602,7 @@ class ConversationManager:
|
|
|
595
602
|
# Move cutoff back to include this tool_use and its result
|
|
596
603
|
cutoff_index -= 1
|
|
597
604
|
messages_to_keep_count += 1
|
|
598
|
-
except:
|
|
605
|
+
except ValueError:
|
|
599
606
|
pass
|
|
600
607
|
|
|
601
608
|
messages_to_summarise = messages[:cutoff_index] if cutoff_index > 0 else []
|
|
@@ -621,7 +628,7 @@ class ConversationManager:
|
|
|
621
628
|
self.database.add_message(
|
|
622
629
|
self.current_conversation_id,
|
|
623
630
|
'user',
|
|
624
|
-
f"
|
|
631
|
+
f"{_SUMMARY_MARKER}\n{summary_content}",
|
|
625
632
|
summary_token_count
|
|
626
633
|
)
|
|
627
634
|
|
|
@@ -782,13 +789,13 @@ class ConversationManager:
|
|
|
782
789
|
import re
|
|
783
790
|
|
|
784
791
|
# Remove [TOOL_RESULTS] prefix if present
|
|
785
|
-
if content.startswith(
|
|
786
|
-
content = content[len(
|
|
792
|
+
if content.startswith(_TOOL_RESULTS_MARKER):
|
|
793
|
+
content = content[len(_TOOL_RESULTS_MARKER):].strip()
|
|
787
794
|
|
|
788
795
|
# Try to parse as JSON
|
|
789
796
|
try:
|
|
790
797
|
data = json.loads(content)
|
|
791
|
-
except:
|
|
798
|
+
except ValueError:
|
|
792
799
|
# Not JSON, try to extract numbers from text
|
|
793
800
|
data = None
|
|
794
801
|
|
|
@@ -861,7 +868,7 @@ class ConversationManager:
|
|
|
861
868
|
content = msg['content']
|
|
862
869
|
|
|
863
870
|
# Parse and clean tool-related content for better summarization
|
|
864
|
-
if content.startswith(
|
|
871
|
+
if content.startswith(_TOOL_RESULTS_MARKER):
|
|
865
872
|
# Extract numerical data from tool results
|
|
866
873
|
numerical_summary = self._extract_numerical_data(content)
|
|
867
874
|
if numerical_summary:
|
|
@@ -887,7 +894,7 @@ class ConversationManager:
|
|
|
887
894
|
conversation_text.append(f"{role}: {' '.join(text_parts)}")
|
|
888
895
|
if tool_parts:
|
|
889
896
|
conversation_text.append(f"{role}: [Called tools: {', '.join(tool_parts)}]")
|
|
890
|
-
except:
|
|
897
|
+
except ValueError:
|
|
891
898
|
# If parsing fails, include content as-is
|
|
892
899
|
conversation_text.append(f"{role}: {content}")
|
|
893
900
|
else:
|
|
@@ -1506,7 +1513,7 @@ Current date and time: {datetime_str}"""
|
|
|
1506
1513
|
Assistant's response content or None on failure
|
|
1507
1514
|
"""
|
|
1508
1515
|
if not self.current_conversation_id:
|
|
1509
|
-
raise ValueError(
|
|
1516
|
+
raise ValueError(_ERR_NO_ACTIVE_CONVERSATION)
|
|
1510
1517
|
|
|
1511
1518
|
logging.debug(f"send_message called with: {user_message[:50]}...")
|
|
1512
1519
|
|
|
@@ -1898,7 +1905,7 @@ Current date and time: {datetime_str}"""
|
|
|
1898
1905
|
|
|
1899
1906
|
# Add tool results as a user message
|
|
1900
1907
|
tool_results_json = json.dumps(tool_results)
|
|
1901
|
-
self.add_user_message(f"
|
|
1908
|
+
self.add_user_message(f"{_TOOL_RESULTS_MARKER}{tool_results_json}")
|
|
1902
1909
|
|
|
1903
1910
|
# Continue loop to get model's next response
|
|
1904
1911
|
continue
|
|
@@ -2339,7 +2346,7 @@ Current date and time: {datetime_str}"""
|
|
|
2339
2346
|
Markdown-formatted string of the conversation
|
|
2340
2347
|
"""
|
|
2341
2348
|
if not self.current_conversation_id:
|
|
2342
|
-
logging.warning(
|
|
2349
|
+
logging.warning(_ERR_NO_CONVERSATION_TO_EXPORT)
|
|
2343
2350
|
return ""
|
|
2344
2351
|
|
|
2345
2352
|
# Get conversation info
|
|
@@ -2389,8 +2396,8 @@ Current date and time: {datetime_str}"""
|
|
|
2389
2396
|
content = msg['content']
|
|
2390
2397
|
|
|
2391
2398
|
# Detect special message types
|
|
2392
|
-
is_rollup_summary = content.startswith(
|
|
2393
|
-
is_tool_result = content.startswith(
|
|
2399
|
+
is_rollup_summary = content.startswith(_SUMMARY_MARKER)
|
|
2400
|
+
is_tool_result = content.startswith(_TOOL_RESULTS_MARKER)
|
|
2394
2401
|
|
|
2395
2402
|
# Check if this is a tool call message (assistant with tool_use blocks)
|
|
2396
2403
|
is_tool_call = False
|
|
@@ -2399,7 +2406,7 @@ Current date and time: {datetime_str}"""
|
|
|
2399
2406
|
content_blocks = json.loads(content)
|
|
2400
2407
|
if isinstance(content_blocks, list) and any(block.get('type') == 'tool_use' for block in content_blocks):
|
|
2401
2408
|
is_tool_call = True
|
|
2402
|
-
except:
|
|
2409
|
+
except ValueError:
|
|
2403
2410
|
pass
|
|
2404
2411
|
|
|
2405
2412
|
# Format role header based on message type
|
|
@@ -2420,10 +2427,10 @@ Current date and time: {datetime_str}"""
|
|
|
2420
2427
|
md_lines.append("")
|
|
2421
2428
|
|
|
2422
2429
|
# Clean up content if it's tool-related
|
|
2423
|
-
if content.startswith(
|
|
2430
|
+
if content.startswith(_TOOL_RESULTS_MARKER) and include_tools:
|
|
2424
2431
|
# Parse and format tool results
|
|
2425
2432
|
try:
|
|
2426
|
-
tool_results_json = content.replace(
|
|
2433
|
+
tool_results_json = content.replace(_TOOL_RESULTS_MARKER, '', 1)
|
|
2427
2434
|
tool_results = json.loads(tool_results_json)
|
|
2428
2435
|
md_lines.append("**Tool Results:**")
|
|
2429
2436
|
md_lines.append("")
|
|
@@ -2431,10 +2438,10 @@ Current date and time: {datetime_str}"""
|
|
|
2431
2438
|
md_lines.append(f"- Tool: `{result.get('tool_use_id', 'unknown')}`")
|
|
2432
2439
|
md_lines.append(f" Result: {result.get('content', '')}")
|
|
2433
2440
|
md_lines.append("")
|
|
2434
|
-
except:
|
|
2441
|
+
except ValueError:
|
|
2435
2442
|
md_lines.append(content)
|
|
2436
2443
|
md_lines.append("")
|
|
2437
|
-
elif content.startswith(
|
|
2444
|
+
elif content.startswith(_TOOL_RESULTS_MARKER) and not include_tools:
|
|
2438
2445
|
# Skip tool results if not including tools
|
|
2439
2446
|
md_lines.append("*[Tool execution details omitted]*")
|
|
2440
2447
|
md_lines.append("")
|
|
@@ -2450,7 +2457,7 @@ Current date and time: {datetime_str}"""
|
|
|
2450
2457
|
md_lines.append(f"**Tool Call:** `{block.get('name')}`")
|
|
2451
2458
|
md_lines.append(f"**Input:** {json.dumps(block.get('input', {}), indent=2)}")
|
|
2452
2459
|
md_lines.append("")
|
|
2453
|
-
except:
|
|
2460
|
+
except ValueError:
|
|
2454
2461
|
md_lines.append(content)
|
|
2455
2462
|
md_lines.append("")
|
|
2456
2463
|
else:
|
|
@@ -2574,7 +2581,7 @@ Current date and time: {datetime_str}"""
|
|
|
2574
2581
|
True if successful, False otherwise
|
|
2575
2582
|
"""
|
|
2576
2583
|
if not self.current_conversation_id:
|
|
2577
|
-
logging.warning(
|
|
2584
|
+
logging.warning(_ERR_NO_CONVERSATION_TO_EXPORT)
|
|
2578
2585
|
return False
|
|
2579
2586
|
|
|
2580
2587
|
try:
|
|
@@ -2814,8 +2821,8 @@ Current date and time: {datetime_str}"""
|
|
|
2814
2821
|
content = msg['content']
|
|
2815
2822
|
|
|
2816
2823
|
# Detect special message types
|
|
2817
|
-
is_rollup_summary = content.startswith(
|
|
2818
|
-
is_tool_result = content.startswith(
|
|
2824
|
+
is_rollup_summary = content.startswith(_SUMMARY_MARKER)
|
|
2825
|
+
is_tool_result = content.startswith(_TOOL_RESULTS_MARKER)
|
|
2819
2826
|
|
|
2820
2827
|
# Check if this is a tool call message (assistant with tool_use blocks)
|
|
2821
2828
|
is_tool_call = False
|
|
@@ -2824,7 +2831,7 @@ Current date and time: {datetime_str}"""
|
|
|
2824
2831
|
content_blocks = json.loads(content)
|
|
2825
2832
|
if isinstance(content_blocks, list) and any(block.get('type') == 'tool_use' for block in content_blocks):
|
|
2826
2833
|
is_tool_call = True
|
|
2827
|
-
except:
|
|
2834
|
+
except ValueError:
|
|
2828
2835
|
pass
|
|
2829
2836
|
|
|
2830
2837
|
# Assign message class and labels based on type
|
|
@@ -2854,9 +2861,9 @@ Current date and time: {datetime_str}"""
|
|
|
2854
2861
|
''')
|
|
2855
2862
|
|
|
2856
2863
|
# Process content
|
|
2857
|
-
if content.startswith(
|
|
2864
|
+
if content.startswith(_TOOL_RESULTS_MARKER) and include_tools:
|
|
2858
2865
|
try:
|
|
2859
|
-
tool_results_json = content.replace(
|
|
2866
|
+
tool_results_json = content.replace(_TOOL_RESULTS_MARKER, '', 1)
|
|
2860
2867
|
tool_results = json.loads(tool_results_json)
|
|
2861
2868
|
html_parts.append(''' <div class="tool-section">
|
|
2862
2869
|
<div class="tool-title">🔧 Tool Results:</div>
|
|
@@ -2874,10 +2881,10 @@ Current date and time: {datetime_str}"""
|
|
|
2874
2881
|
''')
|
|
2875
2882
|
html_parts.append(''' </div>
|
|
2876
2883
|
''')
|
|
2877
|
-
except:
|
|
2884
|
+
except ValueError:
|
|
2878
2885
|
html_parts.append(f''' {content.replace('<', '<').replace('>', '>')}
|
|
2879
2886
|
''')
|
|
2880
|
-
elif content.startswith(
|
|
2887
|
+
elif content.startswith(_TOOL_RESULTS_MARKER) and not include_tools:
|
|
2881
2888
|
html_parts.append(''' <em>[Tool execution details omitted]</em>
|
|
2882
2889
|
''')
|
|
2883
2890
|
elif content.startswith('['):
|
|
@@ -2893,7 +2900,7 @@ Current date and time: {datetime_str}"""
|
|
|
2893
2900
|
<pre>{json.dumps(block.get('input', {}), indent=2)}</pre>
|
|
2894
2901
|
</div>
|
|
2895
2902
|
''')
|
|
2896
|
-
except:
|
|
2903
|
+
except ValueError:
|
|
2897
2904
|
html_parts.append(f''' {content.replace('<', '<').replace('>', '>')}
|
|
2898
2905
|
''')
|
|
2899
2906
|
else:
|
|
@@ -2936,7 +2943,7 @@ Current date and time: {datetime_str}"""
|
|
|
2936
2943
|
True if successful, False otherwise
|
|
2937
2944
|
"""
|
|
2938
2945
|
if not self.current_conversation_id:
|
|
2939
|
-
logging.warning(
|
|
2946
|
+
logging.warning(_ERR_NO_CONVERSATION_TO_EXPORT)
|
|
2940
2947
|
return False
|
|
2941
2948
|
|
|
2942
2949
|
try:
|
|
@@ -2951,7 +2958,7 @@ Current date and time: {datetime_str}"""
|
|
|
2951
2958
|
messages = self.get_conversation_history(include_rolled_up=True)
|
|
2952
2959
|
|
|
2953
2960
|
with open(file_path, 'w', newline='', encoding='utf-8') as csvfile:
|
|
2954
|
-
fieldnames = ['Timestamp', 'Type', 'Role', 'Content',
|
|
2961
|
+
fieldnames = ['Timestamp', 'Type', 'Role', 'Content', _LABEL_TOKEN_COUNT]
|
|
2955
2962
|
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|
|
2956
2963
|
|
|
2957
2964
|
# Write header
|
|
@@ -2963,21 +2970,21 @@ Current date and time: {datetime_str}"""
|
|
|
2963
2970
|
'Type': '',
|
|
2964
2971
|
'Role': 'Conversation',
|
|
2965
2972
|
'Content': conv_info['name'],
|
|
2966
|
-
|
|
2973
|
+
_LABEL_TOKEN_COUNT: ''
|
|
2967
2974
|
})
|
|
2968
2975
|
writer.writerow({
|
|
2969
2976
|
'Timestamp': 'METADATA',
|
|
2970
2977
|
'Type': '',
|
|
2971
2978
|
'Role': 'Model',
|
|
2972
2979
|
'Content': conv_info['model_id'],
|
|
2973
|
-
|
|
2980
|
+
_LABEL_TOKEN_COUNT: ''
|
|
2974
2981
|
})
|
|
2975
2982
|
writer.writerow({
|
|
2976
2983
|
'Timestamp': 'METADATA',
|
|
2977
2984
|
'Type': '',
|
|
2978
2985
|
'Role': 'Total Tokens',
|
|
2979
2986
|
'Content': str(conv_info['total_tokens']),
|
|
2980
|
-
|
|
2987
|
+
_LABEL_TOKEN_COUNT: ''
|
|
2981
2988
|
})
|
|
2982
2989
|
|
|
2983
2990
|
# Write messages
|
|
@@ -2987,8 +2994,8 @@ Current date and time: {datetime_str}"""
|
|
|
2987
2994
|
content = msg['content']
|
|
2988
2995
|
|
|
2989
2996
|
# Detect special message types
|
|
2990
|
-
is_rollup_summary = content.startswith(
|
|
2991
|
-
is_tool_result = content.startswith(
|
|
2997
|
+
is_rollup_summary = content.startswith(_SUMMARY_MARKER)
|
|
2998
|
+
is_tool_result = content.startswith(_TOOL_RESULTS_MARKER)
|
|
2992
2999
|
|
|
2993
3000
|
# Check if this is a tool call message
|
|
2994
3001
|
is_tool_call = False
|
|
@@ -2997,7 +3004,7 @@ Current date and time: {datetime_str}"""
|
|
|
2997
3004
|
content_blocks = json.loads(content)
|
|
2998
3005
|
if isinstance(content_blocks, list) and any(block.get('type') == 'tool_use' for block in content_blocks):
|
|
2999
3006
|
is_tool_call = True
|
|
3000
|
-
except:
|
|
3007
|
+
except ValueError:
|
|
3001
3008
|
pass
|
|
3002
3009
|
|
|
3003
3010
|
# Assign type label
|
|
@@ -3011,13 +3018,13 @@ Current date and time: {datetime_str}"""
|
|
|
3011
3018
|
msg_type = 'Message'
|
|
3012
3019
|
|
|
3013
3020
|
# Process tool-related content
|
|
3014
|
-
if content.startswith(
|
|
3021
|
+
if content.startswith(_TOOL_RESULTS_MARKER):
|
|
3015
3022
|
if include_tools:
|
|
3016
3023
|
try:
|
|
3017
|
-
tool_results_json = content.replace(
|
|
3024
|
+
tool_results_json = content.replace(_TOOL_RESULTS_MARKER, '', 1)
|
|
3018
3025
|
tool_results = json.loads(tool_results_json)
|
|
3019
3026
|
content = f"Tool Results: {json.dumps(tool_results, indent=2)}"
|
|
3020
|
-
except:
|
|
3027
|
+
except ValueError:
|
|
3021
3028
|
pass
|
|
3022
3029
|
else:
|
|
3023
3030
|
content = "[Tool execution details omitted]"
|
|
@@ -3031,7 +3038,7 @@ Current date and time: {datetime_str}"""
|
|
|
3031
3038
|
elif block.get('type') == 'tool_use' and include_tools:
|
|
3032
3039
|
text_parts.append(f"Tool Call: {block.get('name')} - Input: {json.dumps(block.get('input', {}))}")
|
|
3033
3040
|
content = '\n'.join(text_parts) if text_parts else content
|
|
3034
|
-
except:
|
|
3041
|
+
except ValueError:
|
|
3035
3042
|
pass
|
|
3036
3043
|
|
|
3037
3044
|
writer.writerow({
|
|
@@ -3039,7 +3046,7 @@ Current date and time: {datetime_str}"""
|
|
|
3039
3046
|
'Type': msg_type,
|
|
3040
3047
|
'Role': role,
|
|
3041
3048
|
'Content': content,
|
|
3042
|
-
|
|
3049
|
+
_LABEL_TOKEN_COUNT: msg.get('token_count', '')
|
|
3043
3050
|
})
|
|
3044
3051
|
|
|
3045
3052
|
logging.info(f"Exported conversation to CSV: {file_path}")
|