Capability-first serving for time-series foundation models.
UniTS-Hub v2 keeps the original single-model deployment model, but replaces the old predict-only interface with a model-capability API designed for AI agents. The service now targets three model families:
TimesFM 2.5for univariate point forecastingChronos-2for quantile, multivariate, and covariate-oriented forecastingKronosfor financial OHLCV forecasting and sampled path generation
It exposes three integration surfaces:
- REST API for Dify, LangChain, Flowise, and generic HTTP clients
- MCP endpoint powered by the official
modelcontextprotocol/python-sdk - A repo-local Codex skill at
.agents/skills/unitshub-agent/SKILL.md
- One container still serves one loaded model at a time.
- Agents discover model capabilities at runtime instead of relying on static docs.
- Task schemas are model-aware and exposed explicitly.
- Legacy
/predictremains for backward compatibility.
GET /models/current
Example response:
{
"id": "chronos",
"name": "Chronos-2",
"version": "2",
"input_modes": ["univariate", "multivariate", "covariates"],
"output_modes": ["quantile_forecast"],
"tasks": [
{
"name": "forecast_quantile",
"title": "Quantile Forecast"
}
]
}GET /models/current/schemaGET /models/current/tasks/{task}/schema
POST /models/current/invoke
Example for TimesFM:
{
"task": "forecast_point",
"input": {
"series": [
{
"target": [10.5, 12.1, 11.8, 13.2, 12.9],
"item_id": "sensor_01"
}
],
"horizon": 5,
"frequency": "1h"
}
}Example for Chronos-2:
{
"task": "forecast_quantile",
"input": {
"series": [
{
"item_id": "retail-sku-42",
"target": [120, 125, 118, 131, 135]
}
],
"horizon": 7,
"quantiles": [0.1, 0.5, 0.9]
}
}Example for Kronos:
{
"task": "generate_paths",
"input": {
"symbol": "AAPL",
"candles": [
{
"timestamp": "2026-04-10T00:00:00Z",
"open": 190.1,
"high": 191.4,
"low": 188.7,
"close": 189.8,
"volume": 51230000
}
],
"horizon": 5,
"num_samples": 4
}
}curl 示例需要显式带 Content-Type: application/json。服务端现在也会兼容常见的 curl -d 省略该头的写法,但仍建议始终带上:
curl -X POST http://localhost:8000/models/current/invoke \
-H "Authorization: Bearer unitshub-secret" \
-H "Content-Type: application/json" \
-d '{
"task": "forecast_ohlcv",
"input": {
"symbol": "AAPL",
"candles": [
{
"timestamp": "2026-04-10T00:00:00Z",
"open": 190.1,
"high": 191.4,
"low": 188.7,
"close": 189.8,
"volume": 51230000
}
],
"horizon": 5
}
}'Single image:
docker run --rm \
-p 8000:8000 \
-e MODEL_TYPE=timesfm \
-e API_KEY=unitshub-secret \
kingfs/unitshub:timesfm-latestCompose profile switching:
- Create a local
.envfile and setCOMPOSE_PROFILES=kronos - Optionally set
API_KEY=unitshub-secret - Start the selected profile with
docker compose -f docker-compose.example.yml up -d
The example compose file keeps one service per model image, and COMPOSE_PROFILES decides which one starts.
POST /mcp
The server uses the official MCP Python SDK in stateless Streamable HTTP mode. Available tools:
get_current_modelget_model_schemaget_task_schemainvoke_task
Example:
curl -X POST http://localhost:8000/mcp/ \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer your-secret-key" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "invoke_task",
"arguments": {
"task": "forecast_point",
"input": {
"history": [1, 2, 3, 4],
"horizon": 3,
"frequency": "auto"
}
}
}
}'The SDK handles MCP protocol details, so UniTS-Hub only defines tool behavior.
The original endpoints still exist:
POST /predictPOST /predict/csv
These are marked as compatibility interfaces. New agent integrations should prefer /models/current/invoke or /mcp.
| Variable | Description | Default |
|---|---|---|
MODEL_TYPE |
timesfm, chronos, or kronos |
chronos |
MODELS_DIR |
Base directory containing model weights | /app/models |
API_KEY |
Bearer token used by API and MCP | unitshub-secret |
KRONOS_TOKENIZER_PATH |
Optional local tokenizer path for Kronos | unset |
KRONOS_RUNTIME_PATH |
Location of the official Kronos source runtime inside the container | /opt/kronos-runtime |
Download bundled model assets:
python3 scripts/download_models.pyDownload a specific model:
python3 scripts/download_models.py --model kronoskronos downloads both the model weights and the tokenizer repository.
uv sync
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reloadAfter you start one model container, you can validate the live service with:
python3 scripts/api_smoke_test.py --base-url http://localhost:8000 --api-key unitshub-secretThe script first calls /models/current, detects whether the service is running timesfm, chronos, or kronos, then sends model-specific sample payloads to /models/current/invoke and the direct model route:
timesfm:/timesfm/forecastchronos:/chronos/forecastkronos:/kronos/forecast-ohlcvand/kronos/generate-paths
You can change the forecast length with --horizon and, for Kronos, sampled path count with --num-samples.
TimesFMuses the Hugging Facetransformersruntime by default and can expose additional quantile capability when the officialtimesfmruntime is installed.Chronos-2is loaded throughchronos-forecasting.Kronosis installed into the image from the official source repository during Docker build, then loaded fromKRONOS_RUNTIME_PATH.
For MODEL_TYPE=kronos, the Docker build now:
- Clones the official runtime from
https://github.com/shiyu-coder/Kronos.git - Checks out
KRONOS_RUNTIME_REF(default:master) - Installs the runtime's
requirements.txt - Copies the runtime source into
/opt/kronos-runtimein the final image
This removes the previous requirement that the deployment environment manually provide an importable model.py.