Add tool composition UI with auto-dependency management

- Add ToolStepDialog for configuring tool steps (tool selection, input mapping, args)
- Add "Add Tool" button in Tool Builder alongside Add Prompt/Add Code
- Add ToolNode in flow graph visualization (purple puzzle piece icon)
- Auto-populate dependencies when adding ToolStep in GUI
- Add --auto-install flag for automatic runtime dependency installation
- Add check_dependencies() and auto_install_dependencies() functions
- Update runner to pass auto_install parameter through execution chain

Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit is contained in:
rob
2026-01-17 05:27:54 -04:00
co-authored by Claude Opus 4.5
parent 05a2fae94c
commit 3f259449d4
5 changed files with 435 additions and 11 deletions
+60
View File
@@ -273,3 +273,63 @@ def get_output_icon(size: int = 24) -> QIcon:
if key not in _icon_cache:
_icon_cache[key] = create_output_icon(size)
return _icon_cache[key]
def create_tool_icon(size: int = 24, color: QColor = None) -> QIcon:
"""Create a puzzle piece icon for tool steps (calling another tool).
Args:
size: Icon size in pixels
color: Icon color (defaults to purple #9f7aea)
"""
if color is None:
color = QColor(159, 122, 234) # Purple
pixmap = QPixmap(size, size)
pixmap.fill(Qt.transparent)
painter = QPainter(pixmap)
painter.setRenderHint(QPainter.Antialiasing)
pen = QPen(color, 1.5)
painter.setPen(pen)
painter.setBrush(QBrush(color))
# Draw a simple puzzle piece shape
margin = size * 0.12
w = size - 2 * margin
h = size - 2 * margin
path = QPainterPath()
# Start from top-left, going clockwise
path.moveTo(margin, margin + h * 0.3)
# Top edge with bump
path.lineTo(margin + w * 0.35, margin + h * 0.3)
path.arcTo(QRectF(margin + w * 0.35 - w * 0.1, margin, w * 0.3, h * 0.3), 180, -180)
path.lineTo(margin + w, margin + h * 0.3)
# Right edge
path.lineTo(margin + w, margin + h * 0.7)
# Bottom edge with notch
path.lineTo(margin + w * 0.65, margin + h * 0.7)
path.arcTo(QRectF(margin + w * 0.35, margin + h * 0.7, w * 0.3, h * 0.3), 0, 180)
path.lineTo(margin, margin + h * 0.7)
# Left edge back to start
path.closeSubpath()
painter.drawPath(path)
painter.end()
return QIcon(pixmap)
def get_tool_icon(size: int = 24) -> QIcon:
"""Get cached tool icon."""
key = ('tool', size)
if key not in _icon_cache:
_icon_cache[key] = create_tool_icon(size)
return _icon_cache[key]
def get_tool_icon_path(size: int = 16) -> str:
"""Get file path to tool icon (for NodeGraphQt)."""
return _get_icon_path('tool', size, create_tool_icon)