Metadata-Version: 2.4
Name: forge-observe
Version: 0.1.2
Summary: OpenTelemetry instrumentation for qwen-think reasoning sessions.
Author: ArkaD171717
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: llm,metrics,observability,opentelemetry,qwen,qwen-think,reasoning,tracing
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software 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: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.9
Requires-Dist: opentelemetry-api>=1.20.0
Requires-Dist: opentelemetry-sdk>=1.20.0
Requires-Dist: qwen-think>=0.1.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Provides-Extra: otlp
Requires-Dist: opentelemetry-exporter-otlp>=1.20.0; extra == 'otlp'
Description-Content-Type: text/markdown

# forge-observe

OpenTelemetry instrumentation for [qwen-think](https://github.com/ArkaD171717/qwen-think) reasoning sessions.

Emits traces and metrics for thinking budget consumption, mode switches, token splits, preserve_thinking utilization, and backend flag normalization. Works with any OTel-compatible backend (Jaeger, Grafana Tempo, Datadog, etc.).

## Install

```bash
pip install forge-observe

# For OTLP export (Jaeger, Tempo, Datadog):
pip install forge-observe[otlp]
```

## Quick start

### Auto-instrumentation (recommended)

```python
from forge_observe import instrument
instrument()

# Now use qwen-think as normal -- spans and metrics are emitted automatically.
from qwen_think import ThinkingSession
session = ThinkingSession(client=your_client)
response = session.chat("Implement a binary search tree")
```

### Manual tracing

```python
from forge_observe import ForgeTracer

tracer = ForgeTracer()
with tracer.session(attributes={"model": "Qwen3.6-35B"}) as span:
    with tracer.think_decision(mode="think", reason="coding task"):
        pass
    with tracer.budget_check(
        total_tokens=200000, used_tokens=50000,
        available_tokens=150000, action="ok",
    ):
        pass
```

### Configuration

```python
from forge_observe import configure, instrument

configure(
    service_name="my-app",
    otlp_endpoint="http://localhost:4317",
    otlp_protocol="grpc",
)
instrument()
```

All settings can be overridden via environment variables:

| Variable | Default | Description |
|----------|---------|-------------|
| `FORGE_OBSERVE_SERVICE_NAME` | `forge-observe` | OTel service name |
| `FORGE_OBSERVE_OTLP_ENDPOINT` | `http://localhost:4317` | OTLP collector endpoint |
| `FORGE_OBSERVE_OTLP_PROTOCOL` | `grpc` | `grpc` or `http` |
| `FORGE_OBSERVE_ENABLED` | `true` | Kill switch |
| `FORGE_OBSERVE_CONSOLE_EXPORT` | `false` | Print spans to stdout |

## What it instruments

### Spans (auto-instrumented)

```
forge.session
  |-- forge.session.think_decision    router chose think/instruct, with reason
  |-- forge.session.param_swap        sampling params changed
  |-- forge.session.budget_check      budget evaluated, remaining tokens logged
  |-- forge.backend.normalize         flag normalization applied
  |-- forge.backend.response          response received, thinking/response split
  |-- forge.session.preserve_check    preserve_thinking reuse evaluated
```

### Spans (manual via ForgeTracer)

```
forge.session.backend_call            wraps a backend API call (ForgeTracer.backend_call)
forge.mtp.config_decision             MTP config selected or disabled, with reason (ForgeTracer.mtp_config)
```

### Metrics

| Name | Type | Description |
|------|------|-------------|
| `forge.session.budget_remaining` | Gauge | Tokens remaining in budget |
| `forge.session.thinking_tokens` | Counter | Total thinking tokens emitted |
| `forge.session.response_tokens` | Counter | Total response tokens emitted |
| `forge.session.mode_switches` | Counter | Think/instruct mode flips |
| `forge.session.preserve_reuse_rate` | Gauge | Fraction of turns reusing prior thinking |
| `forge.mtp.acceptance_rate` | Gauge | Speculative token acceptance rate |

## Examples

See `examples/` for setups targeting Jaeger, Grafana Tempo, and Datadog.

## License

Apache-2.0
