Hello world
diff --git a/.github/workflows/oke-cicd.yaml b/.github/workflows/oke-cicd.yaml index 0e156c9..9a9592f 100644 --- a/.github/workflows/oke-cicd.yaml +++ b/.github/workflows/oke-cicd.yaml @@ -1,236 +1,236 @@ -# Test + optional OKE CD. PRs and main always run compile/test/lint. -# Deploy job runs only when repository variable ENABLE_OKE_DEPLOY=true (set on operator forks). -name: Build, Test, and Deploy to OKE - -on: - push: - branches: - - main - pull_request: - workflow_dispatch: - inputs: - deploy_kserve: - description: Deploy/update KServe Qwen (single GPU — recycles revision) - type: boolean - default: false - -env: - REGISTRY: ghcr.io - IMAGE_NAME: mcp-kubeflow-docs - K8S_NAMESPACE: docs-agent - OKE_CLUSTER_OCID: ${{ secrets.OKE_CLUSTER_OCID }} - -jobs: - test-and-compile: - name: Compile and Test - runs-on: ubuntu-latest - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: "3.10" - - - name: Install Dependencies - run: | - python -m pip install --upgrade pip - pip install -r docs-agent-mcp/mcp-server/requirements.txt - pip install -r requirements-test.txt - pip install ruff==0.15.9 kfp kfp-kubernetes - - - name: Compile docs RAG pipeline - working-directory: docs-agent-mcp/pipelines - run: | - python kubeflow-pipeline.py - python issues-pipeline.py - python code-pipeline.py - - - name: Ruff lint - run: ruff check docs-agent-mcp/mcp-server docs-agent-mcp/session-issuer tests docs-agent-mcp/pipelines - - - name: Compile MCP server - run: python -m py_compile docs-agent-mcp/mcp-server/*.py docs-agent-mcp/session-issuer/*.py - - - name: Run Unit Tests - run: pytest -v --tb=short - - build-and-deploy: - name: Build, Push, and Deploy to OKE - needs: test-and-compile - # Off by default in kubeflow/docs-agent (no OKE secrets). Fork operators set repo variable ENABLE_OKE_DEPLOY=true. - if: | - (github.event_name == 'workflow_dispatch' || github.event_name == 'push') && - vars.ENABLE_OKE_DEPLOY == 'true' - runs-on: ubuntu-latest - # Secrets are stored under Settings → Environments → kubeflow (not repo secrets) - environment: kubeflow - permissions: - contents: read - packages: write - env: - # oracle-actions/configure-kubectl-oke expects OCI_CLI_* env vars - OCI_CLI_USER: ${{ secrets.OCI_USER_OCID }} - OCI_CLI_TENANCY: ${{ secrets.OCI_TENANCY_OCID }} - OCI_CLI_FINGERPRINT: ${{ secrets.OCI_FINGERPRINT }} - OCI_CLI_KEY_CONTENT: ${{ secrets.OCI_KEY_FILE }} - OCI_CLI_REGION: ${{ secrets.OCI_REGION }} - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - - name: Validate deploy secrets - env: - GHCR_PULL_TOKEN: ${{ secrets.GHCR_TOKEN || secrets.GHCR_PULL_TOKEN || secrets.Github_Pat }} - OCI_USER_OCID: ${{ secrets.OCI_USER_OCID }} - OCI_TENANCY_OCID: ${{ secrets.OCI_TENANCY_OCID }} - OCI_FINGERPRINT: ${{ secrets.OCI_FINGERPRINT }} - OCI_KEY_FILE: ${{ secrets.OCI_KEY_FILE }} - OCI_REGION: ${{ secrets.OCI_REGION }} - OKE_CLUSTER_OCID: ${{ secrets.OKE_CLUSTER_OCID }} - run: | - set -euo pipefail - missing=() - for name in OCI_USER_OCID OCI_TENANCY_OCID OCI_FINGERPRINT OCI_KEY_FILE OCI_REGION OKE_CLUSTER_OCID; do - if [ -z "${!name:-}" ]; then - missing+=("$name") - fi - done - if [ -z "${GHCR_PULL_TOKEN:-}" ]; then - missing+=("GHCR_TOKEN or GHCR_PULL_TOKEN or Github_Pat (needs read:packages for cluster image pull)") - fi - if [ "${#missing[@]}" -gt 0 ]; then - echo "::error::Missing required GitHub Actions secrets in environment 'kubeflow':" - printf ' - %s\n' "${missing[@]}" - echo "Add them under Settings → Environments → kubeflow → Environment secrets." - exit 1 - fi - - - name: Set image coordinates - env: - GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }} - run: | - owner_lc="$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')" - ghcr_user="${GHCR_USERNAME:-$owner_lc}" - echo "IMAGE_REPO=ghcr.io/${owner_lc}/${{ env.IMAGE_NAME }}" >> "$GITHUB_ENV" - echo "GHCR_USERNAME=${ghcr_user}" >> "$GITHUB_ENV" - echo "tag=${GITHUB_SHA::7}" >> "$GITHUB_ENV" - - - name: Log in to GHCR - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and Push MCP Image - uses: docker/build-push-action@v5 - with: - context: ./docs-agent-mcp/mcp-server - file: ./docs-agent-mcp/mcp-server/Dockerfile - push: true - tags: | - ${{ env.IMAGE_REPO }}:${{ env.tag }} - - - name: Configure kubectl for OKE - uses: oracle-actions/configure-kubectl-oke@v1.5.0 - with: - cluster: ${{ secrets.OKE_CLUSTER_OCID }} - - - name: Deploy to OKE - env: - FULL_IMAGE: ${{ env.IMAGE_REPO }}:${{ env.tag }} - GHCR_PULL_TOKEN: ${{ secrets.GHCR_TOKEN || secrets.GHCR_PULL_TOKEN || secrets.Github_Pat }} - GHCR_USERNAME: ${{ env.GHCR_USERNAME }} - run: | - set -euo pipefail - - kubectl create namespace "${{ env.K8S_NAMESPACE }}" --dry-run=client -o yaml | kubectl apply -f - - - kubectl create secret docker-registry ghcrsecret \ - --namespace "${{ env.K8S_NAMESPACE }}" \ - --docker-server="${{ env.REGISTRY }}" \ - --docker-username="${GHCR_USERNAME}" \ - --docker-password="${GHCR_PULL_TOKEN}" \ - --docker-email="${GHCR_USERNAME}@users.noreply.github.com" \ - --dry-run=client -o yaml | kubectl apply -f - - - # Replace pinned manifest image with the commit-scoped tag built above. - sed "s|ghcr.io/kubeflow/mcp-kubeflow-docs:v0.1.0|${FULL_IMAGE}|g" \ - docs-agent-mcp/manifests/mcp-server/mcp-server.yaml | kubectl apply -f - - kubectl set image deployment/mcp-kubeflow-docs \ - mcp-server="${FULL_IMAGE}" \ - -n "${{ env.K8S_NAMESPACE }}" || true - kubectl patch deployment/mcp-kubeflow-docs -n "${{ env.K8S_NAMESPACE }}" --type=merge \ - -p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"ghcrsecret"}]}}}}' - kubectl rollout status deployment/mcp-kubeflow-docs \ - -n "${{ env.K8S_NAMESPACE }}" --timeout=600s - - kubectl apply -f docs-agent-mcp/manifests/kagent/setup.yaml - - DEPLOY_KSERVE=false - if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.deploy_kserve }}" = "true" ]; then - DEPLOY_KSERVE=true - elif [ "${{ github.event_name }}" = "push" ]; then - if git diff --name-only --diff-filter=M "${{ github.event.before }}" "${{ github.sha }}" \ - | grep -qE '^docs-agent-mcp/manifests/vllm/kserve-qwen\.yaml$'; then - DEPLOY_KSERVE=true - fi - fi - - if [ "${DEPLOY_KSERVE}" = "true" ]; then - echo "Removing legacy docs-agent GPU InferenceService (frees GPU for ml-infra/qwen-llm)" - kubectl delete inferenceservice/qwen -n "${{ env.K8S_NAMESPACE }}" --ignore-not-found=true - kubectl delete svc/qwen-llm -n "${{ env.K8S_NAMESPACE }}" --ignore-not-found=true - echo "Applying ml-infra Qwen KServe manifests" - kubectl apply -f docs-agent-mcp/manifests/vllm/kserve-qwen.yaml - kubectl rollout status deployment -n ml-infra -l serving.kserve.io/inferenceservice=qwen-llm --timeout=600s 2>/dev/null || true - else - echo "Skipping Qwen GPU deploy (no vllm manifest change; use workflow_dispatch to force)" - fi - - - name: Wait for ml-infra dependencies - run: | - set -euo pipefail - kubectl wait --for=condition=Ready inferenceservice/embeddings-service \ - -n ml-infra --timeout=600s - # Milvus CR reports Healthy in .status.status, not a Ready condition. - for i in $(seq 1 60); do - status="$(kubectl get milvus milvus -n ml-infra -o jsonpath='{.status.status}' 2>/dev/null || true)" - if [ "${status}" = "Healthy" ]; then - echo "milvus status=${status}" - break - fi - echo "waiting for milvus (status=${status:-unknown}) attempt ${i}/60" - sleep 10 - done - kubectl get milvus -n ml-infra - test "$(kubectl get milvus milvus -n ml-infra -o jsonpath='{.status.status}')" = "Healthy" - - - name: Smoke test MCP tools and embeddings (ml-infra) - run: | - set -euo pipefail - kubectl rollout status deployment/mcp-kubeflow-docs \ - -n "${{ env.K8S_NAMESPACE }}" --timeout=120s - kubectl exec -n "${{ env.K8S_NAMESPACE }}" deploy/mcp-kubeflow-docs -- \ - python3 /app/smoke_tools.py - kubectl get agent,modelconfig -n "${{ env.K8S_NAMESPACE }}" - - - name: Smoke test Qwen (non-blocking) - continue-on-error: true - run: | - set -euo pipefail - POD="$(kubectl get pods -n ml-infra -l serving.kserve.io/inferenceservice=qwen-llm \ - --field-selector=status.phase=Running \ - -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)" - if [ -z "${POD}" ]; then - echo "No running qwen-llm pod in ml-infra — skipping LLM smoke test" - exit 0 - fi - kubectl exec -n ml-infra "${POD}" -c kserve-container -- python3 -c " - import urllib.request, json - p=json.dumps({'model':'qwen2.5-7B','messages':[{'role':'user','content':'ping'}],'max_tokens':8}).encode() - r=urllib.request.urlopen(urllib.request.Request('http://127.0.0.1:8080/openai/v1/chat/completions',data=p,headers={'Content-Type':'application/json'}), timeout=60) - print('kserve ok', r.status) - " +# Test + optional OKE CD. PRs and main always run compile/test/lint. +# Deploy job runs only when repository variable ENABLE_OKE_DEPLOY=true (set on operator forks). +name: Build, Test, and Deploy to OKE + +on: + push: + branches: + - main + pull_request: + workflow_dispatch: + inputs: + deploy_kserve: + description: Deploy/update KServe Qwen (single GPU — recycles revision) + type: boolean + default: false + +env: + REGISTRY: ghcr.io + IMAGE_NAME: mcp-kubeflow-docs + K8S_NAMESPACE: docs-agent + OKE_CLUSTER_OCID: ${{ secrets.OKE_CLUSTER_OCID }} + +jobs: + test-and-compile: + name: Compile and Test + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r kagent-feast-mcp/mcp-server/requirements.txt + pip install -r requirements-test.txt + pip install ruff==0.15.9 kfp kfp-kubernetes + + - name: Compile docs RAG pipeline + working-directory: kagent-feast-mcp/pipelines + run: | + python kubeflow-pipeline.py + python issues-pipeline.py + python code-pipeline.py + + - name: Ruff lint + run: ruff check kagent-feast-mcp/mcp-server kagent-feast-mcp/session-issuer tests kagent-feast-mcp/pipelines + + - name: Compile MCP server + run: python -m py_compile kagent-feast-mcp/mcp-server/*.py kagent-feast-mcp/session-issuer/*.py + + - name: Run Unit Tests + run: pytest -v --tb=short + + build-and-deploy: + name: Build, Push, and Deploy to OKE + needs: test-and-compile + # Off by default in kubeflow/docs-agent (no OKE secrets). Fork operators set repo variable ENABLE_OKE_DEPLOY=true. + if: | + (github.event_name == 'workflow_dispatch' || github.event_name == 'push') && + vars.ENABLE_OKE_DEPLOY == 'true' + runs-on: ubuntu-latest + # Secrets are stored under Settings → Environments → kubeflow (not repo secrets) + environment: kubeflow + permissions: + contents: read + packages: write + env: + # oracle-actions/configure-kubectl-oke expects OCI_CLI_* env vars + OCI_CLI_USER: ${{ secrets.OCI_USER_OCID }} + OCI_CLI_TENANCY: ${{ secrets.OCI_TENANCY_OCID }} + OCI_CLI_FINGERPRINT: ${{ secrets.OCI_FINGERPRINT }} + OCI_CLI_KEY_CONTENT: ${{ secrets.OCI_KEY_FILE }} + OCI_CLI_REGION: ${{ secrets.OCI_REGION }} + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Validate deploy secrets + env: + GHCR_PULL_TOKEN: ${{ secrets.GHCR_TOKEN || secrets.GHCR_PULL_TOKEN || secrets.Github_Pat }} + OCI_USER_OCID: ${{ secrets.OCI_USER_OCID }} + OCI_TENANCY_OCID: ${{ secrets.OCI_TENANCY_OCID }} + OCI_FINGERPRINT: ${{ secrets.OCI_FINGERPRINT }} + OCI_KEY_FILE: ${{ secrets.OCI_KEY_FILE }} + OCI_REGION: ${{ secrets.OCI_REGION }} + OKE_CLUSTER_OCID: ${{ secrets.OKE_CLUSTER_OCID }} + run: | + set -euo pipefail + missing=() + for name in OCI_USER_OCID OCI_TENANCY_OCID OCI_FINGERPRINT OCI_KEY_FILE OCI_REGION OKE_CLUSTER_OCID; do + if [ -z "${!name:-}" ]; then + missing+=("$name") + fi + done + if [ -z "${GHCR_PULL_TOKEN:-}" ]; then + missing+=("GHCR_TOKEN or GHCR_PULL_TOKEN or Github_Pat (needs read:packages for cluster image pull)") + fi + if [ "${#missing[@]}" -gt 0 ]; then + echo "::error::Missing required GitHub Actions secrets in environment 'kubeflow':" + printf ' - %s\n' "${missing[@]}" + echo "Add them under Settings → Environments → kubeflow → Environment secrets." + exit 1 + fi + + - name: Set image coordinates + env: + GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }} + run: | + owner_lc="$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')" + ghcr_user="${GHCR_USERNAME:-$owner_lc}" + echo "IMAGE_REPO=ghcr.io/${owner_lc}/${{ env.IMAGE_NAME }}" >> "$GITHUB_ENV" + echo "GHCR_USERNAME=${ghcr_user}" >> "$GITHUB_ENV" + echo "tag=${GITHUB_SHA::7}" >> "$GITHUB_ENV" + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and Push MCP Image + uses: docker/build-push-action@v5 + with: + context: ./kagent-feast-mcp/mcp-server + file: ./kagent-feast-mcp/mcp-server/Dockerfile + push: true + tags: | + ${{ env.IMAGE_REPO }}:${{ env.tag }} + + - name: Configure kubectl for OKE + uses: oracle-actions/configure-kubectl-oke@v1.5.0 + with: + cluster: ${{ secrets.OKE_CLUSTER_OCID }} + + - name: Deploy to OKE + env: + FULL_IMAGE: ${{ env.IMAGE_REPO }}:${{ env.tag }} + GHCR_PULL_TOKEN: ${{ secrets.GHCR_TOKEN || secrets.GHCR_PULL_TOKEN || secrets.Github_Pat }} + GHCR_USERNAME: ${{ env.GHCR_USERNAME }} + run: | + set -euo pipefail + + kubectl create namespace "${{ env.K8S_NAMESPACE }}" --dry-run=client -o yaml | kubectl apply -f - + + kubectl create secret docker-registry ghcrsecret \ + --namespace "${{ env.K8S_NAMESPACE }}" \ + --docker-server="${{ env.REGISTRY }}" \ + --docker-username="${GHCR_USERNAME}" \ + --docker-password="${GHCR_PULL_TOKEN}" \ + --docker-email="${GHCR_USERNAME}@users.noreply.github.com" \ + --dry-run=client -o yaml | kubectl apply -f - + + # Replace pinned manifest image with the commit-scoped tag built above. + sed "s|ghcr.io/kubeflow/mcp-kubeflow-docs:v0.1.0|${FULL_IMAGE}|g" \ + kagent-feast-mcp/manifests/mcp-server/mcp-server.yaml | kubectl apply -f - + kubectl set image deployment/mcp-kubeflow-docs \ + mcp-server="${FULL_IMAGE}" \ + -n "${{ env.K8S_NAMESPACE }}" || true + kubectl patch deployment/mcp-kubeflow-docs -n "${{ env.K8S_NAMESPACE }}" --type=merge \ + -p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"ghcrsecret"}]}}}}' + kubectl rollout status deployment/mcp-kubeflow-docs \ + -n "${{ env.K8S_NAMESPACE }}" --timeout=600s + + kubectl apply -f kagent-feast-mcp/manifests/kagent/setup.yaml + + DEPLOY_KSERVE=false + if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.deploy_kserve }}" = "true" ]; then + DEPLOY_KSERVE=true + elif [ "${{ github.event_name }}" = "push" ]; then + if git diff --name-only --diff-filter=M "${{ github.event.before }}" "${{ github.sha }}" \ + | grep -qE '^kagent-feast-mcp/manifests/vllm/kserve-qwen\.yaml$'; then + DEPLOY_KSERVE=true + fi + fi + + if [ "${DEPLOY_KSERVE}" = "true" ]; then + echo "Removing legacy docs-agent GPU InferenceService (frees GPU for ml-infra/qwen-llm)" + kubectl delete inferenceservice/qwen -n "${{ env.K8S_NAMESPACE }}" --ignore-not-found=true + kubectl delete svc/qwen-llm -n "${{ env.K8S_NAMESPACE }}" --ignore-not-found=true + echo "Applying ml-infra Qwen KServe manifests" + kubectl apply -f kagent-feast-mcp/manifests/vllm/kserve-qwen.yaml + kubectl rollout status deployment -n ml-infra -l serving.kserve.io/inferenceservice=qwen-llm --timeout=600s 2>/dev/null || true + else + echo "Skipping Qwen GPU deploy (no vllm manifest change; use workflow_dispatch to force)" + fi + + - name: Wait for ml-infra dependencies + run: | + set -euo pipefail + kubectl wait --for=condition=Ready inferenceservice/embeddings-service \ + -n ml-infra --timeout=600s + # Milvus CR reports Healthy in .status.status, not a Ready condition. + for i in $(seq 1 60); do + status="$(kubectl get milvus milvus -n ml-infra -o jsonpath='{.status.status}' 2>/dev/null || true)" + if [ "${status}" = "Healthy" ]; then + echo "milvus status=${status}" + break + fi + echo "waiting for milvus (status=${status:-unknown}) attempt ${i}/60" + sleep 10 + done + kubectl get milvus -n ml-infra + test "$(kubectl get milvus milvus -n ml-infra -o jsonpath='{.status.status}')" = "Healthy" + + - name: Smoke test MCP tools and embeddings (ml-infra) + run: | + set -euo pipefail + kubectl rollout status deployment/mcp-kubeflow-docs \ + -n "${{ env.K8S_NAMESPACE }}" --timeout=120s + kubectl exec -n "${{ env.K8S_NAMESPACE }}" deploy/mcp-kubeflow-docs -- \ + python3 /app/smoke_tools.py + kubectl get agent,modelconfig -n "${{ env.K8S_NAMESPACE }}" + + - name: Smoke test Qwen (non-blocking) + continue-on-error: true + run: | + set -euo pipefail + POD="$(kubectl get pods -n ml-infra -l serving.kserve.io/inferenceservice=qwen-llm \ + --field-selector=status.phase=Running \ + -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)" + if [ -z "${POD}" ]; then + echo "No running qwen-llm pod in ml-infra — skipping LLM smoke test" + exit 0 + fi + kubectl exec -n ml-infra "${POD}" -c kserve-container -- python3 -c " + import urllib.request, json + p=json.dumps({'model':'qwen2.5-7B','messages':[{'role':'user','content':'ping'}],'max_tokens':8}).encode() + r=urllib.request.urlopen(urllib.request.Request('http://127.0.0.1:8080/openai/v1/chat/completions',data=p,headers={'Content-Type':'application/json'}), timeout=60) + print('kserve ok', r.status) + " diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 66a8835..24fb956 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,74 +1,74 @@ -name: PR Safety - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - lint: - name: Lint and format - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" - cache: pip - - - name: Install lint tools - run: | - python -m pip install --upgrade pip - python -m pip install ruff==0.15.9 - - - name: Run ruff lint - run: ruff check . - - - name: Check formatting - run: ruff format --check docs-agent-mcp/mcp-server tests - - compile: - name: Python compile check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Compile Python sources - run: | - python -m compileall \ - docs-agent-mcp/pipelines \ - docs-agent-mcp/mcp-server \ - legacy/server \ - legacy/server-https \ - scripts \ - tests - - test: - name: Pytest - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" - cache: 'pip' - cache-dependency-path: requirements-test.txt - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements-test.txt - - - name: Run tests - run: pytest -v --tb=short +name: PR Safety + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + lint: + name: Lint and format + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: pip + + - name: Install lint tools + run: | + python -m pip install --upgrade pip + python -m pip install ruff==0.15.9 + + - name: Run ruff lint + run: ruff check . + + - name: Check formatting + run: ruff format --check kagent-feast-mcp/mcp-server tests + + compile: + name: Python compile check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Compile Python sources + run: | + python -m compileall \ + kagent-feast-mcp/pipelines \ + kagent-feast-mcp/mcp-server \ + legacy/server \ + legacy/server-https \ + scripts \ + tests + + test: + name: Pytest + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: 'pip' + cache-dependency-path: requirements-test.txt + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements-test.txt + + - name: Run tests + run: pytest -v --tb=short diff --git a/.gitignore b/.gitignore index 6496072..3e83a79 100644 --- a/.gitignore +++ b/.gitignore @@ -1,227 +1,227 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[codz] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py.cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# UV -# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -#uv.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock -#poetry.toml - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. -# https://pdm-project.org/en/latest/usage/project/#working-with-version-control -#pdm.lock -#pdm.toml -.pdm-python -.pdm-build/ - -# pixi -# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. -#pixi.lock -# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one -# in the .venv directory. It is recommended not to include this directory in version control. -.pixi - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.envrc -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ -my_env/ -temp/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - -# Abstra -# Abstra is an AI-powered process automation framework. -# Ignore directories containing user credentials, local state, and settings. -# Learn more at https://abstra.io/docs -.abstra/ - -# Visual Studio Code -# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore -# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore -# and can be added to the global gitignore or merged into this file. However, if you prefer, -# you could uncomment the following to ignore the entire vscode folder -# .vscode/ - -# Ruff stuff: -.ruff_cache/ - -# PyPI configuration file -.pypirc - -# Claude Code -.claude/ - -# Cursor -# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to -# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data -# refer to https://docs.cursor.com/context/ignore-files -.cursorignore -.cursorindexingignore - -# Marimo -marimo/_static/ -marimo/_lsp/ -__marimo__/ - -# KFP -test/ - -# Feast artifacts -feast_repo/data/ -feast_repo/registry.db - -# Compiled pipeline YAML -docs-agent-mcp/pipelines/*.yaml -!docs-agent-mcp/pipelines/README.md - -# Local cluster / kubectl notes (optional; keep untracked) -Arch.md -kube.md*.swp +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[codz] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py.cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +#uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock +#poetry.toml + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. +# https://pdm-project.org/en/latest/usage/project/#working-with-version-control +#pdm.lock +#pdm.toml +.pdm-python +.pdm-build/ + +# pixi +# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. +#pixi.lock +# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one +# in the .venv directory. It is recommended not to include this directory in version control. +.pixi + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.envrc +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ +my_env/ +temp/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# Abstra +# Abstra is an AI-powered process automation framework. +# Ignore directories containing user credentials, local state, and settings. +# Learn more at https://abstra.io/docs +.abstra/ + +# Visual Studio Code +# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore +# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore +# and can be added to the global gitignore or merged into this file. However, if you prefer, +# you could uncomment the following to ignore the entire vscode folder +# .vscode/ + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc + +# Claude Code +.claude/ + +# Cursor +# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to +# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data +# refer to https://docs.cursor.com/context/ignore-files +.cursorignore +.cursorindexingignore + +# Marimo +marimo/_static/ +marimo/_lsp/ +__marimo__/ + +# KFP +test/ + +# Feast artifacts +feast_repo/data/ +feast_repo/registry.db + +# Compiled pipeline YAML +kagent-feast-mcp/pipelines/*.yaml +!kagent-feast-mcp/pipelines/README.md + +# Local cluster / kubectl notes (optional; keep untracked) +Arch.md +kube.md*.swp diff --git a/README.md b/README.md index 276dfc4..adac1ac 100644 --- a/README.md +++ b/README.md @@ -1,756 +1,756 @@ -# Kubeflow Documentation AI Assistant - -**Author**: Santhosh Toorpu - -[](https://github.com/kubeflow/community/issues/867) - -The official LLM implementation of the Kubeflow Documentation Assistant powered by Retrieval-Augmented Generation (RAG). This repository provides a comprehensive solution for Kubeflow users to search across documentation and get accurate, contextual answers to their queries. - -## Table of Contents - -- [Overview](#overview) -- [Architecture](#architecture) -- [Prerequisites](#prerequisites) -- [Installation](#installation) - - [Milvus Vector Database](#milvus-vector-database) - - [KServe Inference Service](#kserve-inference-service) - - [Kubeflow Pipelines](#kubeflow-pipelines) - - [API Server](#api-server) -- [Usage](#usage) -- [Configuration](#configuration) -- [Troubleshooting](#troubleshooting) -- [Contributing](#contributing) - -## Repository layout - -| Path | Purpose | -|------|---------| -| `docs-agent-mcp/` | MCP server, Kagent manifests, RAG pipelines, and Terraform platform stack | -| `legacy/` | Historical FastAPI servers, older manifests, and Feast-era pipeline copies | -| `frontend/` | Docs site chatbot assets (`docs_scripts/`, `docs_styles/`) | -| `.github/workflows/` | CI/CD (`oke-cicd.yaml` builds MCP, runs tests, deploys to OKE) | - -## Overview - -### Why This Project Exists - -Kubeflow users often struggle to find relevant information across the extensive documentation scattered across different services, components, and repositories. The traditional search approach lacks context and often returns irrelevant results. This documentation assistant addresses these challenges by: - -- **Semantic Search**: Understanding the intent behind queries rather than just keyword matching -- **Contextual Responses**: Providing answers based on the most relevant documentation chunks -- **Real-time Processing**: Enabling instant responses through streaming APIs -- **Scalable Architecture**: Leveraging Kubernetes for automatic scaling and resource management - -### Key Features - -- 🔍 **Intelligent Search**: Semantic search across Kubeflow documentation -- 🤖 **AI-Powered Responses**: Contextual answers using Llama 3.1-8B model -- ⚡ **Real-time Streaming**: WebSocket and HTTP streaming support -- 🔧 **Tool Calling**: Automatic documentation lookup when needed -- 📊 **Vector Database**: Milvus for efficient similarity search -- 🚀 **Kubernetes Native**: Built for cloud-native environments -- 🔄 **Automated ETL**: Kubeflow Pipelines for data processing - -## Architecture - -### High-Level Architecture - - - -### Data Flow - - - -## Prerequisites - -- Kubernetes cluster (1.20+) -- Helm 3.x -- Kubeflow Pipelines -- GPU nodes (for LLM inference) -- SSL certificate (for HTTPS API) - -## Installation - -### Milvus Vector Database - -#### What is Milvus? - -Milvus is an open-source vector database designed for AI applications. It provides: - -- **High Performance**: Optimized for vector similarity search -- **Scalability**: Horizontal scaling capabilities -- **Multiple Index Types**: Support for various vector indexing algorithms -- **Cloud Native**: Built for Kubernetes environments -- **Multiple APIs**: REST, gRPC, and Python SDK support - -#### Installation Steps - -1. **Add Helm Repository**: - ```bash - helm repo add milvus https://milvus-io.github.io/milvus-helm/ - helm repo update - ``` - -2. **Install Milvus**: - ```bash - helm upgrade --install my-release zilliztech/milvus -n docs-agent \ - --set cluster.enabled=false \ - --set standalone.enabled=true \ - --set etcd.replicaCount=1 \ - --set etcd.persistence.enabled=false \ - --set minio.mode=standalone \ - --set minio.replicas=1 \ - --set pulsar.enabled=false \ - --set pulsarv3.enabled=false \ - --set standalone.podAnnotations."sidecar\.istio\.io/inject"="false" - ``` - -#### Configuration Rationale - -- **Standalone Mode**: Single-node deployment for development/testing -- **Single etcd Replica**: Reduced resource usage with `etcd.persistence.enabled=false` -- **Standalone MinIO**: Single MinIO instance for object storage -- **Disabled Pulsar**: Not needed for standalone deployment -- **Istio Sidecar Injection**: Disabled to avoid networking issues - -3. **Test Connection**: - ```python - from pymilvus import connections - connections.connect("default", host="my-release-milvus.docs-agent.svc.cluster.local", port="19530") - print("Connected to Milvus successfully!") - ``` - -4. **External Access** (if needed for different clusters): - ```bash - kubectl expose service my-release-milvus \ - --name milvus-external \ - --type=NodePort \ - --port=19530 - ``` - -### KServe Inference Service - -The LLM inference is handled by KServe with vLLM backend for high-performance serving. - -#### Serving Runtime Configuration - -```yaml -# manifests/serving-runtime.yaml -apiVersion: serving.kserve.io/v1alpha1 -kind: ServingRuntime -metadata: - name: llm-runtime - namespace: docs-agent -spec: - supportedModelFormats: - - name: huggingface - version: "1" - autoSelect: true - containers: - - name: kserve-container - image: kserve/huggingfaceserver:latest-gpu - command: ["python", "-m", "huggingfaceserver"] - resources: - requests: - cpu: "4" - memory: "16Gi" - nvidia.com/gpu: "1" - limits: - cpu: "6" - memory: "24Gi" - nvidia.com/gpu: "1" -``` - -#### Inference Service Configuration - -```yaml -# manifests/inference-service.yaml -apiVersion: serving.kserve.io/v1beta1 -kind: InferenceService -metadata: - name: llama - namespace: docs-agent -spec: - predictor: - model: - modelFormat: - name: huggingface - version: "1" - runtime: llm-runtime - args: - - --model_name=llama3.1-8B - - --model_id=RedHatAI/Llama-3.1-8B-Instruct - - --backend=vllm - - --max-model-len=32768 - - --gpu-memory-utilization=0.90 - - --enable-auto-tool-choice - - --tool-call-parser=llama3_json - - --enable-tool-call-parser - env: - - name: HF_TOKEN - valueFrom: - secretKeyRef: - name: huggingface-secret - key: token - - name: CUDA_VISIBLE_DEVICES - value: "0" - resources: - requests: - cpu: "4" - memory: "16Gi" - nvidia.com/gpu: "1" - limits: - cpu: "6" - memory: "24Gi" - nvidia.com/gpu: "1" -``` - -#### Key Configuration Points - -- **Tool Calling**: Enabled with `--enable-auto-tool-choice` and `--enable-tool-call-parser` -- **Custom Template**: vLLM supports custom templates for different model formats -- **Resource Allocation**: GPU memory utilization set to 90% for optimal performance -- **HuggingFace Token**: Required for accessing the model - -**Connection Details**: -```python -KSERVE_URL = os.getenv("KSERVE_URL", "http://llama.docs-agent.svc.cluster.local/openai/v1/chat/completions") -MODEL = os.getenv("MODEL", "llama3.1-8B") -``` - -For more details, refer to [KServe documentation](https://kserve.github.io/website/) and [vLLM documentation](https://docs.vllm.ai/). - -### Kubeflow Pipelines - -The ETL (Extract, Transform, Load) process is implemented as a Kubeflow Pipeline for automated, scalable data processing. - -#### Why Kubeflow Pipelines? - -- **Infrastructure Management**: Kubernetes handles all infrastructure automatically -- **Scalability**: Auto-scaling based on workload demands -- **Reproducibility**: Version-controlled pipeline definitions -- **Integration**: Seamless integration with other Kubeflow components -- **CI/CD Ready**: Can be triggered via GitHub Actions or other automation tools - -#### Pipeline Components - -The pipeline consists of three main phases: - -##### 1. Repository Fetching - -```python -@dsl.component( - base_image="python:3.9", - packages_to_install=["requests", "beautifulsoup4"] -) -def download_github_directory( - repo_owner: str, - repo_name: str, - directory_path: str, - github_token: str, - github_data: dsl.Output[dsl.Dataset] -): - # Fetches documentation files from GitHub repositories - # Supports .md and .html files - # Handles authentication and recursive directory traversal -``` - -##### 2. Text Chunking and Embedding - -```python -@dsl.component( - base_image="pytorch/pytorch:2.3.0-cuda12.1-cudnn8-runtime", - packages_to_install=["sentence-transformers", "langchain"] -) -def chunk_and_embed( - github_data: dsl.Input[dsl.Dataset], - repo_name: str, - base_url: str, - chunk_size: int, - chunk_overlap: int, - embedded_data: dsl.Output[dsl.Dataset] -): - # Processes text with aggressive cleaning - # Creates embeddings using sentence-transformers - # Handles chunking with configurable overlap -``` - -##### 3. Vector Database Storage - -```python -@dsl.component( - base_image="python:3.9", - packages_to_install=["pymilvus", "numpy"] -) -def store_milvus( - embedded_data: dsl.Input[dsl.Dataset], - milvus_host: str, - milvus_port: str, - collection_name: str -): - # Creates Milvus collection with proper schema - # Inserts vectors in batches for efficiency - # Creates indexes for optimal search performance -``` - -#### RBAC Configuration - -For Kubeflow Pipelines to access Milvus, proper RBAC permissions are required: - -```bash -# Create role for Milvus access -kubectl create role milvus-access \ - --namespace docs-agent \ - --verb=get,list,watch \ - --resource=services,endpoints - -# Bind role to KFP service account -kubectl create rolebinding kfp-to-milvus-editor \ - --namespace docs-agent \ - --role=milvus-access \ - --serviceaccount=kubeflow:default-editor -``` - -**Note**: Without these permissions, you'll encounter RBAC errors during the embedding phase. - -#### Future Improvements - -A better improvement would be using the embedding model as a service where users could call the service instead of installing heavy sentence transformers package every time. This would: - -- Reduce pipeline execution time -- Lower resource requirements -- Enable better caching and optimization -- Improve scalability - -### API Server - -Two API implementations are provided for different use cases: - -#### WebSocket API (`server/app.py`) - -**Use Case**: Real-time chat applications, interactive interfaces - -**Features**: -- Bidirectional communication -- Real-time streaming responses -- Tool call execution with live updates -- Connection management and error handling - -**Key Components**: -```python -async def handle_websocket(websocket, path): - """Handle WebSocket connections with tool calling support""" - # Manages connection lifecycle - # Handles message routing and tool execution - # Provides real-time streaming responses - -async def stream_llm_response(payload, websocket, citations_collector): - """Stream LLM responses with tool call handling""" - # Processes streaming responses from KServe - # Manages tool call accumulation and execution - # Handles follow-up requests after tool execution -``` - -#### HTTPS API (`server-https/app.py`) - -**Use Case**: RESTful integrations, server-to-server communication, web applications - -**Key Features**: -- **Dual Response Modes**: Both streaming (Server-Sent Events) and non-streaming JSON responses -- **RAG Integration**: Automatic tool calling for Kubeflow documentation search -- **CORS Support**: Full cross-origin resource sharing for web applications -- **FastAPI Framework**: Automatic OpenAPI documentation and type validation -- **Production Ready**: Health checks, error handling, and Kubernetes integration -- **Citation Management**: Automatic collection and deduplication of source citations - -**API Endpoints**: - -**Main Chat Endpoint**: -```python -@app.post("/chat") -async def chat(request: ChatRequest): - """Main chat endpoint with RAG capabilities""" - # Supports both streaming and non-streaming responses - # Handles tool calling and citation collection - # Returns structured JSON responses -``` - -**Health Check Endpoint**: -```python -@app.get("/health") -async def health_check(): - """Health check for Kubernetes probes""" - # Essential for production deployments - # Used by readiness and liveness probes -``` - -**Request/Response Models**: -```python -class ChatRequest(BaseModel): - message: str - stream: Optional[bool] = True # Default to streaming - -# Streaming Response (SSE) -data: {"type": "content", "content": "response text"} -data: {"type": "tool_result", "tool_name": "search_kubeflow_docs", "content": "search results"} -data: {"type": "citations", "citations": ["url1", "url2"]} -data: {"type": "done"} - -# Non-streaming Response -{ - "response": "Complete response text", - "citations": ["url1", "url2"] # or null if no citations -} -``` - -**Advanced Features**: - -- **Intelligent Tool Calling**: Automatically determines when to search documentation based on query context -- **Streaming Tool Execution**: Real-time tool call execution with live updates -- **Citation Tracking**: Automatic collection and deduplication of source URLs -- **Error Handling**: Comprehensive error handling with detailed error messages -- **CORS Configuration**: Full CORS support for web application integration -- **Resource Management**: Proper connection pooling and cleanup for Milvus and KServe - -#### SSL Certificate Requirements - -**Critical**: Both APIs require SSL certificates from a trusted Certificate Authority. Without proper SSL certificates, browsers will block WebSocket connections and HTTPS requests. - -## Usage - -### Starting the Services - -1. **Deploy Milvus and KServe** (as described above) - -2. **Run the Pipeline**: - ```bash - python docs-agent-mcp/pipelines/kubeflow-pipeline.py - ``` - -3. **Start the API Server**: - ```bash - # WebSocket API - python server/app.py - - # HTTPS API - python server-https/app.py - ``` - -### API Usage Examples - -#### WebSocket API - -```javascript -const ws = new WebSocket('wss://your-domain.com:8000'); - -ws.onmessage = function(event) { - const data = JSON.parse(event.data); - switch(data.type) { - case 'content': - // Handle streaming content - break; - case 'citations': - // Handle citations - break; - case 'done': - // Handle completion - break; - } -}; - -ws.send(JSON.stringify({ - message: "How do I create a Kubeflow pipeline?" -})); -``` - -#### HTTPS API - -**Streaming Request (Server-Sent Events)**: -```bash -curl -X POST "https://your-domain.com/chat" \ - -H "Content-Type: application/json" \ - -H "Accept: text/event-stream" \ - -d '{"message": "What is KServe?", "stream": true}' -``` - -**Non-streaming Request (JSON Response)**: -```bash -curl -X POST "https://your-domain.com/chat" \ - -H "Content-Type: application/json" \ - -d '{"message": "What is KServe?", "stream": false}' -``` - -**JavaScript Integration Example**: -```javascript -// Streaming request -const response = await fetch('https://your-domain.com/chat', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Accept': 'text/event-stream' - }, - body: JSON.stringify({ - message: 'How do I create a Kubeflow pipeline?', - stream: true - }) -}); - -const reader = response.body.getReader(); -const decoder = new TextDecoder(); - -while (true) { - const { done, value } = await reader.read(); - if (done) break; - - const chunk = decoder.decode(value); - const lines = chunk.split('\n'); - - for (const line of lines) { - if (line.startsWith('data: ')) { - const data = JSON.parse(line.slice(6)); - switch(data.type) { - case 'content': - console.log('Content:', data.content); - break; - case 'tool_result': - console.log('Tool:', data.tool_name, data.content); - break; - case 'citations': - console.log('Citations:', data.citations); - break; - case 'done': - console.log('Response complete'); - break; - } - } - } -} -``` - -**Python Integration Example**: -```python -import requests -import json - -# Non-streaming request -response = requests.post( - 'https://your-domain.com/chat', - json={ - 'message': 'What is KServe?', - 'stream': False - } -) - -data = response.json() -print(f"Response: {data['response']}") -if data.get('citations'): - print(f"Sources: {data['citations']}") -``` - -## Configuration - -### Environment Variables - -
| Variable | -Default | -Description | -
|---|---|---|
KSERVE_URL |
-http://llama.docs-agent.svc.cluster.local/openai/v1/chat/completions |
-KServe endpoint URL | -
MODEL |
-llama3.1-8B |
-Model name | -
PORT |
-8000 |
-API server port | -
MILVUS_HOST |
-my-release-milvus.docs-agent.svc.cluster.local |
-Milvus host | -
MILVUS_PORT |
-19530 |
-Milvus port | -
MILVUS_COLLECTION |
-kubeflow_docs |
-Milvus collection name | -
EMBEDDING_MODEL |
-sentence-transformers/all-mpnet-base-v2 |
-Embedding model | -
| Parameter | -Default | -Description | -
|---|---|---|
repo_owner |
-kubeflow |
-GitHub repository owner | -
repo_name |
-website |
-GitHub repository name | -
directory_path |
-content/en |
-Documentation directory path | -
chunk_size |
-1000 |
-Text chunk size for embedding | -
chunk_overlap |
-100 |
-Overlap between chunks | -
base_url |
-https://www.kubeflow.org/docs |
-Base URL for citations | -
milvus_host |
-milvus-standalone-final.docs-agent.svc.cluster.local |
-Milvus host (used by kubeflow-pipeline.py and incremental-pipeline.py) |
-
| Variable | +Default | +Description | +
|---|---|---|
KSERVE_URL |
+http://llama.docs-agent.svc.cluster.local/openai/v1/chat/completions |
+KServe endpoint URL | +
MODEL |
+llama3.1-8B |
+Model name | +
PORT |
+8000 |
+API server port | +
MILVUS_HOST |
+my-release-milvus.docs-agent.svc.cluster.local |
+Milvus host | +
MILVUS_PORT |
+19530 |
+Milvus port | +
MILVUS_COLLECTION |
+kubeflow_docs |
+Milvus collection name | +
EMBEDDING_MODEL |
+sentence-transformers/all-mpnet-base-v2 |
+Embedding model | +
| Parameter | +Default | +Description | +
|---|---|---|
repo_owner |
+kubeflow |
+GitHub repository owner | +
repo_name |
+website |
+GitHub repository name | +
directory_path |
+content/en |
+Documentation directory path | +
chunk_size |
+1000 |
+Text chunk size for embedding | +
chunk_overlap |
+100 |
+Overlap between chunks | +
base_url |
+https://www.kubeflow.org/docs |
+Base URL for citations | +
milvus_host |
+milvus-standalone-final.docs-agent.svc.cluster.local |
+Milvus host (used by kubeflow-pipeline.py and incremental-pipeline.py) |
+
Hello world
Hello world