Skip to content

Commit 93f9489

Browse files
authored
helm: upgrade helm 1.4.3 with ai analysis
helm: upgrade helm 1.4.3 with ai analysis
2 parents 6f2d575 + 498ef9a commit 93f9489

7 files changed

Lines changed: 122 additions & 112 deletions

File tree

helm/versus-incident/Chart.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ apiVersion: v2
22
name: versus-incident
33
description: A Helm chart for Versus Incident Management System
44
type: application
5-
version: 1.4.0
6-
appVersion: "1.4.0"
5+
version: 1.4.3
6+
appVersion: "1.4.3"
77

88
# Dependencies
99
dependencies:

helm/versus-incident/README.md

Lines changed: 13 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ alert:
105105
| `agent.ai.apiKey` | OpenAI API key (stored in chart Secret) | `""` |
106106
| `agent.ai.model` | Model identifier | `"gpt-4o-mini"` |
107107
| `agent.ai.maxCallsPerHour` | Per-hour AI call rate limit (`0` = unlimited) | `60` |
108+
| `agent.ai.analyze.model` | Override model for the on-demand analyze agent (empty inherits `agent.ai.model`) | `""` |
109+
| `agent.tools.toolTimeout` | Per-tool dispatch timeout for analyze tools | `"20s"` |
110+
| `agent.tools.parallelTools` | Run multiple tool calls in one model turn concurrently | `false` |
111+
| `agent.tools.recentChanges.git.repos` | Remote git repos read by the `recent_changes` tool (empty = unregistered) | `[]` |
112+
| `agent.tools.describeDependencies.services` | Service-dependency graph for the `describe_dependencies` tool (empty = unregistered) | `[]` |
108113
| `agent.sources` | Inline list of signal sources (snake_case keys) | `[]` |
109114
| `alert.slack.enable` | Enable Slack notifications | `false` |
110115
| `alert.slack.token` | Slack bot token | `""` |
@@ -404,49 +409,19 @@ config:
404409
publicHost: "https://versus-incident.example.com"
405410
```
406411

407-
## Horizontal Pod Autoscaler Configuration
412+
## Scaling and Replicas
408413

409-
The Helm chart supports configuring a Horizontal Pod Autoscaler (HPA) to automatically scale the number of pods based on CPU and memory utilization:
414+
This chart does NOT ship a HorizontalPodAutoscaler. The AI SRE Agent worker is
415+
a single writer to the pattern catalog and detect log, so the agent must run
416+
with `replicaCount: 1` — horizontal scaling would produce racing writes (the
417+
chart fails fast if `agent.enable=true` with more than one replica). For
418+
deployments that do not enable the agent you may raise `replicaCount`, but the
419+
number of pods is fixed by that value and is not autoscaled.
410420

411421
```yaml
412-
autoscaling:
413-
enabled: true
414-
minReplicas: 2
415-
maxReplicas: 10
416-
targetCPUUtilizationPercentage: 80
417-
targetMemoryUtilizationPercentage: 80
422+
replicaCount: 1 # required when agent.enable=true
418423
```
419424

420-
For more advanced scaling behavior, you can use the `behavior` configuration:
421-
422-
```yaml
423-
autoscaling:
424-
enabled: true
425-
minReplicas: 2
426-
maxReplicas: 10
427-
targetCPUUtilizationPercentage: 80
428-
targetMemoryUtilizationPercentage: 80
429-
behavior:
430-
scaleDown:
431-
stabilizationWindowSeconds: 300
432-
policies:
433-
- type: Percent
434-
value: 100
435-
periodSeconds: 15
436-
scaleUp:
437-
stabilizationWindowSeconds: 0
438-
policies:
439-
- type: Percent
440-
value: 100
441-
periodSeconds: 15
442-
- type: Pods
443-
value: 4
444-
periodSeconds: 15
445-
selectPolicy: Max
446-
```
447-
448-
Note: When enabling autoscaling, the `replicaCount` value in your values.yaml is only used for the initial deployment before the HPA takes over scaling control.
449-
450425
## Uninstalling the Chart
451426

452427
To uninstall/delete the `versus-incident` deployment:

helm/versus-incident/templates/_validate.tpl

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,10 @@ Caught here:
4747
{{- end -}}
4848
{{- if eq $type "file" -}}
4949
{{- $replicas := int (default 1 .Values.replicaCount) -}}
50-
{{- if .Values.autoscaling.enabled -}}
51-
{{- $replicas = int (default 1 .Values.autoscaling.minReplicas) -}}
52-
{{- end -}}
5350
{{- if and .Values.storage.persistence.enabled (gt $replicas 1) -}}
5451
{{- $access := .Values.storage.persistence.accessMode | default "ReadWriteOnce" -}}
5552
{{- if eq $access "ReadWriteOnce" -}}
56-
{{- fail (printf "versus-incident: storage.persistence.enabled=true with %d replicas and accessMode=ReadWriteOnce. The PVC cannot be mounted on more than one pod. Set replicaCount=1 (and autoscaling.enabled=false), use accessMode=ReadWriteMany, or switch to a non-file storage backend." $replicas) -}}
53+
{{- fail (printf "versus-incident: storage.persistence.enabled=true with %d replicas and accessMode=ReadWriteOnce. The PVC cannot be mounted on more than one pod. Set replicaCount=1, use accessMode=ReadWriteMany, or switch to a non-file storage backend." $replicas) -}}
5754
{{- end -}}
5855
{{- end -}}
5956
{{- if and .Values.storage.persistence.existingClaim (not .Values.storage.persistence.enabled) -}}
@@ -79,11 +76,8 @@ Caught here:
7976
{{- fail (printf "versus-incident: agent.mode=%q is not recognised. Valid values: training, shadow, detect." $mode) -}}
8077
{{- end -}}
8178
{{- $replicas := int (default 1 .Values.replicaCount) -}}
82-
{{- if .Values.autoscaling.enabled -}}
83-
{{- $replicas = int (default 1 .Values.autoscaling.minReplicas) -}}
84-
{{- end -}}
8579
{{- if gt $replicas 1 -}}
86-
{{- fail (printf "versus-incident: agent.enable=true with %d replicas. The agent worker is single-writer to the pattern catalog and detect log; running multiple replicas will produce racing writes. Set replicaCount=1 and autoscaling.enabled=false when running the agent." $replicas) -}}
80+
{{- fail (printf "versus-incident: agent.enable=true with %d replicas. The agent worker is single-writer to the pattern catalog and detect log; running multiple replicas will produce racing writes. Set replicaCount=1 when running the agent." $replicas) -}}
8781
{{- end -}}
8882
{{- if .Values.agent.ai.enable -}}
8983
{{- if not .Values.agent.ai.apiKey -}}

helm/versus-incident/templates/configmap.yaml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ data:
211211
max_tokens: {{ .Values.agent.ai.maxTokens | default 512 }}
212212
max_calls_per_hour: {{ .Values.agent.ai.maxCallsPerHour | default 60 }}
213213
cache_ttl: {{ .Values.agent.ai.cacheTtl | default "1h" | quote }}
214+
{{- if .Values.agent.ai.analyze.model }}
215+
analyze:
216+
model: {{ .Values.agent.ai.analyze.model | quote }}
217+
{{- end }}
214218
{{- end }}
215219
216220
{{- if .Values.agent.enable }}
@@ -223,6 +227,55 @@ data:
223227
{{- end }}
224228
{{- end }}
225229

230+
{{- if .Values.agent.enable }}
231+
tools.yaml: |
232+
# Per-tool DATA config for the analyze tools (rendered by Helm).
233+
tools:
234+
tool_timeout: {{ .Values.agent.tools.toolTimeout | default "20s" | quote }}
235+
parallel_tools: {{ .Values.agent.tools.parallelTools | default false }}
236+
recent_changes:
237+
git:
238+
auth:
239+
token: {{ .Values.agent.tools.recentChanges.git.auth.token | default "" | quote }}
240+
ssh_key_path: {{ .Values.agent.tools.recentChanges.git.auth.sshKeyPath | default "" | quote }}
241+
repos:
242+
{{- if .Values.agent.tools.recentChanges.git.repos }}
243+
{{- range .Values.agent.tools.recentChanges.git.repos }}
244+
- url: {{ .url | quote }}
245+
{{- if .branch }}
246+
branch: {{ .branch | quote }}
247+
{{- end }}
248+
{{- if .service }}
249+
service: {{ .service | quote }}
250+
{{- end }}
251+
{{- if .auth }}
252+
auth:
253+
token: {{ .auth.token | default "" | quote }}
254+
ssh_key_path: {{ .auth.sshKeyPath | default "" | quote }}
255+
{{- end }}
256+
{{- end }}
257+
{{- else }}
258+
[]
259+
{{- end }}
260+
describe_dependencies:
261+
services:
262+
{{- if .Values.agent.tools.describeDependencies.services }}
263+
{{- range .Values.agent.tools.describeDependencies.services }}
264+
- name: {{ .name | quote }}
265+
depends_on:
266+
{{- if .dependsOn }}
267+
{{- range .dependsOn }}
268+
- {{ . | quote }}
269+
{{- end }}
270+
{{- else }}
271+
[]
272+
{{- end }}
273+
{{- end }}
274+
{{- else }}
275+
[]
276+
{{- end }}
277+
{{- end }}
278+
226279
{{- if .Values.templates.slack }}
227280
slack_message.tmpl: |
228281
{{ .Values.templates.slack | indent 4 }}

helm/versus-incident/templates/deployment.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ metadata:
55
labels:
66
{{- include "versus-incident.labels" . | nindent 4 }}
77
spec:
8-
{{- if not .Values.autoscaling.enabled }}
98
replicas: {{ .Values.replicaCount }}
10-
{{- end }}
119
selector:
1210
matchLabels:
1311
{{- include "versus-incident.selectorLabels" . | nindent 6 }}
@@ -406,6 +404,9 @@ spec:
406404
- name: config-volume
407405
mountPath: /app/config/agent_sources.yaml
408406
subPath: agent_sources.yaml
407+
- name: config-volume
408+
mountPath: /app/config/tools.yaml
409+
subPath: tools.yaml
409410
{{- end }}
410411
{{- if eq (.Values.storage.type | default "file") "file" }}
411412
- name: data-volume

helm/versus-incident/templates/hpa.yaml

Lines changed: 0 additions & 36 deletions
This file was deleted.

helm/versus-incident/values.yaml

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,32 +44,6 @@ resources:
4444
cpu: 200m
4545
memory: 256Mi
4646

47-
# Autoscaling configuration
48-
autoscaling:
49-
enabled: false
50-
minReplicas: 2
51-
maxReplicas: 10
52-
targetCPUUtilizationPercentage: 80
53-
targetMemoryUtilizationPercentage: 80
54-
# Optional: configure scaling behavior
55-
# behavior:
56-
# scaleDown:
57-
# stabilizationWindowSeconds: 300
58-
# policies:
59-
# - type: Percent
60-
# value: 100
61-
# periodSeconds: 15
62-
# scaleUp:
63-
# stabilizationWindowSeconds: 0
64-
# policies:
65-
# - type: Percent
66-
# value: 100
67-
# periodSeconds: 15
68-
# - type: Pods
69-
# value: 4
70-
# periodSeconds: 15
71-
# selectPolicy: Max
72-
7347
livenessProbe:
7448
httpGet:
7549
path: /healthz
@@ -150,6 +124,55 @@ agent:
150124
maxTokens: 512
151125
maxCallsPerHour: 60
152126
cacheTtl: "1h"
127+
# AnalyzeAgent — powers POST /api/admin/incidents/:id/analyze and the
128+
# "Run analysis" button in the UI. Tool-calling (ReAct), read-only, never
129+
# emits a notification. Active whenever ai.enable=true; this block only
130+
# tunes it.
131+
analyze:
132+
# Override the shared ai.model for analyze deep dives. Empty inherits
133+
# the top-level model above.
134+
model: ""
135+
136+
# Per-tool configuration for the analyze tools (rendered into tools.yaml).
137+
# This is DATA config only, never a registration allow-list — tools are
138+
# wired in code. A missing/empty block degrades the affected tool to a
139+
# clean "nothing found" rather than an error.
140+
tools:
141+
# Shared tool-loop knobs applied to every analyze tool dispatch.
142+
toolTimeout: "20s" # cap per tool dispatch; empty/"0"/invalid = 20s default
143+
parallelTools: false # run tool calls in one model turn concurrently
144+
# recent_changes — correlate an incident with recent deploys / config
145+
# changes pulled from one or more REMOTE git repositories' commit
146+
# histories (pure-Go go-git; no git binary required). An empty repos
147+
# list leaves the tool unregistered.
148+
recentChanges:
149+
git:
150+
# Global default auth applied to every repo without its own block.
151+
# Empty relies on ambient credentials.
152+
auth:
153+
token: "" # HTTPS access token / PAT (e.g. ${GIT_TOKEN})
154+
sshKeyPath: "" # path to a private SSH key for ssh/scp-like remotes
155+
# Each entry: { url, branch?, service?, auth? }. url is required.
156+
repos: []
157+
# - url: https://github.com/acme/api.git
158+
# branch: main # optional; empty = default HEAD
159+
# service: api # optional; empty = auto-detected from repo name
160+
# - url: git@github.com:acme/web.git # service auto-detected as "web"
161+
# auth: # optional; per-repo override of git.auth
162+
# sshKeyPath: /home/versus/.ssh/web_deploy
163+
# describe_dependencies — surface a service's upstream/downstream
164+
# neighbours. Only depends_on (upstream) is authored; downstream edges
165+
# are derived automatically. An empty services list leaves the tool
166+
# unregistered.
167+
describeDependencies:
168+
services: []
169+
# - name: web
170+
# dependsOn:
171+
# - api
172+
# - name: api
173+
# dependsOn:
174+
# - database
175+
# - cache
153176

154177
# Inline signal sources. Each entry is rendered verbatim (via toYaml)
155178
# into agent_sources.yaml — use snake_case keys matching the Go config

0 commit comments

Comments
 (0)