mirror of
https://github.com/hanzoai/python-sdk.git
synced 2026-10-23 20:23:00 +00:00
docs(tools): add comprehensive documentation for all tool packages
Add detailed documentation with examples for: - hanzo-tools-fs: read, write, edit, tree, find, search, ast - hanzo-tools-shell: cmd, ps, zsh, bash, auto-backgrounding - hanzo-tools-browser: 70+ Playwright actions, device emulation - hanzo-tools-memory: memories, facts, knowledge bases, scopes - hanzo-tools-reasoning: think and critic tools - hanzo-tools-lsp: go-to-definition, references, rename, hover - hanzo-tools-refactor: rename, extract, inline, batch operations - hanzo-tools-agent: multi-agent orchestration, consensus, swarm - hanzo-tools-llm: unified LLM interface with 100+ models Each doc includes: - Installation instructions - Quick start examples - Full API reference - Usage examples - Best practices
This commit is contained in:
+363
-2
@@ -1,2 +1,363 @@
|
||||
# agent
|
||||
Documentation coming soon.
|
||||
# hanzo-tools-agent
|
||||
|
||||
Multi-agent orchestration with CLI spawning, DAG execution, swarm distribution, and Metastable consensus.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hanzo-tools-agent
|
||||
```
|
||||
|
||||
With optional features:
|
||||
|
||||
```bash
|
||||
pip install hanzo-tools-agent[api] # httpx for direct API mode
|
||||
pip install hanzo-tools-agent[perf] # uvloop for high performance
|
||||
pip install hanzo-tools-agent[full] # All features
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
`hanzo-tools-agent` provides:
|
||||
|
||||
- **agent** - Multi-agent orchestration (run, dag, swarm, consensus, dispatch)
|
||||
- **iching** - I Ching wisdom for engineering decisions
|
||||
- **review** - Code review tool
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
# Run a single agent
|
||||
agent(action="run", name="claude", prompt="Explain this code")
|
||||
|
||||
# List available agents
|
||||
agent(action="list")
|
||||
|
||||
# Run consensus across multiple models
|
||||
agent(action="consensus", prompt="Best approach for caching?", agents=["claude", "gemini", "codex"])
|
||||
|
||||
# Swarm pattern - distribute work
|
||||
agent(action="swarm", items=["file1.py", "file2.py"], template="Review {item}")
|
||||
|
||||
# DAG execution with dependencies
|
||||
agent(action="dag", tasks=[
|
||||
{"id": "analyze", "prompt": "Analyze the codebase"},
|
||||
{"id": "plan", "prompt": "Create implementation plan", "after": ["analyze"]}
|
||||
])
|
||||
```
|
||||
|
||||
## Available Agents
|
||||
|
||||
| Agent | Description | API Key Env |
|
||||
|-------|-------------|-------------|
|
||||
| `claude` | Anthropic Claude Code CLI | `ANTHROPIC_API_KEY` |
|
||||
| `codex` | OpenAI Codex CLI | `OPENAI_API_KEY` |
|
||||
| `gemini` | Google Gemini CLI | `GOOGLE_API_KEY` |
|
||||
| `grok` | xAI Grok CLI | `XAI_API_KEY` |
|
||||
| `qwen` | Alibaba Qwen CLI | `DASHSCOPE_API_KEY` |
|
||||
| `vibe` | Vibe coding agent | - |
|
||||
| `dev` | Hanzo Dev agent | - |
|
||||
|
||||
## Actions Reference
|
||||
|
||||
### run
|
||||
|
||||
Run a single agent with a prompt.
|
||||
|
||||
```python
|
||||
# Default agent (claude in Claude Code environment)
|
||||
agent(action="run", prompt="Explain this error")
|
||||
|
||||
# Specific agent
|
||||
agent(action="run", name="gemini", prompt="Review this code")
|
||||
|
||||
# With working directory
|
||||
agent(action="run", name="codex", prompt="Fix the tests", cwd="/project/path")
|
||||
|
||||
# With timeout
|
||||
agent(action="run", name="claude", prompt="Complex task", timeout=300)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `name`: Agent to use (default: auto-detect)
|
||||
- `prompt` (required): Task for the agent
|
||||
- `cwd`: Working directory
|
||||
- `timeout`: Timeout in seconds (default: 300)
|
||||
|
||||
### dag
|
||||
|
||||
Execute tasks with dependencies using a DAG (Directed Acyclic Graph).
|
||||
|
||||
```python
|
||||
agent(
|
||||
action="dag",
|
||||
tasks=[
|
||||
{"id": "research", "prompt": "Research best practices for caching"},
|
||||
{"id": "design", "prompt": "Design cache architecture", "after": ["research"]},
|
||||
{"id": "implement", "prompt": "Implement the cache", "after": ["design"]},
|
||||
{"id": "test", "prompt": "Write tests", "after": ["implement"]}
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
**Task format:**
|
||||
- `id` (required): Unique task identifier
|
||||
- `prompt` (required): Task description
|
||||
- `after`: List of task IDs that must complete first
|
||||
- `agent`: Specific agent for this task (optional)
|
||||
|
||||
### swarm
|
||||
|
||||
Distribute work across multiple agents in parallel.
|
||||
|
||||
```python
|
||||
# Process multiple files
|
||||
agent(
|
||||
action="swarm",
|
||||
items=["auth.py", "api.py", "models.py"],
|
||||
template="Review {item} for security issues",
|
||||
max_concurrent=5
|
||||
)
|
||||
|
||||
# Multiple prompts
|
||||
agent(
|
||||
action="swarm",
|
||||
items=["Add error handling", "Add logging", "Add tests"],
|
||||
template="{item} to the authentication module"
|
||||
)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `items` (required): List of items to process
|
||||
- `template` (required): Prompt template with `{item}` placeholder
|
||||
- `max_concurrent`: Maximum parallel agents (default: 100)
|
||||
|
||||
### consensus
|
||||
|
||||
Run Metastable consensus across multiple models.
|
||||
|
||||
```python
|
||||
agent(
|
||||
action="consensus",
|
||||
prompt="What's the best database for this use case?",
|
||||
agents=["claude", "gemini", "codex"],
|
||||
rounds=3, # Consensus rounds
|
||||
k=3, # Sample size per round
|
||||
alpha=0.6, # Agreement threshold
|
||||
beta_1=0.5, # Preference threshold
|
||||
beta_2=0.8 # Decision threshold
|
||||
)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `prompt` (required): Question for consensus
|
||||
- `agents`: Models to participate (default: all available)
|
||||
- `rounds`: Number of consensus rounds (default: 3)
|
||||
- `k`: Sample size per round (default: 3)
|
||||
- `alpha`: Agreement threshold (default: 0.6)
|
||||
- `beta_1`: Phase I preference threshold (default: 0.5)
|
||||
- `beta_2`: Phase II decision threshold (default: 0.8)
|
||||
|
||||
**Consensus Protocol:**
|
||||
Based on [Metastable Consensus](https://github.com/luxfi/consensus):
|
||||
- Phase I (Sampling): k-peer sampling, confidence accumulation
|
||||
- Phase II (Finality): Threshold aggregation, winner synthesis
|
||||
|
||||
### dispatch
|
||||
|
||||
Route different tasks to different agents.
|
||||
|
||||
```python
|
||||
agent(
|
||||
action="dispatch",
|
||||
tasks=[
|
||||
{"agent": "claude", "prompt": "Review code quality"},
|
||||
{"agent": "codex", "prompt": "Suggest optimizations"},
|
||||
{"agent": "gemini", "prompt": "Check documentation"}
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
### list
|
||||
|
||||
List all available agents.
|
||||
|
||||
```python
|
||||
agent(action="list")
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"agents": ["claude", "codex", "gemini", "grok", "qwen", "vibe", "dev"],
|
||||
"available": ["claude", "gemini"],
|
||||
"configured": ["claude", "codex", "gemini"]
|
||||
}
|
||||
```
|
||||
|
||||
### status
|
||||
|
||||
Check if a specific agent is available.
|
||||
|
||||
```python
|
||||
agent(action="status", name="claude")
|
||||
```
|
||||
|
||||
### config
|
||||
|
||||
Show agent configuration.
|
||||
|
||||
```python
|
||||
agent(action="config")
|
||||
```
|
||||
|
||||
## Agent Configuration
|
||||
|
||||
### Config Files
|
||||
|
||||
Configure agents via `~/.hanzo/agents/<name>.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"cmd": "claude",
|
||||
"args": ["--print", "--dangerously-skip-permissions"],
|
||||
"env_key": "ANTHROPIC_API_KEY",
|
||||
"max_turns": 999,
|
||||
"session": true,
|
||||
"model": "claude-3-opus",
|
||||
"system_prompt": "You are a helpful assistant"
|
||||
}
|
||||
```
|
||||
|
||||
### Environment Overrides
|
||||
|
||||
Override arguments via environment:
|
||||
|
||||
```bash
|
||||
export HANZO_AGENT_CLAUDE_ARGS="--verbose --model claude-3-5-sonnet"
|
||||
```
|
||||
|
||||
### API Mode
|
||||
|
||||
Configure direct API calls (no CLI needed):
|
||||
|
||||
```json
|
||||
{
|
||||
"endpoint": "https://api.openai.com/v1/chat/completions",
|
||||
"api_type": "openai",
|
||||
"model": "gpt-4",
|
||||
"env_key": "OPENAI_API_KEY",
|
||||
"system_prompt": "You are a helpful assistant"
|
||||
}
|
||||
```
|
||||
|
||||
## YOLO Mode
|
||||
|
||||
All agents are configured with autonomous operation flags:
|
||||
|
||||
| Agent | YOLO Flags |
|
||||
|-------|------------|
|
||||
| claude | `--dangerously-skip-permissions`, `--print`, `--output-format text` |
|
||||
| codex | `--full-auto` |
|
||||
| gemini | `-y`, `-q` |
|
||||
| grok | `-y` |
|
||||
| qwen | `--approval-mode yolo`, `-p` |
|
||||
| vibe | `--auto-approve`, `--max-turns 999`, `-p` |
|
||||
|
||||
## Auto-Backgrounding
|
||||
|
||||
Long-running agents automatically background after timeout:
|
||||
|
||||
```python
|
||||
# Long task - will auto-background
|
||||
agent(action="run", name="claude", prompt="Complex refactoring task", timeout=300)
|
||||
|
||||
# Check status with ps tool
|
||||
ps() # List all processes
|
||||
ps(logs="agent_xxx") # View output
|
||||
ps(kill="agent_xxx") # Stop process
|
||||
```
|
||||
|
||||
## IChingTool
|
||||
|
||||
Apply I Ching wisdom to engineering challenges.
|
||||
|
||||
```python
|
||||
iching(challenge="How should I approach refactoring this legacy codebase?")
|
||||
```
|
||||
|
||||
**Response:**
|
||||
- Hexagram interpretation
|
||||
- Relevant Hanzo principles
|
||||
- Actionable recommendations
|
||||
|
||||
## ReviewTool
|
||||
|
||||
Request balanced code review.
|
||||
|
||||
```python
|
||||
review(
|
||||
focus="FUNCTIONALITY",
|
||||
work_description="Implemented auto-import feature for Go files",
|
||||
code_snippets=["func AddImport(file string) error { ... }"],
|
||||
file_paths=["/path/to/import_handler.go"],
|
||||
context="This will be used to automatically fix missing imports"
|
||||
)
|
||||
```
|
||||
|
||||
**Focus areas:**
|
||||
- `GENERAL` - Overall code quality
|
||||
- `FUNCTIONALITY` - Does it work correctly?
|
||||
- `READABILITY` - Is it easy to understand?
|
||||
- `MAINTAINABILITY` - Is it easy to modify?
|
||||
- `TESTING` - Is it well tested?
|
||||
- `DOCUMENTATION` - Is it well documented?
|
||||
- `ARCHITECTURE` - Is the design sound?
|
||||
|
||||
## Examples
|
||||
|
||||
### Multi-Agent Code Review
|
||||
|
||||
```python
|
||||
# Get perspectives from multiple agents
|
||||
agent(
|
||||
action="consensus",
|
||||
prompt="Review this pull request for issues",
|
||||
agents=["claude", "gemini", "codex"]
|
||||
)
|
||||
```
|
||||
|
||||
### Parallel File Processing
|
||||
|
||||
```python
|
||||
# Review all files in parallel
|
||||
agent(
|
||||
action="swarm",
|
||||
items=["src/auth.py", "src/api.py", "src/models.py", "src/utils.py"],
|
||||
template="Review {item} and suggest improvements",
|
||||
max_concurrent=4
|
||||
)
|
||||
```
|
||||
|
||||
### Sequential Workflow
|
||||
|
||||
```python
|
||||
# Plan → Implement → Test
|
||||
agent(
|
||||
action="dag",
|
||||
tasks=[
|
||||
{"id": "plan", "prompt": "Create implementation plan for user auth"},
|
||||
{"id": "implement", "prompt": "Implement the plan", "after": ["plan"]},
|
||||
{"id": "test", "prompt": "Write comprehensive tests", "after": ["implement"]},
|
||||
{"id": "review", "prompt": "Review implementation", "after": ["test"]}
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use consensus for decisions** - Multiple perspectives reduce bias
|
||||
2. **Use swarm for bulk operations** - Parallel processing is faster
|
||||
3. **Use DAG for workflows** - Dependencies ensure correct ordering
|
||||
4. **Configure timeouts appropriately** - Complex tasks need more time
|
||||
5. **Check agent availability** - Use `status` before assuming an agent exists
|
||||
|
||||
+350
-2
@@ -1,2 +1,350 @@
|
||||
# urowser
|
||||
Documentation coming soon.
|
||||
# hanzo-tools-browser
|
||||
|
||||
Complete browser automation with full Playwright API. Provides 70+ actions for navigation, forms, mouse control, assertions, and more.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hanzo-tools-browser
|
||||
playwright install chromium
|
||||
```
|
||||
|
||||
Or as part of the full toolkit:
|
||||
|
||||
```bash
|
||||
pip install hanzo-mcp[tools-all]
|
||||
playwright install chromium
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
`hanzo-tools-browser` provides comprehensive browser automation:
|
||||
|
||||
- **Navigation**: navigate, reload, go_back, go_forward
|
||||
- **Input**: click, type, fill, press, select_option
|
||||
- **Mouse**: hover, drag, scroll, mouse_move
|
||||
- **Touch**: tap, swipe, pinch (mobile emulation)
|
||||
- **Assertions**: expect_visible, expect_text, expect_url
|
||||
- **Content**: get_text, get_attribute, screenshot
|
||||
- **Storage**: cookies, localStorage, sessionStorage
|
||||
- **Network**: route (mock/block requests)
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
# Navigate to page
|
||||
browser(action="navigate", url="https://example.com")
|
||||
|
||||
# Click a button
|
||||
browser(action="click", selector="button.submit")
|
||||
|
||||
# Fill a form
|
||||
browser(action="fill", selector="input[name='email']", text="[email protected]")
|
||||
|
||||
# Take screenshot
|
||||
browser(action="screenshot", full_page=True)
|
||||
```
|
||||
|
||||
## Device Emulation
|
||||
|
||||
Built-in device presets for responsive testing:
|
||||
|
||||
```python
|
||||
# User-friendly aliases
|
||||
browser(action="emulate", device="mobile") # iPhone-like (390x844)
|
||||
browser(action="emulate", device="tablet") # iPad-like (1024x1366)
|
||||
browser(action="emulate", device="laptop") # MacBook-like (1440x900)
|
||||
browser(action="emulate", device="desktop") # Full HD (1920x1080)
|
||||
|
||||
# Specific devices
|
||||
browser(action="emulate", device="iphone_14")
|
||||
browser(action="emulate", device="pixel_7")
|
||||
browser(action="emulate", device="ipad_pro")
|
||||
```
|
||||
|
||||
## Navigation
|
||||
|
||||
```python
|
||||
# Basic navigation
|
||||
browser(action="navigate", url="https://example.com")
|
||||
browser(action="reload")
|
||||
browser(action="go_back")
|
||||
browser(action="go_forward")
|
||||
|
||||
# Get page info
|
||||
browser(action="url") # Current URL
|
||||
browser(action="title") # Page title
|
||||
browser(action="content") # HTML content
|
||||
```
|
||||
|
||||
## Input Actions
|
||||
|
||||
```python
|
||||
# Click variants
|
||||
browser(action="click", selector="button")
|
||||
browser(action="dblclick", selector=".item")
|
||||
browser(action="right_click", selector=".context-menu")
|
||||
|
||||
# Text input
|
||||
browser(action="type", selector="input", text="Hello", interval=0.1)
|
||||
browser(action="fill", selector="input", text="Instant fill")
|
||||
browser(action="clear", selector="input")
|
||||
|
||||
# Keyboard
|
||||
browser(action="press", key="Enter")
|
||||
browser(action="press", key="Control+c")
|
||||
```
|
||||
|
||||
## Form Handling
|
||||
|
||||
```python
|
||||
# Select dropdowns
|
||||
browser(action="select_option", selector="select", value="option1")
|
||||
|
||||
# Checkboxes
|
||||
browser(action="check", selector="input[type='checkbox']")
|
||||
browser(action="uncheck", selector="input[type='checkbox']")
|
||||
|
||||
# File uploads
|
||||
browser(action="upload", selector="input[type='file']", files=["./doc.pdf"])
|
||||
```
|
||||
|
||||
## Mouse Control
|
||||
|
||||
```python
|
||||
# Hover
|
||||
browser(action="hover", selector=".menu-item")
|
||||
|
||||
# Drag and drop
|
||||
browser(action="drag", selector=".draggable", target_selector=".dropzone")
|
||||
|
||||
# Scroll
|
||||
browser(action="scroll", delta_y=500)
|
||||
browser(action="scroll", selector=".container", delta_y=300)
|
||||
|
||||
# Mouse coordinates
|
||||
browser(action="mouse_move", x=100, y=200)
|
||||
browser(action="mouse_down")
|
||||
browser(action="mouse_up")
|
||||
```
|
||||
|
||||
## Touch & Mobile
|
||||
|
||||
```python
|
||||
# Touch actions
|
||||
browser(action="tap", selector="button")
|
||||
browser(action="swipe", direction="up", distance=300)
|
||||
browser(action="pinch", scale=0.5) # Zoom out
|
||||
browser(action="pinch", scale=2.0) # Zoom in
|
||||
```
|
||||
|
||||
## Locators
|
||||
|
||||
```python
|
||||
# CSS/XPath
|
||||
browser(action="locator", selector="div.class")
|
||||
browser(action="locator", selector="//button[@id='submit']")
|
||||
|
||||
# Semantic locators
|
||||
browser(action="get_by_role", role="button", name="Submit")
|
||||
browser(action="get_by_text", text="Click me")
|
||||
browser(action="get_by_label", text="Email")
|
||||
browser(action="get_by_placeholder", text="Enter email")
|
||||
browser(action="get_by_test_id", text="submit-btn")
|
||||
|
||||
# Composition
|
||||
browser(action="first", selector=".items")
|
||||
browser(action="last", selector=".items")
|
||||
browser(action="nth", selector=".items", index=2)
|
||||
browser(action="filter", selector=".items", has_text="Important")
|
||||
```
|
||||
|
||||
## Assertions
|
||||
|
||||
```python
|
||||
# Element assertions
|
||||
browser(action="expect_visible", selector=".modal")
|
||||
browser(action="expect_hidden", selector=".loading")
|
||||
browser(action="expect_enabled", selector="button")
|
||||
browser(action="expect_text", selector="h1", expected="Welcome")
|
||||
browser(action="expect_count", selector=".items", index=5)
|
||||
|
||||
# Page assertions
|
||||
browser(action="expect_url", expected="*/dashboard*")
|
||||
browser(action="expect_title", expected="Dashboard")
|
||||
|
||||
# Negative assertions
|
||||
browser(action="expect_visible", selector=".loading", not_=True)
|
||||
```
|
||||
|
||||
## Content Extraction
|
||||
|
||||
```python
|
||||
# Get text content
|
||||
browser(action="get_text", selector="h1")
|
||||
browser(action="get_inner_text", selector=".content")
|
||||
|
||||
# Get attributes
|
||||
browser(action="get_attribute", selector="a", attribute="href")
|
||||
browser(action="get_value", selector="input")
|
||||
|
||||
# Get HTML
|
||||
browser(action="get_html", selector=".container")
|
||||
|
||||
# Get bounding box
|
||||
browser(action="get_bounding_box", selector=".element")
|
||||
```
|
||||
|
||||
## State Checking
|
||||
|
||||
```python
|
||||
browser(action="is_visible", selector=".modal")
|
||||
browser(action="is_hidden", selector=".loading")
|
||||
browser(action="is_enabled", selector="button")
|
||||
browser(action="is_editable", selector="input")
|
||||
browser(action="is_checked", selector="input[type='checkbox']")
|
||||
```
|
||||
|
||||
## Screenshots & PDFs
|
||||
|
||||
```python
|
||||
# Screenshots
|
||||
browser(action="screenshot")
|
||||
browser(action="screenshot", full_page=True)
|
||||
browser(action="screenshot", selector=".chart")
|
||||
|
||||
# PDF export
|
||||
browser(action="pdf")
|
||||
```
|
||||
|
||||
## Wait Operations
|
||||
|
||||
```python
|
||||
# Wait for load states
|
||||
browser(action="wait_for_load", state="networkidle")
|
||||
browser(action="wait_for_url", url="*/success*")
|
||||
|
||||
# Wait for elements
|
||||
browser(action="wait", selector=".loaded", state="visible")
|
||||
browser(action="wait", timeout=5000)
|
||||
|
||||
# Wait for events
|
||||
browser(action="wait_for_event", event="download")
|
||||
browser(action="wait_for_response", pattern="*/api/*")
|
||||
```
|
||||
|
||||
## Network Interception
|
||||
|
||||
```python
|
||||
# Mock API responses
|
||||
browser(
|
||||
action="route",
|
||||
pattern="*/api/users*",
|
||||
response={"users": [{"name": "Mock User"}]},
|
||||
status_code=200
|
||||
)
|
||||
|
||||
# Block requests
|
||||
browser(action="route", pattern="*.png", block=True)
|
||||
|
||||
# Remove route
|
||||
browser(action="unroute", pattern="*/api/users*")
|
||||
```
|
||||
|
||||
## Storage
|
||||
|
||||
```python
|
||||
# Cookies
|
||||
browser(action="cookies")
|
||||
browser(action="cookies", cookies=[{"name": "token", "value": "abc"}])
|
||||
browser(action="clear_cookies")
|
||||
|
||||
# Local/Session storage
|
||||
browser(action="storage", storage_type="local")
|
||||
browser(action="storage", storage_type="session", storage_data={"key": "value"})
|
||||
|
||||
# Save/restore auth state
|
||||
browser(action="storage_state", auth_file="./auth.json")
|
||||
```
|
||||
|
||||
## Tab Management
|
||||
|
||||
```python
|
||||
# Multiple tabs
|
||||
browser(action="new_tab", url="https://example.com")
|
||||
browser(action="tabs") # List all tabs
|
||||
browser(action="close_tab", tab_index=1)
|
||||
```
|
||||
|
||||
## Parallel Agents
|
||||
|
||||
For parallel execution, create isolated contexts:
|
||||
|
||||
```python
|
||||
# Create new context (isolated cookies/storage)
|
||||
browser(action="new_context")
|
||||
|
||||
# Each agent uses separate context
|
||||
# One Chrome process, many parallel sessions
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Headless Mode
|
||||
|
||||
```python
|
||||
# Toggle headless mode
|
||||
browser(action="set_headless", headless=True)
|
||||
browser(action="set_headless", headless=False) # Show browser
|
||||
```
|
||||
|
||||
### CDP Connection
|
||||
|
||||
Share browser instance across MCPs:
|
||||
|
||||
```bash
|
||||
BROWSER_CDP_ENDPOINT=http://localhost:9222 hanzo-mcp
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Login Flow
|
||||
|
||||
```python
|
||||
# Navigate to login
|
||||
browser(action="navigate", url="https://app.example.com/login")
|
||||
|
||||
# Fill credentials
|
||||
browser(action="fill", selector="input[name='email']", text="[email protected]")
|
||||
browser(action="fill", selector="input[name='password']", text="password123")
|
||||
|
||||
# Submit
|
||||
browser(action="click", selector="button[type='submit']")
|
||||
|
||||
# Wait for redirect
|
||||
browser(action="wait_for_url", url="*/dashboard*")
|
||||
|
||||
# Verify login
|
||||
browser(action="expect_visible", selector=".user-menu")
|
||||
```
|
||||
|
||||
### E2E Test
|
||||
|
||||
```python
|
||||
# Test shopping cart
|
||||
browser(action="navigate", url="https://shop.example.com")
|
||||
browser(action="click", selector=".product-card:first-child button")
|
||||
browser(action="expect_text", selector=".cart-count", expected="1")
|
||||
browser(action="click", selector=".cart-icon")
|
||||
browser(action="expect_visible", selector=".cart-modal")
|
||||
browser(action="expect_text", selector=".total", expected="$99.00")
|
||||
```
|
||||
|
||||
### Screenshot Comparison
|
||||
|
||||
```python
|
||||
# Capture baseline
|
||||
browser(action="navigate", url="https://example.com")
|
||||
browser(action="screenshot", full_page=True)
|
||||
# Returns base64 image for comparison
|
||||
```
|
||||
|
||||
+261
-2
@@ -1,2 +1,261 @@
|
||||
# core
|
||||
Documentation coming soon.
|
||||
# hanzo-tools-core
|
||||
|
||||
The foundation package for all Hanzo tool implementations. Provides base classes, type definitions, and utilities for building MCP-compatible tools.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hanzo-tools-core
|
||||
```
|
||||
|
||||
Or as part of the full toolkit:
|
||||
|
||||
```bash
|
||||
pip install hanzo-mcp[tools-all]
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
`hanzo-tools-core` provides:
|
||||
|
||||
- **BaseTool** - Abstract base class for all tool implementations
|
||||
- **FileSystemTool** - Specialized base for file operations
|
||||
- **ToolRegistry** - Central registry for tool management
|
||||
- **MCPResourceDocument** - Structured response format
|
||||
- **ToolContext** - Runtime context for tool execution
|
||||
- **PermissionManager** - Path-based access control
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Creating a Custom Tool
|
||||
|
||||
```python
|
||||
from hanzo_tools.core import BaseTool, ToolContext
|
||||
|
||||
class MyTool(BaseTool):
|
||||
"""A custom tool implementation."""
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return "my_tool"
|
||||
|
||||
@property
|
||||
def description(self) -> str:
|
||||
return "Does something useful"
|
||||
|
||||
async def call(self, ctx: ToolContext, message: str) -> str:
|
||||
"""Execute the tool.
|
||||
|
||||
Args:
|
||||
ctx: Tool execution context
|
||||
message: Input message to process
|
||||
|
||||
Returns:
|
||||
Processed result
|
||||
"""
|
||||
return f"Processed: {message}"
|
||||
|
||||
def register(self, mcp_server):
|
||||
"""Register with MCP server."""
|
||||
@mcp_server.tool(name=self.name, description=self.description)
|
||||
async def handler(message: str) -> str:
|
||||
ctx = ToolContext()
|
||||
return await self.call(ctx, message=message)
|
||||
```
|
||||
|
||||
### Using the Tool Registry
|
||||
|
||||
```python
|
||||
from hanzo_tools.core import ToolRegistry, BaseTool
|
||||
|
||||
# Register tools
|
||||
registry = ToolRegistry()
|
||||
registry.register(MyTool())
|
||||
|
||||
# Get a tool by name
|
||||
tool = registry.get("my_tool")
|
||||
|
||||
# List all registered tools
|
||||
for name, tool in registry.items():
|
||||
print(f"{name}: {tool.description}")
|
||||
```
|
||||
|
||||
## Base Classes
|
||||
|
||||
### BaseTool
|
||||
|
||||
The abstract base class all tools must inherit from:
|
||||
|
||||
```python
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
class BaseTool(ABC):
|
||||
"""Abstract base class for all Hanzo tools."""
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def name(self) -> str:
|
||||
"""Unique identifier for the tool."""
|
||||
...
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def description(self) -> str:
|
||||
"""Human-readable description shown to LLMs."""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def call(self, ctx: ToolContext, **params) -> str:
|
||||
"""Execute the tool with given parameters."""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def register(self, mcp_server: FastMCP) -> None:
|
||||
"""Register the tool with an MCP server."""
|
||||
...
|
||||
```
|
||||
|
||||
### FileSystemTool
|
||||
|
||||
Specialized base class for tools that operate on the filesystem:
|
||||
|
||||
```python
|
||||
from hanzo_tools.core import FileSystemTool
|
||||
|
||||
class ReadTool(FileSystemTool):
|
||||
"""Read file contents."""
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return "read"
|
||||
|
||||
async def call(self, ctx, file_path: str) -> str:
|
||||
# Automatic path validation and permission checking
|
||||
validated_path = self.validate_path(file_path)
|
||||
async with aiofiles.open(validated_path) as f:
|
||||
return await f.read()
|
||||
```
|
||||
|
||||
## Response Format
|
||||
|
||||
### MCPResourceDocument
|
||||
|
||||
Structured format for tool responses:
|
||||
|
||||
```python
|
||||
from hanzo_tools.core import MCPResourceDocument
|
||||
|
||||
# Create a document response
|
||||
doc = MCPResourceDocument(
|
||||
uri="file:///path/to/file.py",
|
||||
mime_type="text/x-python",
|
||||
text="def hello(): pass"
|
||||
)
|
||||
|
||||
# Convert to JSON string for MCP
|
||||
response = doc.to_json_string()
|
||||
```
|
||||
|
||||
## Context Management
|
||||
|
||||
### ToolContext
|
||||
|
||||
Runtime context passed to every tool invocation:
|
||||
|
||||
```python
|
||||
from hanzo_tools.core import ToolContext, create_tool_context
|
||||
|
||||
# Create context with custom settings
|
||||
ctx = create_tool_context(
|
||||
allowed_paths=["/home/user/project"],
|
||||
enable_write=True,
|
||||
timeout=30.0
|
||||
)
|
||||
|
||||
# Access context in tool
|
||||
async def call(self, ctx: ToolContext, **params):
|
||||
if ctx.enable_write:
|
||||
# Perform write operation
|
||||
...
|
||||
```
|
||||
|
||||
## Permission Management
|
||||
|
||||
### PermissionManager
|
||||
|
||||
Controls which paths tools can access:
|
||||
|
||||
```python
|
||||
from hanzo_tools.core import PermissionManager
|
||||
|
||||
pm = PermissionManager(
|
||||
allowed_paths=[
|
||||
"/home/user/project",
|
||||
"/tmp"
|
||||
],
|
||||
denied_paths=[
|
||||
"/home/user/project/.env",
|
||||
"/home/user/project/secrets"
|
||||
]
|
||||
)
|
||||
|
||||
# Check if path is allowed
|
||||
if pm.is_allowed("/home/user/project/src/main.py"):
|
||||
# Safe to access
|
||||
...
|
||||
```
|
||||
|
||||
## Decorators
|
||||
|
||||
### auto_timeout
|
||||
|
||||
Automatically handle timeouts for long-running operations:
|
||||
|
||||
```python
|
||||
from hanzo_tools.core import auto_timeout
|
||||
|
||||
class SlowTool(BaseTool):
|
||||
@auto_timeout(seconds=30)
|
||||
async def call(self, ctx, **params):
|
||||
# Will automatically timeout after 30 seconds
|
||||
result = await slow_operation()
|
||||
return result
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
Tools should return error messages as strings rather than raising exceptions:
|
||||
|
||||
```python
|
||||
async def call(self, ctx, file_path: str) -> str:
|
||||
try:
|
||||
content = await read_file(file_path)
|
||||
return content
|
||||
except FileNotFoundError:
|
||||
return f"Error: File not found: {file_path}"
|
||||
except PermissionError:
|
||||
return f"Error: Permission denied: {file_path}"
|
||||
except Exception as e:
|
||||
return f"Error: {type(e).__name__}: {str(e)}"
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
::: hanzo_tools.core.base.BaseTool
|
||||
options:
|
||||
show_source: false
|
||||
members:
|
||||
- name
|
||||
- description
|
||||
- call
|
||||
- register
|
||||
|
||||
::: hanzo_tools.core.base.FileSystemTool
|
||||
|
||||
::: hanzo_tools.core.base.ToolRegistry
|
||||
|
||||
::: hanzo_tools.core.types.MCPResourceDocument
|
||||
|
||||
::: hanzo_tools.core.context.ToolContext
|
||||
|
||||
::: hanzo_tools.core.permissions.PermissionManager
|
||||
|
||||
+326
-2
@@ -1,2 +1,326 @@
|
||||
# fs
|
||||
Documentation coming soon.
|
||||
# hanzo-tools-fs
|
||||
|
||||
Filesystem tools for reading, writing, editing, and searching files with permission management.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hanzo-tools-fs
|
||||
```
|
||||
|
||||
Or as part of the full toolkit:
|
||||
|
||||
```bash
|
||||
pip install hanzo-mcp[tools-all]
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
`hanzo-tools-fs` provides:
|
||||
|
||||
- **read** - Read file contents with line numbers
|
||||
- **write** - Write/create files
|
||||
- **edit** - Edit files with find/replace
|
||||
- **tree** - Directory tree view
|
||||
- **find** - Find files by pattern
|
||||
- **search** - Search file contents (ripgrep-powered)
|
||||
- **ast** - AST-based code structure search
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
# Read a file
|
||||
read(file_path="/path/to/file.py")
|
||||
|
||||
# Write a file
|
||||
write(file_path="/path/to/new.py", content="print('hello')")
|
||||
|
||||
# Edit a file
|
||||
edit(file_path="/path/to/file.py", old_string="foo", new_string="bar")
|
||||
|
||||
# Search for patterns
|
||||
search(pattern="TODO", path="./src")
|
||||
|
||||
# Find files
|
||||
find(pattern="*.py", path="./src")
|
||||
|
||||
# View directory structure
|
||||
tree(path="./src", depth=3)
|
||||
|
||||
# AST-based code search
|
||||
ast(pattern="class.*Service", path="./src")
|
||||
```
|
||||
|
||||
## Tools Reference
|
||||
|
||||
### read
|
||||
|
||||
Read file contents with line numbers.
|
||||
|
||||
```python
|
||||
# Basic read
|
||||
read(file_path="/path/to/file.py")
|
||||
|
||||
# Read with offset and limit (for large files)
|
||||
read(file_path="/path/to/large.py", offset=100, limit=50)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `file_path` (required): Absolute path to the file
|
||||
- `offset`: Starting line number (0-based, default: 0)
|
||||
- `limit`: Maximum lines to read (default: 2000)
|
||||
|
||||
**Output format:**
|
||||
```
|
||||
1→def hello():
|
||||
2→ print("Hello, World!")
|
||||
3→
|
||||
[Showing lines 1-3 of 3]
|
||||
```
|
||||
|
||||
### write
|
||||
|
||||
Write content to a file, creating it if it doesn't exist.
|
||||
|
||||
```python
|
||||
# Create new file
|
||||
write(file_path="/path/to/new.py", content="print('hello')")
|
||||
|
||||
# Overwrite existing file
|
||||
write(file_path="/path/to/existing.py", content="new content")
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `file_path` (required): Absolute path to the file
|
||||
- `content` (required): Content to write
|
||||
|
||||
### edit
|
||||
|
||||
Edit a file by replacing text.
|
||||
|
||||
```python
|
||||
# Simple replacement
|
||||
edit(
|
||||
file_path="/path/to/file.py",
|
||||
old_string="def old_name():",
|
||||
new_string="def new_name():"
|
||||
)
|
||||
|
||||
# Replace multiple occurrences
|
||||
edit(
|
||||
file_path="/path/to/file.py",
|
||||
old_string="TODO",
|
||||
new_string="DONE",
|
||||
expected_replacements=5
|
||||
)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `file_path` (required): Absolute path to the file
|
||||
- `old_string` (required): Text to find
|
||||
- `new_string` (required): Text to replace with
|
||||
- `expected_replacements`: Expected number of replacements (default: 1)
|
||||
|
||||
### tree
|
||||
|
||||
Display directory tree structure.
|
||||
|
||||
```python
|
||||
# Basic tree view
|
||||
tree(path="/project")
|
||||
|
||||
# Limited depth
|
||||
tree(path="/project", depth=2)
|
||||
|
||||
# Include filtered directories
|
||||
tree(path="/project", include_filtered=True)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `path` (required): Directory path
|
||||
- `depth`: Maximum depth (default: 3)
|
||||
- `include_filtered`: Include commonly filtered dirs like node_modules (default: false)
|
||||
|
||||
**Output format:**
|
||||
```
|
||||
├── src/
|
||||
│ ├── main.py
|
||||
│ └── utils/
|
||||
│ └── helpers.py
|
||||
├── tests/
|
||||
│ └── test_main.py
|
||||
└── pyproject.toml
|
||||
```
|
||||
|
||||
### find
|
||||
|
||||
Find files and directories by pattern.
|
||||
|
||||
```python
|
||||
# Find Python files
|
||||
find(pattern="*.py", path="/project")
|
||||
|
||||
# Find test files
|
||||
find(pattern="test_*.py", path="/project")
|
||||
|
||||
# Find directories
|
||||
find(pattern="*config*", path="/project", type="dir")
|
||||
|
||||
# Limit results
|
||||
find(pattern="*.md", path="/project", max_results=20)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `pattern` (required): Glob pattern to match
|
||||
- `path`: Directory to search (default: current directory)
|
||||
- `type`: Filter by type - "file", "dir", or None for both
|
||||
- `max_results`: Maximum results (default: 100)
|
||||
|
||||
### search
|
||||
|
||||
Search for patterns in file contents using ripgrep.
|
||||
|
||||
```python
|
||||
# Basic search
|
||||
search(pattern="TODO", path="./src")
|
||||
|
||||
# Search with file filter
|
||||
search(pattern="import", path="./src", include="*.py")
|
||||
|
||||
# Search with context lines
|
||||
search(pattern="error", path="./logs", context_lines=5)
|
||||
|
||||
# Limit results
|
||||
search(pattern="function", path="./src", max_results=20)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `pattern` (required): Regex pattern to search for
|
||||
- `path`: Directory or file to search (default: current directory)
|
||||
- `include`: Glob pattern to filter files (e.g., "*.py")
|
||||
- `context_lines`: Lines of context around matches (default: 2)
|
||||
- `max_results`: Maximum results (default: 50)
|
||||
|
||||
**Features:**
|
||||
- Uses ripgrep (rg) if available for high performance
|
||||
- Falls back to Python regex if ripgrep not installed
|
||||
- Async file I/O for non-blocking operation
|
||||
|
||||
### ast
|
||||
|
||||
AST-based code structure search using tree-sitter.
|
||||
|
||||
```python
|
||||
# Find function definitions
|
||||
ast(pattern="def test_", path="./tests")
|
||||
|
||||
# Find class definitions
|
||||
ast(pattern="class.*Service", path="./src")
|
||||
|
||||
# Find with line numbers
|
||||
ast(pattern="async def", path="./src", line_number=True)
|
||||
|
||||
# Case-insensitive search
|
||||
ast(pattern="config", path="./src", ignore_case=True)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `pattern` (required): Regex pattern to search for
|
||||
- `path` (required): File or directory to search
|
||||
- `ignore_case`: Case-insensitive matching (default: false)
|
||||
- `line_number`: Display line numbers (default: false)
|
||||
|
||||
**Supported Languages:**
|
||||
- Python (.py, .pyw)
|
||||
- JavaScript/TypeScript (.js, .jsx, .ts, .tsx)
|
||||
- Go (.go)
|
||||
- Rust (.rs)
|
||||
- C/C++ (.c, .cpp, .h, .hpp)
|
||||
- Java (.java)
|
||||
- Ruby (.rb)
|
||||
- PHP (.php)
|
||||
- And more...
|
||||
|
||||
## Permission Management
|
||||
|
||||
All filesystem tools respect permission boundaries:
|
||||
|
||||
```python
|
||||
from hanzo_tools.fs import register_tools
|
||||
from hanzo_tools.core import PermissionManager
|
||||
|
||||
# Set up permission manager
|
||||
pm = PermissionManager(
|
||||
allowed_paths=["/home/user/project"],
|
||||
denied_paths=["/home/user/project/.env"]
|
||||
)
|
||||
|
||||
# Register tools with MCP server
|
||||
register_tools(mcp_server, pm)
|
||||
```
|
||||
|
||||
### Read-Only Tools
|
||||
|
||||
For sandboxed environments, use read-only tools:
|
||||
|
||||
```python
|
||||
from hanzo_tools.fs import get_read_only_filesystem_tools
|
||||
|
||||
# Get only read operations
|
||||
tools = get_read_only_filesystem_tools(permission_manager)
|
||||
# Includes: read, tree, find, search, ast
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Code Review Workflow
|
||||
|
||||
```python
|
||||
# Find all TODO comments
|
||||
search(pattern="TODO|FIXME", path="./src")
|
||||
|
||||
# Check code structure
|
||||
ast(pattern="class.*", path="./src")
|
||||
|
||||
# Review specific file
|
||||
read(file_path="./src/main.py")
|
||||
```
|
||||
|
||||
### Refactoring Workflow
|
||||
|
||||
```python
|
||||
# Find all usages of old function name
|
||||
search(pattern="old_function_name", path="./src")
|
||||
|
||||
# Find function definition
|
||||
ast(pattern="def old_function_name", path="./src")
|
||||
|
||||
# Edit the function
|
||||
edit(
|
||||
file_path="./src/utils.py",
|
||||
old_string="def old_function_name(",
|
||||
new_string="def new_function_name("
|
||||
)
|
||||
```
|
||||
|
||||
### Project Exploration
|
||||
|
||||
```python
|
||||
# Get project structure
|
||||
tree(path="./", depth=3)
|
||||
|
||||
# Find configuration files
|
||||
find(pattern="*.toml", path="./")
|
||||
find(pattern="*.json", path="./")
|
||||
|
||||
# Search for entry points
|
||||
ast(pattern="def main|if __name__", path="./src")
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use absolute paths** - All tools expect absolute paths for reliability
|
||||
2. **Set appropriate limits** - Use `limit` and `max_results` to avoid overwhelming output
|
||||
3. **Prefer search over read** - Use search/ast to find relevant code instead of reading entire files
|
||||
4. **Use tree for orientation** - Start with tree to understand project structure
|
||||
5. **Combine tools** - Use find + read or search + edit for efficient workflows
|
||||
|
||||
+321
-2
@@ -1,2 +1,321 @@
|
||||
# Llm
|
||||
Documentation coming soon.
|
||||
# hanzo-tools-llm
|
||||
|
||||
Unified LLM interface with multi-model consensus. Access 100+ models through a single tool.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hanzo-tools-llm[full]
|
||||
```
|
||||
|
||||
Note: This package requires `litellm` which is a heavy dependency. It's disabled by default in hanzo-mcp.
|
||||
|
||||
## Overview
|
||||
|
||||
`hanzo-tools-llm` provides:
|
||||
|
||||
- **llm** - Unified LLM interface (query, consensus, model management)
|
||||
- **consensus** - Multi-model consensus protocol
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
# Simple query
|
||||
llm(action="query", prompt="Explain quantum computing", model="gpt-4")
|
||||
|
||||
# Multi-model consensus
|
||||
llm(
|
||||
action="consensus",
|
||||
prompt="Best approach for distributed caching?",
|
||||
models=["gpt-4", "claude-3-opus", "gemini-pro"]
|
||||
)
|
||||
|
||||
# List available models
|
||||
llm(action="list")
|
||||
|
||||
# Enable/disable providers
|
||||
llm(action="enable", provider="anthropic")
|
||||
llm(action="disable", provider="openai")
|
||||
```
|
||||
|
||||
## Actions Reference
|
||||
|
||||
### query
|
||||
|
||||
Send a prompt to an LLM.
|
||||
|
||||
```python
|
||||
# Basic query
|
||||
llm(action="query", prompt="Hello, world!", model="gpt-4")
|
||||
|
||||
# With system prompt
|
||||
llm(
|
||||
action="query",
|
||||
prompt="Explain this code",
|
||||
model="claude-3-opus-20240229",
|
||||
system_prompt="You are a senior software engineer"
|
||||
)
|
||||
|
||||
# With temperature control
|
||||
llm(
|
||||
action="query",
|
||||
prompt="Generate creative names",
|
||||
model="gpt-4",
|
||||
temperature=0.9
|
||||
)
|
||||
|
||||
# JSON mode
|
||||
llm(
|
||||
action="query",
|
||||
prompt="List 5 programming languages with pros/cons",
|
||||
model="gpt-4",
|
||||
json_mode=True
|
||||
)
|
||||
|
||||
# Streaming
|
||||
llm(
|
||||
action="query",
|
||||
prompt="Write a long story",
|
||||
model="gpt-4",
|
||||
stream=True
|
||||
)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `prompt` (required): The prompt to send
|
||||
- `model`: Model name (default: auto-select)
|
||||
- `system_prompt`: System context
|
||||
- `temperature`: Response randomness (0-2, default: 0.7)
|
||||
- `max_tokens`: Maximum response tokens
|
||||
- `json_mode`: Request JSON output (default: false)
|
||||
- `stream`: Stream response (default: false)
|
||||
|
||||
### consensus
|
||||
|
||||
Get consensus from multiple models.
|
||||
|
||||
```python
|
||||
llm(
|
||||
action="consensus",
|
||||
prompt="What's the best way to handle errors in Go?",
|
||||
models=["gpt-4", "claude-3-opus", "gemini-pro"],
|
||||
include_raw=True, # Include individual responses
|
||||
judge_model="gpt-4", # Model to synthesize consensus
|
||||
devils_advocate=True # Add critical analysis
|
||||
)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `prompt` (required): Question for consensus
|
||||
- `models`: List of models to query (default: auto-select 3)
|
||||
- `consensus_size`: Number of models if not specifying (default: 3)
|
||||
- `include_raw`: Include raw responses (default: false)
|
||||
- `judge_model`: Model to aggregate responses
|
||||
- `devils_advocate`: Add 10th model for critique (default: false)
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"consensus": "The agreed-upon answer synthesized from all models...",
|
||||
"confidence": 0.85,
|
||||
"models_queried": ["gpt-4", "claude-3-opus", "gemini-pro"],
|
||||
"agreement_level": "high",
|
||||
"raw_responses": [...] // if include_raw=true
|
||||
}
|
||||
```
|
||||
|
||||
### list
|
||||
|
||||
List available models and providers.
|
||||
|
||||
```python
|
||||
llm(action="list")
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"providers": {
|
||||
"openai": {"enabled": true, "models": ["gpt-4", "gpt-3.5-turbo"]},
|
||||
"anthropic": {"enabled": true, "models": ["claude-3-opus", "claude-3-sonnet"]},
|
||||
"google": {"enabled": false, "models": ["gemini-pro"]}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### models
|
||||
|
||||
List models for a specific provider.
|
||||
|
||||
```python
|
||||
llm(action="models", provider="openai")
|
||||
```
|
||||
|
||||
### enable / disable
|
||||
|
||||
Enable or disable a provider.
|
||||
|
||||
```python
|
||||
# Enable a provider
|
||||
llm(action="enable", provider="anthropic")
|
||||
|
||||
# Disable a provider
|
||||
llm(action="disable", provider="openai")
|
||||
```
|
||||
|
||||
### test
|
||||
|
||||
Test connectivity to a model.
|
||||
|
||||
```python
|
||||
llm(action="test", model="gpt-4")
|
||||
```
|
||||
|
||||
## Supported Providers
|
||||
|
||||
The LLM tool uses [LiteLLM](https://github.com/BerriAI/litellm) to support 100+ models:
|
||||
|
||||
| Provider | Models | API Key Env |
|
||||
|----------|--------|-------------|
|
||||
| OpenAI | gpt-4, gpt-3.5-turbo | `OPENAI_API_KEY` |
|
||||
| Anthropic | claude-3-opus, claude-3-sonnet | `ANTHROPIC_API_KEY` |
|
||||
| Google | gemini-pro, gemini-ultra | `GOOGLE_API_KEY` |
|
||||
| Azure | All Azure OpenAI models | `AZURE_API_KEY` |
|
||||
| AWS Bedrock | claude, titan | AWS credentials |
|
||||
| Cohere | command, command-r | `COHERE_API_KEY` |
|
||||
| Together | Various open models | `TOGETHER_API_KEY` |
|
||||
| Ollama | Local models | - |
|
||||
| And more... | | |
|
||||
|
||||
## ConsensusTool
|
||||
|
||||
Dedicated tool for multi-model consensus:
|
||||
|
||||
```python
|
||||
consensus(
|
||||
prompt="Should we use microservices or monolith?",
|
||||
models=["gpt-4", "claude-3-opus", "gemini-pro"],
|
||||
rounds=3
|
||||
)
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Code Review with Consensus
|
||||
|
||||
```python
|
||||
# Get multiple perspectives on code
|
||||
llm(
|
||||
action="consensus",
|
||||
prompt="""Review this function for issues:
|
||||
|
||||
def process(data):
|
||||
result = []
|
||||
for item in data:
|
||||
if item > 0:
|
||||
result.append(item * 2)
|
||||
return result
|
||||
""",
|
||||
models=["gpt-4", "claude-3-opus", "gemini-pro"],
|
||||
devils_advocate=True
|
||||
)
|
||||
```
|
||||
|
||||
### Choosing Best Model for Task
|
||||
|
||||
```python
|
||||
# List available models
|
||||
models = llm(action="list")
|
||||
|
||||
# Test specific model
|
||||
llm(action="test", model="claude-3-opus-20240229")
|
||||
|
||||
# Query with best model
|
||||
llm(
|
||||
action="query",
|
||||
prompt="Complex reasoning task",
|
||||
model="claude-3-opus-20240229"
|
||||
)
|
||||
```
|
||||
|
||||
### JSON Output
|
||||
|
||||
```python
|
||||
# Get structured data
|
||||
response = llm(
|
||||
action="query",
|
||||
prompt="List 3 Python web frameworks with their pros and cons",
|
||||
model="gpt-4",
|
||||
json_mode=True
|
||||
)
|
||||
|
||||
# Response will be valid JSON
|
||||
```
|
||||
|
||||
### Creative vs Deterministic
|
||||
|
||||
```python
|
||||
# Creative task (high temperature)
|
||||
llm(
|
||||
action="query",
|
||||
prompt="Write a poem about coding",
|
||||
model="gpt-4",
|
||||
temperature=0.9
|
||||
)
|
||||
|
||||
# Deterministic task (low temperature)
|
||||
llm(
|
||||
action="query",
|
||||
prompt="Convert this SQL to Python",
|
||||
model="gpt-4",
|
||||
temperature=0.1
|
||||
)
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### API Keys
|
||||
|
||||
Set API keys via environment variables:
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY="sk-..."
|
||||
export ANTHROPIC_API_KEY="sk-ant-..."
|
||||
export GOOGLE_API_KEY="..."
|
||||
```
|
||||
|
||||
### Default Model
|
||||
|
||||
Set default model via environment:
|
||||
|
||||
```bash
|
||||
export HANZO_DEFAULT_LLM_MODEL="gpt-4"
|
||||
```
|
||||
|
||||
### Model Aliases
|
||||
|
||||
Configure model aliases in `~/.hanzo/llm/aliases.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"smart": "gpt-4",
|
||||
"fast": "gpt-3.5-turbo",
|
||||
"creative": "claude-3-opus-20240229"
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Tips
|
||||
|
||||
1. **Use streaming for long responses** - Better UX for users
|
||||
2. **Cache responses when appropriate** - Same prompt = same response
|
||||
3. **Choose model based on task** - GPT-3.5 for simple, GPT-4 for complex
|
||||
4. **Set max_tokens** - Avoid unnecessarily long responses
|
||||
5. **Use consensus for important decisions** - Multiple perspectives reduce errors
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Set appropriate temperature** - Low for factual, high for creative
|
||||
2. **Use system prompts** - Provide context for better responses
|
||||
3. **Validate JSON output** - Even with json_mode, validate responses
|
||||
4. **Handle rate limits** - LiteLLM handles retries automatically
|
||||
5. **Monitor costs** - Different models have different pricing
|
||||
|
||||
+283
-2
@@ -1,2 +1,283 @@
|
||||
# lsp
|
||||
Documentation coming soon.
|
||||
# hanzo-tools-lsp
|
||||
|
||||
Language Server Protocol tool for code intelligence. Provides go-to-definition, find references, rename, hover, and more.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hanzo-tools-lsp
|
||||
```
|
||||
|
||||
Or as part of the full toolkit:
|
||||
|
||||
```bash
|
||||
pip install hanzo-mcp[tools-all]
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
`hanzo-tools-lsp` provides on-demand LSP configuration and automatic installation:
|
||||
|
||||
- **definition** - Go to definition of symbol at position
|
||||
- **references** - Find all references to symbol
|
||||
- **rename** - Rename symbol across codebase
|
||||
- **hover** - Get hover information at position
|
||||
- **completion** - Get code completions at position
|
||||
- **diagnostics** - Get errors and warnings for file
|
||||
- **status** - Check LSP server status
|
||||
|
||||
## Supported Languages
|
||||
|
||||
| Language | LSP Server | Install Command |
|
||||
|----------|------------|-----------------|
|
||||
| Go | gopls | `go install golang.org/x/tools/gopls@latest` |
|
||||
| Python | pyright | `npm install -g pyright` |
|
||||
| TypeScript/JS | typescript-language-server | `npm install -g typescript typescript-language-server` |
|
||||
| Rust | rust-analyzer | `rustup component add rust-analyzer` |
|
||||
| Java | jdtls | `brew install jdtls` |
|
||||
| C/C++ | clangd | `brew install llvm` |
|
||||
| Ruby | solargraph | `gem install solargraph` |
|
||||
| Lua | lua-language-server | `brew install lua-language-server` |
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
# Go to definition
|
||||
lsp(action="definition", file="/path/to/file.go", line=10, character=15)
|
||||
|
||||
# Find all references
|
||||
lsp(action="references", file="/path/to/file.py", line=25, character=8)
|
||||
|
||||
# Rename symbol
|
||||
lsp(action="rename", file="/path/to/file.ts", line=5, character=10, new_name="newName")
|
||||
|
||||
# Get hover info
|
||||
lsp(action="hover", file="/path/to/file.rs", line=42, character=20)
|
||||
|
||||
# Get completions
|
||||
lsp(action="completion", file="/path/to/file.py", line=30, character=5)
|
||||
|
||||
# Check status
|
||||
lsp(action="status", file="/path/to/file.go")
|
||||
```
|
||||
|
||||
## Actions Reference
|
||||
|
||||
### definition
|
||||
|
||||
Find where a symbol is defined.
|
||||
|
||||
```python
|
||||
lsp(action="definition", file="main.go", line=42, character=15)
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"action": "definition",
|
||||
"file": "main.go",
|
||||
"definition": {
|
||||
"file": "/project/pkg/utils.go",
|
||||
"start": {"line": 25, "character": 5},
|
||||
"end": {"line": 25, "character": 15}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### references
|
||||
|
||||
Find all references to a symbol.
|
||||
|
||||
```python
|
||||
lsp(action="references", file="utils.py", line=10, character=4)
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"action": "references",
|
||||
"file": "utils.py",
|
||||
"references": [
|
||||
{"file": "main.py", "start": {"line": 15, "character": 8}},
|
||||
{"file": "tests/test_utils.py", "start": {"line": 22, "character": 12}}
|
||||
],
|
||||
"count": 2
|
||||
}
|
||||
```
|
||||
|
||||
### rename
|
||||
|
||||
Rename a symbol across the codebase.
|
||||
|
||||
```python
|
||||
lsp(action="rename", file="models.ts", line=5, character=10, new_name="newClassName")
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"action": "rename",
|
||||
"file": "models.ts",
|
||||
"new_name": "newClassName",
|
||||
"changes": {
|
||||
"/project/models.ts": [
|
||||
{"range": {...}, "newText": "newClassName"}
|
||||
],
|
||||
"/project/index.ts": [
|
||||
{"range": {...}, "newText": "newClassName"}
|
||||
]
|
||||
},
|
||||
"files_affected": 2
|
||||
}
|
||||
```
|
||||
|
||||
### hover
|
||||
|
||||
Get documentation and type information at a position.
|
||||
|
||||
```python
|
||||
lsp(action="hover", file="main.rs", line=30, character=8)
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"action": "hover",
|
||||
"file": "main.rs",
|
||||
"position": {"line": 30, "character": 8},
|
||||
"contents": "fn process(data: &[u8]) -> Result<(), Error>\n\nProcesses the input data..."
|
||||
}
|
||||
```
|
||||
|
||||
### completion
|
||||
|
||||
Get code completions at a position.
|
||||
|
||||
```python
|
||||
lsp(action="completion", file="app.py", line=25, character=10)
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"action": "completion",
|
||||
"file": "app.py",
|
||||
"position": {"line": 25, "character": 10},
|
||||
"completions": [
|
||||
{"label": "append", "kind": 2, "detail": "(element) -> None"},
|
||||
{"label": "extend", "kind": 2, "detail": "(iterable) -> None"}
|
||||
],
|
||||
"count": 2
|
||||
}
|
||||
```
|
||||
|
||||
### status
|
||||
|
||||
Check if LSP server is installed and get capabilities.
|
||||
|
||||
```python
|
||||
lsp(action="status", file="main.go")
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"language": "go",
|
||||
"lsp_server": "gopls",
|
||||
"installed": true,
|
||||
"capabilities": ["definition", "references", "rename", "diagnostics", "hover", "completion"]
|
||||
}
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### Automatic Server Management
|
||||
|
||||
The LSP tool automatically:
|
||||
1. Detects language from file extension
|
||||
2. Finds project root based on language markers (go.mod, package.json, etc.)
|
||||
3. Checks if LSP server is installed
|
||||
4. Installs LSP server if needed
|
||||
5. Starts and initializes the server
|
||||
6. Maintains singleton server per language:project_root
|
||||
|
||||
### Server Lifecycle
|
||||
|
||||
```
|
||||
Request → Detect Language → Find Project Root
|
||||
↓
|
||||
Check Cache (language:root_uri)
|
||||
↓
|
||||
If not running: Install → Start → Initialize
|
||||
↓
|
||||
Execute LSP Request → Return Result
|
||||
```
|
||||
|
||||
### Global Server Registry
|
||||
|
||||
LSP servers are managed globally to avoid redundant instances:
|
||||
|
||||
```python
|
||||
# Servers are keyed by language:root_uri
|
||||
# e.g., "go:/home/user/project"
|
||||
# Cleanup happens automatically on process exit
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Code Navigation
|
||||
|
||||
```python
|
||||
# Find where a function is defined
|
||||
lsp(action="definition", file="handlers/user.go", line=45, character=12)
|
||||
|
||||
# Find all places that call this function
|
||||
lsp(action="references", file="handlers/user.go", line=45, character=12)
|
||||
```
|
||||
|
||||
### Safe Refactoring
|
||||
|
||||
```python
|
||||
# First, check all references
|
||||
refs = lsp(action="references", file="models.py", line=10, character=6)
|
||||
|
||||
# Then rename
|
||||
lsp(action="rename", file="models.py", line=10, character=6, new_name="UserProfile")
|
||||
```
|
||||
|
||||
### IDE-like Experience
|
||||
|
||||
```python
|
||||
# Get documentation on hover
|
||||
lsp(action="hover", file="main.rs", line=25, character=8)
|
||||
|
||||
# Get completions while typing
|
||||
lsp(action="completion", file="app.ts", line=30, character=15)
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Project Root Detection
|
||||
|
||||
The LSP tool finds project roots using language-specific markers:
|
||||
|
||||
| Language | Markers |
|
||||
|----------|---------|
|
||||
| Go | go.mod, go.sum |
|
||||
| Python | pyproject.toml, setup.py, requirements.txt |
|
||||
| TypeScript | tsconfig.json, package.json |
|
||||
| Rust | Cargo.toml |
|
||||
| Java | pom.xml, build.gradle |
|
||||
| C/C++ | compile_commands.json, CMakeLists.txt |
|
||||
| Ruby | Gemfile |
|
||||
|
||||
### Custom LSP Servers
|
||||
|
||||
For custom configurations, ensure the LSP server is in your PATH before using the tool.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use status first** - Check if LSP is available before heavy operations
|
||||
2. **Provide accurate positions** - Line and character must match exact symbol position
|
||||
3. **Let servers persist** - Servers are cached; avoid restarting unnecessarily
|
||||
4. **Combine with other tools** - Use with search/ast for comprehensive code analysis
|
||||
|
||||
+283
-2
@@ -1,2 +1,283 @@
|
||||
# memory
|
||||
Documentation coming soon.
|
||||
# hanzo-tools-memory
|
||||
|
||||
Unified memory and knowledge management for AI agents. Store, recall, and manage memories and facts across sessions.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hanzo-tools-memory
|
||||
```
|
||||
|
||||
Or as part of the full toolkit:
|
||||
|
||||
```bash
|
||||
pip install hanzo-mcp[tools-all]
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
`hanzo-tools-memory` provides:
|
||||
|
||||
- **Memory** - Episodic memory for storing and recalling information
|
||||
- **Facts** - Knowledge base management for structured information
|
||||
- **Scopes** - Session, project, and global memory levels
|
||||
- **Summarization** - Automatic content summarization
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
# Store a memory
|
||||
memory(action="create", data={"content": "User prefers dark mode"})
|
||||
|
||||
# Recall memories
|
||||
memory(action="recall", query="user preferences")
|
||||
|
||||
# Store facts
|
||||
memory(action="store_facts", data={
|
||||
"facts": ["API rate limit is 100/hour"],
|
||||
"kb_name": "api_docs"
|
||||
})
|
||||
|
||||
# Recall facts
|
||||
memory(action="facts", query="rate limit")
|
||||
```
|
||||
|
||||
## Memory Actions
|
||||
|
||||
### create
|
||||
|
||||
Store new memories:
|
||||
|
||||
```python
|
||||
memory(action="create", data={
|
||||
"content": "User prefers TypeScript over JavaScript",
|
||||
"scope": "project" # session, project, or global
|
||||
})
|
||||
|
||||
# Store multiple memories
|
||||
memory(action="create", data={
|
||||
"statements": [
|
||||
"User works in Python",
|
||||
"Project uses FastAPI",
|
||||
"Prefers minimal dependencies"
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
### recall
|
||||
|
||||
Search and retrieve memories:
|
||||
|
||||
```python
|
||||
# Simple query
|
||||
memory(action="recall", query="user preferences")
|
||||
|
||||
# With scope filter
|
||||
memory(action="recall", query="coding style", scope="project")
|
||||
|
||||
# Limit results
|
||||
memory(action="recall", query="API endpoints", limit=5)
|
||||
|
||||
# Multiple queries (parallel search)
|
||||
memory(action="recall", data={
|
||||
"queries": ["database schema", "API design", "error handling"]
|
||||
})
|
||||
```
|
||||
|
||||
### update
|
||||
|
||||
Modify existing memories:
|
||||
|
||||
```python
|
||||
memory(action="update", data={
|
||||
"updates": [
|
||||
{"id": "mem_123", "statement": "User now prefers light mode"},
|
||||
{"id": "mem_456", "statement": "Updated API endpoint"}
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
### delete
|
||||
|
||||
Remove memories:
|
||||
|
||||
```python
|
||||
memory(action="delete", data={
|
||||
"ids": ["mem_123", "mem_456"]
|
||||
})
|
||||
```
|
||||
|
||||
### manage
|
||||
|
||||
Batch operations (create, update, delete in one call):
|
||||
|
||||
```python
|
||||
memory(action="manage", data={
|
||||
"creations": ["New fact 1", "New fact 2"],
|
||||
"updates": [{"id": "mem_1", "statement": "Updated"}],
|
||||
"deletions": ["mem_old1", "mem_old2"]
|
||||
})
|
||||
```
|
||||
|
||||
## Facts & Knowledge Bases
|
||||
|
||||
### store_facts
|
||||
|
||||
Store structured facts in knowledge bases:
|
||||
|
||||
```python
|
||||
memory(action="store_facts", data={
|
||||
"facts": [
|
||||
"Python uses indentation for blocks",
|
||||
"FastAPI supports async/await"
|
||||
],
|
||||
"kb_name": "python_basics",
|
||||
"scope": "project"
|
||||
})
|
||||
```
|
||||
|
||||
### facts
|
||||
|
||||
Query knowledge bases:
|
||||
|
||||
```python
|
||||
# Query specific knowledge base
|
||||
memory(action="facts", query="async patterns", kb_name="python_basics")
|
||||
|
||||
# Query all knowledge bases
|
||||
memory(action="facts", query="error handling")
|
||||
|
||||
# With scope
|
||||
memory(action="facts", query="API docs", scope="global")
|
||||
```
|
||||
|
||||
### kb_manage
|
||||
|
||||
Manage knowledge bases:
|
||||
|
||||
```python
|
||||
# Create knowledge base
|
||||
memory(action="kb_manage", data={
|
||||
"action": "create",
|
||||
"kb_name": "api_docs",
|
||||
"description": "API documentation and endpoints"
|
||||
})
|
||||
|
||||
# List knowledge bases
|
||||
memory(action="kb_manage", data={"action": "list", "scope": "project"})
|
||||
|
||||
# Delete knowledge base
|
||||
memory(action="kb_manage", data={"action": "delete", "kb_name": "old_docs"})
|
||||
```
|
||||
|
||||
## Summarization
|
||||
|
||||
### summarize
|
||||
|
||||
Summarize content and store in memory:
|
||||
|
||||
```python
|
||||
memory(action="summarize", data={
|
||||
"content": "Long discussion about API design decisions...",
|
||||
"topic": "API Design Decisions",
|
||||
"scope": "project",
|
||||
"auto_facts": True # Auto-extract facts
|
||||
})
|
||||
```
|
||||
|
||||
## Scopes
|
||||
|
||||
Memories exist at three levels:
|
||||
|
||||
| Scope | Persistence | Use Case |
|
||||
|-------|-------------|----------|
|
||||
| `session` | Current session only | Temporary context |
|
||||
| `project` | Per-project | Project-specific knowledge |
|
||||
| `global` | All projects | User preferences, global facts |
|
||||
|
||||
```python
|
||||
# Session memory (temporary)
|
||||
memory(action="create", data={
|
||||
"content": "Currently debugging auth issue",
|
||||
"scope": "session"
|
||||
})
|
||||
|
||||
# Project memory (persistent)
|
||||
memory(action="create", data={
|
||||
"content": "Project uses PostgreSQL",
|
||||
"scope": "project"
|
||||
})
|
||||
|
||||
# Global memory (shared)
|
||||
memory(action="create", data={
|
||||
"content": "User prefers Vim keybindings",
|
||||
"scope": "global"
|
||||
})
|
||||
```
|
||||
|
||||
## Storage
|
||||
|
||||
Memories are stored in:
|
||||
|
||||
- `~/.hanzo/memory/session/` - Session memories
|
||||
- `~/.hanzo/memory/project/<project>/` - Project memories
|
||||
- `~/.hanzo/memory/global/` - Global memories
|
||||
|
||||
## Examples
|
||||
|
||||
### Context Building
|
||||
|
||||
```python
|
||||
# At start of session, recall relevant context
|
||||
memories = memory(action="recall", data={
|
||||
"queries": [
|
||||
"project architecture",
|
||||
"recent changes",
|
||||
"pending tasks"
|
||||
],
|
||||
"scope": "project"
|
||||
})
|
||||
```
|
||||
|
||||
### Learning User Preferences
|
||||
|
||||
```python
|
||||
# Store preference when learned
|
||||
memory(action="create", data={
|
||||
"content": "User prefers functional programming style",
|
||||
"scope": "global"
|
||||
})
|
||||
|
||||
# Later, recall preferences
|
||||
prefs = memory(action="recall", query="coding style preferences")
|
||||
```
|
||||
|
||||
### Project Documentation
|
||||
|
||||
```python
|
||||
# Store project facts
|
||||
memory(action="store_facts", data={
|
||||
"facts": [
|
||||
"Database: PostgreSQL 15",
|
||||
"ORM: SQLAlchemy 2.0",
|
||||
"API Framework: FastAPI",
|
||||
"Auth: JWT tokens"
|
||||
],
|
||||
"kb_name": "tech_stack",
|
||||
"scope": "project"
|
||||
})
|
||||
|
||||
# Query later
|
||||
stack = memory(action="facts", query="what database", kb_name="tech_stack")
|
||||
```
|
||||
|
||||
### Session Summarization
|
||||
|
||||
```python
|
||||
# At end of session, summarize work
|
||||
memory(action="summarize", data={
|
||||
"content": conversation_history,
|
||||
"topic": "Session Summary - Auth Implementation",
|
||||
"scope": "project"
|
||||
})
|
||||
```
|
||||
|
||||
+328
-2
@@ -1,2 +1,328 @@
|
||||
# reasoning
|
||||
Documentation coming soon.
|
||||
# hanzo-tools-reasoning
|
||||
|
||||
Structured thinking and critical analysis tools for AI agents. Provides the `think` and `critic` tools for deliberate reasoning.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hanzo-tools-reasoning
|
||||
```
|
||||
|
||||
Or as part of the full toolkit:
|
||||
|
||||
```bash
|
||||
pip install hanzo-mcp[tools-all]
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
`hanzo-tools-reasoning` provides:
|
||||
|
||||
- **think** - Structured reasoning and brainstorming
|
||||
- **critic** - Critical analysis and devil's advocate
|
||||
|
||||
## think
|
||||
|
||||
Use the think tool for deliberate reasoning without taking action.
|
||||
|
||||
### When to Use
|
||||
|
||||
1. **Exploring solutions** - Brainstorm approaches before implementing
|
||||
2. **Debugging** - Organize hypotheses about failures
|
||||
3. **Planning** - Think through architecture decisions
|
||||
4. **Complex problems** - Break down multi-step solutions
|
||||
|
||||
### Usage
|
||||
|
||||
```python
|
||||
think(thought="""
|
||||
Feature Implementation Planning
|
||||
- New code search feature requirements:
|
||||
* Search for code patterns across multiple files
|
||||
* Identify function usages and references
|
||||
* Analyze import relationships
|
||||
* Generate summary of matching patterns
|
||||
|
||||
- Implementation considerations:
|
||||
* Need to leverage existing search mechanisms
|
||||
* Should use regex for pattern matching
|
||||
* Results need consistent format
|
||||
* Must handle large codebases efficiently
|
||||
|
||||
- Design approach:
|
||||
1. Create new CodeSearcher class
|
||||
2. Implement core pattern matching
|
||||
3. Add result formatting
|
||||
4. Integrate with file traversal
|
||||
5. Add caching for performance
|
||||
|
||||
- Testing strategy:
|
||||
* Unit tests for search accuracy
|
||||
* Integration tests with existing components
|
||||
* Performance tests with large codebases
|
||||
""")
|
||||
```
|
||||
|
||||
### Best Practices
|
||||
|
||||
- **Be specific**: Include concrete details and constraints
|
||||
- **Structure thoughts**: Use lists, sections, and hierarchies
|
||||
- **Consider alternatives**: List multiple approaches
|
||||
- **Note tradeoffs**: Document pros/cons of each option
|
||||
|
||||
### Examples
|
||||
|
||||
#### Bug Investigation
|
||||
|
||||
```python
|
||||
think(thought="""
|
||||
Bug Analysis: API returning 500 errors
|
||||
|
||||
Symptoms:
|
||||
- Intermittent 500 errors on /api/users endpoint
|
||||
- Happens under high load
|
||||
- Error logs show connection pool exhausted
|
||||
|
||||
Hypotheses:
|
||||
1. Connection pool too small
|
||||
- Check: current pool size vs concurrent requests
|
||||
- Fix: increase pool size or add connection recycling
|
||||
|
||||
2. Slow queries blocking connections
|
||||
- Check: query execution times
|
||||
- Fix: add indexes, optimize queries
|
||||
|
||||
3. Connection leak in error paths
|
||||
- Check: connection release in exception handlers
|
||||
- Fix: ensure connections released in finally blocks
|
||||
|
||||
Investigation order:
|
||||
1. Check connection pool metrics
|
||||
2. Review slow query logs
|
||||
3. Audit connection handling code
|
||||
""")
|
||||
```
|
||||
|
||||
#### Architecture Decision
|
||||
|
||||
```python
|
||||
think(thought="""
|
||||
Architecture Decision: State Management
|
||||
|
||||
Options:
|
||||
1. Redux
|
||||
+ Predictable state updates
|
||||
+ Great devtools
|
||||
- Boilerplate heavy
|
||||
- Overkill for simple apps
|
||||
|
||||
2. Zustand
|
||||
+ Minimal API
|
||||
+ No providers needed
|
||||
+ TypeScript friendly
|
||||
- Less ecosystem
|
||||
|
||||
3. React Context + useReducer
|
||||
+ Built-in, no dependencies
|
||||
+ Familiar patterns
|
||||
- Performance concerns at scale
|
||||
- Manual optimization needed
|
||||
|
||||
Recommendation: Zustand
|
||||
- Our app is medium complexity
|
||||
- Team prefers minimal boilerplate
|
||||
- TypeScript is priority
|
||||
- Performance is acceptable for our scale
|
||||
""")
|
||||
```
|
||||
|
||||
## critic
|
||||
|
||||
Use the critic tool for critical analysis and quality assurance.
|
||||
|
||||
### When to Use
|
||||
|
||||
1. **Code review** - Analyze implementations for issues
|
||||
2. **Before finalizing** - Ensure quality standards met
|
||||
3. **Testing** - Question if tests are comprehensive
|
||||
4. **Design review** - Challenge assumptions
|
||||
|
||||
### Usage
|
||||
|
||||
```python
|
||||
critic(analysis="""
|
||||
Code Review Analysis:
|
||||
|
||||
Implementation Issues:
|
||||
- No error handling for network failures in API calls
|
||||
- Missing validation for user input boundaries
|
||||
- Race condition possible in concurrent updates
|
||||
- Memory leak potential in event listener registration
|
||||
|
||||
Test Coverage Gaps:
|
||||
- No tests for error scenarios
|
||||
- Missing edge case: empty array input
|
||||
- No performance benchmarks for large datasets
|
||||
- Integration tests don't cover auth failures
|
||||
|
||||
Security Concerns:
|
||||
- SQL injection vulnerability in query construction
|
||||
- Missing rate limiting on public endpoints
|
||||
- Sensitive data logged in debug mode
|
||||
|
||||
Performance Issues:
|
||||
- O(n²) algorithm where O(n log n) is possible
|
||||
- Database queries in a loop (N+1 problem)
|
||||
- No caching for expensive computations
|
||||
|
||||
Code Quality:
|
||||
- Functions too long and doing multiple things
|
||||
- Inconsistent naming conventions
|
||||
- Missing type annotations
|
||||
- No documentation for complex algorithms
|
||||
|
||||
Design Flaws:
|
||||
- Tight coupling between modules
|
||||
- Hard-coded configuration values
|
||||
- No abstraction for external dependencies
|
||||
- Violates single responsibility principle
|
||||
|
||||
Recommendations:
|
||||
1. Add comprehensive error handling
|
||||
2. Implement input validation
|
||||
3. Use database transactions for race conditions
|
||||
4. Parameterize SQL queries
|
||||
5. Implement rate limiting
|
||||
6. Refactor to smaller functions
|
||||
7. Add missing type annotations
|
||||
8. Batch database queries
|
||||
""")
|
||||
```
|
||||
|
||||
### The Inner Critic Mindset
|
||||
|
||||
The critic tool forces critical thinking that:
|
||||
|
||||
- **Questions assumptions** - "Is this really necessary?"
|
||||
- **Looks for bugs** - "What could go wrong?"
|
||||
- **Checks edge cases** - "What about empty input?"
|
||||
- **Verifies security** - "Can this be exploited?"
|
||||
- **Reviews performance** - "Will this scale?"
|
||||
- **Ensures quality** - "Is this maintainable?"
|
||||
|
||||
### Examples
|
||||
|
||||
#### Feature Review
|
||||
|
||||
```python
|
||||
critic(analysis="""
|
||||
Review: User Authentication Feature
|
||||
|
||||
Positive aspects:
|
||||
- Clean API design
|
||||
- Good separation of concerns
|
||||
- Follows existing patterns
|
||||
|
||||
Issues found:
|
||||
1. Token expiry not handled
|
||||
- Tokens never expire
|
||||
- No refresh token mechanism
|
||||
- Risk: Stolen tokens valid forever
|
||||
|
||||
2. Password handling
|
||||
- Using MD5 (insecure)
|
||||
- No salt
|
||||
- Should use bcrypt/argon2
|
||||
|
||||
3. Rate limiting missing
|
||||
- No limit on login attempts
|
||||
- Vulnerable to brute force
|
||||
|
||||
4. Error messages too specific
|
||||
- "Invalid password" reveals user exists
|
||||
- Should use generic "Invalid credentials"
|
||||
|
||||
5. Session management
|
||||
- No logout invalidation
|
||||
- Can't revoke sessions
|
||||
- No concurrent session limit
|
||||
|
||||
Required before merge:
|
||||
- Switch to bcrypt
|
||||
- Add rate limiting
|
||||
- Implement token refresh
|
||||
- Generic error messages
|
||||
""")
|
||||
```
|
||||
|
||||
#### Test Review
|
||||
|
||||
```python
|
||||
critic(analysis="""
|
||||
Test Suite Analysis:
|
||||
|
||||
Coverage gaps:
|
||||
- No tests for boundary conditions
|
||||
- Error paths untested
|
||||
- Async behavior not verified
|
||||
- No integration tests with real DB
|
||||
|
||||
Test quality issues:
|
||||
- Tests too coupled to implementation
|
||||
- Magic numbers without explanation
|
||||
- No test documentation
|
||||
- Flaky tests due to timing
|
||||
|
||||
Missing test categories:
|
||||
- Performance/load tests
|
||||
- Security tests
|
||||
- Accessibility tests
|
||||
- Cross-browser tests
|
||||
|
||||
Recommendations:
|
||||
1. Add boundary condition tests
|
||||
2. Test all error scenarios
|
||||
3. Use proper test fixtures
|
||||
4. Add integration test suite
|
||||
5. Document test intentions
|
||||
""")
|
||||
```
|
||||
|
||||
## Combining Think and Critic
|
||||
|
||||
Use both tools together for thorough analysis:
|
||||
|
||||
```python
|
||||
# First, think through the problem
|
||||
think(thought="""
|
||||
Planning: Implement caching layer
|
||||
- Need to cache API responses
|
||||
- Options: Redis, in-memory, file-based
|
||||
- Must handle invalidation
|
||||
- Need TTL support
|
||||
""")
|
||||
|
||||
# Then, critically analyze the plan
|
||||
critic(analysis="""
|
||||
Cache Implementation Review:
|
||||
|
||||
Potential issues:
|
||||
- Cache invalidation strategy unclear
|
||||
- No handling for cache stampede
|
||||
- Memory limits not considered
|
||||
- No monitoring/metrics planned
|
||||
|
||||
Missing considerations:
|
||||
- What happens when cache is full?
|
||||
- How to warm cache on startup?
|
||||
- How to handle partial failures?
|
||||
- What's the fallback if Redis down?
|
||||
|
||||
Recommendations:
|
||||
1. Define explicit invalidation triggers
|
||||
2. Add circuit breaker for cache failures
|
||||
3. Implement cache warming strategy
|
||||
4. Add memory limits with eviction
|
||||
5. Include cache hit/miss metrics
|
||||
""")
|
||||
```
|
||||
|
||||
+353
-2
@@ -1,2 +1,353 @@
|
||||
# refactor
|
||||
Documentation coming soon.
|
||||
# hanzo-tools-refactor
|
||||
|
||||
Advanced refactoring with LSP/AST support. FAST parallel processing for large codebases.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hanzo-tools-refactor
|
||||
```
|
||||
|
||||
Or as part of the full toolkit:
|
||||
|
||||
```bash
|
||||
pip install hanzo-mcp[tools-all]
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
`hanzo-tools-refactor` provides intelligent code refactoring:
|
||||
|
||||
- **rename** - Rename symbol across entire codebase
|
||||
- **rename_batch** - Batch rename multiple symbols
|
||||
- **extract_function** - Extract code into a new function
|
||||
- **extract_variable** - Extract expression into a variable
|
||||
- **inline** - Inline a function or variable
|
||||
- **move** - Move symbol to another file
|
||||
- **change_signature** - Modify function parameters
|
||||
- **find_references** - Find all references to a symbol
|
||||
- **organize_imports** - Clean up and sort imports
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
# Rename a symbol
|
||||
refactor(action="rename", file="main.py", line=10, column=5, new_name="newName")
|
||||
|
||||
# Batch rename multiple symbols
|
||||
refactor(
|
||||
action="rename_batch",
|
||||
renames=[
|
||||
{"old": "foo", "new": "bar"},
|
||||
{"old": "baz", "new": "qux"}
|
||||
],
|
||||
path="./src"
|
||||
)
|
||||
|
||||
# Change function signature
|
||||
refactor(
|
||||
action="change_signature",
|
||||
file="utils.py",
|
||||
line=15,
|
||||
add_parameter={"name": "timeout", "default": "30"}
|
||||
)
|
||||
|
||||
# Find references
|
||||
refactor(action="find_references", file="models.py", line=25, column=8)
|
||||
```
|
||||
|
||||
## Actions Reference
|
||||
|
||||
### rename
|
||||
|
||||
Rename a symbol at a specific location.
|
||||
|
||||
```python
|
||||
refactor(
|
||||
action="rename",
|
||||
file="/path/to/file.py",
|
||||
line=42,
|
||||
column=10,
|
||||
new_name="betterName"
|
||||
)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `file` (required): File containing the symbol
|
||||
- `line` (required): Line number (1-based)
|
||||
- `column` (required): Column number (1-based)
|
||||
- `new_name` (required): New name for the symbol
|
||||
|
||||
### rename_batch
|
||||
|
||||
Rename multiple symbols across the codebase in parallel.
|
||||
|
||||
```python
|
||||
refactor(
|
||||
action="rename_batch",
|
||||
renames=[
|
||||
{"old": "getUserData", "new": "fetchUserData"},
|
||||
{"old": "setUserData", "new": "updateUserData"},
|
||||
{"old": "deleteUserData", "new": "removeUserData"}
|
||||
],
|
||||
path="./src",
|
||||
parallel=True # Default: true
|
||||
)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `renames` (required): List of {old, new} pairs
|
||||
- `path`: Directory to search (default: current directory)
|
||||
- `parallel`: Process in parallel (default: true)
|
||||
|
||||
### extract_function
|
||||
|
||||
Extract selected code into a new function.
|
||||
|
||||
```python
|
||||
refactor(
|
||||
action="extract_function",
|
||||
file="/path/to/file.py",
|
||||
start_line=20,
|
||||
end_line=30,
|
||||
new_name="processData"
|
||||
)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `file` (required): Source file
|
||||
- `start_line` (required): First line of code to extract
|
||||
- `end_line` (required): Last line of code to extract
|
||||
- `new_name`: Name for the new function
|
||||
|
||||
### extract_variable
|
||||
|
||||
Extract an expression into a variable.
|
||||
|
||||
```python
|
||||
refactor(
|
||||
action="extract_variable",
|
||||
file="/path/to/file.py",
|
||||
line=15,
|
||||
start_column=10,
|
||||
end_column=45,
|
||||
new_name="calculatedValue"
|
||||
)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `file` (required): Source file
|
||||
- `line` (required): Line containing the expression
|
||||
- `start_column`: Start of expression
|
||||
- `end_column`: End of expression
|
||||
- `new_name`: Variable name
|
||||
|
||||
### inline
|
||||
|
||||
Inline a function or variable at its call sites.
|
||||
|
||||
```python
|
||||
refactor(
|
||||
action="inline",
|
||||
file="/path/to/file.py",
|
||||
line=10,
|
||||
column=5
|
||||
)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `file` (required): Source file
|
||||
- `line` (required): Line of the symbol
|
||||
- `column` (required): Column of the symbol
|
||||
|
||||
### move
|
||||
|
||||
Move a symbol to a different file.
|
||||
|
||||
```python
|
||||
refactor(
|
||||
action="move",
|
||||
file="/path/to/source.py",
|
||||
line=15,
|
||||
column=6,
|
||||
target_file="/path/to/destination.py"
|
||||
)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `file` (required): Source file
|
||||
- `line` (required): Line of the symbol
|
||||
- `column` (required): Column of the symbol
|
||||
- `target_file` (required): Destination file
|
||||
|
||||
### change_signature
|
||||
|
||||
Modify a function's parameters.
|
||||
|
||||
```python
|
||||
# Add a parameter
|
||||
refactor(
|
||||
action="change_signature",
|
||||
file="api.py",
|
||||
line=20,
|
||||
add_parameter={"name": "timeout", "default": "30", "type": "int"}
|
||||
)
|
||||
|
||||
# Remove a parameter
|
||||
refactor(
|
||||
action="change_signature",
|
||||
file="api.py",
|
||||
line=20,
|
||||
remove_parameter="deprecated_param"
|
||||
)
|
||||
|
||||
# Reorder parameters
|
||||
refactor(
|
||||
action="change_signature",
|
||||
file="api.py",
|
||||
line=20,
|
||||
reorder_parameters=["user_id", "data", "options"]
|
||||
)
|
||||
```
|
||||
|
||||
### find_references
|
||||
|
||||
Find all references to a symbol.
|
||||
|
||||
```python
|
||||
refactor(action="find_references", file="models.py", line=10, column=6)
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"symbol": "UserModel",
|
||||
"references": [
|
||||
{"file": "views.py", "line": 15, "column": 8},
|
||||
{"file": "tests/test_models.py", "line": 22, "column": 12}
|
||||
],
|
||||
"count": 2
|
||||
}
|
||||
```
|
||||
|
||||
### organize_imports
|
||||
|
||||
Clean up and sort imports in a file.
|
||||
|
||||
```python
|
||||
refactor(action="organize_imports", file="main.py")
|
||||
```
|
||||
|
||||
## Parallel Processing
|
||||
|
||||
The refactor tool uses parallel processing for large-scale operations:
|
||||
|
||||
```python
|
||||
# Parallel is enabled by default
|
||||
refactor(
|
||||
action="rename_batch",
|
||||
renames=[...], # Many renames
|
||||
path="./large_codebase",
|
||||
parallel=True # Uses all CPU cores
|
||||
)
|
||||
|
||||
# Disable for sequential processing
|
||||
refactor(
|
||||
action="rename_batch",
|
||||
renames=[...],
|
||||
parallel=False
|
||||
)
|
||||
```
|
||||
|
||||
## Preview Mode
|
||||
|
||||
Preview changes before applying them:
|
||||
|
||||
```python
|
||||
# Preview only - don't apply changes
|
||||
refactor(
|
||||
action="rename",
|
||||
file="main.py",
|
||||
line=10,
|
||||
column=5,
|
||||
new_name="newName",
|
||||
preview=True
|
||||
)
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"preview": true,
|
||||
"changes": [
|
||||
{"file": "main.py", "line": 10, "old": "oldName", "new": "newName"},
|
||||
{"file": "utils.py", "line": 25, "old": "oldName", "new": "newName"}
|
||||
],
|
||||
"files_affected": 2
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Safe Symbol Rename
|
||||
|
||||
```python
|
||||
# 1. Find all usages first
|
||||
refs = refactor(action="find_references", file="models.py", line=10, column=5)
|
||||
|
||||
# 2. Preview the rename
|
||||
preview = refactor(
|
||||
action="rename",
|
||||
file="models.py",
|
||||
line=10,
|
||||
column=5,
|
||||
new_name="BetterName",
|
||||
preview=True
|
||||
)
|
||||
|
||||
# 3. Apply the rename
|
||||
refactor(
|
||||
action="rename",
|
||||
file="models.py",
|
||||
line=10,
|
||||
column=5,
|
||||
new_name="BetterName"
|
||||
)
|
||||
```
|
||||
|
||||
### Large-Scale Refactoring
|
||||
|
||||
```python
|
||||
# Rename multiple patterns across codebase
|
||||
refactor(
|
||||
action="rename_batch",
|
||||
renames=[
|
||||
{"old": "v1_api", "new": "legacy_api"},
|
||||
{"old": "v2_api", "new": "current_api"},
|
||||
{"old": "v3_api", "new": "api"}
|
||||
],
|
||||
path="./src",
|
||||
parallel=True
|
||||
)
|
||||
```
|
||||
|
||||
### Extract Common Code
|
||||
|
||||
```python
|
||||
# Extract duplicated logic into a function
|
||||
refactor(
|
||||
action="extract_function",
|
||||
file="handlers.py",
|
||||
start_line=45,
|
||||
end_line=60,
|
||||
new_name="validate_and_process"
|
||||
)
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always preview first** - Use `preview=True` for important refactors
|
||||
2. **Run tests after** - Verify refactoring didn't break functionality
|
||||
3. **Use batch operations** - `rename_batch` is faster than individual renames
|
||||
4. **Commit before refactoring** - Have a clean git state to easily revert
|
||||
5. **Combine with LSP** - Use `lsp` tool for initial symbol discovery
|
||||
|
||||
+277
-2
@@ -1,2 +1,277 @@
|
||||
# shell
|
||||
Documentation coming soon.
|
||||
# hanzo-tools-shell
|
||||
|
||||
Unified command execution with DAG support, auto-backgrounding, and process management. The shell toolkit provides the `cmd`, `zsh`, `bash`, and `ps` tools.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install hanzo-tools-shell
|
||||
```
|
||||
|
||||
Or as part of the full toolkit:
|
||||
|
||||
```bash
|
||||
pip install hanzo-mcp[tools-all]
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
`hanzo-tools-shell` provides:
|
||||
|
||||
- **cmd** - Unified command execution with DAG support
|
||||
- **zsh** / **bash** / **shell** - Shell-specific execution
|
||||
- **ps** - Process management (list, kill, logs)
|
||||
- **npx** / **uvx** - Package runner tools
|
||||
- **open** - Platform-aware file/URL opener
|
||||
|
||||
## Key Features
|
||||
|
||||
### Auto-Backgrounding
|
||||
|
||||
Commands automatically background after 45 seconds (configurable):
|
||||
|
||||
```python
|
||||
# Long-running command auto-backgrounds
|
||||
cmd("npm run build") # If takes >45s, continues in background
|
||||
|
||||
# Check status later
|
||||
ps() # List all background processes
|
||||
ps(logs="cmd_abc123") # View output
|
||||
ps(kill="cmd_abc123") # Stop process
|
||||
```
|
||||
|
||||
### DAG Execution
|
||||
|
||||
Execute commands with dependency graphs:
|
||||
|
||||
```python
|
||||
# Sequential (default)
|
||||
cmd(["mkdir dist", "cp files dist/", "zip -r out.zip dist/"])
|
||||
|
||||
# Parallel
|
||||
cmd(["npm install", "cargo build"], parallel=True)
|
||||
|
||||
# Mixed DAG with dependencies
|
||||
cmd([
|
||||
"mkdir -p dist",
|
||||
{"parallel": ["cp a.txt dist/", "cp b.txt dist/"]},
|
||||
"zip -r out.zip dist/"
|
||||
])
|
||||
```
|
||||
|
||||
## Tools Reference
|
||||
|
||||
### cmd
|
||||
|
||||
The primary command execution tool:
|
||||
|
||||
```python
|
||||
# Simple command
|
||||
cmd("ls -la")
|
||||
|
||||
# Sequential commands
|
||||
cmd(["git status", "git diff", "git log -5"])
|
||||
|
||||
# Parallel execution
|
||||
cmd(["npm install", "pip install -r requirements.txt"], parallel=True)
|
||||
|
||||
# Mixed DAG
|
||||
cmd([
|
||||
"mkdir -p dist",
|
||||
{"parallel": ["build-frontend", "build-backend"]},
|
||||
"deploy"
|
||||
])
|
||||
|
||||
# With options
|
||||
cmd(
|
||||
"npm test",
|
||||
timeout=120, # Command timeout in seconds
|
||||
cwd="/project", # Working directory
|
||||
env={"NODE_ENV": "test"}, # Environment variables
|
||||
quiet=True, # Suppress stdout
|
||||
strict=True # Stop on first error
|
||||
)
|
||||
```
|
||||
|
||||
### zsh / bash / shell
|
||||
|
||||
Shell-specific wrappers around `cmd`:
|
||||
|
||||
```python
|
||||
# Use specific shell
|
||||
zsh("echo $SHELL") # Uses zsh
|
||||
bash("echo $SHELL") # Uses bash
|
||||
shell("echo $SHELL") # Auto-detects: zsh > bash > sh
|
||||
|
||||
# Same options as cmd
|
||||
zsh(["cmd1", "cmd2"], parallel=True, timeout=60)
|
||||
```
|
||||
|
||||
### ps
|
||||
|
||||
Process management for background commands:
|
||||
|
||||
```python
|
||||
# List all background processes
|
||||
ps()
|
||||
|
||||
# Get specific process info
|
||||
ps(id="cmd_abc123")
|
||||
|
||||
# View process output (last 100 lines by default)
|
||||
ps(logs="cmd_abc123")
|
||||
ps(logs="cmd_abc123", n=50) # Last 50 lines
|
||||
|
||||
# Kill process
|
||||
ps(kill="cmd_abc123") # SIGTERM (default)
|
||||
ps(kill="cmd_abc123", sig=9) # SIGKILL
|
||||
```
|
||||
|
||||
### npx / uvx
|
||||
|
||||
Package runners with auto-backgrounding:
|
||||
|
||||
```python
|
||||
# Run npm packages
|
||||
npx("create-react-app my-app")
|
||||
npx("http-server -p 8080") # Auto-backgrounds if long-running
|
||||
|
||||
# Run Python packages
|
||||
uvx("ruff check .")
|
||||
uvx("mkdocs serve") # Auto-backgrounds if long-running
|
||||
```
|
||||
|
||||
### open
|
||||
|
||||
Platform-aware opener for files and URLs:
|
||||
|
||||
```python
|
||||
# Open URLs
|
||||
open("https://example.com")
|
||||
|
||||
# Open files with default application
|
||||
open("./document.pdf")
|
||||
open("/path/to/image.png")
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `HANZO_AUTO_BACKGROUND_TIMEOUT` | `45` | Seconds before auto-backgrounding (0 to disable) |
|
||||
| `HANZO_DEFAULT_SHELL` | `zsh` | Default shell for execution |
|
||||
|
||||
### Timeout Configuration
|
||||
|
||||
```python
|
||||
# Disable auto-backgrounding for a command
|
||||
cmd("long-running-command", timeout=0)
|
||||
|
||||
# Set global timeout via environment
|
||||
import os
|
||||
os.environ["HANZO_AUTO_BACKGROUND_TIMEOUT"] = "120" # 2 minutes
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Build Pipeline
|
||||
|
||||
```python
|
||||
# Parallel build with sequential deploy
|
||||
cmd([
|
||||
{"parallel": [
|
||||
"npm run build:frontend",
|
||||
"npm run build:backend",
|
||||
"npm run build:docs"
|
||||
]},
|
||||
"npm run test",
|
||||
"npm run deploy"
|
||||
])
|
||||
```
|
||||
|
||||
### Development Server
|
||||
|
||||
```python
|
||||
# Start dev server (auto-backgrounds)
|
||||
cmd("npm run dev")
|
||||
|
||||
# Later, check status
|
||||
ps()
|
||||
# Output: cmd_abc123 | running | npm run dev | started 5m ago
|
||||
|
||||
# View logs
|
||||
ps(logs="cmd_abc123")
|
||||
|
||||
# Stop when done
|
||||
ps(kill="cmd_abc123")
|
||||
```
|
||||
|
||||
### Tool Invocation in DAG
|
||||
|
||||
```python
|
||||
# Mix shell commands with tool calls
|
||||
cmd([
|
||||
"git pull origin main",
|
||||
{"tool": "search", "input": {"pattern": "TODO"}},
|
||||
"npm test"
|
||||
])
|
||||
```
|
||||
|
||||
### Parallel File Operations
|
||||
|
||||
```python
|
||||
# Process multiple files in parallel
|
||||
cmd([
|
||||
["process file1.txt", "process file2.txt", "process file3.txt"]
|
||||
], parallel=True)
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### ShellExecutor
|
||||
|
||||
Single async execution engine for all shell tools:
|
||||
|
||||
```
|
||||
CmdTool (cmd) # Unified execution graph (DAG)
|
||||
├── ZshTool (zsh) # Thin shim: shell=zsh
|
||||
├── BashTool (bash) # Thin shim: shell=bash
|
||||
└── ShellTool # Smart shim: zsh > bash > sh
|
||||
|
||||
ShellExecutor (singleton)
|
||||
└── ProcessManager (singleton)
|
||||
└── ps tool (process listing/kill/logs)
|
||||
```
|
||||
|
||||
### Process Lifecycle
|
||||
|
||||
1. Command starts with `asyncio.create_subprocess_exec`
|
||||
2. Wait for completion with configured timeout
|
||||
3. If timeout reached: register with ProcessManager, continue in background
|
||||
4. User can monitor with `ps --logs <id>` or stop with `ps --kill <id>`
|
||||
|
||||
## Error Handling
|
||||
|
||||
```python
|
||||
# Strict mode: stop on first error
|
||||
cmd(["cmd1", "cmd2", "cmd3"], strict=True)
|
||||
|
||||
# Default: continue on errors, report all
|
||||
cmd(["cmd1", "cmd2", "cmd3"]) # Returns combined output with errors
|
||||
|
||||
# Check exit codes in response
|
||||
result = cmd("might-fail")
|
||||
if "exit code" in result.lower():
|
||||
# Handle error
|
||||
...
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use DAG for dependencies**: Let the executor handle ordering
|
||||
2. **Parallelize independent operations**: Use `parallel=True` for speed
|
||||
3. **Set appropriate timeouts**: Avoid blocking on hung processes
|
||||
4. **Use `ps` for long tasks**: Don't wait for builds, check later
|
||||
5. **Prefer `cmd` over raw shell**: Better error handling and logging
|
||||
|
||||
Reference in New Issue
Block a user