Metadata-Version: 2.4
Name: shavira
Version: 0.1.2
Summary: Official Python SDK for SHAVIRA — trace-first security observability for AI and agentic workflows.
Author: SHAVIRA
License: MIT
Project-URL: Homepage, https://harbindersingh.github.io/shavira-docs/
Project-URL: Documentation, https://harbindersingh.github.io/shavira-docs/
Project-URL: Source, https://github.com/harbindersingh/shavira
Keywords: shavira,observability,tracing,llm,ai,agents,opentelemetry,security
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
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 :: System :: Monitoring
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# shavira

Official Python SDK for **SHAVIRA** — trace-first security observability for AI and agentic workflows. Ingest traces, spans, events, and cost records from any Python application.

## Install

```bash
pip install shavira
```

Or from source (within the SHAVIRA monorepo):

```bash
pip install -e packages/python-sdk
```

## Quick start

The intended integration path is:

1. configure the SDK with environment variables
2. initialize it once
3. wrap your route or function
4. let SHAVIRA infer runtime identity and cost whenever it can

```python
from shavira import SecurityTelemetry, observe_route

telemetry = SecurityTelemetry.from_env(service_name="ai-chatbot")
```

## Required and Optional Parameters

### Required environment variables

```bash
SECURITY_SDK_ENABLED=true
SECURITY_SDK_BASE_URL=http://localhost:4000
RUNTIME_ENVIRONMENT=local
SERVICE_NAME=ai-chatbot
```

### Optional environment variables

```bash
INSTANCE_ID=dev-machine-1
HOSTNAME=my-host
SECURITY_SDK_API_KEY=
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
```

### What each parameter does

- `SECURITY_SDK_ENABLED`
  Turns SHAVIRA tracing on or off. Set to `true` to emit traces.
- `SECURITY_SDK_BASE_URL`
  The SHAVIRA API base URL that receives SDK events.
- `RUNTIME_ENVIRONMENT`
  The deployment environment for this running instance, for example `local`, `staging`, `prod`, or `hs-local-test4`.
- `SERVICE_NAME`
  The logical app or service name shown in SHAVIRA, for example `ai-chatbot`.
- `INSTANCE_ID`
  Optional stable instance identity. If omitted, the SDK builds one from hostname and pid.
- `HOSTNAME`
  Optional hostname override.
- `SECURITY_SDK_API_KEY`
  Optional auth token for SHAVIRA ingest if you enable API auth later.
- `OPENAI_API_KEY`
  Optional. Only needed if this service actually uses OpenAI and you want automatic OpenAI usage capture.
- `ANTHROPIC_API_KEY`
  Optional. Only needed if this service actually uses Anthropic and you want automatic Anthropic usage capture.

## What the SDK Handles Automatically

When you use `SecurityTelemetry.from_env(...)`, the SDK automatically attaches:

- `service_name`
- `environment`
- `instance_id`
- `hostname`
- `pid`

When you use `observe_route(...)` on a FastAPI route, the SDK also tries to infer:

- route path
- input payload
- prompt text when present
- user id from `request.state.security_user_id`
- session id from `request.state.security_session_id`

SHAVIRA then tries to determine cost in this order:

1. verified cost from usage and known model pricing
2. estimated cost from prompt/output text plus known model pricing
3. reported cost from the app if provided
4. `unknown` only when there is not enough data to infer anything

## Current Provider Adapter Coverage

The Python SDK uses provider-specific adapters at the instrumentation edge, then normalizes provider and model identity in SHAVIRA.

Current automatic adapter coverage includes:

- Google ADK on Gemini / Vertex AI
- `google.genai`
- `vertexai`
- `google.generativeai`
- OpenAI
- Anthropic

This means the architecture is multi-provider, but provider coverage is not yet complete.

Planned next-phase adapters and parity work:

- AWS Bedrock
- Azure OpenAI specific paths
- Cohere
- LiteLLM / proxy-style gateways
- local runtimes such as Ollama and vLLM

If a provider path does not yet have a dedicated adapter, SHAVIRA can still ingest route/span traces, but verified model-call usage and cost may fall back to estimated or reported values rather than provider-native usage.

## Decorator-style tracing

If your function is a regular request handler, you can use the SDK in a more `@observe()`-style way:

```python
from shavira import SecurityTelemetry

telemetry = SecurityTelemetry.from_env(service_name="ai-chatbot")


@telemetry.observe(
    trace_name="chat-request",
    user_id=lambda chat, user_id: user_id,
    input_payload=lambda chat, user_id: {"prompt": chat.prompt},
    tags=["assistant"],
)
async def handle_chat(chat, user_id: str) -> dict:
    return {"ok": True}
```

For FastAPI routes, the sleeker path is to let the SDK infer the route, prompt payload, runtime metadata, and user identity from the request context:

```python
from fastapi import Depends, FastAPI, Request

from shavira import SecurityTelemetry, observe_route

app = FastAPI()
telemetry = SecurityTelemetry.from_env(service_name="ai-chatbot")


def get_token(request: Request) -> str:
    token = request.headers["authorization"]
    request.state.security_user_id = "user@example.com"
    request.state.security_metadata = {
        "provider": "vertex-ai",
        "model": "gemini-2.5-flash",
        "agent_model": "gemini-2.5-flash",
    }
    return token


@app.post("/chat")
@observe_route(telemetry, trace_name="main-chat-flow")
async def chat_endpoint(chat: dict, request: Request, token: str = Depends(get_token)) -> dict:
    return {"ok": True}
```

This is the recommended minimum integration for most FastAPI apps.

## Streaming and long-running flows

For long-running or streaming flows, start one trace and use `trace.span(...)` for the important phases:

```python
with trace.span("settings_fetch", {"phase": "settings_fetch", "provider": "kleene-api"}):
    settings = await api.get_ai_settings()
```

If your LLM provider returns usage, attach it on the span so SHAVIRA can compute verified cost:

```python
with trace.span("assistant_run", {"phase": "assistant_run", "provider": "vertex-ai", "model": "gemini-2.5-flash"}) as span:
    response = llm_call(...)
    span.set_usage(
        provider="vertex-ai",
        model="gemini-2.5-flash",
        prompt_tokens=response.prompt_tokens,
        completion_tokens=response.completion_tokens,
    )
```

You do not need to emit a separate `cost.record` for normal integrations if usage is available.

## Local diagnostics

```python
from shavira import SecurityTelemetry

telemetry = SecurityTelemetry.from_env(service_name="ai-chatbot")
print(telemetry.diagnostics())
```

Use this when you want to confirm that a restarted app picked up the latest `RUNTIME_ENVIRONMENT` and is actually configured to emit traces.
