Metadata-Version: 2.5
Name: wolf-agent
Version: 0.1.0
Summary: Python client for the wolf mcp server: offline Office document tools for AI agents
Project-URL: Homepage, https://wolfsdk.com
Project-URL: Documentation, https://wolfsdk.com/runtime/docs#integrations
Author: Wolfgang Schoenberger
License-Expression: MIT
License-File: LICENSE
Keywords: agents,docx,mcp,model-context-protocol,office,pdf,pptx,xlsx
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Office/Business :: Office Suites
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown

# wolf-agent (Python)

A thin client for the `wolf mcp` stdio server. `wolf` itself is a native executable: it needs no
Python, no pip packages and no network. This client uses only the Python standard library
(Python 3.11 or newer), opens no sockets, and holds no tool logic: it spawns
`wolf mcp --workspace-root ROOT`, speaks newline-delimited JSON-RPC 2.0 (`initialize`,
`notifications/initialized`, `tools/list`, `tools/call`), and stops the child on close.

## Install

```sh
pip install wolf-agent
```

The `wolf` executable ships with Wolf Runtime. Start a free evaluation at
<https://wolfxl.com/evaluate>, then run `wolf mcp --help` to check that your build includes the
server. MCP clients that launch servers by command can also run `wolf mcp --workspace-root ROOT`
directly, without this package.

## Use

```python
from wolf_agent import WolfAgentClient, ToolError

with WolfAgentClient("/abs/workspace", wolf="/path/to/wolf") as wolf:
    read = wolf.read("report.docx")  # revision_sha256, html, blocks
    hits = wolf.search("report.docx", "Quarterly")  # anchored matches
    old = hits["matches"][0]["html"]
    try:
        receipt = wolf.edit(
            "report.docx",
            read["revision_sha256"],
            "revised",
            [{"old_html": old, "new_html": old.replace("Quarterly", "Annual")}],
            approved=True,
        )
    except ToolError as refusal:  # isError: typed refusal
        print(refusal.code, refusal.hint)
    else:
        print(receipt["status"], receipt["published"])
```

`wolf_observe`, `wolf_transact` and `wolf_diff` take the native agent request directly
(`wolf.wolf_observe(request)`); `wolf.lifecycle(phase, transaction, approved=None)` continues a
server-owned transaction (`lifecycle_plan` through `lifecycle_discard`; commit needs
`approved=True`); `call_tool(name, arguments)` reaches any tool and `list_tools()` returns the
server's descriptors. Each result is the tool's `structuredContent`.

## Behaviour

| Condition | Result |
|---|---|
| Tool result with `isError` | `ToolError` with `.tool`, `.code`, `.hint`, `.document`; the session stays usable |
| JSON-RPC error object | `RpcError` with `.code`, `.message`, `.data`; the session stays usable |
| Non-JSON line, wrong response id, malformed result | `ProtocolError`; the child is stopped and later calls re-raise it |
| No response within `request_timeout` (default 120 s; `startup_timeout` 30 s) | `WolfTimeoutError`; the child is stopped |
| Spawn failure, exit or closed pipes | `WolfProcessError` with `.returncode` and the stderr tail |

`close()` (and leaving the `with` block) closes stdin, waits `shutdown_timeout` (5 s), then
terminates, then kills. `wolf` may also be an argv prefix, for example
`["docker", "run", "-i", "--rm", "--network", "none", ...]`; `env` replaces the child's whole
environment.

## Tests

```sh
python3 -m pytest tests
```

The tests drive a scripted stand-in server and need only `pytest`.
