This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch 
gh-readonly-queue/main/pr-5272-531d79ff226acba9d5f8d1d13d57564359ba0cec
in repository https://gitbox.apache.org/repos/asf/texera.git

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:

Reply via email to