abstractassistant 0.3.2__py3-none-any.whl → 0.3.4__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.
- abstractassistant/create_app_bundle.py +350 -8
- abstractassistant/ui/chat_bubble.py +15 -2
- abstractassistant/ui/history_dialog.py +575 -51
- abstractassistant/ui/qt_bubble.py +434 -8
- {abstractassistant-0.3.2.dist-info → abstractassistant-0.3.4.dist-info}/METADATA +21 -21
- {abstractassistant-0.3.2.dist-info → abstractassistant-0.3.4.dist-info}/RECORD +10 -11
- {abstractassistant-0.3.2.dist-info → abstractassistant-0.3.4.dist-info}/top_level.txt +0 -1
- setup_macos_app.py +0 -323
- {abstractassistant-0.3.2.dist-info → abstractassistant-0.3.4.dist-info}/WHEEL +0 -0
- {abstractassistant-0.3.2.dist-info → abstractassistant-0.3.4.dist-info}/entry_points.txt +0 -0
- {abstractassistant-0.3.2.dist-info → abstractassistant-0.3.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -405,6 +405,7 @@ class QtChatBubble(QWidget):
|
|
|
405
405
|
("Clear", self.clear_session),
|
|
406
406
|
("Load", self.load_session),
|
|
407
407
|
("Save", self.save_session),
|
|
408
|
+
# ("Compact", self.compact_session), # Hidden for now - functionality preserved
|
|
408
409
|
("History", self.show_history)
|
|
409
410
|
]
|
|
410
411
|
|
|
@@ -1070,13 +1071,15 @@ class QtChatBubble(QWidget):
|
|
|
1070
1071
|
|
|
1071
1072
|
# Check for Enter/Return key
|
|
1072
1073
|
if event.key() == Qt.Key.Key_Return or event.key() == Qt.Key.Key_Enter:
|
|
1073
|
-
# Shift+Enter
|
|
1074
|
-
if
|
|
1075
|
-
|
|
1076
|
-
|
|
1074
|
+
# Shift+Enter should add a new line
|
|
1075
|
+
if event.modifiers() & Qt.KeyboardModifier.ShiftModifier:
|
|
1076
|
+
# Allow default behavior (new line)
|
|
1077
|
+
QTextEdit.keyPressEvent(self.input_text, event)
|
|
1078
|
+
return
|
|
1079
|
+
# Plain Enter should send message
|
|
1080
|
+
else:
|
|
1077
1081
|
self.send_message()
|
|
1078
1082
|
return
|
|
1079
|
-
# Plain Enter should add a new line (default behavior)
|
|
1080
1083
|
|
|
1081
1084
|
# Call original keyPressEvent for all other keys
|
|
1082
1085
|
QTextEdit.keyPressEvent(self.input_text, event)
|
|
@@ -1969,6 +1972,268 @@ class QtChatBubble(QWidget):
|
|
|
1969
1972
|
if self.debug:
|
|
1970
1973
|
print("🧹 Session cleared (including attached files and file tracking)")
|
|
1971
1974
|
|
|
1975
|
+
def compact_session(self):
|
|
1976
|
+
"""Compact the current session using AbstractCore's summarizer functionality."""
|
|
1977
|
+
if not self.message_history:
|
|
1978
|
+
QMessageBox.information(
|
|
1979
|
+
self,
|
|
1980
|
+
"No Session",
|
|
1981
|
+
"No conversation history to compact. Start a conversation first."
|
|
1982
|
+
)
|
|
1983
|
+
return
|
|
1984
|
+
|
|
1985
|
+
# Check if session is too short to compact
|
|
1986
|
+
if len(self.message_history) < 4: # Need at least 2 exchanges to be worth compacting
|
|
1987
|
+
QMessageBox.information(
|
|
1988
|
+
self,
|
|
1989
|
+
"Session Too Short",
|
|
1990
|
+
"Session is too short to compact. Need at least 2 exchanges (4 messages)."
|
|
1991
|
+
)
|
|
1992
|
+
return
|
|
1993
|
+
|
|
1994
|
+
reply = QMessageBox.question(
|
|
1995
|
+
self,
|
|
1996
|
+
"Compact Session",
|
|
1997
|
+
"This will summarize the conversation history into a concise system message, "
|
|
1998
|
+
"keeping only the most recent 2 exchanges for context.\n\n"
|
|
1999
|
+
"This action cannot be undone. Continue?",
|
|
2000
|
+
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
|
2001
|
+
QMessageBox.StandardButton.No
|
|
2002
|
+
)
|
|
2003
|
+
|
|
2004
|
+
if reply == QMessageBox.StandardButton.Yes:
|
|
2005
|
+
try:
|
|
2006
|
+
# Show progress
|
|
2007
|
+
self.status_label.setText("compacting")
|
|
2008
|
+
self.status_label.setStyleSheet("""
|
|
2009
|
+
QLabel {
|
|
2010
|
+
background: rgba(250, 179, 135, 0.2);
|
|
2011
|
+
border: 1px solid rgba(250, 179, 135, 0.3);
|
|
2012
|
+
border-radius: 12px;
|
|
2013
|
+
padding: 4px 12px;
|
|
2014
|
+
font-size: 11px;
|
|
2015
|
+
font-weight: 600;
|
|
2016
|
+
text-transform: uppercase;
|
|
2017
|
+
letter-spacing: 0.5px;
|
|
2018
|
+
color: #fab387;
|
|
2019
|
+
}
|
|
2020
|
+
""")
|
|
2021
|
+
|
|
2022
|
+
# Notify main app about status change
|
|
2023
|
+
if self.status_callback:
|
|
2024
|
+
self.status_callback("compacting")
|
|
2025
|
+
|
|
2026
|
+
# Create conversation text for summarization
|
|
2027
|
+
conversation_text = self._format_conversation_for_summarization()
|
|
2028
|
+
|
|
2029
|
+
# Use AbstractCore's summarizer functionality through LLMManager
|
|
2030
|
+
summary = self._generate_conversation_summary(conversation_text)
|
|
2031
|
+
|
|
2032
|
+
if summary:
|
|
2033
|
+
# Keep the last 2 exchanges (4 messages) for context
|
|
2034
|
+
recent_messages = self.message_history[-4:] if len(self.message_history) >= 4 else self.message_history[-2:]
|
|
2035
|
+
|
|
2036
|
+
# Create new session with summary as system context
|
|
2037
|
+
self._create_compacted_session(summary, recent_messages)
|
|
2038
|
+
|
|
2039
|
+
# Update UI
|
|
2040
|
+
self.token_count = 0 # Reset token count
|
|
2041
|
+
self.update_token_display()
|
|
2042
|
+
|
|
2043
|
+
# Show success message
|
|
2044
|
+
QMessageBox.information(
|
|
2045
|
+
self,
|
|
2046
|
+
"Session Compacted",
|
|
2047
|
+
f"Session successfully compacted!\n\n"
|
|
2048
|
+
f"Original: {len(self.message_history)} messages\n"
|
|
2049
|
+
f"Compacted: Summary + {len(recent_messages)} recent messages"
|
|
2050
|
+
)
|
|
2051
|
+
|
|
2052
|
+
if self.debug:
|
|
2053
|
+
print(f"🗜️ Session compacted: {len(self.message_history)} -> summary + {len(recent_messages)} recent")
|
|
2054
|
+
else:
|
|
2055
|
+
raise Exception("Failed to generate summary")
|
|
2056
|
+
|
|
2057
|
+
except Exception as e:
|
|
2058
|
+
QMessageBox.critical(
|
|
2059
|
+
self,
|
|
2060
|
+
"Compaction Error",
|
|
2061
|
+
f"Failed to compact session:\n{str(e)}"
|
|
2062
|
+
)
|
|
2063
|
+
if self.debug:
|
|
2064
|
+
print(f"❌ Failed to compact session: {e}")
|
|
2065
|
+
import traceback
|
|
2066
|
+
traceback.print_exc()
|
|
2067
|
+
finally:
|
|
2068
|
+
# Reset status
|
|
2069
|
+
self.status_label.setText("ready")
|
|
2070
|
+
self.status_label.setStyleSheet("""
|
|
2071
|
+
QLabel {
|
|
2072
|
+
background: rgba(166, 227, 161, 0.2);
|
|
2073
|
+
border: 1px solid rgba(166, 227, 161, 0.3);
|
|
2074
|
+
border-radius: 12px;
|
|
2075
|
+
padding: 4px 12px;
|
|
2076
|
+
font-size: 11px;
|
|
2077
|
+
font-weight: 600;
|
|
2078
|
+
text-transform: uppercase;
|
|
2079
|
+
letter-spacing: 0.5px;
|
|
2080
|
+
color: #a6e3a1;
|
|
2081
|
+
}
|
|
2082
|
+
""")
|
|
2083
|
+
if self.status_callback:
|
|
2084
|
+
self.status_callback("ready")
|
|
2085
|
+
|
|
2086
|
+
def _format_conversation_for_summarization(self) -> str:
|
|
2087
|
+
"""Format the conversation history for summarization."""
|
|
2088
|
+
lines = []
|
|
2089
|
+
lines.append("=== CONVERSATION HISTORY ===\n")
|
|
2090
|
+
|
|
2091
|
+
for i, msg in enumerate(self.message_history):
|
|
2092
|
+
role = "USER" if msg.get('type') == 'user' else "ASSISTANT"
|
|
2093
|
+
content = msg.get('content', '')
|
|
2094
|
+
timestamp = msg.get('timestamp', '')
|
|
2095
|
+
|
|
2096
|
+
# Add timestamp if available
|
|
2097
|
+
if timestamp:
|
|
2098
|
+
try:
|
|
2099
|
+
from datetime import datetime
|
|
2100
|
+
if isinstance(timestamp, str):
|
|
2101
|
+
dt = datetime.fromisoformat(timestamp)
|
|
2102
|
+
time_str = dt.strftime("%Y-%m-%d %H:%M")
|
|
2103
|
+
lines.append(f"[{time_str}] {role}:")
|
|
2104
|
+
else:
|
|
2105
|
+
lines.append(f"{role}:")
|
|
2106
|
+
except:
|
|
2107
|
+
lines.append(f"{role}:")
|
|
2108
|
+
else:
|
|
2109
|
+
lines.append(f"{role}:")
|
|
2110
|
+
|
|
2111
|
+
lines.append(content)
|
|
2112
|
+
lines.append("") # Empty line between messages
|
|
2113
|
+
|
|
2114
|
+
return "\n".join(lines)
|
|
2115
|
+
|
|
2116
|
+
def _generate_conversation_summary(self, conversation_text: str) -> str:
|
|
2117
|
+
"""Generate a conversation summary using AbstractCore's summarizer functionality."""
|
|
2118
|
+
try:
|
|
2119
|
+
# Use the current LLM to generate a summary
|
|
2120
|
+
# This mimics what the AbstractCore summarizer CLI does
|
|
2121
|
+
summary_prompt = f"""Please provide a comprehensive but concise summary of the following conversation.
|
|
2122
|
+
Focus on:
|
|
2123
|
+
- Key topics discussed
|
|
2124
|
+
- Important decisions or conclusions reached
|
|
2125
|
+
- Relevant context that should be preserved
|
|
2126
|
+
- Any ongoing tasks or questions
|
|
2127
|
+
|
|
2128
|
+
The summary should be detailed enough to provide context for continuing the conversation, but concise enough to save tokens.
|
|
2129
|
+
|
|
2130
|
+
Conversation to summarize:
|
|
2131
|
+
{conversation_text}
|
|
2132
|
+
|
|
2133
|
+
Please provide the summary in a clear, structured format:"""
|
|
2134
|
+
|
|
2135
|
+
if self.llm_manager and self.llm_manager.llm:
|
|
2136
|
+
# Generate summary using current LLM
|
|
2137
|
+
response = self.llm_manager.llm.generate(summary_prompt)
|
|
2138
|
+
|
|
2139
|
+
if hasattr(response, 'content'):
|
|
2140
|
+
return response.content
|
|
2141
|
+
else:
|
|
2142
|
+
return str(response)
|
|
2143
|
+
else:
|
|
2144
|
+
raise Exception("No LLM available for summarization")
|
|
2145
|
+
|
|
2146
|
+
except Exception as e:
|
|
2147
|
+
if self.debug:
|
|
2148
|
+
print(f"❌ Error generating summary: {e}")
|
|
2149
|
+
raise
|
|
2150
|
+
|
|
2151
|
+
def _create_compacted_session(self, summary: str, recent_messages: list):
|
|
2152
|
+
"""Create a new session with the summary and recent messages."""
|
|
2153
|
+
try:
|
|
2154
|
+
# Create new session with summary as enhanced system prompt
|
|
2155
|
+
enhanced_system_prompt = f"""You are a helpful AI assistant who has access to tools to help the user.
|
|
2156
|
+
Always be a critical and creative thinker who leverage constructive skepticism to progress and evolve its reasoning and answers.
|
|
2157
|
+
Always answer in nicely formatted markdown.
|
|
2158
|
+
|
|
2159
|
+
=== CONVERSATION CONTEXT ===
|
|
2160
|
+
The following is a summary of our previous conversation:
|
|
2161
|
+
|
|
2162
|
+
{summary}
|
|
2163
|
+
|
|
2164
|
+
=== END CONTEXT ===
|
|
2165
|
+
|
|
2166
|
+
Continue the conversation naturally, referring to the context above when relevant."""
|
|
2167
|
+
|
|
2168
|
+
# Create new session with enhanced system prompt
|
|
2169
|
+
if self.llm_manager:
|
|
2170
|
+
# Create new session with custom system prompt
|
|
2171
|
+
from abstractcore import BasicSession
|
|
2172
|
+
|
|
2173
|
+
# Prepare tools list (same as in LLMManager)
|
|
2174
|
+
tools = []
|
|
2175
|
+
try:
|
|
2176
|
+
from abstractcore.tools.common_tools import (
|
|
2177
|
+
list_files, search_files, read_file, edit_file,
|
|
2178
|
+
write_file, execute_command, web_search
|
|
2179
|
+
)
|
|
2180
|
+
tools = [
|
|
2181
|
+
list_files, search_files, read_file, edit_file,
|
|
2182
|
+
write_file, execute_command, web_search
|
|
2183
|
+
]
|
|
2184
|
+
except ImportError:
|
|
2185
|
+
pass
|
|
2186
|
+
|
|
2187
|
+
# Create new session with summary in system prompt
|
|
2188
|
+
new_session = BasicSession(
|
|
2189
|
+
self.llm_manager.llm,
|
|
2190
|
+
system_prompt=enhanced_system_prompt,
|
|
2191
|
+
tools=tools
|
|
2192
|
+
)
|
|
2193
|
+
|
|
2194
|
+
# Add recent messages to the new session
|
|
2195
|
+
for msg in recent_messages:
|
|
2196
|
+
if msg.get('type') == 'user':
|
|
2197
|
+
# Add user message without generating response
|
|
2198
|
+
from abstractcore.messages import UserMessage
|
|
2199
|
+
user_msg = UserMessage(content=msg.get('content', ''))
|
|
2200
|
+
new_session.messages.append(user_msg)
|
|
2201
|
+
elif msg.get('type') == 'assistant':
|
|
2202
|
+
# Add assistant message
|
|
2203
|
+
from abstractcore.messages import AssistantMessage
|
|
2204
|
+
assistant_msg = AssistantMessage(content=msg.get('content', ''))
|
|
2205
|
+
new_session.messages.append(assistant_msg)
|
|
2206
|
+
|
|
2207
|
+
# Replace current session
|
|
2208
|
+
self.llm_manager.current_session = new_session
|
|
2209
|
+
|
|
2210
|
+
# Update local message history to reflect the compacted state
|
|
2211
|
+
# Create a special "system" message to represent the summary
|
|
2212
|
+
compacted_history = [
|
|
2213
|
+
{
|
|
2214
|
+
'timestamp': datetime.now().isoformat(),
|
|
2215
|
+
'type': 'system',
|
|
2216
|
+
'content': f"📋 **Session Compacted**\n\n{summary}",
|
|
2217
|
+
'provider': self.current_provider,
|
|
2218
|
+
'model': self.current_model,
|
|
2219
|
+
'attached_files': []
|
|
2220
|
+
}
|
|
2221
|
+
]
|
|
2222
|
+
|
|
2223
|
+
# Add recent messages
|
|
2224
|
+
compacted_history.extend(recent_messages)
|
|
2225
|
+
|
|
2226
|
+
# Update message history
|
|
2227
|
+
self.message_history = compacted_history
|
|
2228
|
+
|
|
2229
|
+
if self.debug:
|
|
2230
|
+
print(f"✅ Created compacted session with enhanced system prompt")
|
|
2231
|
+
|
|
2232
|
+
except Exception as e:
|
|
2233
|
+
if self.debug:
|
|
2234
|
+
print(f"❌ Error creating compacted session: {e}")
|
|
2235
|
+
raise
|
|
2236
|
+
|
|
1972
2237
|
def load_session(self):
|
|
1973
2238
|
"""Load a session using AbstractCore via LLMManager."""
|
|
1974
2239
|
file_path, _ = QFileDialog.getOpenFileName(
|
|
@@ -2190,8 +2455,12 @@ class QtChatBubble(QWidget):
|
|
|
2190
2455
|
# Toggle behavior: create dialog if doesn't exist, toggle visibility if it does
|
|
2191
2456
|
if iPhoneMessagesDialog:
|
|
2192
2457
|
if self.history_dialog is None:
|
|
2193
|
-
# Create dialog first time
|
|
2194
|
-
self.history_dialog = iPhoneMessagesDialog.create_dialog(
|
|
2458
|
+
# Create dialog first time with deletion support
|
|
2459
|
+
self.history_dialog = iPhoneMessagesDialog.create_dialog(
|
|
2460
|
+
self.message_history,
|
|
2461
|
+
self,
|
|
2462
|
+
delete_callback=self._handle_message_deletion
|
|
2463
|
+
)
|
|
2195
2464
|
# Set callback to update button when dialog is hidden via Back button
|
|
2196
2465
|
self.history_dialog.set_hide_callback(lambda: self._update_history_button_appearance(False))
|
|
2197
2466
|
self.history_dialog.show()
|
|
@@ -2203,7 +2472,11 @@ class QtChatBubble(QWidget):
|
|
|
2203
2472
|
self._update_history_button_appearance(False)
|
|
2204
2473
|
else:
|
|
2205
2474
|
# Update dialog with latest messages before showing
|
|
2206
|
-
self.history_dialog = iPhoneMessagesDialog.create_dialog(
|
|
2475
|
+
self.history_dialog = iPhoneMessagesDialog.create_dialog(
|
|
2476
|
+
self.message_history,
|
|
2477
|
+
self,
|
|
2478
|
+
delete_callback=self._handle_message_deletion
|
|
2479
|
+
)
|
|
2207
2480
|
# Set callback to update button when dialog is hidden via Back button
|
|
2208
2481
|
self.history_dialog.set_hide_callback(lambda: self._update_history_button_appearance(False))
|
|
2209
2482
|
self.history_dialog.show()
|
|
@@ -2254,6 +2527,159 @@ class QtChatBubble(QWidget):
|
|
|
2254
2527
|
}
|
|
2255
2528
|
""")
|
|
2256
2529
|
|
|
2530
|
+
def _handle_message_deletion(self, indices_to_delete: List[int]):
|
|
2531
|
+
"""Handle deletion of messages from the history dialog."""
|
|
2532
|
+
try:
|
|
2533
|
+
if not indices_to_delete:
|
|
2534
|
+
return
|
|
2535
|
+
|
|
2536
|
+
# Validate indices
|
|
2537
|
+
for index in indices_to_delete:
|
|
2538
|
+
if not (0 <= index < len(self.message_history)):
|
|
2539
|
+
QMessageBox.critical(
|
|
2540
|
+
self,
|
|
2541
|
+
"Invalid Selection",
|
|
2542
|
+
f"Invalid message index {index}. Please refresh and try again."
|
|
2543
|
+
)
|
|
2544
|
+
return
|
|
2545
|
+
|
|
2546
|
+
# Delete messages from local history (indices are sorted in reverse order)
|
|
2547
|
+
original_count = len(self.message_history)
|
|
2548
|
+
|
|
2549
|
+
for index in indices_to_delete:
|
|
2550
|
+
if 0 <= index < len(self.message_history):
|
|
2551
|
+
del self.message_history[index]
|
|
2552
|
+
|
|
2553
|
+
# Update AbstractCore session to reflect deletions
|
|
2554
|
+
self._update_abstractcore_session_after_deletion()
|
|
2555
|
+
|
|
2556
|
+
# Update token count
|
|
2557
|
+
self._update_token_count_from_session()
|
|
2558
|
+
|
|
2559
|
+
# Update history dialog if it's open (keep it open!)
|
|
2560
|
+
if self.history_dialog and self.history_dialog.isVisible():
|
|
2561
|
+
try:
|
|
2562
|
+
# Update the dialog content without closing it
|
|
2563
|
+
self.history_dialog.update_message_history(self.message_history)
|
|
2564
|
+
except Exception as dialog_error:
|
|
2565
|
+
import traceback
|
|
2566
|
+
traceback.print_exc()
|
|
2567
|
+
# Fallback: recreate dialog if update fails
|
|
2568
|
+
try:
|
|
2569
|
+
if len(self.message_history) == 0:
|
|
2570
|
+
self.history_dialog.hide()
|
|
2571
|
+
self._update_history_button_appearance(False)
|
|
2572
|
+
else:
|
|
2573
|
+
new_dialog = iPhoneMessagesDialog.create_dialog(
|
|
2574
|
+
self.message_history,
|
|
2575
|
+
self,
|
|
2576
|
+
delete_callback=self._handle_message_deletion
|
|
2577
|
+
)
|
|
2578
|
+
if new_dialog:
|
|
2579
|
+
old_pos = self.history_dialog.pos()
|
|
2580
|
+
self.history_dialog.hide()
|
|
2581
|
+
self.history_dialog = new_dialog
|
|
2582
|
+
self.history_dialog.move(old_pos) # Keep same position
|
|
2583
|
+
self.history_dialog.set_hide_callback(lambda: self._update_history_button_appearance(False))
|
|
2584
|
+
self.history_dialog.show()
|
|
2585
|
+
except:
|
|
2586
|
+
try:
|
|
2587
|
+
self.history_dialog.hide()
|
|
2588
|
+
self._update_history_button_appearance(False)
|
|
2589
|
+
except:
|
|
2590
|
+
pass
|
|
2591
|
+
|
|
2592
|
+
# Log success (no popup)
|
|
2593
|
+
deleted_count = original_count - len(self.message_history)
|
|
2594
|
+
|
|
2595
|
+
if self.debug:
|
|
2596
|
+
print(f"🗑️ Deleted {deleted_count} messages from history")
|
|
2597
|
+
|
|
2598
|
+
except Exception as e:
|
|
2599
|
+
print(f"❌ Critical error in _handle_message_deletion: {e}")
|
|
2600
|
+
import traceback
|
|
2601
|
+
traceback.print_exc()
|
|
2602
|
+
|
|
2603
|
+
try:
|
|
2604
|
+
QMessageBox.critical(
|
|
2605
|
+
self,
|
|
2606
|
+
"Deletion Error",
|
|
2607
|
+
f"Failed to delete messages:\n{str(e)}\n\nCheck console for details."
|
|
2608
|
+
)
|
|
2609
|
+
except:
|
|
2610
|
+
print("❌ Could not show error dialog")
|
|
2611
|
+
|
|
2612
|
+
if self.debug:
|
|
2613
|
+
print(f"❌ Failed to delete messages: {e}")
|
|
2614
|
+
import traceback
|
|
2615
|
+
traceback.print_exc()
|
|
2616
|
+
|
|
2617
|
+
def _update_abstractcore_session_after_deletion(self):
|
|
2618
|
+
"""Update AbstractCore session to reflect message deletions."""
|
|
2619
|
+
try:
|
|
2620
|
+
if not self.llm_manager or not self.llm_manager.current_session:
|
|
2621
|
+
return
|
|
2622
|
+
|
|
2623
|
+
# Get current system prompt
|
|
2624
|
+
current_session = self.llm_manager.current_session
|
|
2625
|
+
system_prompt = getattr(current_session, 'system_prompt', None) or """
|
|
2626
|
+
You are a helpful AI assistant who has access to tools to help the user.
|
|
2627
|
+
Always be a critical and creative thinker who leverage constructive skepticism to progress and evolve its reasoning and answers.
|
|
2628
|
+
Always answer in nicely formatted markdown.
|
|
2629
|
+
"""
|
|
2630
|
+
|
|
2631
|
+
# Prepare tools list (same as in LLMManager)
|
|
2632
|
+
tools = []
|
|
2633
|
+
try:
|
|
2634
|
+
from abstractcore.tools.common_tools import (
|
|
2635
|
+
list_files, search_files, read_file, edit_file,
|
|
2636
|
+
write_file, execute_command, web_search
|
|
2637
|
+
)
|
|
2638
|
+
tools = [
|
|
2639
|
+
list_files, search_files, read_file, edit_file,
|
|
2640
|
+
write_file, execute_command, web_search
|
|
2641
|
+
]
|
|
2642
|
+
except ImportError as import_error:
|
|
2643
|
+
pass
|
|
2644
|
+
pass
|
|
2645
|
+
|
|
2646
|
+
# Create new session with updated message history
|
|
2647
|
+
from abstractcore import BasicSession
|
|
2648
|
+
new_session = BasicSession(
|
|
2649
|
+
self.llm_manager.llm,
|
|
2650
|
+
system_prompt=system_prompt,
|
|
2651
|
+
tools=tools
|
|
2652
|
+
)
|
|
2653
|
+
|
|
2654
|
+
# Add remaining messages to the new session
|
|
2655
|
+
for i, msg in enumerate(self.message_history):
|
|
2656
|
+
try:
|
|
2657
|
+
if msg.get('type') == 'user':
|
|
2658
|
+
from abstractcore.messages import UserMessage
|
|
2659
|
+
user_msg = UserMessage(content=msg.get('content', ''))
|
|
2660
|
+
new_session.messages.append(user_msg)
|
|
2661
|
+
elif msg.get('type') == 'assistant':
|
|
2662
|
+
from abstractcore.messages import AssistantMessage
|
|
2663
|
+
assistant_msg = AssistantMessage(content=msg.get('content', ''))
|
|
2664
|
+
new_session.messages.append(assistant_msg)
|
|
2665
|
+
elif msg.get('type') == 'system':
|
|
2666
|
+
# Skip system messages (handled by system_prompt)
|
|
2667
|
+
pass
|
|
2668
|
+
else:
|
|
2669
|
+
# Unknown message type
|
|
2670
|
+
pass
|
|
2671
|
+
except Exception as msg_error:
|
|
2672
|
+
# Continue with other messages
|
|
2673
|
+
pass
|
|
2674
|
+
|
|
2675
|
+
# Replace current session
|
|
2676
|
+
self.llm_manager.current_session = new_session
|
|
2677
|
+
|
|
2678
|
+
except Exception as e:
|
|
2679
|
+
import traceback
|
|
2680
|
+
traceback.print_exc()
|
|
2681
|
+
# Don't raise - this is not critical for the UI operation
|
|
2682
|
+
|
|
2257
2683
|
def close_app(self):
|
|
2258
2684
|
"""Close the entire application completely."""
|
|
2259
2685
|
if self.debug:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: abstractassistant
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: A sleek (macOS) system tray application providing instant access to LLMs
|
|
5
5
|
Author-email: Laurent-Philippe Albou <contact@abstractcore.ai>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -211,26 +211,26 @@ assistant --debug
|
|
|
211
211
|
|
|
212
212
|
```
|
|
213
213
|
abstractassistant/
|
|
214
|
-
├── pyproject.toml
|
|
215
|
-
├── requirements.txt
|
|
216
|
-
├── config.toml
|
|
217
|
-
├── abstractassistant/
|
|
218
|
-
│ ├── cli.py
|
|
219
|
-
│ ├── app.py
|
|
220
|
-
│ ├── config.py
|
|
221
|
-
│ ├── core/
|
|
222
|
-
│ │ ├── llm_manager.py
|
|
223
|
-
│ │ └── tts_manager.py
|
|
224
|
-
│ ├── ui/
|
|
225
|
-
│ │ ├── qt_bubble.py
|
|
226
|
-
│ │ └── toast_window.py
|
|
227
|
-
│ └── utils/
|
|
228
|
-
│ ├── icon_generator.py
|
|
229
|
-
│ └── markdown_renderer.py
|
|
230
|
-
└── docs/
|
|
231
|
-
├──
|
|
232
|
-
├──
|
|
233
|
-
└──
|
|
214
|
+
├── pyproject.toml # Package configuration
|
|
215
|
+
├── requirements.txt # Dependencies
|
|
216
|
+
├── config.toml # Default configuration
|
|
217
|
+
├── abstractassistant/ # Main package
|
|
218
|
+
│ ├── cli.py # CLI entry point
|
|
219
|
+
│ ├── app.py # Main application
|
|
220
|
+
│ ├── config.py # Configuration management
|
|
221
|
+
│ ├── core/ # Business logic
|
|
222
|
+
│ │ ├── llm_manager.py # LLM provider management
|
|
223
|
+
│ │ └── tts_manager.py # Voice/TTS integration
|
|
224
|
+
│ ├── ui/ # User interface
|
|
225
|
+
│ │ ├── qt_bubble.py # Main Qt chat interface
|
|
226
|
+
│ │ └── toast_window.py # Notification system
|
|
227
|
+
│ └── utils/ # Utilities
|
|
228
|
+
│ ├── icon_generator.py # Dynamic icon creation
|
|
229
|
+
│ └── markdown_renderer.py # Markdown processing
|
|
230
|
+
└── docs/ # Documentation
|
|
231
|
+
├── architecture.md # Technical documentation
|
|
232
|
+
├── installation.md # Installation guide
|
|
233
|
+
└── getting-started.md # Usage guide
|
|
234
234
|
```
|
|
235
235
|
|
|
236
236
|
## 🌟 Why AbstractAssistant?
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
setup_macos_app.py,sha256=9dIPr9TipjtgdIhd0MnR2syRNoFyBVMnRsWDW0UCT3A,10736
|
|
2
1
|
abstractassistant/__init__.py,sha256=homfqMDh6sX2nBROtk6-y72jnrStPph8gEOeT0OjKyU,35
|
|
3
2
|
abstractassistant/app.py,sha256=yGFszbaqja_Y1ejSMcVYIcq8f1qdeZpVTb032geI-ZE,40374
|
|
4
3
|
abstractassistant/cli.py,sha256=SQPxQCLjX-LOlhSEvG302D0AOyxlxo5QM2imxr9wxmc,4385
|
|
5
4
|
abstractassistant/config.py,sha256=KodfPYTpHtavJyne-h-B-r3kbEt1uusSY8GknGLtDL8,5809
|
|
6
|
-
abstractassistant/create_app_bundle.py,sha256=
|
|
5
|
+
abstractassistant/create_app_bundle.py,sha256=lJJsdnjl-WSdQVn8uFp7c_3cJkx8liZbK2C7elOCG1A,14215
|
|
7
6
|
abstractassistant/web_server.py,sha256=_pqMzy13qfim9BMBqQJQifWyX7UQXFD_sZeiu4ZBt40,12816
|
|
8
7
|
abstractassistant/core/__init__.py,sha256=TETStgToTe7QSsCZgRHDk2oSErlLJoeGN0sFg4Yx2_c,15
|
|
9
8
|
abstractassistant/core/llm_manager.py,sha256=hJun-nDfRv9zxv_3tfrHAmVYSYT96E-0zDJB2TiaSeQ,19226
|
|
10
9
|
abstractassistant/core/tts_manager.py,sha256=Cxh302EgIycwkWxe7XntmLW-j_WusbJOYRCs3Jms3CU,9892
|
|
11
10
|
abstractassistant/ui/__init__.py,sha256=aRNE2pS50nFAX6y--rSGMNYwhz905g14gRd6g4BolYU,13
|
|
12
|
-
abstractassistant/ui/chat_bubble.py,sha256=
|
|
13
|
-
abstractassistant/ui/history_dialog.py,sha256=
|
|
11
|
+
abstractassistant/ui/chat_bubble.py,sha256=bY48b4IeQzOrRN2_sJ5OazhZcJ8IMaBM6R3EexvU30Q,11885
|
|
12
|
+
abstractassistant/ui/history_dialog.py,sha256=lVyNrZVu73CZo593DvnuWU1iCpmZybTCFTjlu4RrqBM,39701
|
|
14
13
|
abstractassistant/ui/provider_manager.py,sha256=9IM-BxIs6lUlk6cDCBi7oZFMXmn4CFMlxh0s-_vhzXY,8403
|
|
15
|
-
abstractassistant/ui/qt_bubble.py,sha256=
|
|
14
|
+
abstractassistant/ui/qt_bubble.py,sha256=kCgj1zqWKxxvVFAroz8NDh1GtcobyhatlrcXT9PhYOI,115598
|
|
16
15
|
abstractassistant/ui/toast_manager.py,sha256=1aU4DPo-J45bC61gTEctHq98ZrHIFxRfZa_9Q8KF588,13721
|
|
17
16
|
abstractassistant/ui/toast_window.py,sha256=BRSwEBlaND5LLipn1HOX0ISWxVH-zOHsYplFkiPaj_g,21727
|
|
18
17
|
abstractassistant/ui/tts_state_manager.py,sha256=UF_zrfl9wf0hNHBGxevcoKxW5Dh7zXibUSVoSSjGP4o,10565
|
|
@@ -20,9 +19,9 @@ abstractassistant/ui/ui_styles.py,sha256=FvE2CVUbHmHu1PKVTBBGyhbt781qh4WjLMrHvil
|
|
|
20
19
|
abstractassistant/utils/__init__.py,sha256=7Q3BxyXETkt3tm5trhuLTyL8PoECOK0QiK-0KUVAR2Q,16
|
|
21
20
|
abstractassistant/utils/icon_generator.py,sha256=SWPgi1V6_8544Zbc2vAfFXAy15H35neyUGCYt2eKoic,16475
|
|
22
21
|
abstractassistant/utils/markdown_renderer.py,sha256=u5tVIhulSwRYADiqJcZNoHhU8e6pJVgzrwZRd61Bov0,12585
|
|
23
|
-
abstractassistant-0.3.
|
|
24
|
-
abstractassistant-0.3.
|
|
25
|
-
abstractassistant-0.3.
|
|
26
|
-
abstractassistant-0.3.
|
|
27
|
-
abstractassistant-0.3.
|
|
28
|
-
abstractassistant-0.3.
|
|
22
|
+
abstractassistant-0.3.4.dist-info/licenses/LICENSE,sha256=QUjFNAE-0yOkW9-Rle2axkpkt9H7xiZ2VbN-VeONhxc,1106
|
|
23
|
+
abstractassistant-0.3.4.dist-info/METADATA,sha256=CXoP8mvao4NdI9qmyght-lTppQvuX3IgveQT7Ku0DVE,11564
|
|
24
|
+
abstractassistant-0.3.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
25
|
+
abstractassistant-0.3.4.dist-info/entry_points.txt,sha256=MIzeCh0XG6MbhIzBHtkdEjmjxYBsQrGFevq8Y1L8Jkc,118
|
|
26
|
+
abstractassistant-0.3.4.dist-info/top_level.txt,sha256=qZc_LQH3CBxLq2P4B1aHayzkj8hn0euR31edkXQVzDA,18
|
|
27
|
+
abstractassistant-0.3.4.dist-info/RECORD,,
|