Skip to content

Commit 351dc2f

Browse files
authored
feat: add MedAssist demo Docker image + CI pipeline (#17)
feat: MedAssist demo Docker image + CI pipeline. Refs devonartis/agentwrit#31, Refs devonartis/agentwrit#33
1 parent e3b9fdc commit 351dc2f

5 files changed

Lines changed: 160 additions & 8 deletions

File tree

.github/workflows/ci.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ jobs:
5959
env:
6060
AA_PORT: "8080"
6161
AA_BIND_ADDRESS: "0.0.0.0"
62-
AA_ADMIN_SECRET: ${{ secrets.AA_ADMIN_SECRET }}
62+
# Broker binary uses AA_ prefix (devonartis/agentwrit#44)
63+
AA_ADMIN_SECRET: ${{ secrets.AGENTWRIT_ADMIN_SECRET }}
6364
options: >-
6465
--health-cmd "wget --spider -q http://localhost:8080/v1/health"
6566
--health-interval 2s
@@ -75,7 +76,7 @@ jobs:
7576
id: register-app
7677
env:
7778
AGENTWRIT_BROKER_URL: http://localhost:8080
78-
AA_ADMIN_SECRET: ${{ secrets.AA_ADMIN_SECRET }}
79+
AA_ADMIN_SECRET: ${{ secrets.AGENTWRIT_ADMIN_SECRET }}
7980
run: |
8081
# Authenticate as admin
8182
ADMIN_TOKEN=$(curl -sf -X POST "${AGENTWRIT_BROKER_URL}/v1/admin/auth" \
@@ -99,7 +100,7 @@ jobs:
99100
- name: Run integration tests (all 15 stories)
100101
env:
101102
AGENTWRIT_BROKER_URL: http://localhost:8080
102-
AGENTWRIT_ADMIN_SECRET: ${{ secrets.AA_ADMIN_SECRET }}
103+
AGENTWRIT_ADMIN_SECRET: ${{ secrets.AGENTWRIT_ADMIN_SECRET }}
103104
AGENTWRIT_CLIENT_ID: ${{ steps.register-app.outputs.client_id }}
104105
AGENTWRIT_CLIENT_SECRET: ${{ steps.register-app.outputs.client_secret }}
105106
run: |
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Build & Push MedAssist Demo
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- "demo/**"
8+
- "src/**"
9+
- "pyproject.toml"
10+
- "uv.lock"
11+
workflow_dispatch:
12+
13+
permissions:
14+
contents: read
15+
16+
jobs:
17+
build-and-push:
18+
name: Build & Push Docker Image
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- name: Set up Docker Buildx
24+
uses: docker/setup-buildx-action@v3
25+
26+
- name: Log in to Docker Hub
27+
uses: docker/login-action@v3
28+
with:
29+
username: ${{ secrets.DOCKERHUB_USERNAME }}
30+
password: ${{ secrets.DOCKERHUB_TOKEN }}
31+
32+
- name: Extract version from pyproject.toml
33+
id: version
34+
run: |
35+
VERSION=$(grep '^version' pyproject.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
36+
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
37+
echo "Version: ${VERSION}"
38+
39+
- name: Build and push
40+
uses: docker/build-push-action@v6
41+
with:
42+
context: .
43+
file: demo/Dockerfile
44+
push: true
45+
tags: |
46+
devonartis/agentwrit-medassist:latest
47+
devonartis/agentwrit-medassist:${{ steps.version.outputs.version }}
48+
cache-from: type=gha
49+
cache-to: type=gha,mode=max

demo/Dockerfile

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
FROM python:3.13-slim AS base
2+
3+
# System deps for cryptography wheel
4+
RUN apt-get update && apt-get install -y --no-install-recommends \
5+
gcc libffi-dev curl \
6+
&& rm -rf /var/lib/apt/lists/*
7+
8+
# Install uv
9+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
10+
11+
WORKDIR /app
12+
13+
# Copy build metadata (hatchling needs README.md)
14+
COPY pyproject.toml uv.lock README.md ./
15+
16+
# Install all dependencies including demo deps (layer cache)
17+
COPY src/ src/
18+
RUN uv sync --frozen
19+
20+
# Copy demo app
21+
COPY demo/ demo/
22+
23+
# Demo entrypoint
24+
COPY demo/entrypoint.sh /entrypoint.sh
25+
RUN chmod +x /entrypoint.sh
26+
27+
EXPOSE 5000
28+
29+
# Runtime config — secrets passed at run time, not baked in
30+
ENV AGENTWRIT_BROKER_URL=http://broker:8080
31+
ENV LLM_BASE_URL=https://api.openai.com/v1
32+
ENV LLM_MODEL=gpt-4o-mini
33+
34+
ENTRYPOINT ["/entrypoint.sh"]

demo/entrypoint.sh

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/bin/sh
2+
set -e
3+
4+
# Wait for broker to be healthy
5+
echo "Waiting for broker at ${AGENTWRIT_BROKER_URL}..."
6+
until curl -sf "${AGENTWRIT_BROKER_URL}/v1/health" > /dev/null 2>&1; do
7+
sleep 1
8+
done
9+
echo "Broker is ready."
10+
11+
# Auto-register app if no client credentials provided
12+
if [ -z "${AGENTWRIT_CLIENT_ID}" ] || [ -z "${AGENTWRIT_CLIENT_SECRET}" ]; then
13+
echo "No client credentials — registering app with broker..."
14+
15+
if [ -z "${AGENTWRIT_ADMIN_SECRET}" ]; then
16+
echo "ERROR: AGENTWRIT_ADMIN_SECRET required for auto-registration"
17+
exit 1
18+
fi
19+
20+
# Authenticate as admin
21+
ADMIN_TOKEN=$(curl -sf -X POST "${AGENTWRIT_BROKER_URL}/v1/admin/auth" \
22+
-H "Content-Type: application/json" \
23+
-d "{\"secret\":\"${AGENTWRIT_ADMIN_SECRET}\"}" \
24+
| python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
25+
26+
# Register the demo app
27+
APP_JSON=$(curl -sf -X POST "${AGENTWRIT_BROKER_URL}/v1/admin/apps" \
28+
-H "Content-Type: application/json" \
29+
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
30+
-d '{
31+
"name": "medassist-demo",
32+
"scopes": [
33+
"read:records:*", "write:records:*", "read:labs:*",
34+
"write:prescriptions:*", "read:formulary:*",
35+
"read:billing:*", "write:billing:*", "read:insurance:*"
36+
],
37+
"token_ttl": 1800
38+
}')
39+
40+
export AGENTWRIT_CLIENT_ID=$(echo "${APP_JSON}" | python3 -c "import sys,json; print(json.load(sys.stdin)['client_id'])")
41+
export AGENTWRIT_CLIENT_SECRET=$(echo "${APP_JSON}" | python3 -c "import sys,json; print(json.load(sys.stdin)['client_secret'])")
42+
43+
echo "App registered: ${AGENTWRIT_CLIENT_ID}"
44+
fi
45+
46+
echo "Starting MedAssist AI on port 5000..."
47+
exec uv run uvicorn demo.app:app --host 0.0.0.0 --port 5000

docker-compose.yml

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ services:
22
broker:
33
image: devonartis/agentwrit:latest
44
ports:
5-
- "${AA_HOST_PORT:-8080}:8080"
5+
- "${AGENTWRIT_HOST_PORT:-8080}:8080"
66
environment:
7+
# Broker binary still uses AA_ prefix (devonartis/agentwrit#44).
8+
# We map from AGENTWRIT_ so users never see the legacy prefix.
79
- AA_PORT=8080
8-
- AA_BIND_ADDRESS=${AA_BIND_ADDRESS:-0.0.0.0}
9-
- AA_ADMIN_SECRET=${AA_ADMIN_SECRET:-}
10-
- AA_SEED_TOKENS=${AA_SEED_TOKENS:-false}
11-
- AA_LOG_LEVEL=${AA_LOG_LEVEL:-standard}
10+
- AA_BIND_ADDRESS=0.0.0.0
11+
- AA_ADMIN_SECRET=${AGENTWRIT_ADMIN_SECRET:-}
12+
- AA_SEED_TOKENS=${AGENTWRIT_SEED_TOKENS:-false}
13+
- AA_LOG_LEVEL=${AGENTWRIT_LOG_LEVEL:-standard}
1214
volumes:
1315
- broker-data:/data
1416
healthcheck:
@@ -17,5 +19,24 @@ services:
1719
timeout: 3s
1820
retries: 10
1921

22+
medassist:
23+
image: devonartis/agentwrit-medassist:latest
24+
build:
25+
context: .
26+
dockerfile: demo/Dockerfile
27+
ports:
28+
- "${AGENTWRIT_DEMO_PORT:-5000}:5000"
29+
environment:
30+
- AGENTWRIT_BROKER_URL=http://broker:8080
31+
- AGENTWRIT_ADMIN_SECRET=${AGENTWRIT_ADMIN_SECRET:-}
32+
- AGENTWRIT_CLIENT_ID=${AGENTWRIT_CLIENT_ID:-}
33+
- AGENTWRIT_CLIENT_SECRET=${AGENTWRIT_CLIENT_SECRET:-}
34+
- LLM_BASE_URL=${LLM_BASE_URL:-https://api.openai.com/v1}
35+
- LLM_API_KEY=${LLM_API_KEY:-}
36+
- LLM_MODEL=${LLM_MODEL:-gpt-4o-mini}
37+
depends_on:
38+
broker:
39+
condition: service_healthy
40+
2041
volumes:
2142
broker-data:

0 commit comments

Comments
 (0)