agentcrew-ai 0.8.6__py3-none-any.whl → 0.8.7__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.
AgentCrew/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.8.6"
1
+ __version__ = "0.8.7"
AgentCrew/app.py CHANGED
@@ -584,7 +584,7 @@ tools = ["memory", "browser", "web_search", "code_analysis"]
584
584
  "No LLM API key found. Please set either ANTHROPIC_API_KEY, GEMINI_API_KEY, OPENAI_API_KEY, GROQ_API_KEY, or DEEPINFRA_API_KEY"
585
585
  )
586
586
 
587
- services = self.setup_services(provider, memory_llm)
587
+ services = self.setup_services(provider, memory_llm, need_memory=False)
588
588
 
589
589
  if mcp_config:
590
590
  os.environ["MCP_CONFIG_PATH"] = mcp_config
@@ -4,10 +4,10 @@ from typing import TYPE_CHECKING
4
4
  from pydantic import BaseModel
5
5
  from .agent_cards import create_agent_card
6
6
  from AgentCrew.modules.agents import LocalAgent
7
+ from typing import Any, Dict, List, Optional
7
8
 
8
9
 
9
10
  if TYPE_CHECKING:
10
- from typing import Any, Dict, List, Optional
11
11
  from AgentCrew.modules.agents import AgentManager
12
12
  from a2a.types import AgentCard
13
13
 
@@ -85,7 +85,7 @@ class AgentTaskManager(TaskManager):
85
85
  if self.agent is None or not isinstance(self.agent, LocalAgent):
86
86
  raise ValueError(f"Agent {agent_name} not found or is not a LocalAgent")
87
87
 
88
- self.memory_service = self.agent.services["memory"]
88
+ self.memory_service = self.agent.services.get("memory", None)
89
89
 
90
90
  def _is_terminal_state(self, state: TaskState) -> bool:
91
91
  """Check if a state is terminal."""
@@ -272,6 +272,7 @@ class AgentTaskManager(TaskManager):
272
272
 
273
273
  finally:
274
274
  # Clean up
275
+ self.tasks.pop(task_id, None)
275
276
  self.streaming_tasks.pop(task_id, None)
276
277
 
277
278
  def _create_ask_tool_message(
@@ -572,9 +573,10 @@ class AgentTaskManager(TaskManager):
572
573
  .get("content", [{}])[0]
573
574
  .get("text", "")
574
575
  )
575
- self.memory_service.store_conversation(
576
- user_message, current_response, self.agent_name
577
- )
576
+ if self.memory_service:
577
+ self.memory_service.store_conversation(
578
+ user_message, current_response, self.agent_name
579
+ )
578
580
 
579
581
  # Create artifact from final response
580
582
  artifact = convert_agent_response_to_a2a_artifact(
@@ -634,7 +634,7 @@ Check if `when` condition in <Global_Behavior> or <Project_Behavior> matches, up
634
634
  - Skip agent evaluation if user request is when...,[action]... related to adaptive behaviors call `adapt` tool instead.""",
635
635
  },
636
636
  )
637
- if self.services.get("memory"):
637
+ if not self.is_remoting_mode and self.services.get("memory"):
638
638
  memory_headers = self.services["memory"].list_memory_headers(
639
639
  agent_name=self.name
640
640
  )
@@ -1290,9 +1290,7 @@ class CodeAnalysisService:
1290
1290
  f"start_line {start_line} exceeds file length ({total_lines} lines)"
1291
1291
  )
1292
1292
  if end_line > total_lines:
1293
- raise ValueError(
1294
- f"end_line {end_line} exceeds file length ({total_lines} lines)"
1295
- )
1293
+ end_line = total_lines
1296
1294
 
1297
1295
  # Extract the line range (convert to 0-indexed)
1298
1296
  selected_lines = lines[start_line - 1 : end_line]
@@ -179,7 +179,11 @@ class DiffDisplay:
179
179
  Returns:
180
180
  Rich Text with character-level highlighting
181
181
  """
182
- result = Text("- " if is_original else "+ ")
182
+ result = Text()
183
+ if is_original:
184
+ result.append("- ", style="red")
185
+ else:
186
+ result.append("+ ", style="green")
183
187
  matcher = difflib.SequenceMatcher(None, orig_line, mod_line)
184
188
 
185
189
  for tag, i1, i2, j1, j2 in matcher.get_opcodes():
@@ -116,7 +116,6 @@ class CustomLLMService(OpenAIService):
116
116
 
117
117
  stream_params = {
118
118
  "model": self.model,
119
- "parallel_tool_calls": False,
120
119
  "messages": messages,
121
120
  # "max_tokens": 16000,
122
121
  }
@@ -7,10 +7,12 @@ from PySide6.QtWidgets import (
7
7
  QVBoxLayout,
8
8
  QPushButton,
9
9
  QLabel,
10
+ QScrollArea,
10
11
  )
11
12
  from PySide6.QtGui import QKeySequence, QShortcut
12
13
  from PySide6.QtCore import Qt
13
14
  from AgentCrew.modules.gui.widgets.tool_widget import ToolWidget
15
+ from AgentCrew.modules.gui.widgets.diff_widget import DiffWidget
14
16
 
15
17
 
16
18
  class ToolEventHandler:
@@ -158,17 +160,18 @@ class ToolEventHandler:
158
160
  tool_use = tool_info.copy()
159
161
  confirmation_id = tool_use.pop("confirmation_id")
160
162
 
161
- # Special handling for 'ask' tool
162
163
  if tool_use["name"] == "ask":
163
164
  self._handle_ask_tool_confirmation(tool_use, confirmation_id)
164
165
  return
165
166
 
166
- # Create dialog
167
+ if tool_use["name"] == "write_or_edit_file":
168
+ self._handle_write_or_edit_file_confirmation(tool_use, confirmation_id)
169
+ return
170
+
167
171
  dialog = QMessageBox(self.chat_window)
168
172
  dialog.setWindowTitle("Tool Execution Confirmation")
169
173
  dialog.setIcon(QMessageBox.Icon.Question)
170
174
 
171
- # Format tool information for display
172
175
  tool_description = f"The assistant wants to use the '{tool_use['name']}' tool."
173
176
  params_text = ""
174
177
 
@@ -189,7 +192,6 @@ class ToolEventHandler:
189
192
  text_edit.setReadOnly(True)
190
193
  text_edit.setText(params_text)
191
194
 
192
- # Style the text edit to match the main theme
193
195
  text_edit.setStyleSheet(
194
196
  self.chat_window.style_provider.get_tool_dialog_text_edit_style()
195
197
  )
@@ -293,6 +295,167 @@ class ToolEventHandler:
293
295
  self.chat_window.current_response_bubble = None
294
296
  self.chat_window.current_response_container = None
295
297
 
298
+ def _handle_write_or_edit_file_confirmation(self, tool_use, confirmation_id):
299
+ """Handle write_or_edit_file tool confirmation with diff view."""
300
+ from PySide6.QtWidgets import QWidget, QHBoxLayout
301
+
302
+ tool_input = tool_use.get("input", {})
303
+ file_path = tool_input.get("file_path", "")
304
+ text_or_blocks = tool_input.get("text_or_search_replace_blocks", "")
305
+ percentage = tool_input.get("percentage_to_change", 0)
306
+
307
+ has_diff = DiffWidget.has_search_replace_blocks(text_or_blocks)
308
+
309
+ dialog = QDialog(self.chat_window)
310
+ dialog.setWindowTitle("File Edit Confirmation")
311
+ dialog.setMinimumWidth(800 if has_diff else 600)
312
+ dialog.setMinimumHeight(600 if has_diff else 400)
313
+
314
+ layout = QVBoxLayout()
315
+
316
+ diff_colors = self.chat_window.style_provider.get_diff_colors()
317
+ header_label = QLabel(f"📝 <b>Edit File:</b> {file_path}")
318
+ header_label.setStyleSheet(
319
+ f"font-size: 14px; padding: 10px; color: {diff_colors.get('header_text', '#89b4fa')};"
320
+ )
321
+ layout.addWidget(header_label)
322
+
323
+ info_label = QLabel(
324
+ f"Change percentage: {percentage}% | "
325
+ f"Mode: {'Search/Replace Blocks' if has_diff else 'Full Content'}"
326
+ )
327
+ info_label.setStyleSheet(
328
+ f"font-size: 11px; color: {diff_colors.get('line_number_text', '#6c7086')}; padding: 0 10px;"
329
+ )
330
+ layout.addWidget(info_label)
331
+
332
+ scroll_area = QScrollArea()
333
+ scroll_area.setWidgetResizable(True)
334
+ scroll_area.setMinimumHeight(350)
335
+
336
+ if has_diff:
337
+ diff_widget = DiffWidget(style_provider=self.chat_window.style_provider)
338
+ diff_widget.set_diff_content(text_or_blocks, file_path)
339
+ scroll_area.setWidget(diff_widget)
340
+ else:
341
+ content_widget = QTextEdit()
342
+ content_widget.setReadOnly(True)
343
+ content_widget.setText(text_or_blocks)
344
+ content_widget.setStyleSheet(
345
+ self.chat_window.style_provider.get_tool_dialog_text_edit_style()
346
+ )
347
+ scroll_area.setWidget(content_widget)
348
+
349
+ layout.addWidget(scroll_area)
350
+
351
+ buttons_container = QWidget()
352
+ buttons_layout = QHBoxLayout(buttons_container)
353
+ buttons_layout.setContentsMargins(0, 10, 0, 0)
354
+
355
+ yes_button = QPushButton("✓ Approve")
356
+ yes_button.setStyleSheet(
357
+ self.chat_window.style_provider.get_tool_dialog_yes_button_style()
358
+ )
359
+
360
+ all_button = QPushButton("✓✓ Yes to All")
361
+ all_button.setStyleSheet(
362
+ self.chat_window.style_provider.get_tool_dialog_all_button_style()
363
+ )
364
+
365
+ forever_button = QPushButton("∞ Forever")
366
+ forever_button.setStyleSheet(
367
+ self.chat_window.style_provider.get_tool_dialog_all_button_style()
368
+ )
369
+
370
+ no_button = QPushButton("✗ Deny")
371
+ no_button.setStyleSheet(
372
+ self.chat_window.style_provider.get_tool_dialog_no_button_style()
373
+ )
374
+
375
+ buttons_layout.addWidget(yes_button)
376
+ buttons_layout.addWidget(all_button)
377
+ buttons_layout.addWidget(forever_button)
378
+ buttons_layout.addStretch()
379
+ buttons_layout.addWidget(no_button)
380
+
381
+ layout.addWidget(buttons_container)
382
+
383
+ dialog.setLayout(layout)
384
+ dialog.setStyleSheet(self.chat_window.style_provider.get_config_window_style())
385
+
386
+ result = {"action": ""}
387
+
388
+ def on_yes():
389
+ result["action"] = "approve"
390
+ dialog.accept()
391
+
392
+ def on_all():
393
+ result["action"] = "approve_all"
394
+ dialog.accept()
395
+
396
+ def on_forever():
397
+ result["action"] = "approve_forever"
398
+ dialog.accept()
399
+
400
+ def on_no():
401
+ result["action"] = "deny"
402
+ dialog.reject()
403
+
404
+ yes_button.clicked.connect(on_yes)
405
+ all_button.clicked.connect(on_all)
406
+ forever_button.clicked.connect(on_forever)
407
+ no_button.clicked.connect(on_no)
408
+
409
+ approve_shortcut = QShortcut(QKeySequence("Ctrl+Return"), dialog)
410
+ approve_shortcut.activated.connect(on_yes)
411
+
412
+ dialog.exec()
413
+
414
+ if result["action"] == "approve":
415
+ self.chat_window.message_handler.resolve_tool_confirmation(
416
+ confirmation_id, {"action": "approve"}
417
+ )
418
+ self.chat_window.display_status_message(f"Approved file edit: {file_path}")
419
+
420
+ elif result["action"] == "approve_all":
421
+ self.chat_window.message_handler.resolve_tool_confirmation(
422
+ confirmation_id, {"action": "approve_all"}
423
+ )
424
+ self.chat_window.display_status_message(
425
+ "Approved all future write_or_edit_file calls"
426
+ )
427
+
428
+ elif result["action"] == "approve_forever":
429
+ from AgentCrew.modules.config import ConfigManagement
430
+
431
+ config_manager = ConfigManagement()
432
+ config_manager.write_auto_approval_tools("write_or_edit_file", add=True)
433
+
434
+ self.chat_window.message_handler.resolve_tool_confirmation(
435
+ confirmation_id, {"action": "approve_all"}
436
+ )
437
+ self.chat_window.display_status_message(
438
+ "write_or_edit_file will be auto-approved forever"
439
+ )
440
+
441
+ else:
442
+ denial_reason = self.show_denial_reason_dialog("write_or_edit_file")
443
+
444
+ if denial_reason:
445
+ self.chat_window.message_handler.resolve_tool_confirmation(
446
+ confirmation_id, {"action": "deny", "reason": denial_reason}
447
+ )
448
+ self.chat_window.display_status_message(
449
+ f"Denied file edit - Reason: {denial_reason[:50]}..."
450
+ if len(denial_reason) > 50
451
+ else f"Denied file edit - Reason: {denial_reason}"
452
+ )
453
+ else:
454
+ self.chat_window.message_handler.resolve_tool_confirmation(
455
+ confirmation_id, {"action": "deny"}
456
+ )
457
+ self.chat_window.display_status_message("Denied file edit")
458
+
296
459
  def _handle_ask_tool_confirmation(self, tool_use, confirmation_id):
297
460
  """Handle the ask tool - display question and guided answers in GUI."""
298
461
  question = tool_use["input"].get("question", "")
@@ -1279,6 +1279,26 @@ QFrame {
1279
1279
  "default": "🔧", # Default icon for unspecified tools
1280
1280
  }
1281
1281
 
1282
+ # Diff Widget colors
1283
+ DIFF_COLORS = {
1284
+ "background": "#fafafa", # Light background
1285
+ "panel_bg": "#ffffff", # White
1286
+ "header_bg": "#e5e5e6", # Light gray
1287
+ "header_text": "#383a42", # Dark text
1288
+ "line_number_bg": "#f0f0f0", # Very light gray
1289
+ "line_number_text": "#9d9d9f", # Medium gray
1290
+ "removed_bg": "#ffeef0", # Light red background
1291
+ "removed_text": "#d73a49", # Red text
1292
+ "removed_highlight": "#d73a49", # Red for character highlight
1293
+ "added_bg": "#e6ffec", # Light green background
1294
+ "added_text": "#22863a", # Green text
1295
+ "added_highlight": "#22863a", # Green for character highlight
1296
+ "unchanged_text": "#9d9d9f", # Gray
1297
+ "border": "#e5e5e6", # Light border
1298
+ "block_header_bg": "#ddf4ff", # Light blue
1299
+ "block_header_text": "#0969da", # Blue text
1300
+ }
1301
+
1282
1302
  # JSON Editor styles
1283
1303
  JSON_EDITOR_COLORS = {
1284
1304
  "background": "#fafafa",
@@ -1318,6 +1318,26 @@ QFrame {
1318
1318
  "default": "🔧", # Default icon for unspecified tools
1319
1319
  }
1320
1320
 
1321
+ # Diff Widget colors
1322
+ DIFF_COLORS = {
1323
+ "background": "#1e1e2e", # Base
1324
+ "panel_bg": "#313244", # Surface0
1325
+ "header_bg": "#45475a", # Surface1
1326
+ "header_text": "#cdd6f4", # Text
1327
+ "line_number_bg": "#181825", # Mantle
1328
+ "line_number_text": "#6c7086", # Overlay0
1329
+ "removed_bg": "#3b2d33", # Subtle red background
1330
+ "removed_text": "#f38ba8", # Red
1331
+ "removed_highlight": "#f38ba8", # Red for character highlight
1332
+ "added_bg": "#2d3b33", # Subtle green background
1333
+ "added_text": "#a6e3a1", # Green
1334
+ "added_highlight": "#a6e3a1", # Green for character highlight
1335
+ "unchanged_text": "#6c7086", # Overlay0
1336
+ "border": "#45475a", # Surface1
1337
+ "block_header_bg": "#585b70", # Surface2
1338
+ "block_header_text": "#b4befe", # Lavender
1339
+ }
1340
+
1321
1341
  # JSON Editor styles
1322
1342
  JSON_EDITOR_COLORS = {
1323
1343
  "background": "#313244", # Surface0
@@ -1286,6 +1286,26 @@ QFrame {
1286
1286
  "default": "🔧", # Default icon for unspecified tools
1287
1287
  }
1288
1288
 
1289
+ # Diff Widget colors
1290
+ DIFF_COLORS = {
1291
+ "background": "#282a36", # Dracula Background
1292
+ "panel_bg": "#21222c", # Darker
1293
+ "header_bg": "#44475a", # Comment
1294
+ "header_text": "#f8f8f2", # Foreground
1295
+ "line_number_bg": "#1e1f29", # Very dark
1296
+ "line_number_text": "#6272a4", # Comment
1297
+ "removed_bg": "#3d2a36", # Subtle red background
1298
+ "removed_text": "#ff5555", # Red
1299
+ "removed_highlight": "#ff5555", # Red
1300
+ "added_bg": "#2a3d36", # Subtle green background
1301
+ "added_text": "#50fa7b", # Green
1302
+ "added_highlight": "#50fa7b", # Green
1303
+ "unchanged_text": "#6272a4", # Comment
1304
+ "border": "#44475a", # Border
1305
+ "block_header_bg": "#bd93f9", # Purple
1306
+ "block_header_text": "#282a36", # Background
1307
+ }
1308
+
1289
1309
  # JSON Editor styles
1290
1310
  JSON_EDITOR_COLORS = {
1291
1311
  "background": "#282a36",
@@ -1279,6 +1279,26 @@ QFrame {
1279
1279
  "default": "🔧", # Default icon for unspecified tools
1280
1280
  }
1281
1281
 
1282
+ # Diff Widget colors
1283
+ DIFF_COLORS = {
1284
+ "background": "#2e3440", # Polar Night
1285
+ "panel_bg": "#3b4252", # Polar Night lighter
1286
+ "header_bg": "#434c5e", # Polar Night
1287
+ "header_text": "#d8dee9", # Snow Storm
1288
+ "line_number_bg": "#2e3440", # Polar Night
1289
+ "line_number_text": "#4c566a", # Polar Night
1290
+ "removed_bg": "#3d2f3a", # Subtle red background
1291
+ "removed_text": "#bf616a", # Aurora Red
1292
+ "removed_highlight": "#bf616a", # Aurora Red
1293
+ "added_bg": "#2f3d38", # Subtle green background
1294
+ "added_text": "#a3be8c", # Aurora Green
1295
+ "added_highlight": "#a3be8c", # Aurora Green
1296
+ "unchanged_text": "#4c566a", # Polar Night
1297
+ "border": "#4c566a", # Border
1298
+ "block_header_bg": "#5e81ac", # Frost
1299
+ "block_header_text": "#eceff4", # Snow Storm
1300
+ }
1301
+
1282
1302
  # JSON Editor styles
1283
1303
  JSON_EDITOR_COLORS = {
1284
1304
  "background": "#2e3440",
@@ -1273,6 +1273,26 @@ QFrame {
1273
1273
  "default": "🔧", # Default icon for unspecified tools
1274
1274
  }
1275
1275
 
1276
+ # Diff Widget colors
1277
+ DIFF_COLORS = {
1278
+ "background": "#334155", # Slate 700
1279
+ "panel_bg": "#475569", # Slate 600
1280
+ "header_bg": "#1e293b", # Slate 800
1281
+ "header_text": "#f8fafc", # Slate 50
1282
+ "line_number_bg": "#1e293b", # Slate 800
1283
+ "line_number_text": "#64748b", # Slate 500
1284
+ "removed_bg": "#4c2c3a", # Subtle red
1285
+ "removed_text": "#fca5a5", # Red 300
1286
+ "removed_highlight": "#fca5a5", # Red 300
1287
+ "added_bg": "#2c4c3a", # Subtle green
1288
+ "added_text": "#7fb239", # Primary Green
1289
+ "added_highlight": "#7fb239", # Primary Green
1290
+ "unchanged_text": "#64748b", # Slate 500
1291
+ "border": "#475569", # Border
1292
+ "block_header_bg": "#638b2c", # Secondary Green
1293
+ "block_header_text": "#f8fafc", # Slate 50
1294
+ }
1295
+
1276
1296
  # JSON Editor styles
1277
1297
  JSON_EDITOR_COLORS = {
1278
1298
  "background": "#475569", # Input Fields - Slate 600
@@ -395,3 +395,28 @@ QPlainTextEdit:focus {
395
395
  }
396
396
  """,
397
397
  )
398
+
399
+ def get_diff_colors(self):
400
+ """Get color scheme for diff widget from current theme."""
401
+ return getattr(
402
+ self.theme_class,
403
+ "DIFF_COLORS",
404
+ {
405
+ "background": "#1e1e2e",
406
+ "panel_bg": "#313244",
407
+ "header_bg": "#45475a",
408
+ "header_text": "#cdd6f4",
409
+ "line_number_bg": "#181825",
410
+ "line_number_text": "#6c7086",
411
+ "removed_bg": "#3b2d33",
412
+ "removed_text": "#f38ba8",
413
+ "removed_highlight": "#f38ba8",
414
+ "added_bg": "#2d3b33",
415
+ "added_text": "#a6e3a1",
416
+ "added_highlight": "#a6e3a1",
417
+ "unchanged_text": "#6c7086",
418
+ "border": "#45475a",
419
+ "block_header_bg": "#585b70",
420
+ "block_header_text": "#b4befe",
421
+ },
422
+ )
@@ -1286,6 +1286,26 @@ QFrame {
1286
1286
  "default": "🔧", # Default icon for unspecified tools
1287
1287
  }
1288
1288
 
1289
+ # Diff Widget colors
1290
+ DIFF_COLORS = {
1291
+ "background": "#f8fafc", # Very light background
1292
+ "panel_bg": "#ffffff", # White
1293
+ "header_bg": "#f1f5f9", # Light slate
1294
+ "header_text": "#374151", # Dark text
1295
+ "line_number_bg": "#f8fafc", # Very light
1296
+ "line_number_text": "#9ca3af", # Gray
1297
+ "removed_bg": "#fef2f2", # Light red
1298
+ "removed_text": "#ef4444", # Red
1299
+ "removed_highlight": "#ef4444", # Red
1300
+ "added_bg": "#ecfdf5", # Light green
1301
+ "added_text": "#10b981", # Green
1302
+ "added_highlight": "#10b981", # Green
1303
+ "unchanged_text": "#9ca3af", # Gray
1304
+ "border": "#d1d5db", # Border
1305
+ "block_header_bg": "#e0e7ff", # Light purple
1306
+ "block_header_text": "#6b46c1", # Purple
1307
+ }
1308
+
1289
1309
  # JSON Editor styles
1290
1310
  JSON_EDITOR_COLORS = {
1291
1311
  "background": "#ffffff",
@@ -3,6 +3,7 @@ from .system_message import SystemMessageWidget
3
3
  from .message_bubble import MessageBubble
4
4
  from .history_sidebar import ConversationSidebar, ConversationLoader
5
5
  from .tool_widget import ToolWidget
6
+ from .diff_widget import DiffWidget, CompactDiffWidget
6
7
 
7
8
  __all__ = [
8
9
  "TokenUsageWidget",
@@ -11,4 +12,6 @@ __all__ = [
11
12
  "ConversationSidebar",
12
13
  "ConversationLoader",
13
14
  "ToolWidget",
15
+ "DiffWidget",
16
+ "CompactDiffWidget",
14
17
  ]
@@ -0,0 +1,532 @@
1
+ """
2
+ Diff display widget for GUI showing file changes with split view.
3
+ Provides visual diff comparison for search/replace blocks.
4
+ """
5
+
6
+ import difflib
7
+ from typing import List, Dict
8
+ from PySide6.QtWidgets import (
9
+ QWidget,
10
+ QVBoxLayout,
11
+ QLabel,
12
+ QFrame,
13
+ )
14
+ from PySide6.QtCore import Qt
15
+
16
+
17
+ class DiffWidget(QWidget):
18
+ """Widget to display split diff view for file changes."""
19
+
20
+ SEARCH_DELIMITER = "<<<<<<< SEARCH"
21
+ MIDDLE_DELIMITER = "======="
22
+ REPLACE_DELIMITER = ">>>>>>> REPLACE"
23
+
24
+ def __init__(self, parent=None, style_provider=None):
25
+ super().__init__(parent)
26
+ self._style_provider = style_provider
27
+ self._colors = self._get_colors()
28
+ self.setup_ui()
29
+
30
+ def _get_colors(self):
31
+ """Get colors from style provider or use defaults."""
32
+ if self._style_provider:
33
+ return self._style_provider.get_diff_colors()
34
+ return {
35
+ "background": "#1e1e2e",
36
+ "panel_bg": "#313244",
37
+ "header_bg": "#45475a",
38
+ "header_text": "#cdd6f4",
39
+ "line_number_bg": "#181825",
40
+ "line_number_text": "#6c7086",
41
+ "removed_bg": "#3b2d33",
42
+ "removed_text": "#f38ba8",
43
+ "removed_highlight": "#f38ba8",
44
+ "added_bg": "#2d3b33",
45
+ "added_text": "#a6e3a1",
46
+ "added_highlight": "#a6e3a1",
47
+ "unchanged_text": "#6c7086",
48
+ "border": "#45475a",
49
+ "block_header_bg": "#585b70",
50
+ "block_header_text": "#b4befe",
51
+ }
52
+
53
+ def set_style_provider(self, style_provider):
54
+ """Update style provider and refresh colors."""
55
+ self._style_provider = style_provider
56
+ self._colors = self._get_colors()
57
+
58
+ def setup_ui(self):
59
+ """Setup the main layout."""
60
+ self.main_layout = QVBoxLayout(self)
61
+ self.main_layout.setContentsMargins(0, 0, 0, 0)
62
+ self.main_layout.setSpacing(8)
63
+
64
+ @staticmethod
65
+ def has_search_replace_blocks(text: str) -> bool:
66
+ """Check if text contains search/replace blocks."""
67
+ return (
68
+ "<<<<<<< SEARCH" in text and "=======" in text and ">>>>>>> REPLACE" in text
69
+ )
70
+
71
+ @staticmethod
72
+ def parse_search_replace_blocks(blocks_text: str) -> List[Dict]:
73
+ """
74
+ Parse search/replace blocks from text.
75
+
76
+ Returns:
77
+ List of dicts with 'index', 'search', and 'replace' keys
78
+ """
79
+ blocks = []
80
+ lines = blocks_text.split("\n")
81
+ i = 0
82
+ block_index = 0
83
+
84
+ while i < len(lines):
85
+ if lines[i].strip() == "<<<<<<< SEARCH":
86
+ search_lines = []
87
+ i += 1
88
+
89
+ while i < len(lines) and lines[i].strip() != "=======":
90
+ search_lines.append(lines[i])
91
+ i += 1
92
+
93
+ if i >= len(lines):
94
+ break
95
+
96
+ i += 1
97
+ replace_lines = []
98
+
99
+ while (
100
+ i < len(lines)
101
+ and lines[i].strip() != ">>>>>>> REPLACE"
102
+ and lines[i].strip() != "======="
103
+ ):
104
+ replace_lines.append(lines[i])
105
+ i += 1
106
+
107
+ if i >= len(lines):
108
+ break
109
+
110
+ blocks.append(
111
+ {
112
+ "index": block_index,
113
+ "search": "\n".join(search_lines),
114
+ "replace": "\n".join(replace_lines),
115
+ }
116
+ )
117
+ block_index += 1
118
+ i += 1
119
+ else:
120
+ i += 1
121
+
122
+ return blocks
123
+
124
+ def set_diff_content(self, blocks_text: str, file_path: str = ""):
125
+ """
126
+ Set the diff content to display.
127
+
128
+ Args:
129
+ blocks_text: Text containing search/replace blocks
130
+ file_path: Optional file path to display in header
131
+ """
132
+ self._clear_layout()
133
+ colors = self._colors
134
+
135
+ if file_path:
136
+ header = QLabel(f"📝 File: {file_path}")
137
+ header.setStyleSheet(
138
+ f"font-weight: bold; font-size: 13px; padding: 4px; color: {colors['block_header_text']};"
139
+ )
140
+ self.main_layout.addWidget(header)
141
+
142
+ blocks = self.parse_search_replace_blocks(blocks_text)
143
+
144
+ if not blocks:
145
+ no_blocks_label = QLabel("No valid search/replace blocks found")
146
+ no_blocks_label.setStyleSheet(
147
+ f"color: {colors['removed_text']}; padding: 8px;"
148
+ )
149
+ self.main_layout.addWidget(no_blocks_label)
150
+ return
151
+
152
+ for idx, block in enumerate(blocks):
153
+ if idx > 0:
154
+ separator = QFrame()
155
+ separator.setFrameShape(QFrame.Shape.HLine)
156
+ separator.setStyleSheet(
157
+ f"background-color: {colors['border']}; margin: 4px 0;"
158
+ )
159
+ self.main_layout.addWidget(separator)
160
+
161
+ block_widget = self._create_diff_block(
162
+ block["search"], block["replace"], idx + 1
163
+ )
164
+ self.main_layout.addWidget(block_widget)
165
+
166
+ def _clear_layout(self):
167
+ """Clear all widgets from the layout."""
168
+ while self.main_layout.count():
169
+ item = self.main_layout.takeAt(0)
170
+ if item.widget():
171
+ item.widget().deleteLater()
172
+
173
+ def _create_diff_block(
174
+ self, original: str, modified: str, block_num: int
175
+ ) -> QWidget:
176
+ """Create a single diff block widget."""
177
+ colors = self._colors
178
+ container = QWidget()
179
+ container_layout = QVBoxLayout(container)
180
+ container_layout.setContentsMargins(0, 0, 0, 0)
181
+ container_layout.setSpacing(4)
182
+
183
+ block_header = QLabel(f"Block {block_num}")
184
+ block_header.setStyleSheet(
185
+ f"font-weight: bold; font-size: 11px; color: {colors['header_text']}; padding: 2px;"
186
+ )
187
+ container_layout.addWidget(block_header)
188
+
189
+ # diff_container = QWidget()
190
+ # diff_layout = QHBoxLayout(diff_container)
191
+ # diff_layout.setContentsMargins(0, 0, 0, 0)
192
+ # diff_layout.setSpacing(8)
193
+ #
194
+ # original_panel = self._create_side_panel("Original", original, is_original=True)
195
+ # modified_panel = self._create_side_panel(
196
+ # "Modified", modified, is_original=False
197
+ # )
198
+ #
199
+ # diff_layout.addWidget(original_panel, 1)
200
+ # diff_layout.addWidget(modified_panel, 1)
201
+
202
+ # container_layout.addWidget(diff_container)
203
+
204
+ diff_view = self._create_inline_diff(original, modified)
205
+ container_layout.addWidget(diff_view)
206
+
207
+ return container
208
+
209
+ def _create_side_panel(
210
+ self, title: str, content: str, is_original: bool
211
+ ) -> QWidget:
212
+ """Create a side panel for original or modified content."""
213
+ colors = self._colors
214
+ panel = QFrame()
215
+ panel.setFrameShape(QFrame.Shape.StyledPanel)
216
+
217
+ bg_color = colors["removed_bg"] if is_original else colors["added_bg"]
218
+ border_color = colors["removed_text"] if is_original else colors["added_text"]
219
+ text_color = colors["removed_text"] if is_original else colors["added_text"]
220
+
221
+ panel.setStyleSheet(
222
+ f"""
223
+ QFrame {{
224
+ background-color: {bg_color};
225
+ border: 1px solid {border_color};
226
+ border-radius: 4px;
227
+ }}
228
+ """
229
+ )
230
+
231
+ layout = QVBoxLayout(panel)
232
+ layout.setContentsMargins(8, 4, 8, 8)
233
+ layout.setSpacing(4)
234
+
235
+ header = QLabel(title)
236
+ header.setStyleSheet(
237
+ f"font-weight: bold; font-size: 11px; color: {text_color}; padding: 2px;"
238
+ )
239
+ layout.addWidget(header)
240
+
241
+ content_label = QLabel(content if content else "(empty)")
242
+ content_label.setWordWrap(True)
243
+ content_label.setTextInteractionFlags(
244
+ Qt.TextInteractionFlag.TextSelectableByMouse
245
+ )
246
+ content_label.setStyleSheet(
247
+ f"""
248
+ font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
249
+ font-size: 12px;
250
+ color: {text_color};
251
+ padding: 4px;
252
+ """
253
+ )
254
+ layout.addWidget(content_label)
255
+
256
+ return panel
257
+
258
+ def _create_inline_diff(self, original: str, modified: str) -> QWidget:
259
+ """Create inline diff view with character-level highlighting."""
260
+ colors = self._colors
261
+ container = QFrame()
262
+ container.setStyleSheet(
263
+ f"""
264
+ QFrame {{
265
+ background-color: {colors["background"]};
266
+ border: 1px solid {colors["border"]};
267
+ border-radius: 4px;
268
+ }}
269
+ """
270
+ )
271
+
272
+ layout = QVBoxLayout(container)
273
+ layout.setContentsMargins(8, 8, 8, 8)
274
+ layout.setSpacing(2)
275
+
276
+ original_lines = original.split("\n")
277
+ modified_lines = modified.split("\n")
278
+
279
+ matcher = difflib.SequenceMatcher(None, original_lines, modified_lines)
280
+
281
+ for tag, i1, i2, j1, j2 in matcher.get_opcodes():
282
+ if tag == "equal":
283
+ for i in range(i1, i2):
284
+ line_label = self._create_diff_line(
285
+ f" {original_lines[i]}", "equal"
286
+ )
287
+ layout.addWidget(line_label)
288
+
289
+ elif tag == "delete":
290
+ for i in range(i1, i2):
291
+ line_label = self._create_diff_line(
292
+ f"- {original_lines[i]}", "delete"
293
+ )
294
+ layout.addWidget(line_label)
295
+
296
+ elif tag == "insert":
297
+ for j in range(j1, j2):
298
+ line_label = self._create_diff_line(
299
+ f"+ {modified_lines[j]}", "insert"
300
+ )
301
+ layout.addWidget(line_label)
302
+
303
+ elif tag == "replace":
304
+ max_lines = max(i2 - i1, j2 - j1)
305
+
306
+ for offset in range(max_lines):
307
+ orig_idx = i1 + offset
308
+ mod_idx = j1 + offset
309
+
310
+ if orig_idx < i2:
311
+ line_label = self._create_diff_line(
312
+ f"- {original_lines[orig_idx]}", "delete"
313
+ )
314
+ layout.addWidget(line_label)
315
+
316
+ if mod_idx < j2:
317
+ line_label = self._create_diff_line(
318
+ f"+ {modified_lines[mod_idx]}", "insert"
319
+ )
320
+ layout.addWidget(line_label)
321
+
322
+ return container
323
+
324
+ def _create_diff_line(self, text: str, line_type: str) -> QLabel:
325
+ """Create a single diff line label with appropriate styling."""
326
+ colors = self._colors
327
+ label = QLabel(text)
328
+ label.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
329
+
330
+ base_font = "font-family: 'Consolas', 'Monaco', 'Courier New', monospace; font-size: 11px;"
331
+
332
+ if line_type == "equal":
333
+ style = f"{base_font} color: {colors['unchanged_text']}; padding: 1px 4px;"
334
+ elif line_type == "delete":
335
+ style = f"{base_font} color: {colors['removed_text']}; background-color: {colors['removed_bg']}; padding: 1px 4px; border-radius: 2px;"
336
+ elif line_type == "insert":
337
+ style = f"{base_font} color: {colors['added_text']}; background-color: {colors['added_bg']}; padding: 1px 4px; border-radius: 2px;"
338
+ else:
339
+ style = f"{base_font} color: {colors['header_text']}; padding: 1px 4px;"
340
+
341
+ label.setStyleSheet(style)
342
+ return label
343
+
344
+
345
+ class CompactDiffWidget(QWidget):
346
+ """Compact diff widget for use inside ToolWidget."""
347
+
348
+ def __init__(self, parent=None, style_provider=None):
349
+ super().__init__(parent)
350
+ self._style_provider = style_provider
351
+ self._colors = self._get_colors()
352
+ self.setup_ui()
353
+
354
+ def _get_colors(self):
355
+ """Get colors from style provider or use defaults."""
356
+ if self._style_provider:
357
+ return self._style_provider.get_diff_colors()
358
+ return {
359
+ "background": "#1e1e2e",
360
+ "panel_bg": "#313244",
361
+ "border": "#45475a",
362
+ "removed_bg": "#2d0a0a",
363
+ "removed_text": "#f38ba8",
364
+ "added_bg": "#0a2d0a",
365
+ "added_text": "#a6e3a1",
366
+ "unchanged_text": "#585b70",
367
+ "line_number_text": "#6c7086",
368
+ }
369
+
370
+ def set_style_provider(self, style_provider):
371
+ """Update style provider and refresh colors."""
372
+ self._style_provider = style_provider
373
+ self._colors = self._get_colors()
374
+
375
+ def setup_ui(self):
376
+ """Setup the compact layout."""
377
+ self.main_layout = QVBoxLayout(self)
378
+ self.main_layout.setContentsMargins(4, 4, 4, 4)
379
+ self.main_layout.setSpacing(4)
380
+
381
+ def set_diff_content(self, blocks_text: str, file_path: str = ""):
382
+ """Set the diff content to display in compact form."""
383
+ self._clear_layout()
384
+ colors = self._colors
385
+
386
+ blocks = DiffWidget.parse_search_replace_blocks(blocks_text)
387
+
388
+ if not blocks:
389
+ return
390
+
391
+ for idx, block in enumerate(blocks):
392
+ if idx > 0:
393
+ separator = QFrame()
394
+ separator.setFrameShape(QFrame.Shape.HLine)
395
+ separator.setFixedHeight(1)
396
+ separator.setStyleSheet(f"background-color: {colors['border']};")
397
+ self.main_layout.addWidget(separator)
398
+
399
+ diff_view = self._create_compact_diff(
400
+ block["search"], block["replace"], idx + 1
401
+ )
402
+ self.main_layout.addWidget(diff_view)
403
+
404
+ def _clear_layout(self):
405
+ """Clear all widgets from the layout."""
406
+ while self.main_layout.count():
407
+ item = self.main_layout.takeAt(0)
408
+ if item.widget():
409
+ item.widget().deleteLater()
410
+
411
+ def _create_compact_diff(
412
+ self, original: str, modified: str, block_num: int
413
+ ) -> QWidget:
414
+ """Create a compact inline diff view."""
415
+ colors = self._colors
416
+ container = QFrame()
417
+ container.setStyleSheet(
418
+ f"""
419
+ QFrame {{
420
+ background-color: {colors["background"]};
421
+ border: 1px solid {colors["panel_bg"]};
422
+ border-radius: 4px;
423
+ }}
424
+ """
425
+ )
426
+
427
+ layout = QVBoxLayout(container)
428
+ layout.setContentsMargins(6, 6, 6, 6)
429
+ layout.setSpacing(1)
430
+
431
+ if len(DiffWidget.parse_search_replace_blocks(original + modified)) > 1:
432
+ block_header = QLabel(f"Block {block_num}")
433
+ block_header.setStyleSheet(
434
+ f"font-size: 10px; color: {colors['line_number_text']}; padding: 0 0 2px 0;"
435
+ )
436
+ layout.addWidget(block_header)
437
+
438
+ original_lines = original.split("\n")
439
+ modified_lines = modified.split("\n")
440
+
441
+ matcher = difflib.SequenceMatcher(None, original_lines, modified_lines)
442
+
443
+ max_display_lines = 20
444
+ line_count = 0
445
+
446
+ for tag, i1, i2, j1, j2 in matcher.get_opcodes():
447
+ if line_count >= max_display_lines:
448
+ truncate_label = QLabel("... (diff truncated)")
449
+ truncate_label.setStyleSheet(
450
+ f"font-size: 10px; color: {colors['line_number_text']}; font-style: italic;"
451
+ )
452
+ layout.addWidget(truncate_label)
453
+ break
454
+
455
+ if tag == "equal":
456
+ lines_to_show = min(2, i2 - i1)
457
+ if i2 - i1 > 2:
458
+ context_label = QLabel(f" ... ({i2 - i1 - 2} unchanged lines)")
459
+ context_label.setStyleSheet(
460
+ f"font-size: 10px; color: {colors['unchanged_text']}; font-style: italic;"
461
+ )
462
+ layout.addWidget(context_label)
463
+ line_count += 1
464
+
465
+ for i in range(i1, min(i1 + lines_to_show, i2)):
466
+ line_label = self._create_compact_line(
467
+ f" {original_lines[i]}", "equal"
468
+ )
469
+ layout.addWidget(line_label)
470
+ line_count += 1
471
+
472
+ elif tag == "delete":
473
+ for i in range(i1, i2):
474
+ if line_count >= max_display_lines:
475
+ break
476
+ line_label = self._create_compact_line(
477
+ f"- {original_lines[i]}", "delete"
478
+ )
479
+ layout.addWidget(line_label)
480
+ line_count += 1
481
+
482
+ elif tag == "insert":
483
+ for j in range(j1, j2):
484
+ if line_count >= max_display_lines:
485
+ break
486
+ line_label = self._create_compact_line(
487
+ f"+ {modified_lines[j]}", "insert"
488
+ )
489
+ layout.addWidget(line_label)
490
+ line_count += 1
491
+
492
+ elif tag == "replace":
493
+ for i in range(i1, i2):
494
+ if line_count >= max_display_lines:
495
+ break
496
+ line_label = self._create_compact_line(
497
+ f"- {original_lines[i]}", "delete"
498
+ )
499
+ layout.addWidget(line_label)
500
+ line_count += 1
501
+
502
+ for j in range(j1, j2):
503
+ if line_count >= max_display_lines:
504
+ break
505
+ line_label = self._create_compact_line(
506
+ f"+ {modified_lines[j]}", "insert"
507
+ )
508
+ layout.addWidget(line_label)
509
+ line_count += 1
510
+
511
+ return container
512
+
513
+ def _create_compact_line(self, text: str, line_type: str) -> QLabel:
514
+ """Create a compact diff line label."""
515
+ colors = self._colors
516
+ label = QLabel(text)
517
+ label.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
518
+
519
+ base_style = "font-family: monospace; font-size: 11px; padding: 0 2px;"
520
+
521
+ if line_type == "equal":
522
+ label.setStyleSheet(f"{base_style} color: {colors['unchanged_text']};")
523
+ elif line_type == "delete":
524
+ label.setStyleSheet(
525
+ f"{base_style} color: {colors['removed_text']}; background-color: {colors['removed_bg']};"
526
+ )
527
+ elif line_type == "insert":
528
+ label.setStyleSheet(
529
+ f"{base_style} color: {colors['added_text']}; background-color: {colors['added_bg']};"
530
+ )
531
+
532
+ return label
@@ -12,6 +12,7 @@ from PySide6.QtWidgets import (
12
12
  )
13
13
  from PySide6.QtCore import Qt
14
14
  from AgentCrew.modules.gui.themes import StyleProvider
15
+ from AgentCrew.modules.gui.widgets.diff_widget import DiffWidget, CompactDiffWidget
15
16
 
16
17
 
17
18
  class ToolWidget(QWidget):
@@ -46,6 +47,7 @@ class ToolWidget(QWidget):
46
47
  self.is_error = is_error
47
48
  self.is_expanded = False
48
49
  self.style_provider = StyleProvider()
50
+ self.is_diff_view = False
49
51
 
50
52
  # Setup main layout - reduced margins and spacing for compactness
51
53
  self.main_layout = QVBoxLayout(self)
@@ -138,22 +140,55 @@ class ToolWidget(QWidget):
138
140
 
139
141
  def _create_content_section(self):
140
142
  """Create the single collapsible content section containing input and result"""
141
- # Container for all content (input + result) - more compact
142
143
  self.content_container = QWidget()
143
144
  self.content_layout = QVBoxLayout(self.content_container)
144
- self.content_layout.setContentsMargins(0, 2, 0, 0) # Minimal margins
145
- self.content_layout.setSpacing(4) # Reduced spacing
145
+ self.content_layout.setContentsMargins(0, 2, 0, 0)
146
+ self.content_layout.setSpacing(4)
146
147
 
147
- # Add input section
148
- self._add_input_content()
148
+ if self._should_show_diff_view():
149
+ self._add_diff_content()
150
+ else:
151
+ self._add_input_content()
149
152
 
150
- # Add result section if we have result data
151
153
  if self.result_data is not None:
152
154
  self._add_result_content()
153
155
 
154
- # Add to card layout
155
156
  self.card_layout.addWidget(self.content_container)
156
157
 
158
+ def _should_show_diff_view(self) -> bool:
159
+ """Check if this tool should display a diff view."""
160
+ if self.tool_name != "write_or_edit_file":
161
+ return False
162
+
163
+ arg_key = "input" if "input" in self.tool_data else "arguments"
164
+ tool_params = self.tool_data.get(arg_key, {})
165
+
166
+ if not isinstance(tool_params, dict):
167
+ return False
168
+
169
+ text_or_blocks = tool_params.get("text_or_search_replace_blocks", "")
170
+ return DiffWidget.has_search_replace_blocks(text_or_blocks)
171
+
172
+ def _add_diff_content(self):
173
+ """Add diff view content for write_or_edit_file tool."""
174
+ self.is_diff_view = True
175
+
176
+ arg_key = "input" if "input" in self.tool_data else "arguments"
177
+ tool_params = self.tool_data.get(arg_key, {})
178
+ file_path = tool_params.get("file_path", "")
179
+ text_or_blocks = tool_params.get("text_or_search_replace_blocks", "")
180
+
181
+ diff_colors = self.style_provider.get_diff_colors()
182
+ file_label = QLabel(f"📝 <b>File:</b> {file_path}")
183
+ file_label.setStyleSheet(
184
+ f"font-size: 12px; color: {diff_colors.get('header_text', '#89b4fa')}; padding: 2px;"
185
+ )
186
+ self.content_layout.addWidget(file_label)
187
+
188
+ diff_widget = CompactDiffWidget(style_provider=self.style_provider)
189
+ diff_widget.set_diff_content(text_or_blocks, file_path)
190
+ self.content_layout.addWidget(diff_widget)
191
+
157
192
  def _add_input_content(self):
158
193
  """Add input parameters to the content section"""
159
194
  # Input title
@@ -530,7 +530,6 @@ _GITHUB_COPILOT_MODELS = [
530
530
  provider="github_copilot",
531
531
  name="Claude Opus 4.5 (Preview)",
532
532
  description="",
533
- max_context_token=144_000,
534
533
  capabilities=["tool_use", "vision", "stream"],
535
534
  default=False,
536
535
  input_token_price_1m=0.0,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentcrew-ai
3
- Version: 0.8.6
3
+ Version: 0.8.7
4
4
  Summary: Multi-Agents Interactive Chat Tool
5
5
  Author-email: Quy Truong <quy.truong@saigontechnology.com>
6
6
  License-Expression: Apache-2.0
@@ -1,5 +1,5 @@
1
- AgentCrew/__init__.py,sha256=VpASnrti7EGWxUfSWGgERUfe7NLJltfVXYosOzHbpPg,22
2
- AgentCrew/app.py,sha256=dXjwoHLKf1tSOq1Vc-9wsF1dpjS5CaGqdiFSksKKwKA,36584
1
+ AgentCrew/__init__.py,sha256=vTwvdJOZi8jZb9U-Em7-d50qNDNPS2z51IXqRoojeNM,22
2
+ AgentCrew/app.py,sha256=s3pPfZfaZYxCNUC3HYWVQScK1iQZil6_Xguht3XX6mc,36603
3
3
  AgentCrew/main.py,sha256=tjyw4Z29YKKyzVKqDgF5icI1IM59DUiJrXZw6Sv_xN8,11187
4
4
  AgentCrew/main_docker.py,sha256=1jpB-XOm-t3GWTKYidGHHkCSzJ-p39ua0E6-_Nj8_9Y,5472
5
5
  AgentCrew/assets/agentcrew_logo.png,sha256=bA4WQ9QrZXxBd_GfbR2s5GWBRrRodzeDynQj7XHIPNw,944381
@@ -8,9 +8,9 @@ AgentCrew/modules/a2a/__init__.py,sha256=gFX0PAA6sxCRyAo_Gbs81cK2FckW11GnTxMhQpc
8
8
  AgentCrew/modules/a2a/adapters.py,sha256=GOTZVstQOhMus1QWcqVQZXEmPovfhxRrJ9loUtypGSY,7989
9
9
  AgentCrew/modules/a2a/agent_cards.py,sha256=SWmo3jVNSrPUqpL8Tv6T3h1a-0oXrOgqJrbPy7tz5XQ,4098
10
10
  AgentCrew/modules/a2a/errors.py,sha256=Yaw7Ew5LYDvrYgKZ34heBnEqlIXFF3_5GqqpNhNlveI,2353
11
- AgentCrew/modules/a2a/registry.py,sha256=1PkasOOpRqulE7mMl1UNSt5GrqGT8AhP9UCWWSAF34I,2671
11
+ AgentCrew/modules/a2a/registry.py,sha256=Qrf8jSZSNc-VWnSsbci0PLRqD00ViE3hCT4VAZDIhZA,2667
12
12
  AgentCrew/modules/a2a/server.py,sha256=CT_0Te4BBWJEwgbX0wLvHcu6gJAMFsGswwS4IOC5L_k,12345
13
- AgentCrew/modules/a2a/task_manager.py,sha256=PWQ759oOIH6C7NFubsmEsKELZ9sED6BChzPop29R9e0,30910
13
+ AgentCrew/modules/a2a/task_manager.py,sha256=vXYOa1_6cJ6_MyT7JuWIPKehX7sP_z0Na8a3IAwKrUg,31014
14
14
  AgentCrew/modules/a2a/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  AgentCrew/modules/a2a/common/client/__init__.py,sha256=PoBTKucH8G2onta-vHT4qUJcBYa3TIabGqCO5GVVyT0,118
16
16
  AgentCrew/modules/a2a/common/client/card_resolver.py,sha256=imtwwMNb1yLxTPcrct1ToH9fA18mzgAFYKR5vYTHHRw,637
@@ -22,7 +22,7 @@ AgentCrew/modules/a2a/common/server/utils.py,sha256=pmIBG5cyzaVNXbyESLux2AcogwPa
22
22
  AgentCrew/modules/agents/__init__.py,sha256=rMwchcGZzapLLZdUQUaJtCLowHoG-dOn8_VljKz8NrI,165
23
23
  AgentCrew/modules/agents/base.py,sha256=i7w0X7mcTRWwgyQwqN-iOIniLce9cSM2wGG3njlZpHk,2641
24
24
  AgentCrew/modules/agents/example.py,sha256=_-Nd7EKHprKXZLN9_ava0b9vR7wGyUzsXSEV7_js7Ho,6894
25
- AgentCrew/modules/agents/local_agent.py,sha256=Qp-89pQonSnM0QedV8w25RYANC290TUB5wRhfh3kT_0,31798
25
+ AgentCrew/modules/agents/local_agent.py,sha256=dVm4DBceUqxICgAM0_5gni2F94vEt2cdqxrakpDEX5s,31828
26
26
  AgentCrew/modules/agents/manager.py,sha256=JHwEp-GwlYMRTv2RItfJOnVJlePZOLK31xYi3taEuF0,24863
27
27
  AgentCrew/modules/agents/remote_agent.py,sha256=bBgO8E3dXZuu9ofklXLfL5-8mxF_XZOLyqj6rrwTXR8,6432
28
28
  AgentCrew/modules/agents/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -63,7 +63,7 @@ AgentCrew/modules/clipboard/__init__.py,sha256=Xb0wwQ-9dwwLT3R3TYB87pwtDTNX5HAzh
63
63
  AgentCrew/modules/clipboard/service.py,sha256=FCo3zSJH0zDdvW73u4D_ty9fTMsXmOeVsAIOfyJ54Ws,6246
64
64
  AgentCrew/modules/clipboard/tool.py,sha256=RMu6Cr5wP79SvfOqojAbu6g1WxBw6EUS4Mdfdr9VEuY,5474
65
65
  AgentCrew/modules/code_analysis/__init__.py,sha256=veGcJQiv2eR2YNRWM1xNhA0WkmEkkL3OLst1uSM-OyM,83
66
- AgentCrew/modules/code_analysis/service.py,sha256=6MW8DrRRX0rUHZfRBe92mDin8xZnf9FWx0HNYP28tVQ,63997
66
+ AgentCrew/modules/code_analysis/service.py,sha256=YMnUZjMtDqMAFoUz-oOIp66yacquqL6Kxkx2jShbDE4,63899
67
67
  AgentCrew/modules/code_analysis/tool.py,sha256=BRkouK2radiW0_IAz8ptPdTLodDMsGzjEORnlDmgKGI,6552
68
68
  AgentCrew/modules/command_execution/__init__.py,sha256=BIy7TSuz6yFaUQ0GEvXZO-ZSlkSwcRxforfIIhHCMTM,380
69
69
  AgentCrew/modules/command_execution/constants.py,sha256=zG2pwmA3MqBhnJgPrcBgzxzH2sWCbXQ4NyidX8lKQ6I,4693
@@ -79,7 +79,7 @@ AgentCrew/modules/console/confirmation_handler.py,sha256=sOhJVmrMgiqTlUI6G9xjzse
79
79
  AgentCrew/modules/console/console_ui.py,sha256=09XkGsIivVQK4z1-gOyuHtdXfiMMAyc4DvnWHlvIqho,29836
80
80
  AgentCrew/modules/console/constants.py,sha256=fwLj52O96_t6m1qb0SOiaotM2dMLwXH83KAERm9ltLA,704
81
81
  AgentCrew/modules/console/conversation_handler.py,sha256=vVtGxQJ4sEZJ77svBFJMIGiWiEfE47yDxvt7gZ9bRCA,3632
82
- AgentCrew/modules/console/diff_display.py,sha256=G1RYFJyu7yVCaEKwfphr0qYsRC1LycqXCBzfUniutk8,7092
82
+ AgentCrew/modules/console/diff_display.py,sha256=HTFy5H0sx6OHN_yjMPUeF8aum7esdgIg9Xd4_gCvPaw,7193
83
83
  AgentCrew/modules/console/display_handlers.py,sha256=ZSpBZxvX5X9VB2dvAB679KQwPTVhRPHRrmsgCMhANyA,17651
84
84
  AgentCrew/modules/console/input_handler.py,sha256=SNoDDhdpIwrQ7mPhF427NnS8tT0pnCIbvbI1bCWwG-Q,18140
85
85
  AgentCrew/modules/console/tool_display.py,sha256=aTjNWcfzmJXwpXU64PqMfNFRCiVrtMD-JFn_Wd2cNYY,7306
@@ -89,7 +89,7 @@ AgentCrew/modules/custom_llm/__init__.py,sha256=NvgE3c6rYd52SmRITqGeHqaGOnHrK9vU
89
89
  AgentCrew/modules/custom_llm/copilot_response_service.py,sha256=tySzxnLMzMt3WjwhvBegtDP7Qk43D2Wc5bxZAi0Z3sA,4605
90
90
  AgentCrew/modules/custom_llm/deepinfra_service.py,sha256=uY7f-lg-hnR7A1ZYwKSE10c4WlJ9C693eBiZxLV6jlw,7553
91
91
  AgentCrew/modules/custom_llm/github_copilot_service.py,sha256=yCWpD5Sn6LiWMeMtR6sKMTq-xeEXxge5WFpHP84SvjU,14391
92
- AgentCrew/modules/custom_llm/service.py,sha256=UkF8RtCw56eY1Tusc-SUSobz7IvnYBIgGvZNctuIWQk,19437
92
+ AgentCrew/modules/custom_llm/service.py,sha256=XLq_n2TTh4CuGb9vmHZvO7l2a45SPSVfAHxZRFquB1Q,19395
93
93
  AgentCrew/modules/file_editing/__init__.py,sha256=Q6oDyP3bHslFpmxHdrCCLVx1M_awaHD2WqFTSEU3VIY,241
94
94
  AgentCrew/modules/file_editing/safety_validator.py,sha256=lLNb_GpIIX2QtN86U2NKbM-b3VYW3b6jNkXL5hKPlok,5575
95
95
  AgentCrew/modules/file_editing/search_replace_engine.py,sha256=i8e18VIvxOwCazjnfrmLp637laDCsJSpZs5YsW9Ic-Y,10751
@@ -113,23 +113,24 @@ AgentCrew/modules/gui/components/input_components.py,sha256=IYKigulYCNJ6Et5rLCEX
113
113
  AgentCrew/modules/gui/components/keyboard_handler.py,sha256=uNBvaOOIcBHaqstA4JbTrkDEmlh0r6Y6_gRG9gD1WCw,5770
114
114
  AgentCrew/modules/gui/components/menu_components.py,sha256=Dy6yo61R4sEANZEfRdl3pOTUb5Io6nmUEqMfYc0nW9I,5327
115
115
  AgentCrew/modules/gui/components/message_handlers.py,sha256=CluNFGNXjWbJFf6RhAlqgmA9o_gcJRXLEG7FIQW07W0,5391
116
- AgentCrew/modules/gui/components/tool_handlers.py,sha256=ia6nq_9Du4W27wkR15isps-nM3f90Ht51J6zVu-QWXg,15893
116
+ AgentCrew/modules/gui/components/tool_handlers.py,sha256=mHJRFwjGuGC8B7Ydy7qmMfZlNH0jfFdwHZaMJMjLNdk,22065
117
117
  AgentCrew/modules/gui/components/ui_state_manager.py,sha256=w_gmdykpFbZE84lgA1I_ordqky_QpPUOf39ni26KEfw,5131
118
118
  AgentCrew/modules/gui/themes/README.md,sha256=mYiu9SV1OjhDgjCpnnvhvME-5ROnAcvEu5AkW3rJEjo,4844
119
119
  AgentCrew/modules/gui/themes/__init__.py,sha256=kOJruvfsx48F9V6ArwsnqfT2QxcJ_THdhJIZ81B3R3k,71
120
- AgentCrew/modules/gui/themes/atom_light.py,sha256=u9HuC3Zw041neEuw50E7pVmDf81N6Ct3L0CqEimReAw,35999
121
- AgentCrew/modules/gui/themes/catppuccin.py,sha256=es9iXegVtesgyVOQbot5tAbUx6sYgY_WhADjzjAtTeU,40262
122
- AgentCrew/modules/gui/themes/dracula.py,sha256=4JXzUqXlWcZjBRYQhBqnb8AKTaeEuD8Kindx0DbIAMI,38518
123
- AgentCrew/modules/gui/themes/nord.py,sha256=BP3RLu9Ym7ZztnV3M0IsJ907SOb3pE5Y_6-soChzYQ0,38282
124
- AgentCrew/modules/gui/themes/saigontech.py,sha256=k7RoX7YQSqD6XD0dNLJGIEx0cuXSxewyiuMnW1WRmRY,40462
125
- AgentCrew/modules/gui/themes/style_provider.py,sha256=CxOCdbtlrhjd0Hxk4imeSJ-mCw3-YCjRLg-jRdmJOJ0,13563
126
- AgentCrew/modules/gui/themes/unicorn.py,sha256=0o-GWdSitnjD0znmPt80CH_i6qxpYj9-rRftbL2aucI,37676
120
+ AgentCrew/modules/gui/themes/atom_light.py,sha256=crx6Yw_5i_Sim5ZxJW_T3HzSpIsskyUdATlHuugpwds,36892
121
+ AgentCrew/modules/gui/themes/catppuccin.py,sha256=hbC4LtGQbRNvfRfSBhmvew2f9Zo8ORL-HfxlN90IkHQ,41116
122
+ AgentCrew/modules/gui/themes/dracula.py,sha256=hLpqmBl8bEV6zlxqmeEFI4BFBOvfH_4bv87cGRDR69o,39340
123
+ AgentCrew/modules/gui/themes/nord.py,sha256=FpwcB2yPN1ybDbiiDF1TD6Tw0MPtpzrFpKeQzMRAP40,39151
124
+ AgentCrew/modules/gui/themes/saigontech.py,sha256=-b-Sc44eM4cVpfcsIyFPrT1FTdjfUZnK06UorzIAl6I,41291
125
+ AgentCrew/modules/gui/themes/style_provider.py,sha256=2BUwvS4iZOGfgtryi8oPL4JaJjJS8VSoqakxW35VPAI,14470
126
+ AgentCrew/modules/gui/themes/unicorn.py,sha256=kGrQB9CNopoy9GS8KFZA07i-xTrN70p_qMrVH2vM2uk,38476
127
127
  AgentCrew/modules/gui/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
128
128
  AgentCrew/modules/gui/utils/macos_clipboard.py,sha256=VV0QP2_lWyaL8CB_9dGZuajpON5i12wiDeh6Nbci1pA,510
129
129
  AgentCrew/modules/gui/utils/strings.py,sha256=zSnec-CHz8JF3H6BgPGjfDr10NilRumorlwh-tuvUBs,540
130
130
  AgentCrew/modules/gui/utils/wins_clipboard.py,sha256=8LXKje-WzR3Iubu8c_37s-j8DP_5KDywrQEEpfxMcZU,2440
131
- AgentCrew/modules/gui/widgets/__init__.py,sha256=QfcwAB-lMGWf0L960VuJX-Wfft3Akd5RM0Evk5AHO5E,395
131
+ AgentCrew/modules/gui/widgets/__init__.py,sha256=Rc6P_K8d9Dw6H3AGAwnmkuhIxEu5ulht3w7VYJK-cds,493
132
132
  AgentCrew/modules/gui/widgets/config_window.py,sha256=QxwnT7N6C0Jm8OOJ4WJE71j7tqDH0kTJVCCGnzR4SZw,3099
133
+ AgentCrew/modules/gui/widgets/diff_widget.py,sha256=p0z3iOwV4-OZfvxIdksp8xjECSrbZ7Jzw16v_L7YyPo,18692
133
134
  AgentCrew/modules/gui/widgets/history_sidebar.py,sha256=n-WMPf5cm5jNB_cT3IoK_nzAAczRCA1GeWsY4O0bg5k,10596
134
135
  AgentCrew/modules/gui/widgets/json_editor.py,sha256=lV-Me8TUJzIkF-tbiRiFSdRGDbxv9bBKDdSSLwof7oU,6211
135
136
  AgentCrew/modules/gui/widgets/loading_overlay.py,sha256=jCfHDDJ5YudfwU15s61l3zQVeWoRhI38WvaTylysR9g,3630
@@ -138,7 +139,7 @@ AgentCrew/modules/gui/widgets/message_bubble.py,sha256=am3qhfilT-5vMSHatuAj44wvP
138
139
  AgentCrew/modules/gui/widgets/paste_aware_textedit.py,sha256=_bbM3S0dWD-Kt5s_xxnwuS0OA7lLpvCmGAfsGrRvfNs,1891
139
140
  AgentCrew/modules/gui/widgets/system_message.py,sha256=3uUwFMIL3vsm3Oa4EiNf9fw2zQzuqWWnb8XmrRCMxaY,5796
140
141
  AgentCrew/modules/gui/widgets/token_usage.py,sha256=xfiY_IiCzMwDIYZi8bjRxgOWhqyAAWMNs22weJUABo0,1917
141
- AgentCrew/modules/gui/widgets/tool_widget.py,sha256=YFlC-MZhEug3ZimfRa-RyRy5hZsHvUuJH8KKA8ghKjA,12422
142
+ AgentCrew/modules/gui/widgets/tool_widget.py,sha256=h9-Pbn_dQ3Oebog-IJ8JcY7MqSduzGyPL9FTqCRZZu8,13849
142
143
  AgentCrew/modules/gui/widgets/configs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
143
144
  AgentCrew/modules/gui/widgets/configs/agent_config.py,sha256=IRU-s6YsLJiPoi0buDiSL4CRFz1-k0VAmL9DLJh7jT0,52234
144
145
  AgentCrew/modules/gui/widgets/configs/custom_llm_provider.py,sha256=TY3AJUl46vlpy9s4OzxdpFr_zsWCJTyM6roz9GBaUCs,35068
@@ -150,7 +151,7 @@ AgentCrew/modules/image_generation/service.py,sha256=OEuVaVd4ecKSdZn-WGMmqyZtqDw
150
151
  AgentCrew/modules/image_generation/tool.py,sha256=TCe6tOvvCXj5LvjMtmxH1AQ5s2FWHDA79ix43hdzGZs,6087
151
152
  AgentCrew/modules/llm/__init__.py,sha256=dMlHRa09bbPEVZnGXm62TcHmbvQzdBqmRIxstlrls8k,63
152
153
  AgentCrew/modules/llm/base.py,sha256=S2Tzg4LXQv69MVjNScWbpid3cM20QCgW0KHQqvghjeI,11511
153
- AgentCrew/modules/llm/constants.py,sha256=zrtjbr2hkzU0NRzbRqFuea2sbJZw5ZEPpNqHsUNE7_Q,19842
154
+ AgentCrew/modules/llm/constants.py,sha256=yur9HHdmRtyvMUj8m5InM0EsOfcL1Q4TuvogAjHxXjA,19807
154
155
  AgentCrew/modules/llm/model_registry.py,sha256=7gJqn-YoentH2Xx0AlF5goyxQDlEBMFWak2poafjhyI,5510
155
156
  AgentCrew/modules/llm/service_manager.py,sha256=oXSjcAbrfcGLdBcm_ylnSWIp87Ecl96yZ8efkWFb4Gw,10669
156
157
  AgentCrew/modules/llm/types.py,sha256=Bkr1OIRJJ5neUiSCMUJco8SwerrycPh5Xg1kVDpO0os,949
@@ -185,9 +186,9 @@ AgentCrew/modules/voice/text_cleaner.py,sha256=NgAVBPkP2hFI330nJOyMK_oqP3R2AGZ22
185
186
  AgentCrew/modules/web_search/__init__.py,sha256=sVf_z6nH2JghK46pG92PUtDghPIkceiX1F0Ul30euXU,111
186
187
  AgentCrew/modules/web_search/service.py,sha256=DKcOdRSHB5AEvbK8pvTXdffSnk6rFRTzaM1FXf2B70E,4006
187
188
  AgentCrew/modules/web_search/tool.py,sha256=GV4xleVFs0UwiPS9toSzPzZei3ehsDZWxTQCJCRaEs8,6655
188
- agentcrew_ai-0.8.6.dist-info/licenses/LICENSE,sha256=O51CIaOUcxVLNf0_PE_a8ap5bf3iXe4SrWN_5NO1PSU,11348
189
- agentcrew_ai-0.8.6.dist-info/METADATA,sha256=IW-DADzKKFX4MXJz_H8IT6wmmuafbeLEHcl15mz2Xrg,18056
190
- agentcrew_ai-0.8.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
191
- agentcrew_ai-0.8.6.dist-info/entry_points.txt,sha256=N9R5jslrBYA8dTaNMRJ_JdSosJ6jkpGEtnJFzlcZD6k,54
192
- agentcrew_ai-0.8.6.dist-info/top_level.txt,sha256=bSsmhCOn6g-JytoVMpxB_QAnCgb7lV56fcnxUhbfrvg,10
193
- agentcrew_ai-0.8.6.dist-info/RECORD,,
189
+ agentcrew_ai-0.8.7.dist-info/licenses/LICENSE,sha256=O51CIaOUcxVLNf0_PE_a8ap5bf3iXe4SrWN_5NO1PSU,11348
190
+ agentcrew_ai-0.8.7.dist-info/METADATA,sha256=pAPP0PKBi1ZUFW77GcCitWRS63n7cRw3N5puToKl2ms,18056
191
+ agentcrew_ai-0.8.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
192
+ agentcrew_ai-0.8.7.dist-info/entry_points.txt,sha256=N9R5jslrBYA8dTaNMRJ_JdSosJ6jkpGEtnJFzlcZD6k,54
193
+ agentcrew_ai-0.8.7.dist-info/top_level.txt,sha256=bSsmhCOn6g-JytoVMpxB_QAnCgb7lV56fcnxUhbfrvg,10
194
+ agentcrew_ai-0.8.7.dist-info/RECORD,,