Skip to content

Commit 2d8ce75

Browse files
committed
v0.2.0: Simplify provider, fix compose-openwebui mounts, clean up build
Provider: - Extract duplicated usage-parsing into _extract_usage() - Replace if/elif role chain with ROLE_PREFIXES dict lookup - datetime.now().timestamp() → time.time() - Remove redundant else branch in completion() - Rename internal methods to private (_format_prompt, _extract_model, _build_response) Bug fix: - compose-openwebui.yaml: wrong volume mount paths (./providers:/app/providers instead of ./providers:/app/config/providers, ./config:/app/config instead of file-level mount) — would break provider loading at runtime Build: - Remove redundant BUILDKIT_INLINE_CACHE=1 (already using GHA cache) - Consolidate 3 separate docker run test invocations into one - Clean up release job (inline variables, deduplicate comments) Cleanup: - Remove redundant Dockerfile/entrypoint comments - Remove overly broad .gitignore wildcards (*api*key*, *secret*, *token*) - Fix .env.openwebui.example reference to nonexistent compose file - Consolidate CHANGELOG v0.1.0 duplicate sections
1 parent a2ecac7 commit 2d8ce75

9 files changed

Lines changed: 110 additions & 185 deletions

File tree

.env.example

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
# LiteLLM Environment Configuration
22

33
# REQUIRED: Master key protects access to your authenticated Claude instance
4-
# Keys MUST start with 'sk-' (LiteLLM requirement)
5-
# Replace with your own key before use
6-
# Generate a secure key: echo "sk-$(openssl rand -hex 32)"
7-
# Or for development: sk-dev-test-key
4+
# Must start with 'sk-' (LiteLLM requirement)
5+
# Generate one: echo "sk-$(openssl rand -hex 32)"
86
LITELLM_MASTER_KEY=sk-your-desired-custom-key
97

108
# Database configuration (required for LiteLLM)

.env.openwebui.example

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
# Open WebUI Test Configuration
2-
# Copy this to .env to use with compose-openwebui.yaml or compose-openwebui-https.yaml
3-
4-
# Use existing LiteLLM configuration from main .env file
5-
# Or set these values for testing:
1+
# Open WebUI Configuration
2+
# Copy this to .env to use with compose-openwebui.yaml
63

74
# REQUIRED: Master key for LiteLLM API access
85
LITELLM_MASTER_KEY=sk-your-test-key-here

.github/workflows/build-and-publish.yml

Lines changed: 16 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,6 @@ jobs:
6969
labels: ${{ steps.meta.outputs.labels }}
7070
cache-from: type=gha
7171
cache-to: type=gha,mode=max
72-
build-args: |
73-
BUILDKIT_INLINE_CACHE=1
7472

7573
test:
7674
if: github.event_name == 'pull_request'
@@ -83,28 +81,17 @@ jobs:
8381
- name: Build test image
8482
run: docker build -t litellm-claude-test .
8583

86-
- name: Test container
84+
- name: Verify container dependencies
8785
run: |
88-
# Test that the container can start
8986
docker run --rm \
9087
-e LITELLM_MASTER_KEY=sk-test-key \
9188
-e CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-test \
9289
litellm-claude-test \
93-
python --version
94-
95-
# Test that LiteLLM is installed
96-
docker run --rm \
97-
-e LITELLM_MASTER_KEY=sk-test-key \
98-
-e CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-test \
99-
litellm-claude-test \
100-
litellm --version || echo "LiteLLM version check"
101-
102-
# Test that the Claude Agent SDK is importable
103-
docker run --rm \
104-
-e LITELLM_MASTER_KEY=sk-test-key \
105-
-e CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-test \
106-
litellm-claude-test \
107-
python -c "import claude_agent_sdk; print('Claude Agent SDK available')"
90+
bash -c '
91+
python --version &&
92+
litellm --version &&
93+
python -c "import claude_agent_sdk; print(\"Claude Agent SDK available\")"
94+
'
10895
10996
release:
11097
needs: build
@@ -120,44 +107,33 @@ jobs:
120107
fetch-depth: 0
121108
token: ${{ secrets.GITHUB_TOKEN }}
122109

123-
- name: Get latest tag
110+
- name: Compute next patch version
124111
id: get_latest_tag
125112
run: |
126-
# Get the latest tag, defaulting to v0.0.0 if no tags exist
127113
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
128114
echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT
129-
130-
# Extract version numbers
115+
131116
VERSION=${LATEST_TAG#v}
132117
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
133-
134-
# Increment patch version
135-
NEW_PATCH=$((PATCH + 1))
136-
NEW_TAG="v${MAJOR}.${MINOR}.${NEW_PATCH}"
137-
118+
NEW_TAG="v${MAJOR}.${MINOR}.$((PATCH + 1))"
119+
138120
echo "new_tag=$NEW_TAG" >> $GITHUB_OUTPUT
139-
echo "Latest tag: $LATEST_TAG"
140-
echo "New tag: $NEW_TAG"
141-
121+
echo "Latest: $LATEST_TAG -> Next: $NEW_TAG"
122+
142123
- name: Generate release notes
143-
id: release_notes
144124
run: |
145-
# Get commit messages since last tag
146125
LATEST_TAG=${{ steps.get_latest_tag.outputs.latest_tag }}
147-
126+
148127
echo "## What's Changed" > release_notes.md
149128
echo "" >> release_notes.md
150-
151-
# Get commit messages since last tag
129+
152130
if [ "$LATEST_TAG" == "v0.0.0" ]; then
153131
git log --pretty=format:"* %s (%h)" >> release_notes.md
154132
else
155133
git log ${LATEST_TAG}..HEAD --pretty=format:"* %s (%h)" >> release_notes.md
156134
fi
157-
158-
echo "" >> release_notes.md
159-
echo "" >> release_notes.md
160-
echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${LATEST_TAG}...${{ steps.get_latest_tag.outputs.new_tag }}" >> release_notes.md
135+
136+
echo -e "\n\n**Full Changelog**: https://github.com/${{ github.repository }}/compare/${LATEST_TAG}...${{ steps.get_latest_tag.outputs.new_tag }}" >> release_notes.md
161137
162138
- name: Create and push tag
163139
run: |

.gitignore

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,13 @@ Thumbs.db
9696
tmp/
9797
temp/
9898

99-
# API keys and secrets (backup protection)
100-
*api*key*
101-
*secret*
102-
*token*
99+
# Secrets and credentials
103100
credentials.*
101+
*.pem.key
102+
*.key.pem
104103

105104
# OAuth tokens and Claude credentials
106-
.claude
105+
.claude
107106
.claude.json
108107
claude.json
109108
**/claude.json
@@ -113,11 +112,8 @@ claude.json
113112
.serena/
114113
certs/
115114

116-
# Test files and directories
115+
# Test files
117116
tests/
118117
test_*.py
119118
test-*.sh
120119
test_*.sh
121-
122-
# Dev research
123-
.archive/docker-compose.override.yml

CHANGELOG.md

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,12 @@ All notable changes to this project will be documented in this file.
2323
## [0.1.0] - 2025-07-19
2424

2525
### Added
26-
- Initial release of LiteLLM Claude Code Provider
27-
- Custom LiteLLM provider implementation for Claude Code SDK
28-
- Support for all Claude models (Opus, Sonnet, Haiku) via OpenAI-compatible API
29-
- OAuth authentication support for Claude Pro/Max users
30-
- Docker-based deployment with automated image publishing
26+
- Custom LiteLLM provider for Claude Code SDK with OpenAI API compatibility
27+
- Support for all Claude models (Opus, Sonnet, Haiku)
28+
- OAuth authentication for Claude Pro/Max users (persists across restarts)
29+
- Docker-based deployment with multi-platform images (amd64/arm64)
3130
- Web UI for testing at `localhost:4000/ui/`
32-
33-
### Features
34-
- OpenAI API compatibility for Claude models
35-
- Auth persists across container restarts
36-
- Support for both OAuth (Claude subscription) tokens and API keys
37-
- Multi-platform Docker images (amd64/arm64)
38-
39-
### Notes
40-
- This is an early release and has not been tested with LiteLLM-compatible clients
41-
- Streaming support is partial due to Claude Code SDK limitations
31+
- Streaming response support (partial, due to Claude Code SDK limitations)
4232

4333
[0.2.0]: https://github.com/cabinlab/litellm-claude-code/releases/tag/v0.2.0
4434
[0.1.0]: https://github.com/cabinlab/litellm-claude-code/releases/tag/v0.1.0

Dockerfile

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
FROM ghcr.io/cabinlab/claude-code-sdk-docker:python
22

3-
# Switch to root for installations
43
USER root
54

6-
# Install dependencies from requirements.txt
75
COPY requirements.txt /tmp/requirements.txt
86
RUN pip install --no-cache-dir -r /tmp/requirements.txt && rm /tmp/requirements.txt
97

10-
# Set up writable cache directories for claude user
8+
# Prisma cache must be writable by the non-root runtime user
119
ENV PRISMA_PYTHON_CACHE_DIR="/home/claude/.cache/prisma-python"
1210
RUN mkdir -p /home/claude/.cache/prisma-python && \
1311
chown -R claude:claude /home/claude/.cache
1412

15-
# Generate Prisma client as the non-root runtime user so binary paths resolve under /home/claude.
13+
# Generate Prisma client as claude so binary paths resolve under /home/claude
1614
ENV PATH="/opt/venv/bin:$PATH"
1715
RUN chown -R claude:claude /opt/venv/lib/python3.11/site-packages/prisma && \
1816
su -s /bin/bash claude -c 'cd /opt/venv/lib/python3.11/site-packages/litellm/proxy && \
@@ -24,27 +22,18 @@ RUN chown -R claude:claude /opt/venv/lib/python3.11/site-packages/prisma && \
2422
chmod -R u+rwX,go+rX /opt/venv/lib/python3.11/site-packages/litellm/proxy/_experimental/out; \
2523
fi
2624

27-
# Copy application code with proper ownership.
28-
# LiteLLM resolves custom_handler paths relative to /app/config.
25+
# LiteLLM resolves custom_handler paths relative to /app/config
2926
COPY --chown=claude:claude config/ /app/config/
3027
COPY --chown=claude:claude providers/ /app/config/providers/
3128

32-
# Copy entrypoint script
3329
COPY scripts/entrypoint.sh /app/scripts/entrypoint.sh
3430
RUN chmod +x /app/scripts/entrypoint.sh
3531

36-
# Switch back to claude user
3732
USER claude
38-
39-
# Working directory
4033
WORKDIR /app
41-
42-
# Expose LiteLLM port
4334
EXPOSE 4000
4435

45-
# Health check (avoid curl dependency; include auth for protected endpoint)
4636
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
4737
CMD python3 -c 'import os, urllib.request; req = urllib.request.Request("http://localhost:4000/health/readiness", headers={"Authorization": "Bearer " + os.environ.get("LITELLM_MASTER_KEY", "")}); urllib.request.urlopen(req, timeout=5)' || exit 1
4838

49-
# Single entrypoint
5039
ENTRYPOINT ["/app/scripts/entrypoint.sh"]

compose-openwebui.yaml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ services:
1919
expose:
2020
- "4000"
2121
volumes:
22-
- ./config:/app/config:ro
23-
- ./providers:/app/providers:ro
22+
- ./config/litellm_config.yaml:/app/config/litellm_config.yaml:ro
23+
- ./providers:/app/config/providers:ro
2424
- claude-auth:/home/claude/.claude
2525
env_file:
2626
- .env
@@ -37,12 +37,11 @@ services:
3737
volumes:
3838
- open-webui:/app/backend/data
3939
environment:
40+
- ENABLE_OPENAI_API=true
4041
- OPENAI_API_KEY=${LITELLM_MASTER_KEY}
4142
- OPENAI_API_BASE_URL=http://litellm:4000/v1
4243
- ENABLE_OLLAMA_API=false
43-
- OLLAMA_BASE_URL=""
4444
- WEBUI_SECRET_KEY=${WEBUI_SECRET_KEY:-}
45-
- ENABLE_OPENAI_API=true
4645
- WEBUI_SESSION_COOKIE_SECURE=true
4746
- WEBUI_AUTH_COOKIE_SECURE=true
4847
env_file:

0 commit comments

Comments
 (0)