Skip to content

Commit b004cdd

Browse files
authored
PLTF-4: Automate LiteLLM setup (#253)
* Automatically provision new LiteLLM team on installation.
1 parent a399588 commit b004cdd

9 files changed

Lines changed: 132 additions & 60 deletions

File tree

.gitignore

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
charts/**/charts
22

3-
**/.DS_Store
3+
**/.DS_Store
4+
5+
# Files generated by JetBrains IDEs, e.g. IntelliJ IDEA
6+
.idea/
7+
*.iml
8+
9+
# Vscode files
10+
.vscode

charts/openhands/Chart.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ dependencies:
1010
version: 1.2.13
1111
- name: litellm-helm
1212
repository: oci://ghcr.io/berriai
13-
version: 0.1.664
13+
version: 0.1.781
1414
- name: minio
1515
repository: https://charts.min.io/
1616
version: 5.0.10
@@ -22,6 +22,6 @@ dependencies:
2222
version: 20.3.0
2323
- name: runtime-api
2424
repository: oci://ghcr.io/all-hands-ai/helm-charts
25-
version: 0.1.9
26-
digest: sha256:0eb3fcb98ec8a1aa3d6c2ba5e317942cbc2030a35440836ad6aec63de0dfb11e
27-
generated: "2025-08-21T14:15:03.196589052Z"
25+
version: 0.1.20
26+
digest: sha256:993e079383b8356e71d7b12cdc0ae82ee0747f5ce72a9d7307471aa2c9be0da9
27+
generated: "2026-01-15T17:32:49.752308-05:00"

charts/openhands/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ apiVersion: v2
22
description: OpenHands is an AI-driven autonomous software engineer
33
name: openhands
44
appVersion: 0.62.0
5-
version: 0.1.35
5+
version: 0.2.0
66
maintainers:
77
- name: rbren
88
- name: xingyao

charts/openhands/README.md

Lines changed: 23 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -247,51 +247,19 @@ authentication as well.
247247

248248
When the chart is deployed, a job will run to configure the Keycloak realm with the identity provider credentials you provided.
249249

250-
### Install OpenHands
251-
252-
Now we can install the helm chart.
253-
254-
```bash
255-
helm dependency update
256-
helm upgrade --install openhands --namespace openhands oci://ghcr.io/all-hands-ai/helm-charts/openhands -f site-values.yaml
257-
```
258-
259-
This installation won't complete successfully the first time because we need to set up LiteLLM.
250+
### LiteLLM configuration
260251

261-
> [!NOTE]
262-
> This process will be automated in the near future.
263-
>
264252
> [!IMPORTANT]
265253
> We recommend using the provided LiteLLM instance rather than bringing your
266254
> own. The provided LiteLLM instance uses an admin key for automated user
267255
> management, which is the most extensively tested scenario. Our automation
268256
> relies on this admin key to create and delete users automatically.
269257

270-
To set up LiteLLM, first use port-forward to connect:
271-
272-
```bash
273-
kubectl port-forward svc/openhands-litellm 4000:4000 -n openhands
274-
```
275-
276-
Next, create a new Team in LiteLLM:
277-
278-
- Navigate to <http://localhost:4000/ui> in your browser.
279-
- login using the username `admin` password $GLOBAL_SECRET (set above).
280-
- go to Teams -> Create New Team.
281-
- Name it whatever you want.
282-
- Get the team id (e.g. `e0a62105-9c6c-4167-b5be-16674a99d502`), and add it to site-values.yaml:
283-
284-
```yaml
285-
litellm:
286-
teamId: "<TEAM_ID>"
287-
```
258+
#### Configure LiteLLM Models
288259

289-
You'll also need to set your model list for LiteLLM, using the LLM secrets you set above:
260+
You'll need to set your model list for LiteLLM, using the LLM secrets you set above:
290261

291262
```yaml
292-
litellm:
293-
teamId: "<TEAM_ID>"
294-
295263
litellm-helm:
296264
proxy_config:
297265
model_list:
@@ -301,25 +269,38 @@ litellm-helm:
301269
api_key: os.environ/ANTHROPIC_API_KEY
302270
```
303271

304-
Finally you will need to set the default LLM model to use in your site-values.yaml. Find the "env:" section below in your site-values.yaml and uncomment the LITELLM_DEFAULT_MODEL. Set "your-model" to one of the models you configured:
272+
You will also need to set the default LLM model to use in your site-values.yaml. Find the "env:" section in your site-values.yaml and uncomment the LITELLM_DEFAULT_MODEL. Set "your-model" to one of the models you configured:
305273

306274
```yaml
307275
env:
308-
# This var will cause the openhands deploy to create the LLM team name if it doesn't exist already
309-
LITE_LLM_TEAM_NAME: openhands
310276
# replace <your-model> with your LLM model and uncomment this variable
311-
# LITELLM_DEFAULT_MODEL: "litellm_proxy/<your-model>"
277+
LITELLM_DEFAULT_MODEL: "litellm_proxy/<your-model>"
312278
```
313279

314-
### Verify your Setup
280+
#### LiteLLM Team Configuration
281+
282+
To use an existing team, provide the team ID.
283+
284+
If you do not set a team ID, a new team with ID `openhands` will be created. If the team ID you provide doesn't
285+
already exist, a new team with that ID will be created.
286+
287+
```yaml
288+
litellm:
289+
teamId: "<TEAM_ID>"
290+
```
315291

316-
Finally, upgrade the release:
292+
### Install OpenHands
293+
294+
Now we can install the helm chart.
317295

318296
```bash
297+
helm dependency update
319298
helm upgrade --install openhands --namespace openhands oci://ghcr.io/all-hands-ai/helm-charts/openhands -f site-values.yaml
320299
```
321300

322-
You should now be able to see OpenHands running with:
301+
### Verify your Setup
302+
303+
After installation, you should be able to see OpenHands running with:
323304

324305
```bash
325306
kubectl port-forward svc/openhands-service 3000:3000 -n openhands

charts/openhands/example-values.yaml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
# tag: 0.47.0
44

55
env:
6-
# This var will cause the openhands deploy to create the LLM team name if it doesn't exist already
7-
LITE_LLM_TEAM_NAME: openhands
86
# replace <your-model> with your LLM model and uncomment this variable
97
# LITELLM_DEFAULT_MODEL: "litellm_proxy/<your-model>"
108

@@ -50,7 +48,7 @@ litellm:
5048
# NOTE: We recommend using the provided LiteLLM instance for simplicity and
5149
# because it is the most extensively tested scenario. Our automation uses an
5250
# admin key to do user management for the LiteLLM instance.
53-
enabled: false
51+
enabled: true
5452
url: "https://llm-proxy.example.com"
5553

5654
litellm-helm:

charts/openhands/templates/_env.yaml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,20 +186,23 @@
186186
{{- else if .Values.litellm.enabled }}
187187
- name: LITE_LLM_API_URL
188188
value: {{ .Values.litellm.url }}
189-
- name: LITE_LLM_TEAM_ID
190-
value: {{ .Values.litellm.teamId }}
191-
- name: LITE_LLM_API_KEY
192-
valueFrom:
193-
secretKeyRef:
194-
name: {{ .Values.litellm.auth.existingSecret }}
195-
key: lite-llm-api-key
196189
{{- end }}
197190
{{- if index .Values "litellm-helm" "enabled" }}
198191
- name: LITE_LLM_API_KEY
199192
valueFrom:
200193
secretKeyRef:
201194
name: {{ index .Values "litellm-helm" "masterkeySecretName" }}
202195
key: {{ index .Values "litellm-helm" "masterkeySecretKey" }}
196+
{{- else if .Values.litellm.enabled }}
197+
- name: LITE_LLM_API_KEY
198+
valueFrom:
199+
secretKeyRef:
200+
name: {{ .Values.litellm.auth.existingSecret }}
201+
key: lite-llm-api-key
202+
{{- end }}
203+
{{- if .Values.litellm.enabled }}
204+
- name: LITE_LLM_TEAM_ID
205+
value: {{ .Values.litellm.teamId }}
203206
{{- end }}
204207
{{- if .Values.stripe.enabled }}
205208
- name: STRIPE_API_KEY

charts/openhands/templates/deployment.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ spec:
1414
labels:
1515
app: openhands
1616
annotations:
17+
checksum/keycloak-config: {{ include (print $.Template.BasePath "/keycloak-config-script.yaml") . | sha256sum }}
18+
{{- if .Values.litellm.enabled }}
19+
checksum/litellm-config: {{ include (print $.Template.BasePath "/litellm-config-script.yaml") . | sha256sum }}
20+
{{- end }}
1721
{{- if .Values.allowedUsers }}
1822
checksum/user-waitlist: {{ include (print $.Template.BasePath "/user-waitlist-configmap.yaml") . | sha256sum }}
1923
{{- end }}
@@ -38,6 +42,12 @@ spec:
3842
configMap:
3943
name: keycloak-config-script
4044
defaultMode: 0755
45+
{{- if .Values.litellm.enabled }}
46+
- name: litellm-config-script
47+
configMap:
48+
name: litellm-config-script
49+
defaultMode: 0755
50+
{{- end }}
4151
initContainers:
4252
- name: keycloak-config
4353
imagePullPolicy: Always
@@ -50,6 +60,19 @@ spec:
5060
command:
5161
- sh
5262
- /scripts/keycloak-config.sh
63+
{{- if .Values.litellm.enabled }}
64+
- name: litellm-config
65+
imagePullPolicy: Always
66+
image: '{{.Values.image.repository}}:{{.Values.image.tag | default .Chart.AppVersion }}'
67+
env:
68+
{{- include "openhands.env" . | nindent 8 }}
69+
volumeMounts:
70+
- name: litellm-config-script
71+
mountPath: /scripts
72+
command:
73+
- sh
74+
- /scripts/litellm-config.sh
75+
{{- end }}
5376
containers:
5477
- name: openhands
5578
imagePullPolicy: Always
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{{- if .Values.litellm.enabled }}
2+
apiVersion: v1
3+
kind: ConfigMap
4+
metadata:
5+
name: litellm-config-script
6+
data:
7+
litellm-config.sh: |
8+
#!/bin/sh
9+
set -eu
10+
11+
echo "Setting up LiteLLM"
12+
13+
MAX_RETRIES=60
14+
RETRY_INTERVAL=5
15+
16+
echo "LiteLLM Configuration Script"
17+
echo "=============================="
18+
echo "API URL: $LITE_LLM_API_URL"
19+
echo "Team ID: $LITE_LLM_TEAM_ID"
20+
21+
echo ""
22+
echo "Waiting for LiteLLM to be ready..."
23+
retries=0
24+
until curl --output /dev/null --silent --fail "$LITE_LLM_API_URL/health/liveness"; do
25+
retries=$((retries + 1))
26+
if [ $retries -ge $MAX_RETRIES ]; then
27+
echo "ERROR: LiteLLM did not become ready after $((MAX_RETRIES * RETRY_INTERVAL)) seconds"
28+
exit 1
29+
fi
30+
echo "LiteLLM not ready yet (attempt $retries/$MAX_RETRIES), waiting ${RETRY_INTERVAL}s..."
31+
sleep $RETRY_INTERVAL
32+
done
33+
echo "LiteLLM is ready!"
34+
35+
echo ""
36+
echo "Checking for existing team with ID: $LITE_LLM_TEAM_ID"
37+
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X GET "$LITE_LLM_API_URL/team/info?team_id=$LITE_LLM_TEAM_ID" \
38+
-H "Authorization: Bearer $LITE_LLM_API_KEY" \
39+
-H "Content-Type: application/json")
40+
41+
if [ "$HTTP_CODE" = "200" ]; then
42+
echo "Team already exists with ID: $LITE_LLM_TEAM_ID"
43+
exit 0
44+
elif [ "$HTTP_CODE" = "404" ]; then
45+
echo "Team does not exist, creating new team with ID: $LITE_LLM_TEAM_ID"
46+
curl --fail -s -X POST "$LITE_LLM_API_URL/team/new" \
47+
-H "Authorization: Bearer $LITE_LLM_API_KEY" \
48+
-H "Content-Type: application/json" \
49+
-d "{
50+
\"team_id\": \"$LITE_LLM_TEAM_ID\",
51+
\"team_alias\": \"$LITE_LLM_TEAM_ID\"
52+
}"
53+
echo ""
54+
echo "Created team with ID: $LITE_LLM_TEAM_ID"
55+
else
56+
echo "ERROR: Unexpected response code: $HTTP_CODE"
57+
exit 1
58+
fi
59+
{{- end }}

charts/openhands/values.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,9 @@ litellm:
169169
# NOTE: to set the LLM model, set the LITELLM_DEFAULT_MODEL variable in the env section above.
170170
# REQUIRED: Update to match the hostname set in the litellm-helm ingress section
171171
url: "https://llm-proxy.example.com"
172-
# REQUIRED: Update this AFTER you initially install the chart and login to litellm to create the team.
173-
# teamId: ""
172+
# Team ID for LiteLLM. If the team ID doesn't exist, it will automatically be created.
173+
# Set this to use an existing team.
174+
teamId: "openhands"
174175
auth:
175176
existingSecret: lite-llm-api-key
176177

0 commit comments

Comments
 (0)