first commit

This commit is contained in:
David Xu
2025-06-07 18:24:34 -07:00
commit 4886fb3236
8 changed files with 410 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
OPENAI_API_KEY=<your-openai-api-key>
LANGSMITH_API_KEY=<your-langsmith-api-key>
+170
View File
@@ -0,0 +1,170 @@
name: Create New Deployment
# Trigger the workflow on push or pull request merge to main
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
types: [ closed ]
# Set environment variables
env:
PYTHON_VERSION: '3.11'
REGISTRY: docker.io # Change to ghcr.io for GitHub Container Registry
IMAGE_NAME: davidxu33/control-plane-api-demo # Replace YOUR_DOCKERHUB_USERNAME with your actual Docker Hub username
jobs:
# Job 1: Run custom logic and tests
run-custom-logic:
if: false && (github.ref == 'refs/heads/main' || (github.event.pull_request.merged == true))
runs-on: ubuntu-latest
outputs:
should-deploy: ${{ steps.validation.outputs.deploy }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then
pip install -r requirements.txt
fi
- name: Run validation and tests
id: validation
run: |
echo "✅ Skipping validation tests - proceeding with deployment"
# Set output to indicate that deployment should proceed
echo "deploy=true" >> $GITHUB_OUTPUT
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Job 2: Build and push Docker image
build-and-push:
needs: run-custom-logic
if: needs.run-custom-logic.outputs.should-deploy == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # Required for pushing to GitHub Container Registry
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Step 1: Set up Docker Buildx (advanced Docker build features)
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Step 2: Log in to Docker registry
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
# Step 3: Extract metadata for Docker tags and labels
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
# Branch-based tags
type=ref,event=branch
# SHA-based tags
type=sha,prefix={{branch}}-
# Latest tag for main branch
type=raw,value=latest,enable={{is_default_branch}}
# Semantic versioning (if you use git tags)
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
labels: |
org.opencontainers.image.title=LangGraph AI Agent
org.opencontainers.image.description=AI Agent built with LangGraph
org.opencontainers.image.vendor=YourCompany
# Step 4: Build and push Docker image
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile # Path to your Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64 # Multi-platform build
cache-from: type=gha # Use GitHub Actions cache
cache-to: type=gha,mode=max
build-args: |
PYTHON_VERSION=${{ env.PYTHON_VERSION }}
BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}
# Step 5: Output image details
- name: Output image details
run: |
echo "🐳 Docker image built and pushed successfully!"
echo "📦 Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
echo "🏷️ Tags: ${{ steps.meta.outputs.tags }}"
echo "📋 Digest: ${{ steps.build.outputs.digest }}"
# Job 3: Post-deployment actions (optional)
post-deployment:
needs: [run-custom-logic, build-and-push]
if: success()
runs-on: ubuntu-latest
steps:
- name: Deploy notification
run: |
echo "✅ Deployment completed successfully!"
echo "🚀 New image available at: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest"
# Deploy to LangChain hosted platform
- name: Trigger LangChain deployment
run: |
echo "🚀 Triggering deployment to LangChain hosted platform..."
response=$(curl -s -w "HTTPSTATUS:%{http_code}" \
https://gtm.smith.langchain.dev/api-host/v1/projects \
--request POST \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: ${{ secrets.LANGSMITH_API_KEY }}' \
--data '{
"name": "multi-agent-${{ github.sha }}",
"lc_hosted": false,
"env_vars": [{"name": "OPENAI_API_KEY", "value": "${{ secrets.OPENAI_API_KEY }}", "type": "secret"}],
"deployment_type": "dev",
"shareable": false,
"image_path": "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest",
"build_on_push": false
}')
# Extract HTTP status and response body
http_status=$(echo $response | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
response_body=$(echo $response | sed -e 's/HTTPSTATUS\:.*//g')
# Check if deployment was successful
if [ $http_status -eq 200 ] || [ $http_status -eq 201 ]; then
echo "✅ LangChain deployment triggered successfully!"
echo "📋 Response: $response_body"
else
echo "❌ LangChain deployment failed with status: $http_status"
echo "📋 Response: $response_body"
exit 1
fi
+161
View File
@@ -0,0 +1,161 @@
name: Create New Revision
# Trigger the workflow on push to main
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
types: [ closed ]
# Set environment variables
env:
PYTHON_VERSION: '3.11'
REGISTRY: docker.io
IMAGE_NAME: davidxu33/control-plane-api-demo
PROJECT_ID: 'd6cee583-a32a-4342-a748-3dfc857ba964' # Replace with your actual project ID
jobs:
# Job 1: Run validation
validate:
if: github.ref == 'refs/heads/main' || (github.event.pull_request.merged == true)
runs-on: ubuntu-latest
outputs:
should-deploy: ${{ steps.validation.outputs.deploy }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then
pip install -r requirements.txt
fi
- name: Run validation
id: validation
run: |
echo "✅ Validation passed - proceeding with revision update"
echo "deploy=true" >> $GITHUB_OUTPUT
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Job 2: Build and push Docker image
build-and-push:
needs: validate
if: needs.validate.outputs.should-deploy == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
labels: |
org.opencontainers.image.title=LangGraph AI Agent
org.opencontainers.image.description=AI Agent built with LangGraph
org.opencontainers.image.vendor=YourCompany
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
PYTHON_VERSION=${{ env.PYTHON_VERSION }}
BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}
- name: Output image details
run: |
echo "🐳 Docker image built and pushed successfully!"
echo "📦 Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
echo "🏷️ Tags: ${{ steps.meta.outputs.tags }}"
# Job 3: Update project revision
update-revision:
needs: [validate, build-and-push]
if: success()
runs-on: ubuntu-latest
steps:
- name: Update notification
run: |
echo "🔄 Updating project revision..."
echo "📦 Project ID: ${{ env.PROJECT_ID }}"
echo "🚀 New image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest"
- name: Update LangChain project revision
run: |
echo "🔄 Triggering revision update for project ${{ env.PROJECT_ID }}..."
response=$(curl -s -w "HTTPSTATUS:%{http_code}" \
https://gtm.smith.langchain.dev/api-host/v1/projects/${{ env.PROJECT_ID }}/revisions \
--request POST \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: ${{ secrets.LANGSMITH_API_KEY }}' \
--data '{
"image_path": "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest",
"env_vars": [{"name": "OPENAI_API_KEY", "value": "${{ secrets.OPENAI_API_KEY }}", "type": "secret"}]
}')
# Extract HTTP status and response body
http_status=$(echo $response | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
response_body=$(echo $response | sed -e 's/HTTPSTATUS\:.*//g')
# Check if revision update was successful
if [ $http_status -eq 200 ] || [ $http_status -eq 201 ]; then
echo "✅ Project revision updated successfully!"
echo "📋 Response: $response_body"
else
echo "❌ Project revision update failed with status: $http_status"
echo "📋 Response: $response_body"
exit 1
fi
- name: Success notification
run: |
echo "🎉 Revision update completed successfully!"
echo "📦 Project: ${{ env.PROJECT_ID }}"
echo "🚀 Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest"
+1
View File
@@ -0,0 +1 @@
.env
+37
View File
@@ -0,0 +1,37 @@
FROM langchain/langgraph-api:3.11
# -- Installing local requirements --
ADD requirements.txt /deps/__outer_control-plane-api-demo/src/requirements.txt
RUN PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt -r /deps/__outer_control-plane-api-demo/src/requirements.txt
# -- End of local requirements install --
# -- Adding non-package dependency control-plane-api-demo --
ADD . /deps/__outer_control-plane-api-demo/src
RUN set -ex && \
for line in '[project]' \
'name = "control-plane-api-demo"' \
'version = "0.1"' \
'[tool.setuptools.package-data]' \
'"*" = ["**/*"]'; do \
echo "$line" >> /deps/__outer_control-plane-api-demo/pyproject.toml; \
done
# -- End of non-package dependency control-plane-api-demo --
# -- Installing all local dependencies --
RUN PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt -e /deps/*
# -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{"agent": "/deps/__outer_control-plane-api-demo/src/agent.py:graph"}'
# -- Ensure user deps didn't inadvertently overwrite langgraph-api
RUN mkdir -p /api/langgraph_api /api/langgraph_runtime /api/langgraph_license && touch /api/langgraph_api/__init__.py /api/langgraph_runtime/__init__.py /api/langgraph_license/__init__.py
RUN PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir --no-deps -e /api
# -- End of ensuring user deps didn't inadvertently overwrite langgraph-api --
# -- Removing pip from the final image ~<:===~~~ --
RUN pip uninstall -y pip setuptools wheel && rm -rf /usr/local/lib/python*/site-packages/pip* /usr/local/lib/python*/site-packages/setuptools* /usr/local/lib/python*/site-packages/wheel* && find /usr/local/bin -name "pip*" -delete
# -- End of pip removal --
WORKDIR /deps/__outer_control-plane-api-demo/src
+28
View File
@@ -0,0 +1,28 @@
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
class State(TypedDict):
# Messages have the type "list". The `add_messages` function
# in the annotation defines how this state key should be updated
# (in this case, it appends messages to the list, rather than overwriting them)
messages: Annotated[list, add_messages]
graph_builder = StateGraph(State)
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="o3-mini")
def chatbot(state: State):
return {"messages": [llm.invoke(state["messages"])]}
graph_builder.add_node("chatbot", chatbot)
graph_builder.add_edge(START, "chatbot")
graph_builder.add_edge("chatbot", END)
graph = graph_builder.compile()
+8
View File
@@ -0,0 +1,8 @@
{
"dependencies": ["."],
"graphs": {
"agent": "./agent.py:graph"
},
"env": ".env"
}
+3
View File
@@ -0,0 +1,3 @@
langgraph
langchain-openai
typing_extensions