Skip to content

Commit fff11cb

Browse files
committed
refactor(agents): replace engine-based character configuration with persona-based system
- Migrated from engine-specific character configurations to a persona-based system for improved flexibility and clarity. - Updated agent mapping to use personas, enabling more dynamic assignments of visual and behavior traits. - Refactored `output-window` and related utilities to reflect persona-based logic for agents. - Simplified and streamlined agent character configuration files and type definitions.
1 parent f995d4d commit fff11cb

4 files changed

Lines changed: 69 additions & 91 deletions

File tree

config/agent-characters.json

Lines changed: 36 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
{
2-
"engines": {
3-
"claude": {
4-
"name": "Claude",
2+
"personas": {
3+
"friendly": {
54
"baseFace": "(˶ᵔ ᵕ ᵔ˶)",
65
"expressions": {
76
"thinking": "(╭ರ_•́)",
@@ -16,8 +15,7 @@
1615
"idle": ["Ready when you are", "Waiting..."]
1716
}
1817
},
19-
"codex": {
20-
"name": "Codex",
18+
"analytical": {
2119
"baseFace": "[•_•]",
2220
"expressions": {
2321
"thinking": "[•_•]~",
@@ -32,24 +30,7 @@
3230
"idle": ["Standing by", "Awaiting input"]
3331
}
3432
},
35-
"cursor": {
36-
"name": "Cursor",
37-
"baseFace": "⌨_⌨",
38-
"expressions": {
39-
"thinking": "⌨~⌨",
40-
"tool": "⌨!⌨",
41-
"error": "⌨x⌨",
42-
"idle": "⌨_⌨"
43-
},
44-
"phrases": {
45-
"thinking": ["Thinking...", "Processing..."],
46-
"tool": ["Executing...", "Working..."],
47-
"error": ["Error", "Something went wrong"],
48-
"idle": ["Ready", "Waiting..."]
49-
}
50-
},
51-
"auggie": {
52-
"name": "Auggie",
33+
"cheerful": {
5334
"baseFace": "◕‿◕",
5435
"expressions": {
5536
"thinking": "◕~◕",
@@ -64,24 +45,7 @@
6445
"idle": ["Here to help!", "Ready for action"]
6546
}
6647
},
67-
"mistral": {
68-
"name": "Mistral",
69-
"baseFace": "≋_≋",
70-
"expressions": {
71-
"thinking": "≋~≋",
72-
"tool": "≋!≋",
73-
"error": "≋x≋",
74-
"idle": "≋_≋"
75-
},
76-
"phrases": {
77-
"thinking": ["Analyzing...", "Processing..."],
78-
"tool": ["Running...", "Executing..."],
79-
"error": ["Error detected", "Retrying..."],
80-
"idle": ["Awaiting", "Standing by"]
81-
}
82-
},
83-
"opencode": {
84-
"name": "OpenCode",
48+
"technical": {
8549
"baseFace": "{•_•}",
8650
"expressions": {
8751
"thinking": "{•~•}",
@@ -96,8 +60,7 @@
9660
"idle": ["Ready", "Waiting..."]
9761
}
9862
},
99-
"ccr": {
100-
"name": "CCR",
63+
"precise": {
10164
"baseFace": "<•_•>",
10265
"expressions": {
10366
"thinking": "<•~•>",
@@ -106,27 +69,37 @@
10669
"idle": "<•_•>"
10770
},
10871
"phrases": {
109-
"thinking": ["Thinking...", "Processing..."],
110-
"tool": ["Running...", "Working..."],
111-
"error": ["Error", "Retrying..."],
112-
"idle": ["Ready", "Waiting..."]
72+
"thinking": ["Evaluating...", "Checking..."],
73+
"tool": ["Validating...", "Running checks..."],
74+
"error": ["Issue detected", "Reviewing..."],
75+
"idle": ["Ready", "Monitoring..."]
11376
}
11477
}
11578
},
116-
"defaults": {
117-
"name": "Agent",
118-
"baseFace": "(•_•)",
119-
"expressions": {
120-
"thinking": "(•_•)?",
121-
"tool": "(•_•)!",
122-
"error": "(•_•);;",
123-
"idle": "(•_•)"
124-
},
125-
"phrases": {
126-
"thinking": ["Thinking..."],
127-
"tool": ["Working..."],
128-
"error": ["Error"],
129-
"idle": ["Ready"]
130-
}
131-
}
79+
"agents": {
80+
"bmad-analyst": "friendly",
81+
"bmad-pm": "analytical",
82+
"bmad-ux": "cheerful",
83+
"bmad-architect": "analytical",
84+
"bmad-epics": "analytical",
85+
"bmad-tea": "precise",
86+
"bmad-readiness": "precise",
87+
"bmad-sprints": "cheerful",
88+
"bmad-stories": "cheerful",
89+
"bmad-dev": "technical",
90+
"bmad-po": "analytical",
91+
"cm-workflow-builder": "friendly",
92+
"init": "friendly",
93+
"principal-analyst": "analytical",
94+
"blueprint-orchestrator": "analytical",
95+
"plan-agent": "analytical",
96+
"task-breakdown": "technical",
97+
"context-manager": "technical",
98+
"code-generation": "technical",
99+
"task-sanity-check": "precise",
100+
"runtime-prep": "technical",
101+
"git-commit": "technical",
102+
"plan-fallback": "analytical"
103+
},
104+
"defaultPersona": "friendly"
132105
}

src/cli/tui/routes/workflow/components/output/output-window.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,11 @@ export function OutputWindow(props: OutputWindowProps) {
166166
return themeCtx.theme.warning
167167
}
168168

169-
// Get display name/engine/model (controller when delegated or controller view, step agent otherwise)
169+
// Get display name/engine/model/id (controller when delegated or controller view, step agent otherwise)
170170
const displayName = () => isControllerActive() ? props.controllerState!.name : props.currentAgent?.name
171171
const displayEngine = () => isControllerActive() ? props.controllerState!.engine : props.currentAgent?.engine
172172
const displayModel = () => isControllerActive() ? props.controllerState!.model : props.currentAgent?.model
173+
const displayAgentId = () => isControllerActive() ? props.controllerState!.id : props.currentAgent?.id
173174

174175
// Derive activity from agent status, with log-based refinement when running
175176
const derivedActivity = (): ActivityType => {
@@ -194,9 +195,9 @@ export function OutputWindow(props: OutputWindowProps) {
194195
return "idle"
195196
}
196197

197-
// Get character face and phrase based on engine and derived activity
198-
const currentFace = () => getFace(displayEngine() ?? "default", derivedActivity())
199-
const currentPhrase = () => getPhrase(displayEngine() ?? "default", derivedActivity())
198+
// Get character face and phrase based on agent ID and derived activity
199+
const currentFace = () => getFace(displayAgentId() ?? "default", derivedActivity())
200+
const currentPhrase = () => getPhrase(displayAgentId() ?? "default", derivedActivity())
200201

201202
// Check if we have something to display (agent or controller in controller view)
202203
const hasDisplayContent = () => props.currentAgent != null || isControllerViewMode()

src/cli/tui/shared/config/agent-characters.ts

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
*
44
* Loads and caches the agent characters configuration,
55
* providing helper functions for accessing faces and phrases.
6+
* Uses a persona-based system where agents map to personas.
67
*/
78

89
import * as path from "node:path"
910
import { existsSync, readFileSync } from "node:fs"
1011
import { resolvePackageRoot } from "../../../../shared/runtime/root.js"
11-
import type { ActivityType, AgentCharactersConfig, EngineCharacter } from "./agent-characters.types.js"
12+
import type { ActivityType, AgentCharactersConfig, Persona } from "./agent-characters.types.js"
1213

1314
let cachedConfig: AgentCharactersConfig | null = null
1415

@@ -59,8 +60,7 @@ export function loadAgentCharactersConfig(): AgentCharactersConfig {
5960
* Returns a minimal default config when the JSON file is unavailable
6061
*/
6162
function getDefaultConfig(): AgentCharactersConfig {
62-
const defaults: EngineCharacter = {
63-
name: "Agent",
63+
const defaultPersona: Persona = {
6464
baseFace: "(•_•)",
6565
expressions: {
6666
thinking: "(•_•)?",
@@ -75,32 +75,36 @@ function getDefaultConfig(): AgentCharactersConfig {
7575
idle: ["Ready"],
7676
},
7777
}
78-
return { engines: {}, defaults }
78+
return {
79+
personas: { default: defaultPersona },
80+
agents: {},
81+
defaultPersona: "default",
82+
}
7983
}
8084

8185
/**
82-
* Gets the character configuration for a specific engine
83-
* Falls back to defaults if engine not found
86+
* Gets the persona configuration for a specific agent
87+
* Looks up agent -> persona mapping, falls back to defaultPersona
8488
*/
85-
export function getCharacter(engineId: string): EngineCharacter {
89+
export function getCharacter(agentId: string): Persona {
8690
const config = loadAgentCharactersConfig()
87-
const normalizedId = engineId.toLowerCase()
88-
return config.engines[normalizedId] ?? config.defaults
91+
const personaName = config.agents[agentId] ?? config.defaultPersona
92+
return config.personas[personaName] ?? config.personas[config.defaultPersona] ?? getDefaultConfig().personas.default
8993
}
9094

9195
/**
92-
* Gets the face expression for a specific engine and activity
96+
* Gets the face expression for a specific agent and activity
9397
*/
94-
export function getFace(engineId: string, activity: ActivityType): string {
95-
const character = getCharacter(engineId)
98+
export function getFace(agentId: string, activity: ActivityType): string {
99+
const character = getCharacter(agentId)
96100
return character.expressions[activity] ?? character.baseFace
97101
}
98102

99103
/**
100-
* Gets a random phrase for a specific engine and activity
104+
* Gets a random phrase for a specific agent and activity
101105
*/
102-
export function getPhrase(engineId: string, activity: ActivityType): string {
103-
const character = getCharacter(engineId)
106+
export function getPhrase(agentId: string, activity: ActivityType): string {
107+
const character = getCharacter(agentId)
104108
const phrases = character.phrases[activity]
105109
if (!phrases || phrases.length === 0) {
106110
return activity === "idle" ? "Ready" : "..."

src/cli/tui/shared/config/agent-characters.types.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Agent Characters Configuration Types
33
*
44
* Defines the types for configurable ASCII art faces and phrases
5-
* that give personality to different AI engines.
5+
* that give personality to different agents via personas.
66
*/
77

88
/**
@@ -11,11 +11,9 @@
1111
export type ActivityType = "thinking" | "tool" | "error" | "idle"
1212

1313
/**
14-
* Configuration for a single engine's character
14+
* Configuration for a persona's visual character
1515
*/
16-
export interface EngineCharacter {
17-
/** Display name for the engine */
18-
name: string
16+
export interface Persona {
1917
/** Default face when no specific activity */
2018
baseFace: string
2119
/** ASCII art faces for different activities */
@@ -28,8 +26,10 @@ export interface EngineCharacter {
2826
* Full agent characters configuration
2927
*/
3028
export interface AgentCharactersConfig {
31-
/** Character configs keyed by engine ID */
32-
engines: Record<string, EngineCharacter>
33-
/** Default character for unknown engines */
34-
defaults: EngineCharacter
29+
/** Persona definitions keyed by persona name */
30+
personas: Record<string, Persona>
31+
/** Agent ID to persona name mapping */
32+
agents: Record<string, string>
33+
/** Default persona for unmapped agents */
34+
defaultPersona: string
3535
}

0 commit comments

Comments
 (0)