567-labs/instructor

8 workflows · maturity 33% · 3 patterns · GitHub ↗

Security 3.12/100

Practices

✓ Matrix✓ Permissions○ Security scan○ AI review○ Cache○ Concurrency○ Reusable workflows

Detected patterns

Security dimensions

permissions
3.1
security scan
0
supply chain
0
secret handling
0
harden runner
0

Workflows (8)

ai-label .github/workflows/ai-label.yml
Triggers
issues, pull_request
Runs on
ubuntu-latest
Jobs
ai-labeler
Actions
jlowin/ai-labeler
View raw YAML
name: AI Labeler

on:
  issues:
    types: [opened, reopened]
  pull_request:
    types: [opened, reopened]

jobs:
  ai-labeler:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      issues: write
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      - uses: jlowin/ai-labeler@v0.4.0
        with:
          include-repo-labels: true
          openai-api-key: ${{ secrets.OPENAI_API_KEY }}
evals .github/workflows/evals.yml
Triggers
workflow_dispatch, schedule, push
Runs on
ubuntu-latest
Jobs
weekly-tests
Actions
astral-sh/setup-uv
Commands
  • uv python install 3.11
  • uv sync --all-extras --dev
  • uv run pytest tests/ --asyncio-mode=auto
View raw YAML
name: Weekly Tests

on:
  workflow_dispatch:
  schedule:
    - cron: "0 0 * * 0" # Runs at 00:00 UTC every Sunday
  push:
    branches: [main]
    paths-ignore:
      - "**" # Ignore all paths to ensure it only triggers on schedule

jobs:
  weekly-tests:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2

      - name: Install uv
        uses: astral-sh/setup-uv@v4
        with:
          enable-cache: true

      - name: Set up Python
        run: uv python install 3.11

      - name: Install dependencies
        run: uv sync --all-extras --dev

      - name: Run all tests
        run: uv run pytest tests/ --asyncio-mode=auto
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
python-publish perms .github/workflows/python-publish.yml
Triggers
release
Runs on
ubuntu-latest
Jobs
release
Actions
astral-sh/setup-uv
Commands
  • uv python install 3.10
  • uv sync --all-extras
  • uv build
  • uv publish
View raw YAML
# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

name: Upload Python Package

on:
  release:
    types: [published]

permissions:
  contents: read

jobs:
  release:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: Install uv
        uses: astral-sh/setup-uv@v4
        with:
          enable-cache: true
      - name: Set up Python
        run: uv python install 3.10
      - name: Install the project
        run: uv sync --all-extras
      - name: Build the project
        run: uv build
      - name: Build and publish Python package
        run: uv publish
        env:
          UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
ruff .github/workflows/ruff.yml
Triggers
push, pull_request
Runs on
ubuntu-latest
Jobs
Ruff
Actions
astral-sh/setup-uv
Commands
  • uv python install 3.9
  • uv sync --all-extras
  • uv run ruff check ${{ env.CUSTOM_PACKAGES }}
  • uv run ruff format --check ${{ env.CUSTOM_PACKAGES }}
View raw YAML
name: Ruff

on:
  push:
  pull_request:
    branches: [main]

env:
  WORKING_DIRECTORY: "."
  CUSTOM_PACKAGES: "instructor examples tests"

jobs:
  Ruff:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Install uv
        uses: astral-sh/setup-uv@v4
        with:
          enable-cache: true
      - name: Set up Python
        run: uv python install 3.9
      - name: Install the project
        run: uv sync --all-extras
      - name: Ruff lint
        run: uv run ruff check ${{ env.CUSTOM_PACKAGES }}
      - name: Ruff format
        run: uv run ruff format --check ${{ env.CUSTOM_PACKAGES }}
scheduled-release .github/workflows/scheduled-release.yml
Triggers
schedule, workflow_dispatch
Runs on
ubuntu-latest
Jobs
test-and-release
Actions
astral-sh/setup-uv, ncipollo/release-action
Commands
  • uv sync --all-extras --dev
  • uv run ruff check instructor examples tests
  • uv run pyright
  • uv run pytest tests/ -k "not openai and not llm and not anthropic and not gemini and not cohere and not mistral and not groq and not vertexai and not xai and not cerebras and not fireworks and not writer and not bedrock and not perplexity and not genai" --tb=short -v --maxfail=10
  • echo "Running basic LLM tests if API keys are available..." # Run a subset of LLM tests to verify basic functionality if [ ! -z "$OPENAI_API_KEY" ]; then echo "Testing OpenAI integration..." uv run pytest tests/llm/test_openai/test_basics.py --tb=short -v --maxfail=1 || echo "OpenAI tests failed" fi if [ ! -z "$ANTHROPIC_API_KEY" ]; then echo "Testing Anthropic integration..." uv run pytest tests/llm/test_anthropic/test_basics.py --tb=short -v --maxfail=1 || echo "Anthropic tests failed" fi echo "LLM tests completed (non-blocking)"
  • LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") if [ -z "$LAST_TAG" ]; then echo "has_changes=true" >> $GITHUB_OUTPUT echo "last_tag=none" >> $GITHUB_OUTPUT echo "change_count=initial" >> $GITHUB_OUTPUT else CHANGES=$(git rev-list $LAST_TAG..HEAD --count) echo "has_changes=$([[ $CHANGES -gt 0 ]] && echo true || echo false)" >> $GITHUB_OUTPUT echo "change_count=$CHANGES" >> $GITHUB_OUTPUT echo "last_tag=$LAST_TAG" >> $GITHUB_OUTPUT fi echo "Last tag: $LAST_TAG" echo "Changes since last tag: $(git rev-list $LAST_TAG..HEAD --count 2>/dev/null || echo 'N/A')"
  • VERSION=$(uv run python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])") echo "version=$VERSION" >> $GITHUB_OUTPUT echo "Current version: $VERSION"
  • # Check commit messages since last tag to determine bump type LAST_TAG="${{ steps.changes.outputs.last_tag }}" if [ "$LAST_TAG" = "none" ]; then COMMITS=$(git log --oneline HEAD~20..HEAD) else COMMITS=$(git log --oneline $LAST_TAG..HEAD) fi echo "Recent commits:" echo "$COMMITS" # Look for breaking changes or major features if echo "$COMMITS" | grep -qE "(BREAKING|feat!|fix!)"; then echo "bump_type=minor" >> $GITHUB_OUTPUT echo "Detected breaking changes - using minor bump" elif echo "$COMMITS" | grep -qE "feat:"; then echo "bump_type=minor" >> $GITHUB_OUTPUT echo "Detected new features - using minor bump" else echo "bump_type=patch" >> $GITHUB_OUTPUT echo "Using patch bump for bug fixes and chores" fi
View raw YAML
name: Scheduled Release

on:
  schedule:
    # Every 2 weeks on Monday at 9 AM UTC
    - cron: '0 9 * * 1/2'
  workflow_dispatch: # Allow manual trigger
    inputs:
      skip_tests:
        description: 'Skip LLM tests (use for testing workflow)'
        required: false
        default: false
        type: boolean
      dry_run:
        description: 'Dry run - dont push changes or create release'
        required: false
        default: false
        type: boolean

jobs:
  test-and-release:
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0
        token: ${{ secrets.GITHUB_TOKEN }}
    
    - name: Setup UV
      uses: astral-sh/setup-uv@v3
    
    - name: Install dependencies
      run: |
        uv sync --all-extras --dev
    
    - name: Run linting
      run: |
        uv run ruff check instructor examples tests
    
    - name: Run type checking
      run: |
        uv run pyright
    
    - name: Run core tests (no LLM)
      run: |
        uv run pytest tests/ -k "not openai and not llm and not anthropic and not gemini and not cohere and not mistral and not groq and not vertexai and not xai and not cerebras and not fireworks and not writer and not bedrock and not perplexity and not genai" --tb=short -v --maxfail=10
    
    # Optional: Run LLM tests if you have API keys in secrets
    - name: Run LLM tests
      if: github.event.inputs.skip_tests != 'true'
      env:
        OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
        ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
        COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
        GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
        MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
      run: |
        echo "Running basic LLM tests if API keys are available..."
        # Run a subset of LLM tests to verify basic functionality
        if [ ! -z "$OPENAI_API_KEY" ]; then
          echo "Testing OpenAI integration..."
          uv run pytest tests/llm/test_openai/test_basics.py --tb=short -v --maxfail=1 || echo "OpenAI tests failed"
        fi
        if [ ! -z "$ANTHROPIC_API_KEY" ]; then
          echo "Testing Anthropic integration..."
          uv run pytest tests/llm/test_anthropic/test_basics.py --tb=short -v --maxfail=1 || echo "Anthropic tests failed"
        fi
        echo "LLM tests completed (non-blocking)"
    
    - name: Check for changes since last release
      id: changes
      run: |
        LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
        if [ -z "$LAST_TAG" ]; then
          echo "has_changes=true" >> $GITHUB_OUTPUT
          echo "last_tag=none" >> $GITHUB_OUTPUT
          echo "change_count=initial" >> $GITHUB_OUTPUT
        else
          CHANGES=$(git rev-list $LAST_TAG..HEAD --count)
          echo "has_changes=$([[ $CHANGES -gt 0 ]] && echo true || echo false)" >> $GITHUB_OUTPUT
          echo "change_count=$CHANGES" >> $GITHUB_OUTPUT
          echo "last_tag=$LAST_TAG" >> $GITHUB_OUTPUT
        fi
        
        echo "Last tag: $LAST_TAG"
        echo "Changes since last tag: $(git rev-list $LAST_TAG..HEAD --count 2>/dev/null || echo 'N/A')"
    
    # Only proceed with release if tests passed AND there are changes
    - name: Get current version
      if: steps.changes.outputs.has_changes == 'true'
      id: current_version
      run: |
        VERSION=$(uv run python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
        echo "version=$VERSION" >> $GITHUB_OUTPUT
        echo "Current version: $VERSION"
    
    - name: Determine version bump type
      if: steps.changes.outputs.has_changes == 'true'
      id: version_type
      run: |
        # Check commit messages since last tag to determine bump type
        LAST_TAG="${{ steps.changes.outputs.last_tag }}"
        if [ "$LAST_TAG" = "none" ]; then
          COMMITS=$(git log --oneline HEAD~20..HEAD)
        else
          COMMITS=$(git log --oneline $LAST_TAG..HEAD)
        fi
        
        echo "Recent commits:"
        echo "$COMMITS"
        
        # Look for breaking changes or major features
        if echo "$COMMITS" | grep -qE "(BREAKING|feat!|fix!)"; then
          echo "bump_type=minor" >> $GITHUB_OUTPUT
          echo "Detected breaking changes - using minor bump"
        elif echo "$COMMITS" | grep -qE "feat:"; then
          echo "bump_type=minor" >> $GITHUB_OUTPUT
          echo "Detected new features - using minor bump"
        else
          echo "bump_type=patch" >> $GITHUB_OUTPUT
          echo "Using patch bump for bug fixes and chores"
        fi
    
    - name: Bump version
      if: steps.changes.outputs.has_changes == 'true'
      id: bump_version
      run: |
        CURRENT="${{ steps.current_version.outputs.version }}"
        BUMP_TYPE="${{ steps.version_type.outputs.bump_type }}"
        
        IFS='.' read -r major minor patch <<< "$CURRENT"
        
        case $BUMP_TYPE in
          major)
            major=$((major + 1))
            minor=0
            patch=0
            ;;
          minor)
            minor=$((minor + 1))
            patch=0
            ;;
          patch)
            patch=$((patch + 1))
            ;;
        esac
        
        NEW_VERSION="$major.$minor.$patch"
        echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
        echo "Bumping from $CURRENT to $NEW_VERSION ($BUMP_TYPE)"
        
        # Update pyproject.toml
        sed -i "s/version = \"$CURRENT\"/version = \"$NEW_VERSION\"/" pyproject.toml
    
    - name: Update lockfile
      if: steps.changes.outputs.has_changes == 'true'
      run: |
        uv lock
    
    # Run tests again after version bump to make sure nothing broke
    - name: Final test run
      if: steps.changes.outputs.has_changes == 'true'
      run: |
        uv sync
        uv run pytest tests/ -k "not openai and not llm and not anthropic and not gemini and not cohere and not mistral and not groq and not vertexai and not xai and not cerebras and not fireworks and not writer and not bedrock and not perplexity and not genai" --tb=short --maxfail=5
    
    - name: Generate changelog
      if: steps.changes.outputs.has_changes == 'true'
      id: changelog
      run: |
        LAST_TAG="${{ steps.changes.outputs.last_tag }}"
        NEW_VERSION="${{ steps.bump_version.outputs.new_version }}"
        
        if [ "$LAST_TAG" = "none" ]; then
          CHANGELOG=$(git log --oneline HEAD~30..HEAD --pretty=format:"- %s" | head -20)
        else
          CHANGELOG=$(git log --oneline $LAST_TAG..HEAD --pretty=format:"- %s")
        fi
        
        # Save changelog to file for GitHub release
        cat > CHANGELOG.md << EOF
        ## 🚀 What's Changed
        
        $CHANGELOG
        
        ## 🔗 Links
        **Full Changelog**: https://github.com/${{ github.repository }}/compare/$LAST_TAG...v$NEW_VERSION
        
        ---
        🤖 *This release was automatically generated every 2 weeks*
        EOF
        
        echo "changelog_file=CHANGELOG.md" >> $GITHUB_OUTPUT
    
    - name: Create release commit
      if: steps.changes.outputs.has_changes == 'true'
      run: |
        git config --local user.email "action@github.com"
        git config --local user.name "GitHub Action"
        git add pyproject.toml uv.lock
        git commit -m "chore: automated release v${{ steps.bump_version.outputs.new_version }}

        🤖 Generated with [Claude Code](https://claude.ai/code)

        Co-Authored-By: GitHub Action <action@github.com>"
        git tag "v${{ steps.bump_version.outputs.new_version }}"
    
    - name: Push changes
      if: steps.changes.outputs.has_changes == 'true' && github.event.inputs.dry_run != 'true'
      run: |
        git push origin main
        git push origin "v${{ steps.bump_version.outputs.new_version }}"
    
    - name: Create GitHub Release
      if: steps.changes.outputs.has_changes == 'true' && github.event.inputs.dry_run != 'true'
      uses: ncipollo/release-action@v1
      with:
        tag: "v${{ steps.bump_version.outputs.new_version }}"
        name: "🚀 Release v${{ steps.bump_version.outputs.new_version }}"
        bodyFile: "CHANGELOG.md"
        draft: false
        prerelease: false
    
    - name: Dry run summary
      if: steps.changes.outputs.has_changes == 'true' && github.event.inputs.dry_run == 'true'
      run: |
        echo "🧪 DRY RUN MODE - No changes pushed"
        echo "Would have released: v${{ steps.bump_version.outputs.new_version }}"
        cat CHANGELOG.md
    
    # Optional: Publish to PyPI (uncomment if you want automatic PyPI releases)
    # - name: Build and publish to PyPI
    #   if: steps.changes.outputs.has_changes == 'true' && secrets.PYPI_TOKEN != ''
    #   env:
    #     PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
    #   run: |
    #     uv build
    #     uv publish --token $PYPI_TOKEN
    
    # Summary outputs
    - name: Summary
      if: always()
      run: |
        echo "## 📊 Scheduled Release Summary" >> $GITHUB_STEP_SUMMARY
        echo "- **Branch**: ${{ github.ref }}" >> $GITHUB_STEP_SUMMARY
        echo "- **Has Changes**: ${{ steps.changes.outputs.has_changes }}" >> $GITHUB_STEP_SUMMARY
        echo "- **Change Count**: ${{ steps.changes.outputs.change_count }}" >> $GITHUB_STEP_SUMMARY
        if [ "${{ steps.changes.outputs.has_changes }}" = "true" ]; then
          echo "- **Version**: ${{ steps.current_version.outputs.version }} → ${{ steps.bump_version.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY
          echo "- **Bump Type**: ${{ steps.version_type.outputs.bump_type }}" >> $GITHUB_STEP_SUMMARY
          echo "- **Status**: ✅ Released" >> $GITHUB_STEP_SUMMARY
        else
          echo "- **Status**: ⏭️ Skipped (no changes)" >> $GITHUB_STEP_SUMMARY
        fi
    
    - name: Notify on failure
      if: failure()
      run: |
        echo "❌ Scheduled release failed - check the logs above"
        echo "Common issues:"
        echo "- Tests failed"
        echo "- Linting issues" 
        echo "- Type checking errors"
        echo "- Git push permissions"
test matrix .github/workflows/test.yml
Triggers
pull_request, push
Runs on
ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
core-tests, core-openai, core-anthropic, core-google, core-other, provider-tests, auto-client-test
Matrix
provider, provider.env_key, provider.name, provider.test_path→ ANTHROPIC_API_KEY, Anthropic, GOOGLE_API_KEY, Gemini, Google GenAI, OPENAI_API_KEY, OpenAI, Vertex AI, WRITER_API_KEY, Writer, tests/llm/test_anthropic, tests/llm/test_gemini, tests/llm/test_genai, tests/llm/test_openai, tests/llm/test_vertexai, tests/llm/test_writer
Actions
astral-sh/setup-uv, astral-sh/setup-uv, astral-sh/setup-uv, astral-sh/setup-uv, astral-sh/setup-uv, astral-sh/setup-uv, astral-sh/setup-uv
Commands
  • uv python install 3.11
  • uv sync --all-extras
  • uv run pytest tests/ --asyncio-mode=auto -n auto -k 'not test_core_providers and not test_openai and not test_anthropic and not test_gemini and not test_genai and not test_writer and not test_vertexai and not docs'
  • uv python install 3.11
  • uv sync --all-extras
  • echo "Skipping OpenAI core provider tests (missing OPENAI_API_KEY)."
  • set +e uv run pytest tests/llm/test_core_providers -v --asyncio-mode=auto -n auto -k "openai" status=$? set -e if [ $status -eq 5 ]; then echo "No tests collected; treating as success." exit 0 fi exit $status
  • uv python install 3.11
View raw YAML
name: Test
on:
  pull_request:
  push:
    branches:
      - main

jobs:
  # Core tests without LLM providers
  core-tests:
    name: Core Tests
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: Install uv
        uses: astral-sh/setup-uv@v4
        with:
          enable-cache: true
      - name: Set up Python
        run: uv python install 3.11
      - name: Install the project
        run: uv sync --all-extras
      - name: Run core tests
        run: >-
          uv run pytest tests/ --asyncio-mode=auto -n auto
          -k 'not test_core_providers and not test_openai and not test_anthropic
          and not test_gemini and not test_genai and not test_writer and not
          test_vertexai and not docs'
        env:
          INSTRUCTOR_ENV: CI
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
          XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
          GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}

  # Core provider tests for OpenAI
  core-openai:
    name: Core Provider Tests (OpenAI)
    runs-on: ubuntu-latest
    needs: core-tests
    env:
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}

    steps:
      - uses: actions/checkout@v2
      - name: Install uv
        uses: astral-sh/setup-uv@v4
        with:
          enable-cache: true
      - name: Set up Python
        run: uv python install 3.11
      - name: Install the project
        run: uv sync --all-extras
      - name: Skip core provider tests (OpenAI)
        if: ${{ env.OPENAI_API_KEY == '' }}
        run: echo "Skipping OpenAI core provider tests (missing OPENAI_API_KEY)."
      - name: Run core provider tests (OpenAI)
        if: ${{ env.OPENAI_API_KEY != '' }}
        run: |
          set +e
          uv run pytest tests/llm/test_core_providers -v --asyncio-mode=auto -n auto -k "openai"
          status=$?
          set -e
          if [ $status -eq 5 ]; then
            echo "No tests collected; treating as success."
            exit 0
          fi
          exit $status
        env:
          INSTRUCTOR_ENV: CI
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}

  # Core provider tests for Anthropic
  core-anthropic:
    name: Core Provider Tests (Anthropic)
    runs-on: ubuntu-latest
    needs: core-tests
    env:
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

    steps:
      - uses: actions/checkout@v2
      - name: Install uv
        uses: astral-sh/setup-uv@v4
        with:
          enable-cache: true
      - name: Set up Python
        run: uv python install 3.11
      - name: Install the project
        run: uv sync --all-extras
      - name: Skip core provider tests (Anthropic)
        if: ${{ env.ANTHROPIC_API_KEY == '' }}
        run: echo "Skipping Anthropic core provider tests (missing ANTHROPIC_API_KEY)."
      - name: Run core provider tests (Anthropic)
        if: ${{ env.ANTHROPIC_API_KEY != '' }}
        run: |
          set +e
          uv run pytest tests/llm/test_core_providers -v --asyncio-mode=auto -n auto -k "anthropic"
          status=$?
          set -e
          if [ $status -eq 5 ]; then
            echo "No tests collected; treating as success."
            exit 0
          fi
          exit $status
        env:
          INSTRUCTOR_ENV: CI
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

  # Core provider tests for Google
  core-google:
    name: Core Provider Tests (Google)
    runs-on: ubuntu-latest
    needs: core-tests
    env:
      GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
      GOOGLE_GENAI_MODEL: ${{ secrets.GOOGLE_GENAI_MODEL }}

    steps:
      - uses: actions/checkout@v2
      - name: Install uv
        uses: astral-sh/setup-uv@v4
        with:
          enable-cache: true
      - name: Set up Python
        run: uv python install 3.11
      - name: Install the project
        run: uv sync --all-extras
      - name: Skip core provider tests (Google)
        if: ${{ env.GOOGLE_API_KEY == '' || env.GOOGLE_GENAI_MODEL == '' }}
        run: echo "Skipping Google core provider tests (missing GOOGLE_API_KEY or GOOGLE_GENAI_MODEL)."
      - name: Run core provider tests (Google)
        if: ${{ env.GOOGLE_API_KEY != '' && env.GOOGLE_GENAI_MODEL != '' }}
        run: |
          set +e
          uv run pytest tests/llm/test_core_providers -v --asyncio-mode=auto -n auto -k "google"
          status=$?
          set -e
          if [ $status -eq 5 ]; then
            echo "No tests collected; treating as success."
            exit 0
          fi
          exit $status
        env:
          INSTRUCTOR_ENV: CI
          GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}

  # Core provider tests for other providers
  core-other:
    name: Core Provider Tests (Other)
    runs-on: ubuntu-latest
    needs: core-tests
    env:
      COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
      XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
      MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
      CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY }}
      FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
      WRITER_API_KEY: ${{ secrets.WRITER_API_KEY }}
      PERPLEXITY_API_KEY: ${{ secrets.PERPLEXITY_API_KEY }}

    steps:
      - uses: actions/checkout@v2
      - name: Install uv
        uses: astral-sh/setup-uv@v4
        with:
          enable-cache: true
      - name: Set up Python
        run: uv python install 3.11
      - name: Install the project
        run: uv sync --all-extras
      - name: Skip core provider tests (Other)
        if: >-
          ${{ env.COHERE_API_KEY == '' && env.XAI_API_KEY == ''
          && env.MISTRAL_API_KEY == '' && env.CEREBRAS_API_KEY == ''
          && env.FIREWORKS_API_KEY == '' && env.WRITER_API_KEY == ''
          && env.PERPLEXITY_API_KEY == '' }}
        run: echo "Skipping core provider tests (Other) (missing provider secrets)."
      - name: Run core provider tests (Cohere, xAI, Mistral, etc)
        if: >-
          ${{ env.COHERE_API_KEY != '' || env.XAI_API_KEY != ''
          || env.MISTRAL_API_KEY != '' || env.CEREBRAS_API_KEY != ''
          || env.FIREWORKS_API_KEY != '' || env.WRITER_API_KEY != ''
          || env.PERPLEXITY_API_KEY != '' }}
        run: |
          set +e
          uv run pytest tests/llm/test_core_providers -v --asyncio-mode=auto -n auto -k "cohere or xai or mistral or cerebras or fireworks or writer or perplexity"
          status=$?
          set -e
          if [ $status -eq 5 ]; then
            echo "No tests collected; treating as success."
            exit 0
          fi
          exit $status
        env:
          INSTRUCTOR_ENV: CI
          COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
          XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
          MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
          CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY }}
          FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
          WRITER_API_KEY: ${{ secrets.WRITER_API_KEY }}
          PERPLEXITY_API_KEY: ${{ secrets.PERPLEXITY_API_KEY }}

  # Provider tests run in parallel
  provider-tests:
    name: ${{ matrix.provider.name }} Tests
    runs-on: ubuntu-latest
    needs: [core-openai, core-anthropic, core-google, core-other]
    env:
      PROVIDER_API_KEY: ${{ secrets[matrix.provider.env_key] }}
      GOOGLE_GENAI_MODEL: ${{ secrets.GOOGLE_GENAI_MODEL }}
    strategy:
      fail-fast: false
      matrix:
        provider:
          - name: OpenAI
            env_key: OPENAI_API_KEY
            test_path: tests/llm/test_openai
          - name: Anthropic
            env_key: ANTHROPIC_API_KEY
            test_path: tests/llm/test_anthropic
          - name: Gemini
            env_key: GOOGLE_API_KEY
            test_path: tests/llm/test_gemini
          - name: Google GenAI
            env_key: GOOGLE_API_KEY
            test_path: tests/llm/test_genai
          - name: Vertex AI
            env_key: GOOGLE_API_KEY
            test_path: tests/llm/test_vertexai
          - name: Writer
            env_key: WRITER_API_KEY
            test_path: tests/llm/test_writer

    steps:
      - uses: actions/checkout@v2
      - name: Install uv
        uses: astral-sh/setup-uv@v4
        with:
          enable-cache: true
      - name: Set up Python
        run: uv python install 3.11
      - name: Install the project
        run: uv sync --all-extras
      - name: Skip ${{ matrix.provider.name }} tests
        if: >-
          ${{ env.PROVIDER_API_KEY == '' ||
          ((matrix.provider.name == 'Gemini' || matrix.provider.name == 'Google GenAI'
          || matrix.provider.name == 'Vertex AI') && env.GOOGLE_GENAI_MODEL == '') }}
        run: >-
          echo "Skipping ${{ matrix.provider.name }} tests
          (missing ${{ matrix.provider.env_key }} or GOOGLE_GENAI_MODEL)."
      - name: Run ${{ matrix.provider.name }} tests
        if: >-
          ${{ env.PROVIDER_API_KEY != '' &&
          ((matrix.provider.name != 'Gemini' && matrix.provider.name != 'Google GenAI'
          && matrix.provider.name != 'Vertex AI') || env.GOOGLE_GENAI_MODEL != '') }}
        run: |
          set +e
          uv run pytest ${{ matrix.provider.test_path }} --asyncio-mode=auto -n auto
          status=$?
          set -e
          if [ $status -eq 5 ]; then
            echo "No tests collected; treating as success."
            exit 0
          fi
          exit $status
        env:
          INSTRUCTOR_ENV: CI
          ${{ matrix.provider.env_key }}: ${{ secrets[matrix.provider.env_key] }}

  # Auto client needs multiple providers
  auto-client-test:
    name: Auto Client Tests
    runs-on: ubuntu-latest
    needs: [core-openai, core-anthropic, core-google, core-other]
    env:
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
      COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      XAI_API_KEY: ${{ secrets.XAI_API_KEY }}

    steps:
      - uses: actions/checkout@v2
      - name: Install uv
        uses: astral-sh/setup-uv@v4
        with:
          enable-cache: true
      - name: Set up Python
        run: uv python install 3.11
      - name: Install the project
        run: uv sync --all-extras
      - name: Skip Auto Client tests
        if: >-
          ${{ env.OPENAI_API_KEY == '' || env.GOOGLE_API_KEY == ''
          || env.COHERE_API_KEY == '' || env.ANTHROPIC_API_KEY == ''
          || env.XAI_API_KEY == '' }}
        run: echo "Skipping Auto Client tests (missing one or more provider secrets)."
      - name: Run Auto Client tests
        if: >-
          ${{ env.OPENAI_API_KEY != '' && env.GOOGLE_API_KEY != ''
          && env.COHERE_API_KEY != '' && env.ANTHROPIC_API_KEY != ''
          && env.XAI_API_KEY != '' }}
        run: |
          set +e
          uv run pytest tests/test_auto_client.py --asyncio-mode=auto -n auto
          status=$?
          set -e
          if [ $status -eq 5 ]; then
            echo "No tests collected; treating as success."
            exit 0
          fi
          exit $status
        env:
          INSTRUCTOR_ENV: CI
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
          COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
test_docs matrix .github/workflows/test_docs.yml
Triggers
schedule
Runs on
ubuntu-latest
Jobs
release
Matrix
python-version→ 3.11
Actions
snok/install-poetry, astral-sh/setup-uv
Commands
  • sudo apt-get update sudo apt-get install -y graphviz libcairo2-dev xdg-utils
  • uv sync --all-extras
  • uv run pytest tests/docs --asyncio-mode=auto
View raw YAML
name: Test Docs
on:
  schedule:
    - cron: '0 0 1 * *'  # Runs at 00:00 on the 1st of every month
jobs:
  release:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        python-version: ["3.11"]

    steps:
      - uses: actions/checkout@v2

      - name: Install system dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y graphviz libcairo2-dev xdg-utils

      - name: Install Poetry
        uses: snok/install-poetry@v1.3.1

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
          cache: "poetry"
      - name: Install uv
        uses: astral-sh/setup-uv@v4
      - name: Install the project
        run: uv sync --all-extras
      - name: Run tests
        run: uv run pytest tests/docs --asyncio-mode=auto
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ty .github/workflows/ty.yml
Triggers
pull_request, push
Runs on
ubuntu-latest
Jobs
type-check
Actions
astral-sh/setup-uv
Commands
  • uv python install 3.11
  • uv sync --all-extras
  • uv run ty check instructor/
  • uv run ty check --config-file ty-tests.toml tests
View raw YAML
name: ty

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

env:
  WORKING_DIRECTORY: "."

jobs:
  type-check:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Install uv
        uses: astral-sh/setup-uv@v4
        with:
          enable-cache: true
      - name: Set up Python
        run: uv python install 3.11
      - name: Install the project
        run: uv sync --all-extras
      - name: Run type check with ty
        run: uv run ty check instructor/
      - name: Run type check with ty (tests)
        run: uv run ty check --config-file ty-tests.toml tests