docs: add supported platforms and Windows installation guide (#700)

* docs: add supported platforms section and Windows installation guide

Adds a platform compatibility table (Linux, macOS, Windows) and a
dedicated Windows setup section with step-by-step instructions for
installing PostgreSQL + pgvector and running Hindsight natively.
Follows up on #699 which added Windows native support.

Also fixes a ty type-check error in metrics.py for the conditional
resource module import.

* chore: sync generated clients and lock file after #699

Regenerate client SDKs to pick up ValidationError model changes
and update uv.lock with platform-specific uvloop/winloop deps.

* docs: update Windows section — pg0 now supports Windows

pg0 v0.12.0 added Windows support, so embedded DB works everywhere.
Restructure Windows section to show simple install-and-run first,
with external PostgreSQL as an optional alternative.

* chore: sync generated docs skill and openapi references
This commit is contained in:
Nicolò Boschi 2026-03-26 12:01:30 +01:00 committed by GitHub
parent 939cb40a73
commit 349c112c61
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 219 additions and 6 deletions

View file

@ -213,10 +213,12 @@ def main():
use_import_string = args.workers > 1 or args.reload use_import_string = args.workers > 1 or args.reload
# Check for uvloop/winloop availability # Check for uvloop/winloop availability
import sys import sys
loop_impl = "asyncio" loop_impl = "asyncio"
if sys.platform == "win32": if sys.platform == "win32":
try: try:
import winloop import winloop
winloop.install() # Patches asyncio globally — uvicorn uses "asyncio" but gets winloop winloop.install() # Patches asyncio globally — uvicorn uses "asyncio" but gets winloop
loop_impl = "asyncio" # Tell uvicorn "asyncio" — it's now winloop underneath loop_impl = "asyncio" # Tell uvicorn "asyncio" — it's now winloop underneath
print("winloop installed as asyncio event loop policy (Windows uvloop port)") print("winloop installed as asyncio event loop policy (Windows uvloop port)")
@ -225,6 +227,7 @@ def main():
else: else:
try: try:
import uvloop # noqa: F401 import uvloop # noqa: F401
loop_impl = "uvloop" loop_impl = "uvloop"
print("uvloop available, will use for event loop") print("uvloop available, will use for event loop")
except ImportError: except ImportError:

View file

@ -13,10 +13,12 @@ This module provides metrics for:
import logging import logging
import os import os
import types
try: try:
import resource import resource
except ImportError: except ImportError:
resource = None # Windows doesn't have resource module resource: types.ModuleType | None = None # Windows doesn't have resource module
import threading import threading
import time import time
from contextlib import contextmanager from contextlib import contextmanager

View file

@ -18,7 +18,7 @@ import re # noqa: F401
import json import json
from pydantic import BaseModel, ConfigDict, StrictStr from pydantic import BaseModel, ConfigDict, StrictStr
from typing import Any, ClassVar, Dict, List from typing import Any, ClassVar, Dict, List, Optional
from hindsight_client_api.models.validation_error_loc_inner import ValidationErrorLocInner from hindsight_client_api.models.validation_error_loc_inner import ValidationErrorLocInner
from typing import Optional, Set from typing import Optional, Set
from typing_extensions import Self from typing_extensions import Self
@ -30,7 +30,10 @@ class ValidationError(BaseModel):
loc: List[ValidationErrorLocInner] loc: List[ValidationErrorLocInner]
msg: StrictStr msg: StrictStr
type: StrictStr type: StrictStr
__properties: ClassVar[List[str]] = ["loc", "msg", "type"] input: Optional[Any] = None
ctx: Optional[Dict[str, Any]] = None
url: Optional[StrictStr] = None
__properties: ClassVar[List[str]] = ["loc", "msg", "type", "input", "ctx", "url"]
model_config = ConfigDict( model_config = ConfigDict(
populate_by_name=True, populate_by_name=True,
@ -78,6 +81,11 @@ class ValidationError(BaseModel):
if _item_loc: if _item_loc:
_items.append(_item_loc.to_dict()) _items.append(_item_loc.to_dict())
_dict['loc'] = _items _dict['loc'] = _items
# set to None if input (nullable) is None
# and model_fields_set contains the field
if self.input is None and "input" in self.model_fields_set:
_dict['input'] = None
return _dict return _dict
@classmethod @classmethod
@ -92,7 +100,10 @@ class ValidationError(BaseModel):
_obj = cls.model_validate({ _obj = cls.model_validate({
"loc": [ValidationErrorLocInner.from_dict(_item) for _item in obj["loc"]] if obj.get("loc") is not None else None, "loc": [ValidationErrorLocInner.from_dict(_item) for _item in obj["loc"]] if obj.get("loc") is not None else None,
"msg": obj.get("msg"), "msg": obj.get("msg"),
"type": obj.get("type") "type": obj.get("type"),
"input": obj.get("input"),
"ctx": obj.get("ctx"),
"url": obj.get("url")
}) })
return _obj return _obj

View file

@ -2343,6 +2343,20 @@ export type ValidationError = {
* Error Type * Error Type
*/ */
type: string; type: string;
/**
* Input
*/
input?: unknown;
/**
* Context
*/
ctx?: {
[key: string]: unknown;
};
/**
* URL
*/
url?: string;
}; };
/** /**

View file

@ -6,6 +6,20 @@ Hindsight can be deployed in several ways depending on your infrastructure and r
**[Hindsight Cloud](https://ui.hindsight.vectorize.io/signup)** is a fully managed service that handles all infrastructure, scaling, and maintenance — [sign up here](https://ui.hindsight.vectorize.io/signup). **[Hindsight Cloud](https://ui.hindsight.vectorize.io/signup)** is a fully managed service that handles all infrastructure, scaling, and maintenance — [sign up here](https://ui.hindsight.vectorize.io/signup).
::: :::
## Supported Platforms
Hindsight runs on **Linux**, **macOS**, and **Windows**:
| Platform | Docker | Bare Metal (pip) | Embedded DB (pg0) | Notes |
|----------|--------|------------------|--------------------|-------|
| **Linux** (x86_64, ARM64) | ✅ | ✅ | ✅ | Fully supported, recommended for production |
| **macOS** (Apple Silicon, Intel) | ✅ | ✅ | ✅ | Fully supported |
| **Windows** (x86_64) | ✅ | ✅ | ✅ | Fully supported — see [Windows setup](#windows) for external PostgreSQL option |
All platforms support the embedded database (pg0) for development. On Windows, you can also use an external PostgreSQL installation — see the [Windows](#windows) section for a step-by-step guide.
---
## Prerequisites ## Prerequisites
### PostgreSQL ### PostgreSQL
@ -207,6 +221,65 @@ PORT=80 HINDSIGHT_CP_DATAPLANE_API_URL=https://api.hindsight.io npx @vectorize-i
--- ---
## Windows
**Best for**: Running Hindsight natively on Windows without Docker
Hindsight works on Windows with the embedded database (pg0) out of the box — just install and run:
```powershell
pip install hindsight-api
set HINDSIGHT_API_LLM_PROVIDER=openai
set HINDSIGHT_API_LLM_API_KEY=sk-xxx
set HINDSIGHT_API_LLM_MODEL=gpt-4o-mini
hindsight-api
```
### Using External PostgreSQL (optional)
If you prefer to use your own PostgreSQL instance instead of the embedded database:
```powershell
# Install PostgreSQL
winget install PostgreSQL.PostgreSQL.17
# Build pgvector (requires Visual Studio Build Tools)
git clone https://github.com/pgvector/pgvector.git
cd pgvector
# Open "x64 Native Tools Command Prompt for VS" and run:
set PGROOT=C:\Program Files\PostgreSQL\17
nmake /F Makefile.win
nmake /F Makefile.win install
# Create the database and enable the vector extension
psql -U postgres -c "CREATE DATABASE hindsight;"
psql -U postgres -d hindsight -c "CREATE EXTENSION vector;"
```
Then run Hindsight pointing to your database:
```powershell
pip install hindsight-api
set HINDSIGHT_API_DATABASE_URL=postgresql://postgres@localhost:5432/hindsight
set HINDSIGHT_API_LLM_PROVIDER=openai
set HINDSIGHT_API_LLM_API_KEY=sk-xxx
set HINDSIGHT_API_LLM_MODEL=gpt-4o-mini
hindsight-api
```
- **API Server**: http://localhost:8888
:::tip
You can also use the slim package (`pip install hindsight-api-slim`) if you configure external providers for embeddings and reranking. See [Configuration](./configuration#embeddings) for details.
:::
---
## Embedded in a Python Application ## Embedded in a Python Application
**Best for**: Using Hindsight programmatically from Python without running a separate server process. **Best for**: Using Hindsight programmatically from Python without running a separate server process.

View file

@ -6,6 +6,20 @@ Hindsight can be deployed in several ways depending on your infrastructure and r
**[Hindsight Cloud](https://ui.hindsight.vectorize.io/signup)** is a fully managed service that handles all infrastructure, scaling, and maintenance — [sign up here](https://ui.hindsight.vectorize.io/signup). **[Hindsight Cloud](https://ui.hindsight.vectorize.io/signup)** is a fully managed service that handles all infrastructure, scaling, and maintenance — [sign up here](https://ui.hindsight.vectorize.io/signup).
::: :::
## Supported Platforms
Hindsight runs on **Linux**, **macOS**, and **Windows**:
| Platform | Docker | Bare Metal (pip) | Embedded DB (pg0) | Notes |
|----------|--------|------------------|--------------------|-------|
| **Linux** (x86_64, ARM64) | ✅ | ✅ | ✅ | Fully supported, recommended for production |
| **macOS** (Apple Silicon, Intel) | ✅ | ✅ | ✅ | Fully supported |
| **Windows** (x86_64) | ✅ | ✅ | ✅ | Fully supported — see [Windows setup](#windows) for external PostgreSQL option |
All platforms support the embedded database (pg0) for development. On Windows, you can also use an external PostgreSQL installation — see the [Windows](#windows) section for a step-by-step guide.
---
## Prerequisites ## Prerequisites
### PostgreSQL ### PostgreSQL
@ -207,6 +221,65 @@ PORT=80 HINDSIGHT_CP_DATAPLANE_API_URL=https://api.hindsight.io npx @vectorize-i
--- ---
## Windows
**Best for**: Running Hindsight natively on Windows without Docker
Hindsight works on Windows with the embedded database (pg0) out of the box — just install and run:
```powershell
pip install hindsight-api
set HINDSIGHT_API_LLM_PROVIDER=openai
set HINDSIGHT_API_LLM_API_KEY=sk-xxx
set HINDSIGHT_API_LLM_MODEL=gpt-4o-mini
hindsight-api
```
### Using External PostgreSQL (optional)
If you prefer to use your own PostgreSQL instance instead of the embedded database:
```powershell
# Install PostgreSQL
winget install PostgreSQL.PostgreSQL.17
# Build pgvector (requires Visual Studio Build Tools)
git clone https://github.com/pgvector/pgvector.git
cd pgvector
# Open "x64 Native Tools Command Prompt for VS" and run:
set PGROOT=C:\Program Files\PostgreSQL\17
nmake /F Makefile.win
nmake /F Makefile.win install
# Create the database and enable the vector extension
psql -U postgres -c "CREATE DATABASE hindsight;"
psql -U postgres -d hindsight -c "CREATE EXTENSION vector;"
```
Then run Hindsight pointing to your database:
```powershell
pip install hindsight-api
set HINDSIGHT_API_DATABASE_URL=postgresql://postgres@localhost:5432/hindsight
set HINDSIGHT_API_LLM_PROVIDER=openai
set HINDSIGHT_API_LLM_API_KEY=sk-xxx
set HINDSIGHT_API_LLM_MODEL=gpt-4o-mini
hindsight-api
```
- **API Server**: http://localhost:8888
:::tip
You can also use the slim package (`pip install hindsight-api-slim`) if you configure external providers for embeddings and reranking. See [Configuration](./configuration#embeddings) for details.
:::
---
## Embedded in a Python Application ## Embedded in a Python Application
**Best for**: Using Hindsight programmatically from Python without running a separate server process. **Best for**: Using Hindsight programmatically from Python without running a separate server process.

View file

@ -8265,6 +8265,17 @@
"type": { "type": {
"type": "string", "type": "string",
"title": "Error Type" "title": "Error Type"
},
"input": {
"title": "Input"
},
"ctx": {
"title": "Context",
"type": "object"
},
"url": {
"title": "URL",
"type": "string"
} }
}, },
"type": "object", "type": "object",

30
uv.lock
View file

@ -450,6 +450,7 @@ dependencies = [
{ name = "jmespath" }, { name = "jmespath" },
{ name = "s3transfer" }, { name = "s3transfer" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/74/ec/636ab2aa7ad9e6bf6e297240ac2d44dba63cc6611e2d5038db318436d449/boto3-1.42.74.tar.gz", hash = "sha256:dbacd808cf2a3dadbf35f3dbd8de97b94dc9f78b1ebd439f38f552e0f9753577", size = 112739 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/ad/16/a264b4da2af99f4a12609b93fea941cce5ec41da14b33ed3fef77a910f0c/boto3-1.42.74-py3-none-any.whl", hash = "sha256:4bf89c044d618fe4435af854ab820f09dd43569c0df15d7beb0398f50b9aa970", size = 140557 }, { url = "https://files.pythonhosted.org/packages/ad/16/a264b4da2af99f4a12609b93fea941cce5ec41da14b33ed3fef77a910f0c/boto3-1.42.74-py3-none-any.whl", hash = "sha256:4bf89c044d618fe4435af854ab820f09dd43569c0df15d7beb0398f50b9aa970", size = 140557 },
] ]
@ -1577,7 +1578,8 @@ dependencies = [
{ name = "typer" }, { name = "typer" },
{ name = "urllib3" }, { name = "urllib3" },
{ name = "uvicorn" }, { name = "uvicorn" },
{ name = "uvloop" }, { name = "uvloop", marker = "sys_platform != 'win32'" },
{ name = "winloop", marker = "sys_platform == 'win32'" },
{ name = "wsproto" }, { name = "wsproto" },
] ]
@ -1696,7 +1698,8 @@ requires-dist = [
{ name = "typer", specifier = ">=0.9.0" }, { name = "typer", specifier = ">=0.9.0" },
{ name = "urllib3", specifier = ">=2.6.3" }, { name = "urllib3", specifier = ">=2.6.3" },
{ name = "uvicorn", specifier = ">=0.38.0" }, { name = "uvicorn", specifier = ">=0.38.0" },
{ name = "uvloop", specifier = ">=0.22.1" }, { name = "uvloop", marker = "sys_platform != 'win32'", specifier = ">=0.22.1" },
{ name = "winloop", marker = "sys_platform == 'win32'", specifier = ">=0.1.0" },
{ name = "wsproto", specifier = ">=1.0.0" }, { name = "wsproto", specifier = ">=1.0.0" },
] ]
provides-extras = ["local-ml", "embedded-db", "all", "test"] provides-extras = ["local-ml", "embedded-db", "all", "test"]
@ -5740,6 +5743,29 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743 }, { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743 },
] ]
[[package]]
name = "winloop"
version = "0.6.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/0e/b9/a7c42bd95a18fc13b63002a028de0f2c3e76efbed20c6afd630c608e89b7/winloop-0.6.0.tar.gz", hash = "sha256:3fa5507c152373a508891468cc02acb0ecf96abfc08d6c296042973be3f40267", size = 2562929 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/56/aa/284717ae7fa5de7fd14b840f8f250dbad8660af6c160381984653453258b/winloop-0.6.0-cp311-cp311-win32.whl", hash = "sha256:16266bd17b819900dbde5918639b97a2a31b5d72867703eeeaedeadbe77c653d", size = 529152 },
{ url = "https://files.pythonhosted.org/packages/87/82/301bdf57d339a3ba919941ea34baeb67bdb3decd2bed79d47305f4360a32/winloop-0.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:f21a54ef2e7a5be0751ebcbec8e48be5a40ab4b1b45d67feff8a9973db3cea2a", size = 651258 },
{ url = "https://files.pythonhosted.org/packages/f8/13/7ec04542984b379f06d7dd68b35e3e94f86d7f541e40fa0e60f2130a0313/winloop-0.6.0-cp311-cp311-win_arm64.whl", hash = "sha256:45d74b9d5cc72f4ad32e4df45bd1e494d9365345112ae235d3207f0ae3af07c5", size = 534325 },
{ url = "https://files.pythonhosted.org/packages/22/c5/580a1d888df994e0b719b1f539947cd734b4d4965f03b89d4e314d06e4d1/winloop-0.6.0-cp312-cp312-win32.whl", hash = "sha256:bd254fd5cea884bed1bf5c76bc315b66ef68ba1638347ca2ba252a85ead5a91b", size = 536047 },
{ url = "https://files.pythonhosted.org/packages/a9/ed/c12383edfe619711437adbb7972a5b9199ccd99838ffe53dc592e803cb7a/winloop-0.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:d240ae761a079a0c80bf1997a240c6358189eccbc9d3742a43929290f8e29668", size = 648816 },
{ url = "https://files.pythonhosted.org/packages/46/1e/ba40e1539c9f8ad1017b63881d40f84e6e14237756323d6ab2d59f2ef628/winloop-0.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:41d2e77e74dec70a7a48f72e5fd48f78f4c64cc1ea5d754bd6a88652c72b06aa", size = 533147 },
{ url = "https://files.pythonhosted.org/packages/a0/60/9f026102aa3af68acd76f4ca29e7c720e29ac429593e6b32a90e6144fe24/winloop-0.6.0-cp313-cp313-win32.whl", hash = "sha256:8ab3d7a77c195d18241b87425d97f422e2d2f0cf7724cb43280d4cf3c799789f", size = 535896 },
{ url = "https://files.pythonhosted.org/packages/ab/21/5d296171f7b3944d004449f622b3d7fc679f5ebf5917d895de51f2d40cec/winloop-0.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:1b92ce03f762117931c18aa281c5c089c88069d9e01edbd2e5039d4926238b7a", size = 648424 },
{ url = "https://files.pythonhosted.org/packages/10/ab/6544b5c30f26d8665bf53be731bb4ba2e54107a991aab33e502d02d17e4f/winloop-0.6.0-cp313-cp313-win_arm64.whl", hash = "sha256:4b03a749f42291e581fca6c3a8eeafe6c2125ca3bff166eb1f78370b2caa5d79", size = 532346 },
{ url = "https://files.pythonhosted.org/packages/10/55/50467648f6d79dc4641c105134981a2f0f012628c0ac0ef3118fe4220cf4/winloop-0.6.0-cp314-cp314-win32.whl", hash = "sha256:9539da7d2bdb82176e0d89a96f5c0c40f05cabfaee240eb6bc4a160642fb5c18", size = 542595 },
{ url = "https://files.pythonhosted.org/packages/6f/39/1d12dd2127b9bad40e925b4eae1aedd292f4ece37628c09afab0e9ae2e38/winloop-0.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:7e9a8b992b207330158f7866e72111d8cee293d0d7b68faee6df4dec6c3922b9", size = 659338 },
{ url = "https://files.pythonhosted.org/packages/a5/4a/0e24a2a7fbf1a92b02c8b2872683ab504fb987881a811cff9a6cdc175db0/winloop-0.6.0-cp314-cp314-win_arm64.whl", hash = "sha256:08df8649fdfe25a48f96fe0d9d1f92b2ce27a2cd9c5bc761284de3626fb77575", size = 550915 },
{ url = "https://files.pythonhosted.org/packages/e6/27/556353390e8ee4fb75f4bb46b8e711b3d6bc091ecc07a9ddabe0bfef6e59/winloop-0.6.0-cp314-cp314t-win32.whl", hash = "sha256:3cf4bed145e8baa5bca865849e4d8b0745bb02da00afb52070d69436906f3794", size = 649712 },
{ url = "https://files.pythonhosted.org/packages/ef/4e/a930cb590bdc7fe9e02e9c5ad5b0a15c9fb3a25cf007a96e6116534fdcbc/winloop-0.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f7d0bf2a83a87a8160c03fe65b3348f59b76f617d3771fbaee44923d5aa2b536", size = 808605 },
{ url = "https://files.pythonhosted.org/packages/e3/03/37f308e32395342b3d9409fff5dddb62f4a80089bbc869261ac54bcddc3d/winloop-0.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:8035b4ad56fa4c49c7aa09f458eb1a53bf61e98cd97c3b6e381ffb1e8f007d83", size = 580005 },
]
[[package]] [[package]]
name = "wrapt" name = "wrapt"
version = "1.17.3" version = "1.17.3"