feat: llm_cli — CLI autocontenida para chatear con Claude
Un solo archivo (llm.py) que habla directo con la API de Anthropic Messages usando el token OAuth que Claude Code guarda en ~/.claude/.credentials.json. Sin servidor, sin arranque: chat interactivo con memoria, one-shot, pipe, y bucle de tools propias (run_tool_loop). Empaqueta standalone la logica del grupo claude-direct del registry para poder distribuirla (basta llm.py + README.md, el receptor solo necesita httpx + Claude Code logueado).
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
# llm — chat con Claude desde la terminal
|
||||
|
||||
CLI mínima y autocontenida para hablar con Claude directamente desde la terminal.
|
||||
Usa el token que **Claude Code ya guarda en tu máquina**, así que no hay nada que
|
||||
configurar: instala `httpx`, ejecútala y escribe.
|
||||
|
||||
Un solo archivo (`llm.py`), respuesta en streaming, arranque instantáneo (no lanza
|
||||
ningún proceso de fondo).
|
||||
|
||||
## Requisitos
|
||||
|
||||
- Python 3.9+
|
||||
- `httpx` → `pip install httpx`
|
||||
- **Claude Code instalado y con sesión iniciada** (para que exista
|
||||
`~/.claude/.credentials.json`, de donde se lee el token automáticamente).
|
||||
|
||||
## Instalar
|
||||
|
||||
```bash
|
||||
pip install httpx
|
||||
# copia llm.py donde quieras; opcionalmente hazlo ejecutable:
|
||||
chmod +x llm.py
|
||||
```
|
||||
|
||||
## Usar
|
||||
|
||||
```bash
|
||||
# Chat interactivo (con memoria de la conversación)
|
||||
python3 llm.py
|
||||
|
||||
# Respuesta de una sola pregunta
|
||||
python3 llm.py "que es un pseudo-terminal en una frase"
|
||||
|
||||
# Por pipe
|
||||
echo "resume esto en 2 lineas: ..." | python3 llm.py
|
||||
|
||||
# Elegir modelo / system prompt
|
||||
python3 llm.py --model claude-opus-4-8 --system "responde conciso" "explica los punteros"
|
||||
```
|
||||
|
||||
### Comandos del chat interactivo
|
||||
|
||||
| Comando | Acción |
|
||||
|---|---|
|
||||
| `/model <id>` | Cambia de modelo (`claude-opus-4-8`, `claude-haiku-4-5-20251001`, ...) |
|
||||
| `/system <texto>` | Fija un system prompt |
|
||||
| `/reset` | Empieza una conversación nueva |
|
||||
| `/exit` | Salir |
|
||||
|
||||
Modelo por defecto: `claude-haiku-4-5-20251001` (rápido). Usa `--model claude-opus-4-8`
|
||||
para respuestas más potentes.
|
||||
|
||||
## Tus propias herramientas (tools)
|
||||
|
||||
`llm.py` incluye `run_tool_loop`, un bucle agéntico donde defines tus tools y el
|
||||
código que las ejecuta. Tú controlas qué puede hacer el modelo:
|
||||
|
||||
```python
|
||||
import llm
|
||||
|
||||
def get_time(inp):
|
||||
import datetime
|
||||
return {"now": datetime.datetime.now().isoformat()}
|
||||
|
||||
tools = [{
|
||||
"name": "get_time",
|
||||
"description": "Devuelve la fecha y hora actual",
|
||||
"input_schema": {"type": "object", "properties": {}},
|
||||
}]
|
||||
|
||||
res = llm.run_tool_loop(
|
||||
messages=[{"role": "user", "content": "que hora es?"}],
|
||||
tools=tools, dispatch={"get_time": get_time},
|
||||
model="claude-haiku-4-5-20251001",
|
||||
on_text=lambda d: print(d, end="", flush=True),
|
||||
)
|
||||
print("\n→", res["final_text"])
|
||||
```
|
||||
|
||||
El modelo pedirá la tool, tu función la ejecuta, el resultado vuelve al modelo y
|
||||
responde. Añade las tools que quieras (consultar una base de datos, llamar a una
|
||||
API, leer un archivo...).
|
||||
|
||||
## API del módulo
|
||||
|
||||
| Función | Para qué |
|
||||
|---|---|
|
||||
| `stream_messages(messages, model, system, tools, max_tokens, token)` | Stream crudo de eventos (text / tool_use / done / error) |
|
||||
| `run_tool_loop(messages, tools, dispatch, ...)` | Bucle agéntico con tus tools |
|
||||
| `load_oauth_token()` | Lee el token de `~/.claude/.credentials.json` (refresh best-effort) |
|
||||
Reference in New Issue
Block a user