This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git
The following commit(s) were added to refs/heads/main by this push:
new d086455291 feat(k8s): add agent service and LiteLLM to the Helm chart
(#5272)
d086455291 is described below
commit d08645529119db0d12cf4f1466f6b5a2db6d5eb5
Author: Jiadong Bai <[email protected]>
AuthorDate: Mon Jun 1 17:34:37 2026 -0700
feat(k8s): add agent service and LiteLLM to the Helm chart (#5272)
### What changes were proposed in this PR?
The agent-service image is built and runs under single-node compose but
had no Helm deployment, and the chart had no in-cluster LLM gateway.
This adds both, mirroring the proven preview/production chart while
aligning the agent service's env to what the code on `main` actually
reads.
**Agent service** (gated on `agentService.enabled`)
- `agent-service-deployment.yaml` + `agent-service-service.yaml`, wired
to in-cluster service DNS using the env names from
`agent-service/src/config/env.ts`: `TEXERA_DASHBOARD_SERVICE_ENDPOINT`
(webserver), `LLM_ENDPOINT` (access-control-service),
`WORKFLOW_COMPILING_SERVICE_ENDPOINT`, and a per-CU
`EXECUTION_ENDPOINT_TEMPLATE`.
- A dedicated `/api/agents` HTTPRoute (REST + the
`/api/agents/:id/react` WebSocket) plus a **`BackendTrafficPolicy` that
consistent-hashes on `X-Agent-Workflow-Id`** — agents are held in memory
per pod, so a workflow's requests must always reach the same replica
(the client already stamps that header).
- Readiness/liveness on `/api/healthcheck`.
**LiteLLM — in-cluster LLM gateway** (gated on `litellm.enabled`)
- `litellm-deployment.yaml` + `litellm-service.yaml` +
`litellm-config.yaml` (ConfigMap).
- **Postgres persistence on by default**: a `texera_litellm` database is
created by the Postgres init script, and the deployment sets
`DATABASE_URL` + `STORE_MODEL_IN_DB=true` so keys, spend, and model
config survive restarts.
- `access-control-service` wired to LiteLLM (`LITELLM_BASE_URL`,
`LITELLM_MASTER_KEY`, copilot enabled).
A shared Opaque `Secret` holds the agent gateway key, the LiteLLM master
key, and the provider API keys (supply via `--set`/override; none
committed).
### Any related issues, documentation, discussions?
Closes #5269
### How was this PR tested?
Tested locally by `helm install`. Worked end 2 end.
`helm lint` and `helm template` against the chart (subchart
`dependencies:` stripped locally so the render needs no remote charts):
```
helm lint . # 1 chart(s) linted, 0
chart(s) failed
helm template texera . -f values-development.yaml # RC=0, 50 objects, no
errors
```
### Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Opus 4.8 (1M context)
---------
Co-authored-by: Bob Bai <[email protected]>
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Co-authored-by: ali risheh <[email protected]>
---
.../access-control-service-deployment.yaml | 12 ++-
.../templates/access-control-service-service.yaml | 4 +-
...l => agent-service-backend-traffic-policy.yaml} | 29 ++++----
bin/k8s/templates/agent-service-deployment.yaml | 79 ++++++++++++++++++++
...vice-service.yaml => agent-service-secret.yaml} | 24 +++---
...ice-service.yaml => agent-service-service.yaml} | 12 +--
bin/k8s/templates/gateway-routes.yaml | 37 ++++++++++
bin/k8s/templates/gateway-security-policy.yaml | 2 +-
...ol-service-service.yaml => litellm-config.yaml} | 17 ++---
bin/k8s/templates/litellm-deployment.yaml | 85 ++++++++++++++++++++++
...l-service-service.yaml => litellm-service.yaml} | 12 +--
.../templates/postgresql-init-script-config.yaml | 7 ++
bin/k8s/templates/pylsp.yaml | 2 +-
bin/k8s/values-development.yaml | 64 +++++++++++++++-
bin/k8s/values.yaml | 56 +++++++++++++-
15 files changed, 388 insertions(+), 54 deletions(-)
diff --git a/bin/k8s/templates/access-control-service-deployment.yaml
b/bin/k8s/templates/access-control-service-deployment.yaml
index f4d4405d33..99713e7071 100644
--- a/bin/k8s/templates/access-control-service-deployment.yaml
+++ b/bin/k8s/templates/access-control-service-deployment.yaml
@@ -50,6 +50,16 @@ spec:
value: {{ .Values.workflowComputingUnitPool.name }}
- name: KUBERNETES_COMPUTE_UNIT_POOL_NAMESPACE
value: {{ .Values.workflowComputingUnitPool.namespace }}
+ {{- if .Values.litellm.enabled }}
+ # LLM gateway used to serve /api/chat and /api/models to the agent
service.
+ - name: LITELLM_BASE_URL
+ value: http://{{ .Values.litellm.name }}-svc:{{
.Values.litellm.service.port }}
+ - name: LITELLM_MASTER_KEY
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Release.Name }}-agent-service-secret
+ key: litellm-master-key
+ {{- end }}
{{- range .Values.texeraEnvVars }}
- name: {{ .name }}
value: "{{ .value }}"
@@ -65,4 +75,4 @@ spec:
path: /api/healthcheck
port: {{ .Values.accessControlService.service.port }}
initialDelaySeconds: 5
- periodSeconds: 5
\ No newline at end of file
+ periodSeconds: 5
diff --git a/bin/k8s/templates/access-control-service-service.yaml
b/bin/k8s/templates/access-control-service-service.yaml
index 25f0390566..4c2137456a 100644
--- a/bin/k8s/templates/access-control-service-service.yaml
+++ b/bin/k8s/templates/access-control-service-service.yaml
@@ -18,7 +18,7 @@
apiVersion: v1
kind: Service
metadata:
- name: {{ .Release.Name }}-{{ .Values.accessControlService.name }}-svc
+ name: {{ .Values.accessControlService.name }}-svc
namespace: {{ .Release.Namespace }}
spec:
type: {{ .Values.accessControlService.service.type }}
@@ -27,4 +27,4 @@ spec:
ports:
- protocol: TCP
port: {{ .Values.accessControlService.service.port }}
- targetPort: {{ .Values.accessControlService.service.port }}
\ No newline at end of file
+ targetPort: {{ .Values.accessControlService.service.port }}
diff --git a/bin/k8s/templates/gateway-security-policy.yaml
b/bin/k8s/templates/agent-service-backend-traffic-policy.yaml
similarity index 64%
copy from bin/k8s/templates/gateway-security-policy.yaml
copy to bin/k8s/templates/agent-service-backend-traffic-policy.yaml
index 4128b5f3d8..dffecbfb60 100644
--- a/bin/k8s/templates/gateway-security-policy.yaml
+++ b/bin/k8s/templates/agent-service-backend-traffic-policy.yaml
@@ -15,25 +15,24 @@
# specific language governing permissions and limitations
# under the License.
+# Agents are stateful and held in memory per pod, so all requests for a given
+# workflow must reach the same replica. The client stamps X-Agent-Workflow-Id
on
+# every agent request; pin routing to it with a consistent hash.
+{{- if .Values.agentService.enabled }}
apiVersion: gateway.envoyproxy.io/v1alpha1
-kind: SecurityPolicy
+kind: BackendTrafficPolicy
metadata:
- name: {{ .Release.Name }}-ext-auth
+ name: {{ .Release.Name }}-agent-service-traffic-policy
namespace: {{ .Release.Namespace }}
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
- name: {{ .Release.Name }}-dynamic-routes
- extAuth:
- http:
- backendRefs:
- - name: {{ .Release.Name }}-{{ .Values.accessControlService.name }}-svc
- port: {{ .Values.accessControlService.service.port }}
- path: /api/auth
- headersToBackend:
- - x-user-computing-unit-access
- - x-user-id
- - x-user-name
- - x-user-email
- - Host
+ name: {{ .Release.Name }}-agent-service-route
+ loadBalancer:
+ type: ConsistentHash
+ consistentHash:
+ type: Header
+ header:
+ name: X-Agent-Workflow-Id
+{{- end }}
diff --git a/bin/k8s/templates/agent-service-deployment.yaml
b/bin/k8s/templates/agent-service-deployment.yaml
new file mode 100644
index 0000000000..5437cd7d9c
--- /dev/null
+++ b/bin/k8s/templates/agent-service-deployment.yaml
@@ -0,0 +1,79 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+{{- if .Values.agentService.enabled }}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ .Release.Name }}-{{ .Values.agentService.name }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ app: {{ .Release.Name }}-{{ .Values.agentService.name }}
+spec:
+ replicas: {{ .Values.agentService.numOfPods | default 1 }}
+ selector:
+ matchLabels:
+ app: {{ .Release.Name }}-{{ .Values.agentService.name }}
+ template:
+ metadata:
+ labels:
+ app: {{ .Release.Name }}-{{ .Values.agentService.name }}
+ spec:
+ containers:
+ - name: {{ .Values.agentService.name }}
+ image: {{ .Values.texera.imageRegistry }}/{{
.Values.agentService.imageName }}:{{ .Values.texera.imageTag }}
+ imagePullPolicy: {{ .Values.texeraImages.pullPolicy }}
+ ports:
+ - containerPort: {{ .Values.agentService.service.port }}
+ # Env names match the agent service's config schema
(agent-service/src/config/env.ts).
+ env:
+ - name: PORT
+ value: "{{ .Values.agentService.service.port }}"
+ # Dashboard service: workflow CRUD + operator metadata.
+ - name: TEXERA_DASHBOARD_SERVICE_ENDPOINT
+ value: http://{{ .Values.webserver.name }}-svc:{{
.Values.webserver.service.port }}
+ # LLM gateway: access-control-service serves /api/chat and
/api/models,
+ # forwarding to LiteLLM (mirrors the single-node nginx routing).
+ - name: LLM_ENDPOINT
+ value: http://{{ .Values.accessControlService.name }}-svc:{{
.Values.accessControlService.service.port }}
+ - name: WORKFLOW_COMPILING_SERVICE_ENDPOINT
+ value: http://{{ .Values.workflowCompilingService.name }}-svc:{{
.Values.workflowCompilingService.service.port }}
+ # Per-computing-unit execution endpoint; "{cuid}" is substituted
with the
+ # computing unit id at request time.
+ - name: EXECUTION_ENDPOINT_TEMPLATE
+ value: http://computing-unit-{cuid}.{{
.Values.workflowComputingUnitPool.name }}-svc.{{
.Values.workflowComputingUnitPool.namespace }}.svc.cluster.local:{{
.Values.workflowComputingUnitPool.service.port }}
+ - name: LLM_API_KEY
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Release.Name }}-agent-service-secret
+ key: llm-api-key
+ # The service loads operator metadata from the dashboard service on
+ # startup, so gate readiness on its health endpoint before the
gateway
+ # routes traffic here. /api/healthcheck needs no auth.
+ readinessProbe:
+ httpGet:
+ path: /api/healthcheck
+ port: {{ .Values.agentService.service.port }}
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ livenessProbe:
+ httpGet:
+ path: /api/healthcheck
+ port: {{ .Values.agentService.service.port }}
+ initialDelaySeconds: 15
+ periodSeconds: 10
+{{- end }}
diff --git a/bin/k8s/templates/access-control-service-service.yaml
b/bin/k8s/templates/agent-service-secret.yaml
similarity index 58%
copy from bin/k8s/templates/access-control-service-service.yaml
copy to bin/k8s/templates/agent-service-secret.yaml
index 25f0390566..61746a0aeb 100644
--- a/bin/k8s/templates/access-control-service-service.yaml
+++ b/bin/k8s/templates/agent-service-secret.yaml
@@ -15,16 +15,20 @@
# specific language governing permissions and limitations
# under the License.
+# Shared secret for the agent service and LiteLLM. Holds the agent's gateway
+# key, LiteLLM's master key, and the upstream provider API keys. Provide real
+# values via `--set` or a values override file; do not commit them.
+{{- if or .Values.agentService.enabled .Values.litellm.enabled }}
apiVersion: v1
-kind: Service
+kind: Secret
metadata:
- name: {{ .Release.Name }}-{{ .Values.accessControlService.name }}-svc
+ name: {{ .Release.Name }}-agent-service-secret
namespace: {{ .Release.Namespace }}
-spec:
- type: {{ .Values.accessControlService.service.type }}
- selector:
- app: {{ .Release.Name }}-{{ .Values.accessControlService.name }}
- ports:
- - protocol: TCP
- port: {{ .Values.accessControlService.service.port }}
- targetPort: {{ .Values.accessControlService.service.port }}
\ No newline at end of file
+type: Opaque
+stringData:
+ llm-api-key: "{{ .Values.agentService.env.llmApiKey }}"
+ litellm-master-key: "{{ .Values.litellm.masterKey }}"
+ {{- range $key, $value := .Values.litellm.providerApiKeys }}
+ {{ $key }}: "{{ $value }}"
+ {{- end }}
+{{- end }}
diff --git a/bin/k8s/templates/access-control-service-service.yaml
b/bin/k8s/templates/agent-service-service.yaml
similarity index 73%
copy from bin/k8s/templates/access-control-service-service.yaml
copy to bin/k8s/templates/agent-service-service.yaml
index 25f0390566..581716bf80 100644
--- a/bin/k8s/templates/access-control-service-service.yaml
+++ b/bin/k8s/templates/agent-service-service.yaml
@@ -15,16 +15,18 @@
# specific language governing permissions and limitations
# under the License.
+{{- if .Values.agentService.enabled }}
apiVersion: v1
kind: Service
metadata:
- name: {{ .Release.Name }}-{{ .Values.accessControlService.name }}-svc
+ name: {{ .Values.agentService.name }}-svc
namespace: {{ .Release.Namespace }}
spec:
- type: {{ .Values.accessControlService.service.type }}
+ type: {{ .Values.agentService.service.type }}
selector:
- app: {{ .Release.Name }}-{{ .Values.accessControlService.name }}
+ app: {{ .Release.Name }}-{{ .Values.agentService.name }}
ports:
- protocol: TCP
- port: {{ .Values.accessControlService.service.port }}
- targetPort: {{ .Values.accessControlService.service.port }}
\ No newline at end of file
+ port: {{ .Values.agentService.service.port }}
+ targetPort: {{ .Values.agentService.service.port }}
+{{- end }}
diff --git a/bin/k8s/templates/gateway-routes.yaml
b/bin/k8s/templates/gateway-routes.yaml
index ab53c184e8..ac8096aa21 100644
--- a/bin/k8s/templates/gateway-routes.yaml
+++ b/bin/k8s/templates/gateway-routes.yaml
@@ -66,6 +66,16 @@ spec:
backendRefs:
- name: config-service-svc
port: 9094
+ - matches:
+ - path:
+ type: PathPrefix
+ value: /api/models
+ - path:
+ type: PathPrefix
+ value: /api/chat
+ backendRefs:
+ - name: access-control-service-svc
+ port: 9096
- matches:
- path:
type: PathPrefix
@@ -133,6 +143,33 @@ spec:
kind: Backend
name: texera-dynamic-backend
---
+# Agent Service Route (a separate HTTPRoute so the BackendTrafficPolicy can
+# target it for consistent-hash routing). Covers REST and the
+# /api/agents/:id/react WebSocket. Longest-prefix matching gives /api/agents
+# priority over the /api catch-all in the static routes above.
+{{- if .Values.agentService.enabled }}
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+ name: {{ .Release.Name }}-agent-service-route
+ namespace: {{ .Release.Namespace }}
+spec:
+ parentRefs:
+ - name: {{ .Release.Name }}-gateway
+ {{- if and .Values.gatewayConfig .Values.gatewayConfig.hostname }}
+ hostnames:
+ - {{ .Values.gatewayConfig.hostname }}
+ {{- end }}
+ rules:
+ - matches:
+ - path:
+ type: PathPrefix
+ value: /api/agents
+ backendRefs:
+ - name: agent-service-svc
+ port: 3001
+{{- end }}
+---
# MinIO Route
{{- if .Values.minio.gateway.enabled }}
apiVersion: gateway.networking.k8s.io/v1
diff --git a/bin/k8s/templates/gateway-security-policy.yaml
b/bin/k8s/templates/gateway-security-policy.yaml
index 4128b5f3d8..47a67532d8 100644
--- a/bin/k8s/templates/gateway-security-policy.yaml
+++ b/bin/k8s/templates/gateway-security-policy.yaml
@@ -28,7 +28,7 @@ spec:
extAuth:
http:
backendRefs:
- - name: {{ .Release.Name }}-{{ .Values.accessControlService.name }}-svc
+ - name: {{ .Values.accessControlService.name }}-svc
port: {{ .Values.accessControlService.service.port }}
path: /api/auth
headersToBackend:
diff --git a/bin/k8s/templates/access-control-service-service.yaml
b/bin/k8s/templates/litellm-config.yaml
similarity index 68%
copy from bin/k8s/templates/access-control-service-service.yaml
copy to bin/k8s/templates/litellm-config.yaml
index 25f0390566..c4c2aa136d 100644
--- a/bin/k8s/templates/access-control-service-service.yaml
+++ b/bin/k8s/templates/litellm-config.yaml
@@ -15,16 +15,13 @@
# specific language governing permissions and limitations
# under the License.
+{{- if .Values.litellm.enabled }}
apiVersion: v1
-kind: Service
+kind: ConfigMap
metadata:
- name: {{ .Release.Name }}-{{ .Values.accessControlService.name }}-svc
+ name: {{ .Release.Name }}-litellm-config
namespace: {{ .Release.Namespace }}
-spec:
- type: {{ .Values.accessControlService.service.type }}
- selector:
- app: {{ .Release.Name }}-{{ .Values.accessControlService.name }}
- ports:
- - protocol: TCP
- port: {{ .Values.accessControlService.service.port }}
- targetPort: {{ .Values.accessControlService.service.port }}
\ No newline at end of file
+data:
+ litellm-config.yaml: |
+{{ .Values.litellm.config | indent 4 }}
+{{- end }}
diff --git a/bin/k8s/templates/litellm-deployment.yaml
b/bin/k8s/templates/litellm-deployment.yaml
new file mode 100644
index 0000000000..ba681da7d1
--- /dev/null
+++ b/bin/k8s/templates/litellm-deployment.yaml
@@ -0,0 +1,85 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+{{- if .Values.litellm.enabled }}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ .Release.Name }}-{{ .Values.litellm.name }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ app: {{ .Release.Name }}-{{ .Values.litellm.name }}
+spec:
+ replicas: {{ .Values.litellm.numOfPods | default 1 }}
+ selector:
+ matchLabels:
+ app: {{ .Release.Name }}-{{ .Values.litellm.name }}
+ template:
+ metadata:
+ labels:
+ app: {{ .Release.Name }}-{{ .Values.litellm.name }}
+ spec:
+ containers:
+ - name: {{ .Values.litellm.name }}
+ image: {{ .Values.litellm.image }}
+ imagePullPolicy: Always
+ args:
+ - "--config"
+ - "/app/config/litellm-config.yaml"
+ ports:
+ - containerPort: {{ .Values.litellm.service.port }}
+ env:
+ - name: LITELLM_MASTER_KEY
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Release.Name }}-agent-service-secret
+ key: litellm-master-key
+ # Postgres persistence: LiteLLM runs its Prisma migrations against
this
+ # database on startup and stores keys, spend, and (with
STORE_MODEL_IN_DB)
+ # model config there, so state survives pod restarts. Defaults to
the
+ # in-cluster Postgres; set litellm.databaseUrl to point at an
external one.
+ - name: DATABASE_URL
+ value: {{ .Values.litellm.databaseUrl | default (printf
"postgresql://postgres:%s@%s-postgresql:5432/%s"
.Values.postgresql.auth.postgresPassword .Release.Name
.Values.litellm.databaseName) | quote }}
+ - name: STORE_MODEL_IN_DB
+ value: "{{ .Values.litellm.storeModelInDb }}"
+ {{- range $key, $value := .Values.litellm.providerApiKeys }}
+ - name: {{ $key }}
+ valueFrom:
+ secretKeyRef:
+ name: {{ $.Release.Name }}-agent-service-secret
+ key: {{ $key }}
+ {{- end }}
+ volumeMounts:
+ - name: litellm-config
+ mountPath: /app/config
+ livenessProbe:
+ httpGet:
+ path: /health/liveliness
+ port: {{ .Values.litellm.service.port }}
+ initialDelaySeconds: 30
+ periodSeconds: 10
+ readinessProbe:
+ httpGet:
+ path: /health/liveliness
+ port: {{ .Values.litellm.service.port }}
+ initialDelaySeconds: 15
+ periodSeconds: 5
+ volumes:
+ - name: litellm-config
+ configMap:
+ name: {{ .Release.Name }}-litellm-config
+{{- end }}
diff --git a/bin/k8s/templates/access-control-service-service.yaml
b/bin/k8s/templates/litellm-service.yaml
similarity index 73%
copy from bin/k8s/templates/access-control-service-service.yaml
copy to bin/k8s/templates/litellm-service.yaml
index 25f0390566..875bdd08f1 100644
--- a/bin/k8s/templates/access-control-service-service.yaml
+++ b/bin/k8s/templates/litellm-service.yaml
@@ -15,16 +15,18 @@
# specific language governing permissions and limitations
# under the License.
+{{- if .Values.litellm.enabled }}
apiVersion: v1
kind: Service
metadata:
- name: {{ .Release.Name }}-{{ .Values.accessControlService.name }}-svc
+ name: {{ .Values.litellm.name }}-svc
namespace: {{ .Release.Namespace }}
spec:
- type: {{ .Values.accessControlService.service.type }}
+ type: {{ .Values.litellm.service.type }}
selector:
- app: {{ .Release.Name }}-{{ .Values.accessControlService.name }}
+ app: {{ .Release.Name }}-{{ .Values.litellm.name }}
ports:
- protocol: TCP
- port: {{ .Values.accessControlService.service.port }}
- targetPort: {{ .Values.accessControlService.service.port }}
\ No newline at end of file
+ port: {{ .Values.litellm.service.port }}
+ targetPort: {{ .Values.litellm.service.port }}
+{{- end }}
diff --git a/bin/k8s/templates/postgresql-init-script-config.yaml
b/bin/k8s/templates/postgresql-init-script-config.yaml
index 9b7e5488b5..f9bb8c4b52 100644
--- a/bin/k8s/templates/postgresql-init-script-config.yaml
+++ b/bin/k8s/templates/postgresql-init-script-config.yaml
@@ -52,5 +52,12 @@ data:
{{ .Files.Get "files/texera_ddl.sql" | indent 6 }}
EOF
psql -U postgres -f /tmp/texera_ddl.sql
+{{- if .Values.litellm.enabled }}
+
+ echo "Initializing LiteLLM database..."
+ # LiteLLM (Prisma) creates its own tables on startup but the database must
exist.
+ psql -U postgres -tc "SELECT 1 FROM pg_database WHERE datname = '{{
.Values.litellm.databaseName }}'" | grep -q 1 \
+ || psql -U postgres -c "CREATE DATABASE {{ .Values.litellm.databaseName
}}"
+{{- end }}
echo "Schema initialization complete."
\ No newline at end of file
diff --git a/bin/k8s/templates/pylsp.yaml b/bin/k8s/templates/pylsp.yaml
index ee6a3e59a5..89f3fd1b48 100644
--- a/bin/k8s/templates/pylsp.yaml
+++ b/bin/k8s/templates/pylsp.yaml
@@ -35,7 +35,7 @@ spec:
containers:
- name: {{ .Values.pythonLanguageServer.name }}
image: {{ .Values.pythonLanguageServer.image | quote }}
- imagePullPolicy: Always
+ imagePullPolicy: {{ .Values.pythonLanguageServer.imagePullPolicy |
quote }}
ports:
- containerPort: 3000
resources:
diff --git a/bin/k8s/values-development.yaml b/bin/k8s/values-development.yaml
index cbf0183f00..5537b39acc 100644
--- a/bin/k8s/values-development.yaml
+++ b/bin/k8s/values-development.yaml
@@ -56,10 +56,10 @@ postgresql:
resources:
requests:
cpu: "0.25"
- memory: "256Mi"
+ memory: "512Mi"
limits:
cpu: "1"
- memory: "256Mi"
+ memory: "1Gi"
persistence:
enabled: true
size: 10Gi
@@ -225,6 +225,63 @@ accessControlService:
cpu: 1000m
memory: 256Mi
+agentService:
+ enabled: true
+ name: agent-service
+ numOfPods: 1
+ imageName: texera-agent-service
+ service:
+ type: ClusterIP
+ port: 3001
+ env:
+ # Authenticates the agent service to the in-cluster LLM gateway
+ # (access-control-service / LiteLLM), not to the upstream provider.
+ llmApiKey: "dummy"
+
+litellm:
+ enabled: true
+ name: litellm
+ image: litellm/litellm:main-stable
+ numOfPods: 1
+ service:
+ type: ClusterIP
+ port: 4000
+ masterKey: "sk-texera-litellm-key"
+ # Postgres persistence: the database is created by the postgres init script
and
+ # LiteLLM stores keys/spend (and model config when storeModelInDb is true)
there.
+ databaseName: texera_litellm
+ # Full Postgres connection string for LiteLLM. Leave empty to use the
in-cluster
+ # Postgres (composed from postgresql.auth + databaseName); set it to point
at an
+ # external database, e.g. postgresql://user:pass@host:5432/dbname.
+ databaseUrl: ""
+ storeModelInDb: true
+ # Provider API keys - injected as env vars into the LiteLLM pod and stored
in a
+ # Secret. Set these via --set or a values override file (do NOT commit real
keys).
+ # The config below references them via "os.environ/KEY_NAME".
+ providerApiKeys:
+ OPENAI_API_KEY: ""
+ ANTHROPIC_API_KEY: ""
+ config: |
+ litellm_settings:
+ drop_params: true
+ model_list:
+ - model_name: claude-sonnet-4
+ litellm_params:
+ model: claude-sonnet-4-20250514
+ api_key: "os.environ/ANTHROPIC_API_KEY"
+ - model_name: claude-haiku-4.5
+ litellm_params:
+ model: claude-haiku-4-5-20251001
+ api_key: "os.environ/ANTHROPIC_API_KEY"
+ - model_name: gpt-4.1
+ litellm_params:
+ model: gpt-4.1
+ api_key: "os.environ/OPENAI_API_KEY"
+ - model_name: gpt-4.1-mini
+ litellm_params:
+ model: gpt-4.1-mini
+ api_key: "os.environ/OPENAI_API_KEY"
+
# headless service for the access of computing units
workflowComputingUnitPool:
createNamespaces: true
@@ -285,6 +342,8 @@ texeraEnvVars:
value: "true"
- name: GUI_WORKFLOW_WORKSPACE_ASYNC_RENDERING_ENABLED
value: "true"
+ - name: GUI_WORKFLOW_WORKSPACE_COPILOT_ENABLED
+ value: "true"
- name: COMPUTING_UNIT_SHARING_ENABLED
value: "true"
- name: USER_SYS_INVITE_ONLY
@@ -308,6 +367,7 @@ pythonLanguageServer:
name: python-language-server
replicaCount: 1
image: texera/pylsp:latest
+ imagePullPolicy: IfNotPresent
imagePullSecret: regcred
resources:
limits:
diff --git a/bin/k8s/values.yaml b/bin/k8s/values.yaml
index 2d7c520ff7..4f708b6da1 100644
--- a/bin/k8s/values.yaml
+++ b/bin/k8s/values.yaml
@@ -18,8 +18,8 @@
texera:
# Container image registry and tag for all Texera services
# Override these to use a different registry or version
- imageRegistry: ghcr.io/apache
- imageTag: latest
+ imageRegistry: docker.io/apache
+ imageTag: 1.1.0-incubating
global:
# Required by Bitnami sub-charts (postgresql, minio) to allow custom images
@@ -207,6 +207,55 @@ accessControlService:
type: ClusterIP
port: 9096
+agentService:
+ enabled: true
+ name: agent-service
+ numOfPods: 1
+ imageName: texera-agent-service
+ service:
+ type: ClusterIP
+ port: 3001
+ env:
+ # Authenticates the agent service to the in-cluster LLM gateway
+ # (access-control-service / LiteLLM), not to the upstream provider.
+ llmApiKey: "dummy"
+
+litellm:
+ enabled: true
+ name: litellm
+ image: litellm/litellm:main-stable
+ numOfPods: 1
+ service:
+ type: ClusterIP
+ port: 4000
+ masterKey: "sk-texera-litellm-key"
+ # Postgres persistence: the database is created by the postgres init script
and
+ # LiteLLM stores keys/spend (and model config when storeModelInDb is true)
there.
+ databaseName: texera_litellm
+ # Full Postgres connection string for LiteLLM. Leave empty to use the
in-cluster
+ # Postgres (composed from postgresql.auth + databaseName); set it to point
at an
+ # external database, e.g. postgresql://user:pass@host:5432/dbname.
+ databaseUrl: ""
+ storeModelInDb: true
+ # Provider API keys - injected as env vars into the LiteLLM pod and stored
in a
+ # Secret. Set these via --set or a values override file (do NOT commit real
keys).
+ # The config below references them via "os.environ/KEY_NAME".
+ providerApiKeys:
+ OPENAI_API_KEY: ""
+ ANTHROPIC_API_KEY: ""
+ config: |
+ litellm_settings:
+ drop_params: true
+ model_list:
+ - model_name: claude-haiku-4.5
+ litellm_params:
+ model: claude-haiku-4-5-20251001
+ api_key: "os.environ/ANTHROPIC_API_KEY"
+ - model_name: gpt-5-mini
+ litellm_params:
+ model: gpt-5-mini
+ api_key: "os.environ/OPENAI_API_KEY"
+
# headless service for the access of computing units
workflowComputingUnitPool:
createNamespaces: true
@@ -267,6 +316,8 @@ texeraEnvVars:
value: "true"
- name: GUI_WORKFLOW_WORKSPACE_ASYNC_RENDERING_ENABLED
value: "true"
+ - name: GUI_WORKFLOW_WORKSPACE_COPILOT_ENABLED
+ value: "true"
- name: COMPUTING_UNIT_SHARING_ENABLED
value: "true"
- name: USER_SYS_INVITE_ONLY
@@ -293,6 +344,7 @@ pythonLanguageServer:
name: python-language-server
replicaCount: 1
image: texera/pylsp:latest
+ imagePullPolicy: IfNotPresent
imagePullSecret: regcred
resources:
limits: