Metadata-Version: 2.4
Name: llm-agent-trace
Version: 0.1.0
Summary: Zero-dependency LLM call tracer — patch once, trace everything
Author-email: Your Name <you@example.com>
License: MIT
Project-URL: Homepage, https://github.com/yourusername/agent-trace
Project-URL: Repository, https://github.com/yourusername/agent-trace
Project-URL: Issues, https://github.com/yourusername/agent-trace/issues
Keywords: llm,tracing,observability,openai,anthropic,langchain,litellm,agents,debugging
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: httpx>=0.25; extra == "dev"
Requires-Dist: requests>=2.31; extra == "dev"

# agent-trace

Zero-dependency LLM call tracer. Patch once — every provider is captured automatically.

```
┌─ research_agent · #a3f2b1  1149 tokens  $0.0022  3.4s
│
│  ├─ summarize  312→87 tok  $0.0004  1.2s
│  │  └─► openai · api.openai.com/v1/chat/completions  gpt-4o  312→87 tok  $0.0004  1.2s  ✓
│  │
│  └─ verify  540→210 tok  $0.0018  2.1s
│     └─► anthropic · api.anthropic.com/v1/messages  claude-sonnet-4-6  540→210 tok  $0.0018  2.1s  ✓
│
│  2 call(s)  ·  852→297 tokens  ·  $0.0022  ·  3.4s
└────────────────────────────────────────
```

## Why

Every LLM observability tool is either a paid SaaS, a massive framework dependency, or tied to a specific provider. `agent-trace` is none of those — it's a small library you drop in and forget about.

- **Zero runtime dependencies** — stdlib only
- **Provider-agnostic** — works with OpenAI, Anthropic, Mistral, Groq, Gemini, Cohere, Ollama, LM Studio, Azure OpenAI, and anything that speaks HTTP
- **Works with LangChain, LiteLLM, and any other framework** — intercepts at the HTTP layer, not the SDK layer
- **Sync + async** — both are captured

## Install

```bash
pip install agent-trace
```

## Quickstart

```python
import agent_trace

# One line at the top of your script
agent_trace.patch()

# Wrap your agent run in a session
with agent_trace.session("my_agent"):
    response = openai.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": "Hello"}]
    )
# Trace is printed to stderr automatically when the session ends
```

Works identically with LiteLLM, LangChain, Anthropic SDK, or any HTTP-based LLM client — no changes to your existing code.

## Adding structure with spans

Without spans you get a flat list of calls. Spans let you group calls into named steps:

```python
import agent_trace

agent_trace.patch()

@agent_trace.span("summarize")
def summarize(text):
    return llm.invoke(f"Summarize: {text}")

@agent_trace.span("verify")
def verify(summary):
    return llm.invoke(f"Is this accurate? {summary}")

with agent_trace.session("research_agent"):
    summary = summarize(long_document)
    verdict = verify(summary)
```

Spans also work as context managers:

```python
with agent_trace.session("agent"):
    with agent_trace.span("step_1"):
        result = llm.invoke(...)
    with agent_trace.span("step_2"):
        result = llm.invoke(...)
```

## Save trace as JSON

```python
with agent_trace.session("my_agent", output="trace.json"):
    ...
```

```json
{
  "session_id": "a3f2b1",
  "name": "my_agent",
  "duration_ms": 3400,
  "total_calls": 2,
  "total_tokens_in": 852,
  "total_tokens_out": 297,
  "total_cost_usd": 0.0022,
  "spans": [...],
  "orphan_calls": [...]
}
```

## Disable terminal output

```python
with agent_trace.session("my_agent", print_trace=False, output="trace.json"):
    ...
```

## Custom cost table

```python
agent_trace.patch(cost_table={
    "my-fine-tuned-model": (0.005, 0.015),  # per 1k tokens: in, out
})
```

## Introspection

```python
import agent_trace

sess = agent_trace.current_session()   # active Session or None
sp   = agent_trace.current_span()      # active Span or None
```

## Supported providers (auto-detected)

| Provider | Endpoint pattern |
|---|---|
| OpenAI | `api.openai.com/v1/chat/completions` |
| Anthropic | `api.anthropic.com/v1/messages` |
| Azure OpenAI | `*.openai.azure.com/*/chat/completions` |
| Mistral | `api.mistral.ai/v1/chat/completions` |
| Groq | `api.groq.com/openai/v1/chat/completions` |
| Gemini | `generativelanguage.googleapis.com/*/generateContent` |
| Cohere | `api.cohere.com/v1/chat` |
| Together AI | `api.together.xyz/v1/chat/completions` |
| Perplexity | `api.perplexity.ai/chat/completions` |
| OpenRouter | `openrouter.ai/api/v1/chat/completions` |
| Ollama / LM Studio | `localhost:*/api/chat` |

Any provider not listed but using HTTP/REST is captured as `unknown`.

## Limitations (v1)

- **Streaming responses** are logged as a single event when the stream closes; per-chunk tracing is not yet supported.
- **gRPC-based providers** are not supported (rare in practice — all major providers use HTTP).
- Monkey-patching works best when `patch()` is called before your LLM library imports. If you import `from litellm import completion` before calling `patch()`, that specific reference won't be intercepted — use `litellm.completion(...)` instead.

## Contributing

Issues and PRs welcome. Please open an issue before starting work on a large change.

## License

MIT
