fix: ignore identity template placeholders

This commit is contained in:
Peter Steinberger
2026-01-24 05:35:34 +00:00
parent 886752217d
commit eba0625a70
4 changed files with 73 additions and 5 deletions

View File

@@ -17,6 +17,7 @@ Docs: https://docs.clawd.bot
- Tlon: add Urbit channel plugin (DMs, group mentions, thread replies). (#1544) Thanks @wca4a.
### Fixes
- Agents: ignore IDENTITY.md template placeholders when parsing identity to avoid placeholder replies. (#1556)
- Docker: update gateway command in docker-compose and Hetzner guide. (#1514)
- Sessions: reject array-backed session stores to prevent silent wipes. (#1469)
- Voice wake: auto-save wake words on blur/submit across iOS/Android and align limits with macOS.

View File

@@ -7,11 +7,16 @@ read_when:
*Fill this in during your first conversation. Make it yours.*
- **Name:** *(pick something you like)*
- **Creature:** *(AI? robot? familiar? ghost in the machine? something weirder?)*
- **Vibe:** *(how do you come across? sharp? warm? chaotic? calm?)*
- **Emoji:** *(your signature — pick one that feels right)*
- **Avatar:** *(workspace-relative path, http(s) URL, or data URI)*
- **Name:**
*(pick something you like)*
- **Creature:**
*(AI? robot? familiar? ghost in the machine? something weirder?)*
- **Vibe:**
*(how do you come across? sharp? warm? chaotic? calm?)*
- **Emoji:**
*(your signature — pick one that feels right)*
- **Avatar:**
*(workspace-relative path, http(s) URL, or data URI)*
---

View File

@@ -0,0 +1,37 @@
import { describe, expect, it } from "vitest";
import { parseIdentityMarkdown } from "./identity-file.js";
describe("parseIdentityMarkdown", () => {
it("ignores identity template placeholders", () => {
const content = `
# IDENTITY.md - Who Am I?
- **Name:** *(pick something you like)*
- **Creature:** *(AI? robot? familiar? ghost in the machine? something weirder?)*
- **Vibe:** *(how do you come across? sharp? warm? chaotic? calm?)*
- **Emoji:** *(your signature - pick one that feels right)*
- **Avatar:** *(workspace-relative path, http(s) URL, or data URI)*
`;
const parsed = parseIdentityMarkdown(content);
expect(parsed).toEqual({});
});
it("parses explicit identity values", () => {
const content = `
- **Name:** Samantha
- **Creature:** Robot
- **Vibe:** Warm
- **Emoji:** :robot:
- **Avatar:** avatars/clawd.png
`;
const parsed = parseIdentityMarkdown(content);
expect(parsed).toEqual({
name: "Samantha",
creature: "Robot",
vibe: "Warm",
emoji: ":robot:",
avatar: "avatars/clawd.png",
});
});
});

View File

@@ -12,6 +12,30 @@ export type AgentIdentityFile = {
avatar?: string;
};
const IDENTITY_PLACEHOLDER_VALUES = new Set([
"pick something you like",
"ai? robot? familiar? ghost in the machine? something weirder?",
"how do you come across? sharp? warm? chaotic? calm?",
"your signature - pick one that feels right",
"workspace-relative path, http(s) url, or data uri",
]);
function normalizeIdentityValue(value: string): string {
let normalized = value.trim();
normalized = normalized.replace(/^[*_]+|[*_]+$/g, "").trim();
if (normalized.startsWith("(") && normalized.endsWith(")")) {
normalized = normalized.slice(1, -1).trim();
}
normalized = normalized.replace(/[\u2013\u2014]/g, "-");
normalized = normalized.replace(/\s+/g, " ").toLowerCase();
return normalized;
}
function isIdentityPlaceholder(value: string): boolean {
const normalized = normalizeIdentityValue(value);
return IDENTITY_PLACEHOLDER_VALUES.has(normalized);
}
export function parseIdentityMarkdown(content: string): AgentIdentityFile {
const identity: AgentIdentityFile = {};
const lines = content.split(/\r?\n/);
@@ -25,6 +49,7 @@ export function parseIdentityMarkdown(content: string): AgentIdentityFile {
.replace(/^[*_]+|[*_]+$/g, "")
.trim();
if (!value) continue;
if (isIdentityPlaceholder(value)) continue;
if (label === "name") identity.name = value;
if (label === "emoji") identity.emoji = value;
if (label === "creature") identity.creature = value;