Metadata-Version: 2.4
Name: mirrorkit
Version: 0.2.2
Summary: Mirrors client: a drop-in production trace collector for LLM agents, plus the `mirrors` CLI (install `mirrorkit[cli]`).
Author: Mirrors
License: MIT
Project-URL: Homepage, https://mirror.dev
Keywords: llm,tracing,observability,langchain,anthropic,openai,cli
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Provides-Extra: cli
Requires-Dist: click>=8.1; extra == "cli"
Requires-Dist: httpx>=0.27; extra == "cli"
Requires-Dist: pydantic>=2.7; extra == "cli"
Provides-Extra: mcp
Requires-Dist: mcp>=1.2; extra == "mcp"
Requires-Dist: click>=8.1; extra == "mcp"
Requires-Dist: httpx>=0.27; extra == "mcp"
Requires-Dist: pydantic>=2.7; extra == "mcp"
Provides-Extra: pii
Requires-Dist: torch>=2.0; extra == "pii"
Requires-Dist: transformers<5,>=4.40; extra == "pii"
Requires-Dist: sentencepiece>=0.2; extra == "pii"
Provides-Extra: langchain
Requires-Dist: langchain-core; extra == "langchain"
Provides-Extra: anthropic
Requires-Dist: anthropic; extra == "anthropic"
Provides-Extra: openai
Requires-Dist: openai; extra == "openai"
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: click>=8.1; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Requires-Dist: pydantic>=2.7; extra == "dev"

# mirrorkit

A lightweight, **drop-in** production trace collector for LLM agents. Add two
lines to your existing LangChain / LangGraph / Anthropic / OpenAI script and
your agent's traces start streaming to your Mirrors backend — keyed by an API
key, with negligible latency (non-blocking, background-batched).

## Install

```bash
pip install mirrorkit
```

Zero required runtime dependencies — the sender uses only the Python stdlib.
LangChain / Anthropic / OpenAI are instrumented only if they're importable.

## Usage (2 lines)

```python
import mirrorkit
mirrorkit.init(api_key="mk_live_...", project="my-agent")
```

That's it. Run your agent normally — traces are captured automatically and
shipped in the background. The endpoint defaults to the `MIRROR_ENDPOINT`
environment variable, then to the production URL.

```python
mirrorkit.init(
    api_key="mk_live_...",
    project="my-agent",
    endpoint="https://api.mirror.dev",  # optional override
    flush_interval=2.0,                  # seconds between batch flushes
    max_batch=50,                        # max traces per POST
    instrument=True,                     # auto-hook LangChain/Anthropic/OpenAI
)
```

## Manual logging

For frameworks you don't auto-instrument, enqueue a trace yourself. Messages
are OpenAI-style chat dicts:

```python
import mirrorkit
mirrorkit.init(api_key="mk_live_...", project="my-agent")

mirrorkit.log_trace(
    [
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "What's the weather in Paris?"},
        {
            "role": "assistant",
            "content": None,
            "tool_calls": [
                {
                    "id": "call_1",
                    "function": {"name": "get_weather", "arguments": '{"city": "Paris"}'},
                }
            ],
        },
        {"role": "tool", "tool_call_id": "call_1", "content": "18C, sunny"},
        {"role": "assistant", "content": "It's 18C and sunny in Paris."},
    ],
    trace_id="optional-id",
    model="gpt-4o",
)

mirrorkit.flush()  # also runs automatically at interpreter exit
```

## LangChain global handler

`init()` registers a global LangChain callback handler automatically, so you
don't need to pass callbacks. If your setup doesn't honor the global hook,
pass the handler explicitly:

```python
from langchain_core.runnables import RunnableConfig
import mirrorkit

mirrorkit.init(api_key="mk_live_...", project="my-agent")
chain.invoke(inputs, config=RunnableConfig(callbacks=[mirrorkit.handler()]))
```

## API

- `mirrorkit.init(api_key, project="default", endpoint=None, *, flush_interval=2.0, max_batch=50, instrument=True)`
- `mirrorkit.log_trace(messages, *, trace_id=None, model=None)`
- `mirrorkit.flush(timeout=5.0)`
- `mirrorkit.shutdown()`
- `mirrorkit.handler()` — LangChain callback handler for manual registration

## The `mirrors` CLI

The same package ships a terminal client of the hosted backend — the things you'd
otherwise do in the web app (log in, ingest+build a twin, explore it, run evals).
It needs a few extra deps, so install the `cli` extra:

```bash
pip install "mirrorkit[cli]"   # adds the `mirrors` command (click + httpx + pydantic)
```

Authenticate with a workspace API key (`mk_live_…`, minted in the web app), then:

```bash
mirrors login                              # paste the key (or --api-key / --dev)
mirrors env ls                             # list environments
mirrors build traces.jsonl --name airline  # ingest + build a twin (streams the log)
mirrors build --project airline --name airline   # build from a collector stream
mirrors env assets|schema|fidelity|traces <env>   # explore the twin
mirrors eval create <env> --name smoke --from cases.json
mirrors eval run <eval-set-id>             # run evals; `mirrors run show <run-id>`
```

Credentials live in `~/.mirrors/config.json` (or `MIRRORS_BASE_URL` /
`MIRRORS_API_KEY` for CI). Add `--json` to any command for machine-readable output.
The CLI talks only HTTP to the backend — it has no engine/build logic of its own.

## MCP server (drive Mirrors from an AI client)

The same package ships an **MCP server** so an AI client (Claude Desktop, Cursor,
Claude Code, any MCP host) can build, inspect, and evaluate your mirrors with the
same operations as the CLI — `list_mirrors`, `get_schema`, `build_mirror`,
`generate_eval_set`, `run_eval_set`, and more (15 tools). It reuses your login and
talks to the hosted backend by default; the only thing you supply is a workspace
API key.

**Easiest — one command sets up every tool you have:**

```bash
mirrors mcp install        # detect Claude Desktop/Code, Cursor, Windsurf, VS Code → wire them up
```

It detects your installed coding tools and writes the launch block into each
(reusing your `mirrors login`), and always offers a skip. `mirrors login` also
offers this once on first run. Pick specific tools with `--tools cursor,vscode`,
non-interactive with `--yes`, or `--print` to copy the block by hand. The block it
writes is the path-free `uvx` form below.

The manual way (needs [uv](https://docs.astral.sh/uv/); no clone, no paths) — add
this to your MCP client's config:

```json
{
  "mcpServers": {
    "mirrors": {
      "command": "uvx",
      "args": ["--from", "mirrorkit[mcp]", "mirrors-mcp"],
      "env": { "MIRRORS_API_KEY": "mk_live_..." }
    }
  }
}
```

`uvx` fetches `mirrorkit[mcp]` into a throwaway environment and runs it — the same
config works on anyone's machine. Equivalents:

```bash
# Claude Code:
claude mcp add mirrors --env MIRRORS_API_KEY=mk_live_... -- uvx --from "mirrorkit[mcp]" mirrors-mcp

# pipx instead of uv:
pipx run --spec "mirrorkit[mcp]" mirrors-mcp

# or a normal install, then point the client at the `mirrors-mcp` command:
pip install "mirrorkit[mcp]"
```

Add `"MIRRORS_BASE_URL"` to `env` only to target a non-default backend (e.g.
`http://localhost:8001` for local dev). The MCP requires Python ≥ 3.10. If no key
is detected, calling any tool returns step-by-step instructions for minting one and
wiring it in — so a first run is never a dead end.

## Wire format

Batches are POSTed to `{endpoint}/api/collect` with
`Authorization: Bearer {api_key}`:

```json
{
  "project": "my-agent",
  "traces": [
    {"id": "abc", "model": "gpt-4o", "messages": [{"role": "user", "content": "hi"}]}
  ]
}
```

Failures (non-2xx / network errors) are retried a couple of times then dropped
— the collector never raises into your program.
