Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/ci-paths.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ ignore = [
]

[suites]
helm = ["deploy/helm/**", "tests/test_helm*.py", "tests/e2e/helm_*.py"]
tests = [
"tests/**", "integrations/**", "examples/**", "scripts/generate_js_operations.py",
"scripts/sync_dsh_plugin_tree.py", "scripts/generate_integration_manifest_docs.py",
Expand Down
35 changes: 35 additions & 0 deletions .github/workflows/master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1051,3 +1051,38 @@ jobs:
env:
POWERCONTEXT_TEST_BLOG_SITE: "1"
run: uv run pytest tests/e2e/test_blog_site.py -q

helm:
name: Helm deployment contracts
needs: changes
if: ${{ !cancelled() && (needs.changes.result != 'success' || fromJSON(needs.changes.outputs.suites || '{}').helm) }}
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: ./.github/actions/setup-python-env
- name: Install Helm
run: |
curl --fail --silent --show-error --location https://get.helm.sh/helm-v3.19.0-linux-amd64.tar.gz -o /tmp/helm.tar.gz
curl --fail --silent --show-error --location https://get.helm.sh/helm-v3.19.0-linux-amd64.tar.gz.sha256sum -o /tmp/helm.sha256
EXPECTED=$(cut -d ' ' -f 1 /tmp/helm.sha256)
echo "$EXPECTED /tmp/helm.tar.gz" | sha256sum --check
tar -xzf /tmp/helm.tar.gz -C /tmp
sudo install /tmp/linux-amd64/helm /usr/local/bin/helm
- name: Lint chart
run: >-
helm lint deploy/helm/powercontext --strict
--set image.repository=example/powercontext
--set image.tag=ci
--set existingSecret=credentials
- name: Lint acceptance profile
run: >-
helm lint deploy/helm/powercontext --strict
--values deploy/helm/powercontext/values-acceptance.yaml
--set image.repository=example/powercontext
--set image.tag=ci
--set existingSecret=credentials
- name: Test deployment configuration and acceptance safeguards
run: uv run --locked pytest tests/test_helm_chart.py tests/test_helm_acceptance.py -q
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ repos:
- id: check-merge-conflict
- id: check-toml
- id: check-yaml
exclude: ^deploy/helm/powercontext/templates/
- id: check-json
exclude: ^.devcontainer/devcontainer.json
- id: pretty-format-json
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ Scope
└── Topic Memory # extracted in the background from eligible Sources
```

For Kubernetes deployments with external OceanBase, see the [Helm chart and deployment guide](deploy/helm/powercontext/README.md).

*The Dashboard screenshots below use synthetic demonstration records.*

### Memory — decisions and constraints that outlive a session
Expand Down
19 changes: 19 additions & 0 deletions deploy/helm/powercontext/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright (c) 2026 OceanBase.
#
# Licensed 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.

apiVersion: v2
name: powercontext
description: PowerContext API and background roles with external OceanBase
type: application
version: 0.1.0
322 changes: 322 additions & 0 deletions deploy/helm/powercontext/README.md

Large diffs are not rendered by default.

43 changes: 43 additions & 0 deletions deploy/helm/powercontext/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{{/*
Copyright (c) 2026 OceanBase.

Licensed 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.

*/}}
{{- define "powercontext.name" -}}
{{- $name := printf "%s-powercontext" .Release.Name -}}
{{- if gt (len $name) 52 -}}
{{- printf "%s-%s" ($name | trunc 43 | trimSuffix "-") (.Release.Name | sha256sum | trunc 8) -}}
{{- else -}}
{{- $name -}}
{{- end -}}
{{- end -}}
{{- define "powercontext.labels" -}}
{{- with .Values.commonLabels }}
{{ toYaml . }}
{{ end -}}
app.kubernetes.io/name: powercontext
app.kubernetes.io/instance: {{ .Release.Name | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | quote }}
{{- end -}}
{{- define "powercontext.image" -}}
{{- $repo := required "image.repository is required" .Values.image.repository -}}
{{- if .Values.image.digest -}}
{{- printf "%s@%s" $repo .Values.image.digest -}}
{{- else -}}
{{- $tag := required "image.tag or image.digest is required" .Values.image.tag -}}
{{- if eq $tag "latest" -}}{{ fail "image.tag must be pinned; latest is unsupported" }}{{- end -}}
{{- printf "%s:%s" $repo $tag -}}
{{- end -}}
{{- end -}}
146 changes: 146 additions & 0 deletions deploy/helm/powercontext/templates/deployments.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Copyright (c) 2026 OceanBase.
#
# Licensed 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.

{{- $root := . -}}
{{- $secret := required "existingSecret is required" .Values.existingSecret -}}
{{- range $role := list "api" "background" }}
{{- $config := index $root.Values $role }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "powercontext.name" $root }}-{{ $role }}
labels:
{{- include "powercontext.labels" $root | nindent 4 }}
app.kubernetes.io/component: {{ $role }}
spec:
replicas: {{ $config.replicas }}
# Upgrades are coordinated offline; this does not promise mixed-version support.
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/instance: {{ $root.Release.Name | quote }}
app.kubernetes.io/name: powercontext
app.kubernetes.io/component: {{ $role }}
template:
metadata:
labels:
{{- include "powercontext.labels" $root | nindent 8 }}
app.kubernetes.io/component: {{ $role }}
{{- with $root.Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
automountServiceAccountToken: false
terminationGracePeriodSeconds: {{ $root.Values.terminationGracePeriodSeconds }}
securityContext:
{{- toYaml $root.Values.podSecurityContext | nindent 8 }}
{{- with $root.Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: powercontext
image: {{ include "powercontext.image" $root | quote }}
imagePullPolicy: {{ $root.Values.image.pullPolicy }}
args: ["server", "run"]
securityContext:
{{- toYaml $root.Values.securityContext | nindent 12 }}
{{- with $root.Values.providerSecret }}
envFrom:
- secretRef:
name: {{ . | quote }}
{{- end }}
env:
- name: POWERCONTEXT_HOME
value: /data
- name: POWERCONTEXT_SERVER_DATABASE_KIND
value: oceanbase
- name: POWERCONTEXT_SERVER_DATABASE_URL
valueFrom:
secretKeyRef:
name: {{ $secret | quote }}
key: {{ $root.Values.secretKeys.databaseUrl | quote }}
- name: POWERCONTEXT_SERVER_AUTH_TOKEN
valueFrom:
secretKeyRef:
name: {{ $secret | quote }}
key: {{ $root.Values.secretKeys.bearerToken | quote }}
- name: POWERCONTEXT_SERVER_CURSOR_SIGNING_SECRET
valueFrom:
secretKeyRef:
name: {{ $secret | quote }}
key: {{ $root.Values.secretKeys.cursorSigningSecret | quote }}
- name: POWERCONTEXT_SERVER_ACCESS_MODE
value: enforced
- name: POWERCONTEXT_SERVER_AUTH_ENABLED
value: "true"
- name: POWERCONTEXT_SERVER_ALLOW_UNAUTHENTICATED_NON_LOOPBACK
value: "false"
- name: POWERCONTEXT_SERVER_HTTP_HOST
value: "0.0.0.0"
- name: POWERCONTEXT_SERVER_HTTP_PORT
value: "8000"
- name: POWERCONTEXT_SERVER_RUNTIME_ARTIFACT_PROCESSING_ROLE
value: {{ $role }}
- name: POWERCONTEXT_SERVER_RUNTIME_ARTIFACT_PROCESSING_SUPERVISOR_MODE
value: global
- name: POWERCONTEXT_SERVER_RUNTIME_ARTIFACT_PROCESSING_MAX_WORKERS
value: {{ $root.Values.background.maxWorkers | quote }}
- name: POWERCONTEXT_SERVER_EXTERNAL_SKILLS
value: '{"targets": []}'
- name: POWERCONTEXT_SERVER_LOGGING_FORMAT
value: json
{{- range $key, $value := $root.Values.inference }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
{{- if eq $role "api" }}
ports:
- name: http
containerPort: 8000
startupProbe:
{{- toYaml $config.startupProbe | nindent 12 }}
livenessProbe:
{{- toYaml $config.livenessProbe | nindent 12 }}
readinessProbe:
{{- toYaml $config.readinessProbe | nindent 12 }}
{{- end }}
resources:
{{- toYaml $config.resources | nindent 12 }}
volumeMounts:
- name: data
mountPath: /data
- name: tmp
mountPath: /tmp
volumes:
- name: data
emptyDir: {}
- name: tmp
emptyDir: {}
{{- with $root.Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with $root.Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with $root.Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
45 changes: 45 additions & 0 deletions deploy/helm/powercontext/templates/ingress.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Copyright (c) 2026 OceanBase.
#
# Licensed 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.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "powercontext.name" . }}
labels:
{{- include "powercontext.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.ingress.className }}
ingressClassName: {{ . | quote }}
{{- end }}
{{- with .Values.ingress.tls }}
tls:
{{- toYaml . | nindent 4 }}
{{- end }}
rules:
- host: {{ required "ingress.host is required when ingress is enabled" .Values.ingress.host | quote }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ include "powercontext.name" . }}
port:
name: http
{{- end }}
30 changes: 30 additions & 0 deletions deploy/helm/powercontext/templates/service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright (c) 2026 OceanBase.
#
# Licensed 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.

apiVersion: v1
kind: Service
metadata:
name: {{ include "powercontext.name" . }}
labels:
{{- include "powercontext.labels" . | nindent 4 }}
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: powercontext
app.kubernetes.io/instance: {{ .Release.Name | quote }}
app.kubernetes.io/component: api
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: http
23 changes: 23 additions & 0 deletions deploy/helm/powercontext/values-acceptance.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright (c) 2026 OceanBase.
#
# Licensed 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.

# Only for an isolated namespace and disposable external OceanBase database.
# Supply the application image and existingSecret in your local values file.
api:
replicas: 2
background:
replicas: 1
inference:
# Enables background processing without calling an external model provider.
POWERCONTEXT_SERVER_INFERENCE_GENERATION_MODEL: test
Loading
Loading