afe8f1103a
Two bugs from review, the second in both agents because identity.py is a copy. The exchanged-token cache grew for the life of the process. It is keyed on (subject token, scope) and the subject token is minted fresh every turn, so every turn added keys nothing would ever read again — and expiry was checked on read but never collected. A slow leak that only shows in a pod up for days, which is the worst way to find one. It now drops expired entries first and evicts oldest beyond a bound. Expired first on purpose: an expired entry is dead weight wherever it sits in the ordering, so evicting by age alone would keep it while discarding a live one. The docstring was wrong before the code was: it claimed the cache lasted one turn. It never did. Corrected rather than quietly made true. message_id reused the context id, which is the conversation — and a conversation makes several calls to the same peer, relaying an approval being exactly that. A peer treating the second call as a replay of the first would surface as a stale answer rather than an error. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
77 lines
2.5 KiB
YAML
77 lines
2.5 KiB
YAML
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: catalogue-agent
|
|
namespace: agents
|
|
spec:
|
|
# One replica, and that is a constraint rather than a default. Conversation
|
|
# history — which the confirm-before-writing flow depends on — lives in the
|
|
# process, keyed by A2A contextId. A second replica would route the user's
|
|
# "yes" to a pod that never saw the question. Scaling out needs sticky routing
|
|
# on contextId or a shared store first.
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: catalogue-agent
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: catalogue-agent
|
|
spec:
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
runAsUser: 10001
|
|
seccompProfile:
|
|
type: RuntimeDefault
|
|
containers:
|
|
- name: agent
|
|
# gitea's own registry, not ghcr: the image sits beside the source it
|
|
# was built from, and the package inherits the repo's visibility. The
|
|
# repo is public, so the pull needs no credentials — which removes an
|
|
# imagePullSecret that would otherwise have to be created by hand in
|
|
# this namespace and kept in step with a GitHub token.
|
|
image: gitea.sttlab.eu/stt/classic-models-agent-catalogue:v0.3.2
|
|
ports:
|
|
- name: http
|
|
containerPort: 8080
|
|
envFrom:
|
|
- configMapRef:
|
|
name: catalogue-agent-config
|
|
- secretRef:
|
|
name: catalogue-agent-secrets
|
|
volumeMounts:
|
|
- name: sttlab-ca
|
|
mountPath: /etc/sttlab-ca
|
|
readOnly: true
|
|
# The Agent Card needs no auth and is served by the same app, so a 200
|
|
# means the A2A routes are genuinely mounted — not merely that the
|
|
# process is alive.
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /.well-known/agent-card.json
|
|
port: http
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 10
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /.well-known/agent-card.json
|
|
port: http
|
|
initialDelaySeconds: 15
|
|
periodSeconds: 20
|
|
resources:
|
|
requests:
|
|
cpu: 50m
|
|
memory: 192Mi
|
|
limits:
|
|
cpu: "1"
|
|
memory: 512Mi
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: true
|
|
capabilities:
|
|
drop: ["ALL"]
|
|
volumes:
|
|
- name: sttlab-ca
|
|
configMap:
|
|
name: sttlab-ca
|