feat(python): add zeroclaw-tools companion package for LangGraph tool calling
- Add Python package with LangGraph-based agent for consistent tool calling - Provides reliable tool execution for providers with inconsistent native support - Includes tools: shell, file_read, file_write, web_search, http_request, memory - Discord bot integration included - CLI tool for quick interactions - Works with any OpenAI-compatible provider (Z.AI, OpenRouter, Groq, etc.) Why: Some LLM providers (e.g., GLM-5/Zhipu) have inconsistent tool calling behavior. LangGraph's structured approach guarantees reliable tool execution across all providers.
This commit is contained in:
parent
bc38994867
commit
e5ef8a3b62
17 changed files with 1371 additions and 0 deletions
86
python/zeroclaw_tools/tools/memory.py
Normal file
86
python/zeroclaw_tools/tools/memory.py
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
"""
|
||||
Memory storage tools for persisting data between conversations.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from langchain_core.tools import tool
|
||||
|
||||
|
||||
def _get_memory_path() -> Path:
|
||||
"""Get the path to the memory storage file."""
|
||||
return Path.home() / ".zeroclaw" / "memory_store.json"
|
||||
|
||||
|
||||
def _load_memory() -> dict:
|
||||
"""Load memory from disk."""
|
||||
path = _get_memory_path()
|
||||
if not path.exists():
|
||||
return {}
|
||||
try:
|
||||
with open(path, "r") as f:
|
||||
return json.load(f)
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
|
||||
def _save_memory(data: dict) -> None:
|
||||
"""Save memory to disk."""
|
||||
path = _get_memory_path()
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(path, "w") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
|
||||
@tool
|
||||
def memory_store(key: str, value: str) -> str:
|
||||
"""
|
||||
Store a key-value pair in persistent memory.
|
||||
|
||||
Args:
|
||||
key: The key to store under
|
||||
value: The value to store
|
||||
|
||||
Returns:
|
||||
Confirmation message
|
||||
"""
|
||||
try:
|
||||
data = _load_memory()
|
||||
data[key] = value
|
||||
_save_memory(data)
|
||||
return f"Stored: {key}"
|
||||
except Exception as e:
|
||||
return f"Error: {e}"
|
||||
|
||||
|
||||
@tool
|
||||
def memory_recall(query: str) -> str:
|
||||
"""
|
||||
Search memory for entries matching the query.
|
||||
|
||||
Args:
|
||||
query: The search query
|
||||
|
||||
Returns:
|
||||
Matching entries or "no matches" message
|
||||
"""
|
||||
try:
|
||||
data = _load_memory()
|
||||
if not data:
|
||||
return "No memories stored yet"
|
||||
|
||||
query_lower = query.lower()
|
||||
matches = {
|
||||
k: v
|
||||
for k, v in data.items()
|
||||
if query_lower in k.lower() or query_lower in str(v).lower()
|
||||
}
|
||||
|
||||
if not matches:
|
||||
return f"No matches for: {query}"
|
||||
|
||||
return json.dumps(matches, indent=2)
|
||||
except Exception as e:
|
||||
return f"Error: {e}"
|
||||
Loading…
Add table
Add a link
Reference in a new issue