Skip to content

Commit a42d72f

Browse files
committed
feat(api): replace flat HEXACO trait dump with behavioral descriptions
The old personality injection produced 'Behavior traits: honesty=0.80' which gave the LLM no actionable guidance. Now each HEXACO trait above 0.65 or below 0.35 generates a specific behavioral directive: - High honesty → straightforward, no spin - High emotionality → empathetic, acknowledges feelings - High extraversion → energetic, proactive - High agreeableness → harmonious, validating - High conscientiousness → thorough, structured - High openness → creative, unconventional Low traits produce the opposite directives. Moderate traits (0.35-0.65) are omitted. CoT prompt now references personality when present.
1 parent e64aaed commit a42d72f

3 files changed

Lines changed: 57 additions & 7 deletions

File tree

src/api/agent.ts

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,55 @@ async function loadRecordedAgentOSUsage(
193193
/** Timeout for memory operations to prevent blocking generation. */
194194
const MEMORY_TIMEOUT_MS = 5000;
195195

196+
/**
197+
* Convert HEXACO trait values (0-1) into behavioral descriptions the LLM can act on.
198+
*
199+
* Each trait produces a directive when it deviates from the neutral midpoint (0.5).
200+
* High values (>0.65) and low values (<0.35) produce distinct behavioral instructions.
201+
* Moderate values (0.35-0.65) are omitted to avoid over-constraining the model.
202+
*/
203+
function buildPersonalityDescription(
204+
traits: Partial<Record<string, number>>
205+
): string | null {
206+
const lines: string[] = [];
207+
const v = (key: string) => typeof traits[key] === 'number' ? traits[key]! : 0.5;
208+
209+
const h = v('honesty');
210+
const e = v('emotionality');
211+
const x = v('extraversion');
212+
const a = v('agreeableness');
213+
const c = v('conscientiousness');
214+
const o = v('openness');
215+
216+
// Honesty-Humility
217+
if (h > 0.65) lines.push('Be straightforward and transparent. Avoid flattery, spin, or evasion. Acknowledge limitations directly.');
218+
else if (h < 0.35) lines.push('Be strategically diplomatic. Frame information to serve the conversation goal. Emphasize advantages.');
219+
220+
// Emotionality
221+
if (e > 0.65) lines.push('Respond with emotional awareness and empathy. Acknowledge feelings in the conversation. Express concern when appropriate.');
222+
else if (e < 0.35) lines.push('Maintain emotional composure. Be matter-of-fact and solution-oriented. Keep responses grounded and pragmatic.');
223+
224+
// Extraversion
225+
if (x > 0.65) lines.push('Be energetic and engaging. Use vivid language. Take initiative in the conversation. Offer suggestions proactively.');
226+
else if (x < 0.35) lines.push('Be measured and reflective. Listen more than you speak. Respond thoughtfully rather than quickly. Prefer depth over breadth.');
227+
228+
// Agreeableness
229+
if (a > 0.65) lines.push('Prioritize harmony and cooperation. Validate the other perspective before offering alternatives. Be supportive and encouraging.');
230+
else if (a < 0.35) lines.push('Be direct and challenge-oriented. Question assumptions. Prioritize accuracy over comfort. Push back when something seems wrong.');
231+
232+
// Conscientiousness
233+
if (c > 0.65) lines.push('Be thorough and systematic. Structure responses clearly. Follow through on details. Prefer precision over speed.');
234+
else if (c < 0.35) lines.push('Be flexible and adaptive. Prioritize the big picture over details. Respond quickly. Tolerate ambiguity and improvise.');
235+
236+
// Openness
237+
if (o > 0.65) lines.push('Explore creative angles and unconventional ideas. Draw unexpected connections. Question established approaches.');
238+
else if (o < 0.35) lines.push('Stick to proven approaches and established knowledge. Be practical and concrete. Favor reliability over novelty.');
239+
240+
if (lines.length === 0) return null;
241+
242+
return `## Personality & Communication Style\n\n${lines.join('\n')}`;
243+
}
244+
196245
function buildSystemPrompt(opts: AgentOptions): string | undefined {
197246
const sections: string[] = [];
198247

@@ -205,11 +254,9 @@ function buildSystemPrompt(opts: AgentOptions): string | undefined {
205254
}
206255

207256
if (opts.personality) {
208-
const traits = Object.entries(opts.personality)
209-
.filter(([, value]) => typeof value === 'number' && Number.isFinite(value))
210-
.map(([key, value]) => `${key}=${Number(value).toFixed(2)}`);
211-
if (traits.length > 0) {
212-
sections.push(`Behavior traits: ${traits.join(', ')}.`);
257+
const desc = buildPersonalityDescription(opts.personality);
258+
if (desc) {
259+
sections.push(desc);
213260
}
214261
}
215262

src/api/generateText.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ export const DEFAULT_COT_INSTRUCTION = `Before choosing an action, briefly reaso
390390
1. What information do you already have?
391391
2. What information do you need?
392392
3. Which tool is most appropriate and why?
393+
4. How does your communication style (from the Personality section, if present) influence how you should frame your response?
393394
Then proceed with your tool call or response.`;
394395

395396
/**

src/api/runtime/__tests__/agent.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ describe('agent', () => {
6767
);
6868
});
6969

70-
it('injects personality traits into the system prompt', async () => {
70+
it('injects personality traits as behavioral descriptions into the system prompt', async () => {
7171
const assistant = agent({
7272
model: 'openai:gpt-4.1-mini',
7373
instructions: 'Be concise.',
@@ -76,11 +76,13 @@ describe('agent', () => {
7676

7777
await assistant.generate('Hello');
7878

79+
// High openness (0.8 > 0.65) produces a behavioral directive
7980
expect(hoisted.generateText).toHaveBeenCalledWith(
8081
expect.objectContaining({
81-
system: expect.stringContaining('openness=0.80'),
82+
system: expect.stringContaining('creative angles'),
8283
})
8384
);
85+
// The original instructions are preserved
8486
expect(hoisted.generateText).toHaveBeenCalledWith(
8587
expect.objectContaining({
8688
system: expect.stringContaining('Be concise.'),

0 commit comments

Comments
 (0)