Metadata-Version: 2.4
Name: sidus
Version: 0.2.0
Summary: Sidus: time series foundation model inference server with unified API
License: Apache-2.0
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: torch>=2.0
Requires-Dist: transformers>=4.50
Requires-Dist: fastapi>=0.100
Requires-Dist: uvicorn>=0.20
Requires-Dist: httpx>=0.25
Requires-Dist: numpy>=1.24
Requires-Dist: pandas>=2.0
Requires-Dist: safetensors>=0.4
Requires-Dist: accelerate>=0.20
Requires-Dist: pydantic>=2.0
Requires-Dist: typer>=0.9
Requires-Dist: python-dotenv>=1.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: httpx>=0.25; extra == "dev"
Requires-Dist: ruff>=0.8; extra == "dev"
Dynamic: license-file

# Sidus

Time series foundation model inference server with a unified API — load any model by pointing at its directory.

## Quick Start

```bash
git clone https://github.com/superlinear-space/sidus
cd sidus

# Install
uv venv --python 3.12
uv pip install -e ".[dev]"

# Point at your models — auto-detects architecture from config.json
sidus -m ~/models/timesfm-2.5-200m-transformers \
      -m ~/models/Toto-2.0-2.5B \
      -m ~/models/chronos-2
```

```
http://localhost:8000/docs      # OpenAPI docs
http://localhost:8000/dashboard  # Interactive forecast dashboard
```

## Configuration

Three layers, highest priority first:

| Priority | Method | Example |
|---|---|---|
| 1 | CLI args | `sidus -m /data/model --port 9000` |
| 2 | Environment variables | `SIDUS_MODEL_PATH=/data/model` |
| 3 | `.env` file (loaded from CWD) | `SIDUS_MODEL_PATH=...` |

### CLI

```bash
sidus --help
```

| Option | Short | Default | Description |
|---|---|---|---|
| `--model-path` | `-m` | `$SIDUS_MODEL_PATH` | Model directory. Repeat for multiple models. |
| `--prometheus-url` | `-p` | `$SIDUS_PROMETHEUS_URL` or `http://localhost:9090` | Prometheus base URL |
| `--host` | | `0.0.0.0` | Bind address |
| `--port` | `-P` | `8000` | Bind port |
| `--version` | `-V` | — | Print version and exit |

```bash
sidus info     # Show config and GPU status
```

### .env

```bash
SIDUS_MODEL_PATH=~/models/timesfm-2.5-200m-transformers,~/models/Toto-2.0-2.5B
SIDUS_PROMETHEUS_URL=http://localhost:9090
```

`SIDUS_MODEL_PATH` supports comma-separated paths. `TIMESFM_*` prefix also works for backward compatibility.

## Supported Models

Sidus auto-detects model architecture from `config.json`. Point `-m` at any model directory:

| Model | ID | Context | Horizon | Capabilities |
|---|---|---|---|---|
| TimesFM 2.5 | `google/timesfm-2.5-200m` | 16,384 | 128 | forecast, quantile, covariates |
| Toto 2.0 | `datadog/toto-2.0-2.5b` | 131,072 | 131,072 | forecast, quantile, multivariate, long-context |
| Chronos 2 | `amazon/chronos-2` | 8,192 | 1,024 | forecast, quantile, multivariate, covariates |

To add a new model, add a detection rule and forecast adapter in `registry.py`. The `GET /v1/models` endpoint returns available models with full capability declarations.

## TSFM.ai-Compatible API (`/v1`)

All `/v1/` endpoints follow the [TSFM.ai API contract](https://tsfm.ai/docs/api) (canonical schema at `spec/tsfm-openapi.json`).

### `POST /v1/forecast`

Canonical TSFM forecast. Target is always 2D — `[[v1], [v2], ...]` for univariate.

```bash
curl -X POST http://localhost:8000/v1/forecast \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/timesfm-2.5-200m",
    "inputs": [{"target": [[10.0], [11.0], [12.0], [11.5], [10.8]]}],
    "parameters": {
      "prediction_length": 4,
      "quantile_levels": [0.1, 0.5, 0.9]
    }
  }'
```

Response (univariate, 4 steps):

```json
{
  "id": "fcst_a1b2c3d4e5f6",
  "object": "forecast",
  "model": "google/timesfm-2.5-200m",
  "provider": "sidus",
  "horizon": 4,
  "prediction_length": 4,
  "quantile_levels": [0.1, 0.5, 0.9],
  "outputs": [{
    "mean": [[24.5], [25.1], [25.3], [25.8]],
    "quantile_predictions": [
      {"level": 0.1, "values": [[23.0], [23.5], [23.8], [24.2]]},
      {"level": 0.5, "values": [[24.5], [25.1], [25.3], [25.8]]},
      {"level": 0.9, "values": [[26.0], [26.5], [27.0], [27.4]]}
    ]
  }],
  "usage": {"input_tokens": 5, "output_tokens": 4, "total_tokens": 9},
  "latency_ms": 51.2
}
```

**Covariates** (TimesFM, Chronos):

```bash
curl -X POST http://localhost:8000/v1/forecast \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/timesfm-2.5-200m",
    "inputs": [{
      "target": [[10.0], [11.0], [12.0]],
      "past_covariates": {"promo": [0, 1, 0]},
      "future_covariates": {"promo": [1, 0, 0, 1]}
    }],
    "parameters": {"prediction_length": 4}
  }'
```

**Multivariate** (Toto, Chronos):

```bash
curl -X POST http://localhost:8000/v1/forecast \
  -H "Content-Type: application/json" \
  -d '{
    "model": "amazon/chronos-2",
    "inputs": [{
      "target": [[10.0, 100.0], [11.0, 101.0], [12.0, 102.0]]
    }],
    "parameters": {"prediction_length": 4}
  }'
```

### Model Catalog

```bash
# List all registered models
curl http://localhost:8000/v1/models

# Get single model detail
curl http://localhost:8000/v1/models/google/timesfm-2.5-200m
```

Response includes `capabilities`, `supported_tasks`, `min_points`, `context_length`.

### Batch & Ensemble

```bash
# Batch: run multiple independent forecasts
curl -X POST http://localhost:8000/v1/forecast/batch \
  -H "Content-Type: application/json" \
  -d '{
    "requests": [
      {"model": "...", "inputs": [...], "parameters": {...}},
      {"model": "...", "inputs": [...], "parameters": {...}}
    ]
  }'

# Ensemble: multi-model weighted blend (501 — not yet implemented)
curl -X POST http://localhost:8000/v1/forecast/ensemble \
  -H "Content-Type: application/json" \
  -d '{"inputs": [...], "parameters": {...}}'
```

### Error Format

All `/v1/` errors follow the TSFM.ai error shape:

```json
{"error": "Model not found", "code": "request_rejected", "endpoint": "/v1/forecast"}
```

13 canonical error codes from `ErrorCode` enum (see `spec/tsfm-openapi.json`).

### Full Endpoint Reference

| Method | Path | Description |
|--------|------|-------------|
| GET | `/healthz` | Liveness check |
| GET | `/v1/models` | List registered models |
| GET | `/v1/models/{model_id}` | Single model detail |
| POST | `/v1/forecast` | Canonical TSFM forecast |
| POST | `/v1/forecast/batch` | Batch forecast jobs |
| POST | `/v1/forecast/ensemble` | Ensemble (not yet implemented) |

## Legacy API (Prometheus / raw values)

TimesFM-only. Uses the HuggingFace `TimesFm2_5ModelForPrediction` backend.

| Endpoint | Description |
|---|---|
| `POST /forecast` | Forecast using PromQL queries |
| `POST /forecast/values` | Forecast using raw time series arrays |
| `POST /forecast/table` | PromQL forecast as flat table |
| `POST /forecast/values/table` | Raw values forecast as flat table |
| `GET /health` | Server and model status |
| `GET /healthz` | Liveness check |
| `GET /dashboard` | Interactive Plotly.js dashboard |
| `GET /metrics` | List Prometheus metric names |
| `GET /labels/{label}/values` | List label values |

## License

Apache 2.0 — see [LICENSE](LICENSE).
