diff --git a/docs/installation.md b/docs/installation.md index 459f060..d20b9b9 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -260,6 +260,36 @@ kubectl -n mosaic get secret mosaic-ui-auth -o jsonpath='{.data.password}' | bas Open `http://localhost:3000` and sign in with the username and password above. +### Agent display name + +Set `openclaw.agentDisplayName` to customize the default agent's display name and +OpenClaw identity: + +```yaml +openclaw: + agentDisplayName: "Operations Agent" +``` + +For an existing release, apply the setting while preserving its site values: + +```bash +helm upgrade mosaic "$MOSAIC_CHART" \ + --devel \ + -n mosaic \ + --reuse-values \ + --set-string openclaw.agentDisplayName="Operations Agent" \ + --wait \ + --timeout 12m +``` + +The default is empty: the agent keeps the seed name `AI Factory Operations Agent` +and no explicit identity override. A nonempty value sets both `agents.list[].name` +and `agents.list[].identity.name`. Channels that display the agent identity can +then show the configured name; each channel controls its message presentation. +The internal agent ID remains `default`, preserving routing and session keys. +The messaging platform's application or bot profile name is managed separately +in that platform's administration console. + ## Extensions All module changes below update an existing AI Factory Operations Agent release and preserve its current site configuration. diff --git a/helm/mosaic-stack/files/agent-documentation.tar.gz b/helm/mosaic-stack/files/agent-documentation.tar.gz index 4abee1d..5c7478a 100644 Binary files a/helm/mosaic-stack/files/agent-documentation.tar.gz and b/helm/mosaic-stack/files/agent-documentation.tar.gz differ diff --git a/helm/mosaic-stack/files/openclaw-seed/nemoclaw.json b/helm/mosaic-stack/files/openclaw-seed/nemoclaw.json index dfcd85f..e3427b5 100644 --- a/helm/mosaic-stack/files/openclaw-seed/nemoclaw.json +++ b/helm/mosaic-stack/files/openclaw-seed/nemoclaw.json @@ -90,7 +90,12 @@ "list": [ { "id": "default", - "name": "AI Factory Operations Agent", + "name": {{ default "AI Factory Operations Agent" .Values.openclaw.agentDisplayName | toJson }}, + {{- if .Values.openclaw.agentDisplayName }} + "identity": { + "name": {{ .Values.openclaw.agentDisplayName | toJson }} + }, + {{- end }} "workspace": "~/.openclaw/workspace", "thinkingDefault": "off", "reasoningDefault": "off" diff --git a/helm/mosaic-stack/templates/validation.yaml b/helm/mosaic-stack/templates/validation.yaml index e336520..9d59dd1 100644 --- a/helm/mosaic-stack/templates/validation.yaml +++ b/helm/mosaic-stack/templates/validation.yaml @@ -7,6 +7,9 @@ {{- if not (has .Values.modules.slurm.backend (list "auto" "vanilla" "bcm")) -}} {{- fail "modules.slurm.backend must be one of: auto, vanilla, bcm" -}} {{- end -}} +{{- if and (hasKey .Values.openclaw "agentDisplayName") (not (kindIs "string" .Values.openclaw.agentDisplayName)) -}} +{{- fail "openclaw.agentDisplayName must be a string" -}} +{{- end -}} {{- if and .Values.openclaw.slack.enabled (not .Values.openclaw.slack.existingSecret) -}} {{- fail "openclaw.slack.existingSecret is required when native Slack is enabled" -}} {{- end -}} diff --git a/helm/mosaic-stack/tests/chart-render.test.mjs b/helm/mosaic-stack/tests/chart-render.test.mjs index 6052459..005c835 100644 --- a/helm/mosaic-stack/tests/chart-render.test.mjs +++ b/helm/mosaic-stack/tests/chart-render.test.mjs @@ -384,6 +384,39 @@ test("generates a bearer credential with a chart-managed Research Agent Secret", assert.match(output, /name: iraop-secrets[\s\S]*IRAOP_API_KEY: "[A-Za-z0-9]{48}"/); }); +test("agent display name defaults preserve the existing agent identity", () => { + const baseline = openclawConfig(); + assert.deepEqual(baseline.agents.list, [{ + id: "default", + name: "AI Factory Operations Agent", + workspace: "~/.openclaw/workspace", + thinkingDefault: "off", + reasoningDefault: "off", + }]); + assert.deepEqual(openclawConfig("--set-string", "openclaw.agentDisplayName="), baseline); + assert.deepEqual(openclawConfig("--set-json", "openclaw.agentDisplayName=null"), baseline); +}); + +test("agent display name overrides both names without changing routing or other configuration", () => { + const baseline = openclawConfig(); + for (const name of ["Operations Agent", '值班 "Agent" \\ {{ .Release.Name }}\n\u0001']) { + const config = openclawConfig("--set-json", `openclaw.agentDisplayName=${JSON.stringify(name)}`); + const expected = structuredClone(baseline); + expected.agents.list[0].name = name; + expected.agents.list[0].identity = { name }; + assert.deepEqual(config, expected); + } +}); + +test("agent display name rejects non-string values", () => { + for (const value of [false, 0, 42, [], {}]) { + const result = spawnSync("helm", ["template", "mosaic", chart, + "--set-json", `openclaw.agentDisplayName=${JSON.stringify(value)}`], { encoding: "utf8" }); + assert.notEqual(result.status, 0); + assert.match(result.stderr, /openclaw\.agentDisplayName must be a string/); + } +}); + test("additional model options preserve the primary provider and model", () => { const baseline = JSON.parse(configMapBlock(render("--show-only", "templates/openclaw-seed-configmap.yaml"), "openclaw.json")); assert.deepEqual(Object.keys(baseline.models.providers), ["llm"]); diff --git a/helm/mosaic-stack/values.yaml b/helm/mosaic-stack/values.yaml index d1d0c32..5e1a7e9 100644 --- a/helm/mosaic-stack/values.yaml +++ b/helm/mosaic-stack/values.yaml @@ -264,6 +264,8 @@ mosaicUi: machineToken: "" openclaw: enabled: true + # Optional display name and channel identity for the default agent; empty preserves the seed defaults. + agentDisplayName: "" # Additional gateway environment variables, including Secret references for providers. extraEnv: [] # OpenClaw provider definitions keyed by provider ID; llm is reserved for the primary provider.