* ci: add Go client integration tests Add test-go-client job to CI workflow following the same pattern as Python, TypeScript, and Rust client tests. The job: - Sets up Go 1.23 with dependency caching - Starts the Hindsight API server - Runs integration tests using the 'integration' build tag - Displays server logs on failure The integration tests (hindsight-clients/go/integration_test.go) cover all core operations: retain, recall, reflect, bank management, and end-to-end workflows. * Move Go cookbook content to hindsight-cookbook repo Removes Go-specific cookbook content that was added in PR #375: - applications/go-memory-service.md - recipes/go-quickstart.md - recipes/go-concurrent-pipeline.md These have been moved to the hindsight-cookbook repository where cookbook content should live per project conventions. * feat(go): add CI test for Go client and patch for ogen null handling - Add test-go-client job to GitHub Actions CI workflow - Create post-generation patch script (patch-ogen.sh) to fix ogen's handling of null values in optional string fields - Patch OptString.Decode() to check jx.Next() type before decoding, properly handling explicit null in JSON responses The patch ensures generated code persists across regenerations and handles the Hindsight API's nullable optional fields correctly. Fixes: Go client integration tests for retain and bank operations Note: Some tests still fail for nullable arrays/objects - those require additional patches for other Opt* types. * feat: use official go generator for Go client * feat: use official go generator for Go client * ci fixes * chore: sync Go client with latest OpenAPI spec - Add model_child_operation_status.go (new model) - Update model_operation_status_response.go with child operations - Update go.mod/go.sum dependencies - Update api/openapi.yaml
1220 lines
No EOL
35 KiB
YAML
1220 lines
No EOL
35 KiB
YAML
name: CI
|
|
|
|
on:
|
|
pull_request:
|
|
branches: [ main ]
|
|
|
|
concurrency:
|
|
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
build-api-python-versions:
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
matrix:
|
|
python-version: ['3.11', '3.12', '3.13', '3.14']
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v5
|
|
with:
|
|
enable-cache: true
|
|
|
|
- name: Set up Python ${{ matrix.python-version }}
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ matrix.python-version }}
|
|
|
|
- name: Build hindsight-api
|
|
working-directory: ./hindsight-api
|
|
run: uv build
|
|
|
|
build-typescript-client:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
cache: 'npm'
|
|
cache-dependency-path: package-lock.json
|
|
|
|
- name: Install dependencies
|
|
run: npm ci --workspace=hindsight-clients/typescript
|
|
|
|
- name: Build TypeScript client
|
|
run: npm run build --workspace=hindsight-clients/typescript
|
|
|
|
build-openclaw-integration:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '22'
|
|
|
|
- name: Install dependencies
|
|
working-directory: ./hindsight-integrations/openclaw
|
|
run: npm ci
|
|
|
|
- name: Run tests
|
|
working-directory: ./hindsight-integrations/openclaw
|
|
run: npm test
|
|
|
|
- name: Build
|
|
working-directory: ./hindsight-integrations/openclaw
|
|
run: npm run build
|
|
|
|
build-ai-sdk-integration:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '22'
|
|
|
|
- name: Install dependencies
|
|
working-directory: ./hindsight-integrations/ai-sdk
|
|
run: npm ci
|
|
|
|
- name: Run tests
|
|
working-directory: ./hindsight-integrations/ai-sdk
|
|
run: npm test
|
|
|
|
- name: Build
|
|
working-directory: ./hindsight-integrations/ai-sdk
|
|
run: npm run build
|
|
|
|
build-control-plane:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
cache: 'npm'
|
|
cache-dependency-path: package-lock.json
|
|
|
|
- name: Install SDK dependencies
|
|
run: npm ci --workspace=hindsight-clients/typescript
|
|
|
|
- name: Build SDK
|
|
run: npm run build --workspace=hindsight-clients/typescript
|
|
|
|
# Install control plane deps and fix hoisted lightningcss binary
|
|
# lightningcss gets hoisted to root node_modules, so we need to reinstall it there
|
|
- name: Install Control Plane dependencies
|
|
run: |
|
|
npm install --workspace=hindsight-control-plane
|
|
rm -rf node_modules/lightningcss node_modules/@tailwindcss
|
|
npm install lightningcss @tailwindcss/postcss @tailwindcss/node
|
|
|
|
- name: Build Control Plane
|
|
run: npm run build --workspace=hindsight-control-plane
|
|
|
|
- name: Verify standalone build
|
|
run: |
|
|
test -f hindsight-control-plane/standalone/server.js || exit 1
|
|
test -d hindsight-control-plane/standalone/node_modules || exit 1
|
|
node hindsight-control-plane/bin/cli.js --help
|
|
|
|
- name: Smoke test - verify server starts
|
|
run: |
|
|
cd hindsight-control-plane
|
|
node bin/cli.js --port 9999 &
|
|
SERVER_PID=$!
|
|
sleep 5
|
|
if curl -sf http://localhost:9999 > /dev/null 2>&1; then
|
|
echo "Server started successfully"
|
|
kill $SERVER_PID 2>/dev/null || true
|
|
exit 0
|
|
else
|
|
echo "Server failed to respond"
|
|
kill $SERVER_PID 2>/dev/null || true
|
|
exit 1
|
|
fi
|
|
|
|
build-docs:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
cache: 'npm'
|
|
cache-dependency-path: package-lock.json
|
|
|
|
- name: Install dependencies
|
|
run: npm ci --workspace=hindsight-docs
|
|
|
|
- name: Build docs
|
|
run: npm run build --workspace=hindsight-docs
|
|
|
|
test-rust-cli:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
HINDSIGHT_API_LLM_PROVIDER: groq
|
|
HINDSIGHT_API_LLM_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL: openai/gpt-oss-20b
|
|
HINDSIGHT_API_URL: http://localhost:8888
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
UV_INDEX: pytorch=https://download.pytorch.org/whl/cpu
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install Rust
|
|
uses: dtolnay/rust-toolchain@stable
|
|
|
|
- name: Cache cargo
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/.cargo/registry
|
|
~/.cargo/git
|
|
hindsight-cli/target
|
|
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
|
|
|
- name: Run unit tests
|
|
working-directory: hindsight-cli
|
|
run: cargo test
|
|
|
|
- name: Build CLI
|
|
working-directory: hindsight-cli
|
|
run: cargo build --release
|
|
|
|
- name: Upload CLI artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: hindsight-cli
|
|
path: hindsight-cli/target/release/hindsight
|
|
retention-days: 1
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v5
|
|
with:
|
|
enable-cache: true
|
|
prune-cache: false
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version-file: ".python-version"
|
|
|
|
- name: Build API
|
|
working-directory: ./hindsight-api
|
|
run: uv build
|
|
|
|
- name: Install API dependencies
|
|
working-directory: ./hindsight-api
|
|
run: uv sync --frozen --no-install-project --index-strategy unsafe-best-match
|
|
|
|
- name: Create .env file
|
|
run: |
|
|
cat > .env << EOF
|
|
HINDSIGHT_API_LLM_PROVIDER=${{ env.HINDSIGHT_API_LLM_PROVIDER }}
|
|
HINDSIGHT_API_LLM_API_KEY=${{ env.HINDSIGHT_API_LLM_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL=${{ env.HINDSIGHT_API_LLM_MODEL }}
|
|
EOF
|
|
|
|
- name: Start API server
|
|
run: |
|
|
./scripts/dev/start-api.sh > /tmp/api-server.log 2>&1 &
|
|
echo "Waiting for API server to be ready..."
|
|
for i in {1..60}; do
|
|
if curl -sf http://localhost:8888/health > /dev/null 2>&1; then
|
|
echo "API server is ready after ${i}s"
|
|
break
|
|
fi
|
|
if [ $i -eq 60 ]; then
|
|
echo "API server failed to start after 60s"
|
|
cat /tmp/api-server.log
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
- name: Run CLI smoke test
|
|
run: |
|
|
HINDSIGHT_CLI=hindsight-cli/target/release/hindsight ./hindsight-cli/smoke-test.sh
|
|
|
|
- name: Show API server logs
|
|
if: always()
|
|
run: |
|
|
echo "=== API Server Logs ==="
|
|
cat /tmp/api-server.log || echo "No API server log found"
|
|
|
|
lint-helm-chart:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install Helm
|
|
uses: azure/setup-helm@v4
|
|
with:
|
|
version: 'latest'
|
|
|
|
- name: Lint Helm chart
|
|
run: helm lint helm/hindsight
|
|
|
|
build-docker-images:
|
|
name: Build Docker (${{ matrix.name }})
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
matrix:
|
|
include:
|
|
- target: api-only
|
|
name: api
|
|
variant: full
|
|
build_args: ""
|
|
- target: api-only
|
|
name: api-slim
|
|
variant: slim
|
|
build_args: |
|
|
INCLUDE_LOCAL_MODELS=false
|
|
PRELOAD_ML_MODELS=false
|
|
- target: cp-only
|
|
name: control-plane
|
|
variant: full
|
|
build_args: ""
|
|
- target: standalone
|
|
name: standalone
|
|
variant: full
|
|
build_args: ""
|
|
- target: standalone
|
|
name: standalone-slim
|
|
variant: slim
|
|
build_args: |
|
|
INCLUDE_LOCAL_MODELS=false
|
|
PRELOAD_ML_MODELS=false
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Free Disk Space
|
|
uses: jlumbroso/free-disk-space@main
|
|
with:
|
|
tool-cache: true
|
|
android: true
|
|
dotnet: true
|
|
haskell: true
|
|
large-packages: true
|
|
docker-images: true
|
|
swap-storage: true
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Build ${{ matrix.name }} image (${{ matrix.variant }})
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
file: docker/standalone/Dockerfile
|
|
target: ${{ matrix.target }}
|
|
build-args: ${{ matrix.build_args }}
|
|
push: false
|
|
load: ${{ matrix.variant == 'slim' }}
|
|
tags: hindsight-${{ matrix.name }}:test
|
|
# Removed GitHub Actions cache (type=gha) - it frequently returns 502 errors
|
|
# causing buildx to fail with "failed to parse error response 502"
|
|
# Build will be slower but more reliable
|
|
|
|
# Only test slim variants to save disk space (they're much smaller)
|
|
# Slim variants require external embedding providers
|
|
- name: Smoke test - verify container starts
|
|
if: matrix.variant == 'slim'
|
|
env:
|
|
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
HINDSIGHT_API_EMBEDDINGS_PROVIDER: openai
|
|
HINDSIGHT_API_EMBEDDINGS_OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
HINDSIGHT_API_RERANKER_PROVIDER: cohere
|
|
HINDSIGHT_API_COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
|
|
run: ./docker/test-image.sh "hindsight-${{ matrix.name }}:test" "${{ matrix.target }}"
|
|
|
|
test-api:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
HINDSIGHT_API_LLM_PROVIDER: groq
|
|
HINDSIGHT_API_LLM_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
|
|
HINDSIGHT_API_EMBEDDINGS_OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL: openai/gpt-oss-20b
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
# Prefer CPU-only PyTorch in CI (but keep PyPI for everything else)
|
|
UV_INDEX: pytorch=https://download.pytorch.org/whl/cpu
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v5
|
|
with:
|
|
enable-cache: true
|
|
prune-cache: false
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version-file: ".python-version"
|
|
|
|
- name: Build API
|
|
working-directory: ./hindsight-api
|
|
run: uv build
|
|
|
|
- name: Install dependencies
|
|
working-directory: ./hindsight-api
|
|
run: uv sync --frozen --extra test --no-install-project --index-strategy unsafe-best-match
|
|
|
|
- name: Cache HuggingFace models
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ~/.cache/huggingface
|
|
key: ${{ runner.os }}-huggingface-${{ hashFiles('hindsight-api/pyproject.toml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-huggingface-
|
|
|
|
- name: Pre-download models
|
|
working-directory: ./hindsight-api
|
|
run: |
|
|
uv run python -c "
|
|
from sentence_transformers import SentenceTransformer, CrossEncoder
|
|
print('Downloading embedding model...')
|
|
SentenceTransformer('BAAI/bge-small-en-v1.5')
|
|
print('Downloading cross-encoder model...')
|
|
CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
|
|
print('Models downloaded successfully')
|
|
"
|
|
|
|
- name: Run tests
|
|
working-directory: ./hindsight-api
|
|
run: uv run pytest tests -v
|
|
|
|
test-python-client:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
HINDSIGHT_API_LLM_PROVIDER: groq
|
|
HINDSIGHT_API_LLM_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL: openai/gpt-oss-20b
|
|
HINDSIGHT_API_URL: http://localhost:8888
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
# Prefer CPU-only PyTorch in CI (but keep PyPI for everything else)
|
|
UV_INDEX: pytorch=https://download.pytorch.org/whl/cpu
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v5
|
|
with:
|
|
enable-cache: true
|
|
prune-cache: false
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version-file: ".python-version"
|
|
|
|
- name: Build API
|
|
working-directory: ./hindsight-api
|
|
run: uv build
|
|
|
|
- name: Build Python client
|
|
working-directory: ./hindsight-clients/python
|
|
run: uv build
|
|
|
|
- name: Install client test dependencies
|
|
working-directory: ./hindsight-clients/python
|
|
run: uv sync --frozen --extra test --index-strategy unsafe-best-match
|
|
|
|
- name: Install API dependencies
|
|
working-directory: ./hindsight-api
|
|
run: uv sync --frozen --no-install-project --index-strategy unsafe-best-match
|
|
|
|
- name: Create .env file
|
|
run: |
|
|
cat > .env << EOF
|
|
HINDSIGHT_API_LLM_PROVIDER=${{ env.HINDSIGHT_API_LLM_PROVIDER }}
|
|
HINDSIGHT_API_LLM_API_KEY=${{ env.HINDSIGHT_API_LLM_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL=${{ env.HINDSIGHT_API_LLM_MODEL }}
|
|
EOF
|
|
|
|
- name: Start API server
|
|
run: |
|
|
./scripts/dev/start-api.sh > /tmp/api-server.log 2>&1 &
|
|
echo "Waiting for API server to be ready..."
|
|
for i in {1..60}; do
|
|
if curl -sf http://localhost:8888/health > /dev/null 2>&1; then
|
|
echo "API server is ready after ${i}s"
|
|
break
|
|
fi
|
|
if [ $i -eq 60 ]; then
|
|
echo "API server failed to start after 60s"
|
|
cat /tmp/api-server.log
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
- name: Run Python client tests
|
|
working-directory: ./hindsight-clients/python
|
|
run: uv run pytest tests -v
|
|
|
|
- name: Show API server logs
|
|
if: always()
|
|
run: |
|
|
echo "=== API Server Logs ==="
|
|
cat /tmp/api-server.log || echo "No API server log found"
|
|
|
|
test-typescript-client:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
HINDSIGHT_API_LLM_PROVIDER: groq
|
|
HINDSIGHT_API_LLM_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL: openai/gpt-oss-20b
|
|
HINDSIGHT_API_URL: http://localhost:8888
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
# Prefer CPU-only PyTorch in CI (but keep PyPI for everything else)
|
|
UV_INDEX: pytorch=https://download.pytorch.org/whl/cpu
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v5
|
|
with:
|
|
enable-cache: true
|
|
prune-cache: false
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version-file: ".python-version"
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
|
|
- name: Build API
|
|
working-directory: ./hindsight-api
|
|
run: uv build
|
|
|
|
- name: Install API dependencies
|
|
working-directory: ./hindsight-api
|
|
run: uv sync --frozen --no-install-project --index-strategy unsafe-best-match
|
|
|
|
- name: Install TypeScript client dependencies
|
|
working-directory: ./hindsight-clients/typescript
|
|
run: npm ci
|
|
|
|
- name: Build TypeScript client
|
|
working-directory: ./hindsight-clients/typescript
|
|
run: npm run build
|
|
|
|
- name: Create .env file
|
|
run: |
|
|
cat > .env << EOF
|
|
HINDSIGHT_API_LLM_PROVIDER=${{ env.HINDSIGHT_API_LLM_PROVIDER }}
|
|
HINDSIGHT_API_LLM_API_KEY=${{ env.HINDSIGHT_API_LLM_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL=${{ env.HINDSIGHT_API_LLM_MODEL }}
|
|
EOF
|
|
|
|
- name: Start API server
|
|
run: |
|
|
./scripts/dev/start-api.sh > /tmp/api-server.log 2>&1 &
|
|
echo "Waiting for API server to be ready..."
|
|
for i in {1..60}; do
|
|
if curl -sf http://localhost:8888/health > /dev/null 2>&1; then
|
|
echo "API server is ready after ${i}s"
|
|
break
|
|
fi
|
|
if [ $i -eq 60 ]; then
|
|
echo "API server failed to start after 60s"
|
|
cat /tmp/api-server.log
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
- name: Run TypeScript client tests
|
|
working-directory: ./hindsight-clients/typescript
|
|
run: npm test
|
|
|
|
- name: Show API server logs
|
|
if: always()
|
|
run: |
|
|
echo "=== API Server Logs ==="
|
|
cat /tmp/api-server.log || echo "No API server log found"
|
|
|
|
test-rust-client:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
HINDSIGHT_API_LLM_PROVIDER: groq
|
|
HINDSIGHT_API_LLM_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL: openai/gpt-oss-20b
|
|
HINDSIGHT_API_URL: http://localhost:8888
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
# Prefer CPU-only PyTorch in CI (but keep PyPI for everything else)
|
|
UV_INDEX: pytorch=https://download.pytorch.org/whl/cpu
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v5
|
|
with:
|
|
enable-cache: true
|
|
prune-cache: false
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version-file: ".python-version"
|
|
|
|
- name: Install Rust
|
|
uses: dtolnay/rust-toolchain@stable
|
|
|
|
- name: Cache cargo
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/.cargo/registry
|
|
~/.cargo/git
|
|
hindsight-clients/rust/target
|
|
key: ${{ runner.os }}-cargo-client-${{ hashFiles('hindsight-clients/rust/Cargo.lock') }}
|
|
|
|
- name: Build API
|
|
working-directory: ./hindsight-api
|
|
run: uv build
|
|
|
|
- name: Install API dependencies
|
|
working-directory: ./hindsight-api
|
|
run: uv sync --frozen --no-install-project --index-strategy unsafe-best-match
|
|
|
|
- name: Create .env file
|
|
run: |
|
|
cat > .env << EOF
|
|
HINDSIGHT_API_LLM_PROVIDER=${{ env.HINDSIGHT_API_LLM_PROVIDER }}
|
|
HINDSIGHT_API_LLM_API_KEY=${{ env.HINDSIGHT_API_LLM_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL=${{ env.HINDSIGHT_API_LLM_MODEL }}
|
|
EOF
|
|
|
|
- name: Start API server
|
|
run: |
|
|
./scripts/dev/start-api.sh > /tmp/api-server.log 2>&1 &
|
|
echo "Waiting for API server to be ready..."
|
|
for i in {1..60}; do
|
|
if curl -sf http://localhost:8888/health > /dev/null 2>&1; then
|
|
echo "API server is ready after ${i}s"
|
|
break
|
|
fi
|
|
if [ $i -eq 60 ]; then
|
|
echo "API server failed to start after 60s"
|
|
cat /tmp/api-server.log
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
- name: Run Rust client tests
|
|
working-directory: ./hindsight-clients/rust
|
|
run: cargo test --lib
|
|
|
|
- name: Show API server logs
|
|
if: always()
|
|
run: |
|
|
echo "=== API Server Logs ==="
|
|
cat /tmp/api-server.log || echo "No API server log found"
|
|
|
|
test-go-client:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
HINDSIGHT_API_LLM_PROVIDER: groq
|
|
HINDSIGHT_API_LLM_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL: openai/gpt-oss-20b
|
|
HINDSIGHT_API_URL: http://localhost:8888
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
# Prefer CPU-only PyTorch in CI (but keep PyPI for everything else)
|
|
UV_INDEX: pytorch=https://download.pytorch.org/whl/cpu
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v5
|
|
with:
|
|
enable-cache: true
|
|
prune-cache: false
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version-file: ".python-version"
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@v5
|
|
with:
|
|
go-version: '1.23'
|
|
cache-dependency-path: hindsight-clients/go/go.sum
|
|
|
|
- name: Build API
|
|
working-directory: ./hindsight-api
|
|
run: uv build
|
|
|
|
- name: Install API dependencies
|
|
working-directory: ./hindsight-api
|
|
run: uv sync --frozen --no-install-project --index-strategy unsafe-best-match
|
|
|
|
- name: Create .env file
|
|
run: |
|
|
cat > .env << EOF
|
|
HINDSIGHT_API_LLM_PROVIDER=${{ env.HINDSIGHT_API_LLM_PROVIDER }}
|
|
HINDSIGHT_API_LLM_API_KEY=${{ env.HINDSIGHT_API_LLM_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL=${{ env.HINDSIGHT_API_LLM_MODEL }}
|
|
EOF
|
|
|
|
- name: Start API server
|
|
run: |
|
|
./scripts/dev/start-api.sh > /tmp/api-server.log 2>&1 &
|
|
echo "Waiting for API server to be ready..."
|
|
for i in {1..60}; do
|
|
if curl -sf http://localhost:8888/health > /dev/null 2>&1; then
|
|
echo "API server is ready after ${i}s"
|
|
break
|
|
fi
|
|
if [ $i -eq 60 ]; then
|
|
echo "API server failed to start after 60s"
|
|
cat /tmp/api-server.log
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
- name: Run Go client tests
|
|
working-directory: ./hindsight-clients/go
|
|
run: go test -v -tags=integration
|
|
|
|
- name: Show API server logs
|
|
if: always()
|
|
run: |
|
|
echo "=== API Server Logs ==="
|
|
cat /tmp/api-server.log || echo "No API server log found"
|
|
|
|
test-integration:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
HINDSIGHT_API_LLM_PROVIDER: groq
|
|
HINDSIGHT_API_LLM_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL: openai/gpt-oss-20b
|
|
HINDSIGHT_API_URL: http://localhost:8888
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
UV_INDEX: pytorch=https://download.pytorch.org/whl/cpu
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v5
|
|
with:
|
|
enable-cache: true
|
|
prune-cache: false
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version-file: ".python-version"
|
|
|
|
- name: Build API
|
|
working-directory: ./hindsight-api
|
|
run: uv build
|
|
|
|
- name: Install API dependencies
|
|
working-directory: ./hindsight-api
|
|
run: uv sync --frozen --no-install-project --index-strategy unsafe-best-match
|
|
|
|
- name: Install integration test dependencies
|
|
working-directory: ./hindsight-integration-tests
|
|
run: uv sync --frozen
|
|
|
|
- name: Cache HuggingFace models
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ~/.cache/huggingface
|
|
key: ${{ runner.os }}-huggingface-${{ hashFiles('hindsight-api/pyproject.toml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-huggingface-
|
|
|
|
- name: Pre-download models
|
|
working-directory: ./hindsight-api
|
|
run: |
|
|
uv run python -c "
|
|
from sentence_transformers import SentenceTransformer, CrossEncoder
|
|
print('Downloading embedding model...')
|
|
SentenceTransformer('BAAI/bge-small-en-v1.5')
|
|
print('Downloading cross-encoder model...')
|
|
CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
|
|
print('Models downloaded successfully')
|
|
"
|
|
|
|
- name: Create .env file
|
|
run: |
|
|
cat > .env << EOF
|
|
HINDSIGHT_API_LLM_PROVIDER=${{ env.HINDSIGHT_API_LLM_PROVIDER }}
|
|
HINDSIGHT_API_LLM_API_KEY=${{ env.HINDSIGHT_API_LLM_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL=${{ env.HINDSIGHT_API_LLM_MODEL }}
|
|
EOF
|
|
|
|
- name: Start API server
|
|
run: |
|
|
./scripts/dev/start-api.sh > /tmp/api-server.log 2>&1 &
|
|
echo "Waiting for API server to be ready..."
|
|
for i in {1..60}; do
|
|
if curl -sf http://localhost:8888/health > /dev/null 2>&1; then
|
|
echo "API server is ready after ${i}s"
|
|
break
|
|
fi
|
|
if [ $i -eq 60 ]; then
|
|
echo "API server failed to start after 60s"
|
|
cat /tmp/api-server.log
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
- name: Run integration tests
|
|
working-directory: ./hindsight-integration-tests
|
|
run: uv run pytest tests/ -v
|
|
|
|
- name: Show API server logs
|
|
if: always()
|
|
run: |
|
|
echo "=== API Server Logs ==="
|
|
cat /tmp/api-server.log || echo "No API server log found"
|
|
|
|
test-litellm-integration:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v5
|
|
with:
|
|
enable-cache: true
|
|
prune-cache: false
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version-file: ".python-version"
|
|
|
|
- name: Build litellm integration
|
|
working-directory: ./hindsight-integrations/litellm
|
|
run: uv build
|
|
|
|
- name: Install dependencies
|
|
working-directory: ./hindsight-integrations/litellm
|
|
run: uv sync --frozen --extra dev
|
|
|
|
- name: Run tests
|
|
working-directory: ./hindsight-integrations/litellm
|
|
run: uv run pytest tests -v
|
|
|
|
test-embed:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
HINDSIGHT_API_LLM_PROVIDER: groq
|
|
HINDSIGHT_API_LLM_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL: openai/gpt-oss-20b
|
|
# Prefer CPU-only PyTorch in CI
|
|
UV_INDEX: pytorch=https://download.pytorch.org/whl/cpu
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v5
|
|
with:
|
|
enable-cache: true
|
|
prune-cache: false
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version-file: ".python-version"
|
|
|
|
- name: Install dependencies
|
|
working-directory: ./hindsight-embed
|
|
run: uv sync --frozen --index-strategy unsafe-best-match
|
|
|
|
- name: Cache HuggingFace models
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ~/.cache/huggingface
|
|
key: ${{ runner.os }}-huggingface-embed-${{ hashFiles('hindsight-embed/pyproject.toml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-huggingface-embed-
|
|
${{ runner.os }}-huggingface-
|
|
|
|
- name: Run unit and integration tests
|
|
working-directory: ./hindsight-embed
|
|
run: uv run pytest tests/ -v
|
|
|
|
- name: Run smoke test
|
|
working-directory: ./hindsight-embed
|
|
run: ./test.sh
|
|
|
|
test-hindsight-all:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
HINDSIGHT_API_LLM_PROVIDER: groq
|
|
HINDSIGHT_API_LLM_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL: openai/gpt-oss-20b
|
|
# For test_server_integration.py compatibility
|
|
HINDSIGHT_LLM_PROVIDER: groq
|
|
HINDSIGHT_LLM_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
HINDSIGHT_LLM_MODEL: openai/gpt-oss-20b
|
|
# Prefer CPU-only PyTorch in CI
|
|
UV_INDEX: pytorch=https://download.pytorch.org/whl/cpu
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v5
|
|
with:
|
|
enable-cache: true
|
|
prune-cache: false
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version-file: ".python-version"
|
|
|
|
- name: Build hindsight-all
|
|
working-directory: ./hindsight
|
|
run: uv build
|
|
|
|
- name: Install dependencies
|
|
working-directory: ./hindsight
|
|
run: uv sync --frozen --extra test --index-strategy unsafe-best-match
|
|
|
|
- name: Cache HuggingFace models
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ~/.cache/huggingface
|
|
key: ${{ runner.os }}-huggingface-all-${{ hashFiles('hindsight/pyproject.toml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-huggingface-all-
|
|
${{ runner.os }}-huggingface-
|
|
|
|
- name: Run unit tests
|
|
working-directory: ./hindsight
|
|
run: uv run pytest tests/ -v
|
|
|
|
test-doc-examples:
|
|
runs-on: ubuntu-latest
|
|
needs: test-rust-cli
|
|
env:
|
|
HINDSIGHT_API_LLM_PROVIDER: groq
|
|
HINDSIGHT_API_LLM_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL: openai/gpt-oss-20b
|
|
HINDSIGHT_API_URL: http://localhost:8888
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
UV_INDEX: pytorch=https://download.pytorch.org/whl/cpu
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Download CLI artifact
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: hindsight-cli
|
|
path: /usr/local/bin
|
|
|
|
- name: Make CLI executable
|
|
run: chmod +x /usr/local/bin/hindsight
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v5
|
|
with:
|
|
enable-cache: true
|
|
prune-cache: false
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version-file: ".python-version"
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
cache: 'npm'
|
|
cache-dependency-path: package-lock.json
|
|
|
|
- name: Build and install API
|
|
working-directory: ./hindsight-api
|
|
run: |
|
|
uv build
|
|
uv sync --frozen --no-install-project --index-strategy unsafe-best-match
|
|
|
|
- name: Install Python client dependencies
|
|
working-directory: ./hindsight-clients/python
|
|
run: uv sync --frozen --extra test --index-strategy unsafe-best-match
|
|
|
|
- name: Install TypeScript client
|
|
run: |
|
|
npm ci --workspace=hindsight-clients/typescript
|
|
npm run build --workspace=hindsight-clients/typescript
|
|
|
|
- name: Create .env file
|
|
run: |
|
|
cat > .env << EOF
|
|
HINDSIGHT_API_LLM_PROVIDER=${{ env.HINDSIGHT_API_LLM_PROVIDER }}
|
|
HINDSIGHT_API_LLM_API_KEY=${{ env.HINDSIGHT_API_LLM_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL=${{ env.HINDSIGHT_API_LLM_MODEL }}
|
|
EOF
|
|
|
|
- name: Start API server
|
|
run: |
|
|
./scripts/dev/start-api.sh > /tmp/api-server.log 2>&1 &
|
|
echo "Waiting for API server to be ready..."
|
|
for i in {1..60}; do
|
|
if curl -sf http://localhost:8888/health > /dev/null 2>&1; then
|
|
echo "API server is ready after ${i}s"
|
|
break
|
|
fi
|
|
if [ $i -eq 60 ]; then
|
|
echo "API server failed to start after 60s"
|
|
cat /tmp/api-server.log
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
- name: Configure CLI
|
|
run: hindsight configure --api-url http://localhost:8888
|
|
|
|
- name: Run all doc examples
|
|
run: ./scripts/test-doc-examples.sh
|
|
|
|
- name: Show API server logs
|
|
if: always()
|
|
run: |
|
|
echo "=== API Server Logs ==="
|
|
cat /tmp/api-server.log || echo "No API server log found"
|
|
|
|
test-upgrade:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
HINDSIGHT_API_LLM_PROVIDER: groq
|
|
HINDSIGHT_API_LLM_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
HINDSIGHT_API_LLM_MODEL: openai/gpt-oss-20b
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
UV_INDEX: pytorch=https://download.pytorch.org/whl/cpu
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0 # Full history needed for git clone of tags
|
|
|
|
- name: Fetch tags
|
|
run: git fetch --tags
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v5
|
|
with:
|
|
enable-cache: true
|
|
prune-cache: false
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version-file: ".python-version"
|
|
|
|
- name: Cache HuggingFace models
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ~/.cache/huggingface
|
|
key: ${{ runner.os }}-huggingface-${{ hashFiles('hindsight-api/pyproject.toml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-huggingface-
|
|
|
|
- name: Install hindsight-dev dependencies
|
|
working-directory: ./hindsight-dev
|
|
run: uv sync --frozen --extra test --index-strategy unsafe-best-match
|
|
|
|
- name: Install current hindsight-api
|
|
working-directory: ./hindsight-api
|
|
run: uv sync --frozen --index-strategy unsafe-best-match
|
|
|
|
- name: Pre-download models
|
|
working-directory: ./hindsight-api
|
|
run: |
|
|
uv run python -c "
|
|
from sentence_transformers import SentenceTransformer, CrossEncoder
|
|
print('Downloading embedding model...')
|
|
SentenceTransformer('BAAI/bge-small-en-v1.5')
|
|
print('Downloading cross-encoder model...')
|
|
CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
|
|
print('Models downloaded successfully')
|
|
"
|
|
|
|
- name: Run upgrade tests
|
|
working-directory: ./hindsight-dev
|
|
run: uv run pytest upgrade_tests/ -v --tb=short
|
|
|
|
- name: Show upgrade test logs
|
|
if: always()
|
|
run: |
|
|
echo "=== Upgrade Test Server Logs ==="
|
|
for log in /tmp/upgrade-test-*.log; do
|
|
if [ -f "$log" ]; then
|
|
echo ""
|
|
echo "--- $log ---"
|
|
tail -500 "$log"
|
|
fi
|
|
done
|
|
|
|
verify-generated-files:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
UV_INDEX: pytorch=https://download.pytorch.org/whl/cpu
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v5
|
|
with:
|
|
enable-cache: true
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version-file: ".python-version"
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
cache: 'npm'
|
|
cache-dependency-path: package-lock.json
|
|
|
|
- name: Install Rust
|
|
uses: dtolnay/rust-toolchain@stable
|
|
|
|
- name: Cache cargo
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/.cargo/registry
|
|
~/.cargo/git
|
|
key: ${{ runner.os }}-cargo-gen-${{ hashFiles('**/Cargo.lock') }}
|
|
|
|
- name: Install Node dependencies
|
|
run: npm ci
|
|
|
|
- name: Install Python dependencies
|
|
run: |
|
|
cd hindsight-dev && uv sync --frozen --index-strategy unsafe-best-match
|
|
cd ../hindsight-api && uv sync --frozen --index-strategy unsafe-best-match
|
|
cd ../hindsight-embed && uv sync --frozen --index-strategy unsafe-best-match
|
|
|
|
- name: Run generate-openapi
|
|
run: ./scripts/generate-openapi.sh
|
|
|
|
- name: Run generate-clients
|
|
run: ./scripts/generate-clients.sh
|
|
|
|
- name: Run lint
|
|
run: ./scripts/hooks/lint.sh
|
|
|
|
- name: Verify no uncommitted changes
|
|
run: |
|
|
if [ -n "$(git status --porcelain)" ]; then
|
|
echo "❌ Error: Generated files are out of sync with committed files."
|
|
echo ""
|
|
echo "The following files have changed after running generation scripts:"
|
|
git status --porcelain
|
|
echo ""
|
|
echo "Please run the following commands locally and commit the changes:"
|
|
echo " ./scripts/generate-openapi.sh"
|
|
echo " ./scripts/generate-clients.sh"
|
|
echo " ./scripts/hooks/lint.sh"
|
|
echo ""
|
|
git diff --stat
|
|
exit 1
|
|
fi
|
|
echo "✓ All generated files are up to date"
|
|
|
|
check-openapi-compatibility:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
UV_INDEX: pytorch=https://download.pytorch.org/whl/cpu
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0 # Fetch full git history to access base branch
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v5
|
|
with:
|
|
enable-cache: true
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version-file: ".python-version"
|
|
|
|
- name: Install hindsight-dev dependencies
|
|
run: |
|
|
cd hindsight-dev && uv sync --frozen --index-strategy unsafe-best-match
|
|
|
|
- name: Check OpenAPI compatibility with base branch
|
|
run: |
|
|
# Get the base branch (usually main)
|
|
BASE_BRANCH="${{ github.base_ref }}"
|
|
|
|
if [ -z "$BASE_BRANCH" ]; then
|
|
echo "⚠️ Warning: No base branch found (not a PR?). Skipping compatibility check."
|
|
exit 0
|
|
fi
|
|
|
|
echo "Checking OpenAPI compatibility against base branch: $BASE_BRANCH"
|
|
|
|
# Extract the old OpenAPI spec from base branch
|
|
git show "origin/$BASE_BRANCH:hindsight-docs/static/openapi.json" > /tmp/old-openapi.json
|
|
|
|
if [ ! -s /tmp/old-openapi.json ]; then
|
|
echo "⚠️ Warning: Could not find OpenAPI spec in base branch. Skipping compatibility check."
|
|
exit 0
|
|
fi
|
|
|
|
# Check compatibility using our tool
|
|
cd hindsight-dev
|
|
uv run check-openapi-compatibility /tmp/old-openapi.json ../hindsight-docs/static/openapi.json |