Metadata-Version: 2.4
Name: pw-agent
Version: 1.54.0
Summary: CLI coding assistant powered by your Ollama GPUs via PastaWater
Home-page: https://pastawater.io
Author: PastaWater
Author-email: support@pastawater.io
Project-URL: Homepage, https://pastawater.io
Project-URL: GPU Setup, https://pastawater.io/gpu-setup
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.28.0
Requires-Dist: rich>=13.0.0
Requires-Dist: prompt_toolkit>=3.0.0
Requires-Dist: numpy>=1.24.0
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: project-url
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# PW Agent 🧠

CLI coding assistant powered by your Ollama GPUs via [PastaWater](https://pastawater.io).

## Install

The recommended way to install `pw-agent` is using **pipx** to keep it isolated from your other Python packages:

```bash
pipx install pw-agent
```

*Alternatively, you can use standard pip:* `pip install pw-agent`

## Usage

```bash
pw-agent
```

First run guides you through setup — paste your API token, pick a GPU, start chatting.

## Features

- **Interactive REPL** with real-time streaming and a premium dashboard status bar.
- **Plan vs Build Modes**: Use `/plan` for read-only analysis and `/build` for execution.
- **Context Discovery**: Automatically finds `PW_AGENT.md` for project-specific rules.
- **Tab Autocomplete** for commands, file paths, and GPU slots.
- **Session Control**: Fresh sessions by default; use `-c` to resume where you left off.
- **File Injection**: `/add file.py` or `@file.py` — inject files into the LLM's context.
- **Batch Processing**: Model can run multiple tool calls in a single turn.
- **GPU Fleet Control**: `/models` to view GPUs and `/use N` to switch connections or slots.
- **AI Commits**: `/commit` to generate and apply git commit messages based on your diff.
- **Safety First**: `-y` flag for auto-approve; otherwise, every file edit requires confirmation.

## Connect

- **Cloud mode**: Use your PastaWater API token to access your remote fleet.
- **Direct mode**: Point at a local Ollama instance (`--brain http://localhost:11434`).

Get your token at [pastawater.io/settings](https://pastawater.io/settings?tab=cli)

## Model compatibility (tool calling)

Agentic tool use needs both a capable model AND an Ollama whose tool-call
parser tolerates that model's output drift.

| Model | Ollama | Tool calling | Notes |
|---|---|---|---|
| `qwen3-coder:30b` | **>= 0.31.2**, pw-agent **>= 1.52.0** | verified | needs native tools mode (below); ~20 GB resident on a single 24 GB card |
| `qwen3-coder:30b` | >= 0.31.2, pw-agent <= 1.51.x | broken | every tool-requiring prompt dies on turn 0 with `[Empty response from model]`, exit 3 |
| `qwen3-coder:30b` | 0.21.x | broken | intermittent `qwen tool call parsing failed: EOF` — session degrades to plain chat |
| `llama3.1:8b` | any recent | works | weaker coder; fine for pipeline text tasks |
| `laguna-xs-2.1` | >= 0.32.x, pw-agent >= 1.54.0 | expected (untested) | flagged for native tools; SWE-bench 70.9. Run the acceptance test before trusting it with tickets |
| `muse-glimmer:30b` | **>= 0.32.8** (CUDA), pw-agent >= 1.54.0 | expected (untested) | flagged for native tools; multimodal. 0.32.7 was MLX-only |

### Native tools mode

Ollama >= 0.31 ships built-in renderer/parser pairs for some model families
(`template selection ... selected=renderer_parser renderer=qwen3-coder`). For
those models the **server** intercepts every `<tool_call>` tag the model emits
and parses it with that family's native grammar. pw-agent's textual protocol
puts JSON inside `<tool_call>`, which is not that grammar, so the server-side
parser dies with `qwen tool call parsing failed: EOF`, discards the whole
assistant message, and answers `/api/chat` with `{"error":"EOF"}`.

From 1.52.0 pw-agent sends Ollama's native `tools` schemas for these models,
drops the textual protocol from the system prompt, and reads structured
`message.tool_calls` back. Two safety nets:

- Any model that hits a server-side parse failure is flagged automatically and
  the turn is **replayed** with native tools — no failed run, just a slower
  first turn.
- `PW_NATIVE_TOOLS=1` forces it on, `PW_NATIVE_TOOLS=0` forces it off (the
  off case now reports the parse failure as a named error rather than an
  empty response).

Side effect: the system prompt drops from ~4.7 KB to ~1.7 KB for these models,
since the renderer injects the tool definitions itself.

### Failure signals

A session that ends without executing any tool due to parse failure/stall
emits `{"type":"result","subtype":"degraded","degraded_reason":...,
"is_error":true}` and exits with code **3**; a missing model or dead endpoint
fails preflight with the installed-model list and exits with code **2**.
Ollama-level errors (including tool-parse failures) are surfaced verbatim as
`[Error: Ollama: ...]` instead of an empty response.

Only one large model fits a 24 GB card at a time — requesting a second large
tag while one is resident forces CPU offload.

### Debugging a silent run

`--debug` (or `PW_DEBUG=1`) dumps the model name, native-tools decision,
`num_ctx`, every request message, the full assembled tool schema, and the raw
model completion. All of it goes to **stderr**, so `--output-format
stream-json` on stdout stays machine-parseable:

```bash
pw-agent --instance 0 --yes --debug \
  --output-format stream-json --print "..." 2>debug.log
```

## Choosing the model

pw-agent is **not** read-only about models — the dashboard is the default,
not a lock.

| | Behaviour |
|---|---|
| `--model <tag>` | Overrides everything. Ollama loads that tag on the first request, evicting whatever is resident. |
| `--model` omitted | Auto-detect: brain's `last_known_chat_model` (the dashboard pick, trusted over VRAM state) → resident chat model → `/api/tags`. |
| `/model` in the REPL | Alias for `/models` — **displays** the fleet, switches nothing. There is no in-session switch; restart with `--model`. |

The brain proxies `/api/chat` straight through with no model filtering, so
nothing server-side rejects your choice. Two constraints:

- The tag must already be **pulled** on that box. pw-agent never downloads —
  preflight fails with `Model 'X' not found. Available: ...` and exit **2**.
- On a 24 GB card a forced swap costs a cold load (~90 s for a 30B) and
  evicts the dashboard's model. If the dashboard swaps back you'll fight over
  the card.
