# zeroclaw-tools

Python companion package for [ZeroClaw](https://github.com/zeroclaw-labs/zeroclaw) — LangGraph-based tool calling for consistent LLM agent execution.

## Why This Package?

Some LLM providers (particularly GLM-5/Zhipu and similar models) have inconsistent tool calling behavior when using text-based tool invocation. This package provides a LangGraph-based approach that delivers:

- **Consistent tool calling** across all OpenAI-compatible providers
- **Automatic tool loop** — keeps calling tools until the task is complete
- **Easy extensibility** — add new tools with a simple `@tool` decorator
- **Framework agnostic** — works with any OpenAI-compatible API

## Installation

```bash
pip install zeroclaw-tools
```

With Discord integration:

```bash
pip install zeroclaw-tools[discord]
```

## Quick Start

### Basic Agent

```python
import asyncio
from zeroclaw_tools import create_agent, shell, file_read, file_write
from langchain_core.messages import HumanMessage

async def main():
    # Create agent with tools
    agent = create_agent(
        tools=[shell, file_read, file_write],
        model="glm-5",
        api_key="your-api-key",
        base_url="https://api.z.ai/api/coding/paas/v4"
    )
    
    # Execute a task
    result = await agent.ainvoke({
        "messages": [HumanMessage(content="List files in /tmp directory")]
    })
    
    print(result["messages"][-1].content)

asyncio.run(main())
```

### CLI Usage

```bash
# Set environment variables
export API_KEY="your-api-key"
export API_BASE="https://api.z.ai/api/coding/paas/v4"

# Run the CLI
zeroclaw-tools "List files in the current directory"

# Interactive mode (no message required)
zeroclaw-tools -i
```

### Discord Bot

```python
import os
from zeroclaw_tools.integrations import DiscordBot

bot = DiscordBot(
    token=os.environ["DISCORD_TOKEN"],
    guild_id=123456789,
    allowed_users=["123456789"]
)

bot.run()
```

## Available Tools

| Tool | Description |
|------|-------------|
| `shell` | Execute shell commands |
| `file_read` | Read file contents |
| `file_write` | Write content to files |
| `web_search` | Search the web (requires Brave API key) |
| `http_request` | Make HTTP requests |
| `memory_store` | Store data in memory |
| `memory_recall` | Recall stored data |

## Creating Custom Tools

```python
from zeroclaw_tools import tool

@tool
def my_custom_tool(query: str) -> str:
    """Description of what this tool does."""
    # Your implementation here
    return f"Result for: {query}"

# Use with agent
agent = create_agent(tools=[my_custom_tool])
```

## Provider Compatibility

Works with any OpenAI-compatible provider:

- **Z.AI / GLM-5** — `https://api.z.ai/api/coding/paas/v4`
- **OpenRouter** — `https://openrouter.ai/api/v1`
- **Groq** — `https://api.groq.com/openai/v1`
- **DeepSeek** — `https://api.deepseek.com`
- **Ollama** — `http://localhost:11434/v1`
- **And many more...**

## Architecture

```
┌─────────────────────────────────────────────┐
│              Your Application               │
├─────────────────────────────────────────────┤
│           zeroclaw-tools Agent              │
│  ┌─────────────────────────────────────┐   │
│  │         LangGraph StateGraph         │   │
│  │    ┌───────────┐    ┌──────────┐    │   │
│  │    │   Agent   │───▶│   Tools  │    │   │
│  │    │   Node    │◀───│   Node   │    │   │
│  │    └───────────┘    └──────────┘    │   │
│  └─────────────────────────────────────┘   │
├─────────────────────────────────────────────┤
│        OpenAI-Compatible LLM Provider       │
└─────────────────────────────────────────────┘
```

## Comparison with Rust ZeroClaw

| Feature | Rust ZeroClaw | zeroclaw-tools |
|---------|---------------|----------------|
| **Binary size** | ~3.4 MB | Python package |
| **Memory** | <5 MB | ~50 MB |
| **Startup** | <10ms | ~500ms |
| **Tool consistency** | Model-dependent | LangGraph guarantees |
| **Extensibility** | Rust traits | Python decorators |

Use **Rust ZeroClaw** for production edge deployments. Use **zeroclaw-tools** when you need guaranteed tool calling consistency or Python ecosystem integration.

## License

MIT License — see [LICENSE](../LICENSE-MIT)
