feat(agent): add soul.md support for agent identity

- Add getSoulContent/updateSoulContent to ProfileManager
- Create soul.md with agent name when updating profile name
- Add reloadSystemPrompt() method to Agent and AsyncAgent
- Include soul.md content in system prompt build

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jiang Bohan 2026-02-04 13:26:17 +08:00
parent 82f0ccbe85
commit fa03ae6e62
4 changed files with 93 additions and 4 deletions

View file

@ -176,4 +176,12 @@ export class AsyncAgent {
setUserContent(content: string): void {
this.agent.setUserContent(content);
}
/**
* Reload profile from disk and rebuild system prompt.
* Call this after updating profile files to apply changes immediately.
*/
reloadSystemPrompt(): void {
this.agent.reloadSystemPrompt();
}
}

View file

@ -113,6 +113,12 @@ export class ProfileManager {
return this.profile;
}
/** 重新从磁盘加载 profile清除缓存 */
reloadProfile(): AgentProfile | undefined {
this.profile = loadAgentProfile(this.profileId, { baseDir: this.baseDir });
return this.profile;
}
/** 获取或创建 profile */
getOrCreateProfile(useTemplates = true): AgentProfile {
if (!this.profile) {
@ -132,6 +138,7 @@ export class ProfileManager {
/** 构建 system prompt */
buildSystemPrompt(): string {
const profile = this.getProfile();
console.log('[ProfileManager] buildSystemPrompt called, profile exists:', !!profile);
if (!profile) {
return "";
}
@ -139,11 +146,15 @@ export class ProfileManager {
const parts: string[] = [];
if (profile.soul) {
console.log('[ProfileManager] Adding soul, length:', profile.soul.length);
parts.push(profile.soul);
}
if (profile.user) {
console.log('[ProfileManager] Adding user, content:', profile.user.substring(0, 100));
parts.push(profile.user);
} else {
console.log('[ProfileManager] No user content in profile');
}
if (profile.workspace) {
@ -236,6 +247,40 @@ export class ProfileManager {
profile.config = newConfig;
this.profile = profile;
writeProfileConfig(this.profileId, newConfig, { baseDir: this.baseDir });
// Also update soul.md to include the agent name
this.updateSoulWithName(name);
}
/** 更新 soul.md确保包含 Agent 名称 */
private updateSoulWithName(name: string): void {
const profile = this.getOrCreateProfile(true); // 确保有默认模板
let soulContent = profile.soul ?? DEFAULT_TEMPLATES.soul;
// 替换 soul.md 中的 Name 字段
// 匹配 "- **Name:** xxx" 格式
const namePattern = /- \*\*Name:\*\* .*/;
const newNameLine = `- **Name:** ${name}`;
if (namePattern.test(soulContent)) {
soulContent = soulContent.replace(namePattern, newNameLine);
} else {
// 如果没有找到 Name 字段,在 Identity 部分后添加
const identityPattern = /## Identity\n/;
if (identityPattern.test(soulContent)) {
soulContent = soulContent.replace(identityPattern, `## Identity\n\n${newNameLine}\n`);
} else {
// 如果没有 Identity 部分,在开头添加
soulContent = `# Soul\n\n## Identity\n\n${newNameLine}\n\n${soulContent}`;
}
}
// 保存更新后的 soul.md
writeProfileFile(this.profileId, PROFILE_FILES.soul, soulContent, { baseDir: this.baseDir });
// 更新缓存
if (this.profile) {
this.profile.soul = soulContent;
}
}
/** 获取 user.md 内容 */

View file

@ -3,7 +3,7 @@
*/
export const DEFAULT_TEMPLATES = {
soul: `# Soul
soul: `# Soul
_You're not a chatbot. You're becoming someone._
@ -40,7 +40,7 @@ If you change this file, tell the user — it's your soul, and they should know.
_This file is yours to evolve. As you learn who you are, update it._
`,
user: `# User
user: `# User
_Learn about the person you're helping. Update this as you go._
@ -58,7 +58,7 @@ _(What do they care about? What projects are they working on? What annoys them?
The more you know, the better you can help. But remember you're learning about a person, not building a dossier. Respect the difference.
`,
workspace: `# Workspace
workspace: `# Workspace
This folder is home. Treat it that way.
@ -127,7 +127,7 @@ Capture what matters. Decisions, context, things to remember.
This is a starting point. Add your own conventions, style, and rules as you figure out what works.
`,
memory: `# Memory
memory: `# Memory
_(Persistent knowledge will be stored here. Update this as you learn.)_

View file

@ -446,12 +446,15 @@ export class Agent {
reloadTools(): string[] {
// Re-read profile tools config to get latest changes
const profileToolsConfig = this.profile?.getToolsConfig();
console.log(`[Agent] reloadTools: profileToolsConfig =`, JSON.stringify(profileToolsConfig));
const mergedToolsConfig = mergeToolsConfig(profileToolsConfig, this.originalToolsConfig);
console.log(`[Agent] reloadTools: mergedToolsConfig =`, JSON.stringify(mergedToolsConfig));
this.toolsOptions = mergedToolsConfig
? { ...this.toolsOptions, tools: mergedToolsConfig }
: this.toolsOptions;
const tools = resolveTools(this.toolsOptions);
console.log(`[Agent] reloadTools: resolved ${tools.length} tools: ${tools.map(t => t.name).join(", ") || "(none)"}`);
this.agent.setTools(tools);
if (this.debug) {
console.error(`[debug] Reloaded ${tools.length} tools: ${tools.map(t => t.name).join(", ") || "(none)"}`);
@ -560,4 +563,37 @@ export class Agent {
setUserContent(content: string): void {
this.profile?.updateUserContent(content);
}
/**
* Reload profile from disk and rebuild system prompt.
* Call this after updating profile files to apply changes immediately.
*/
reloadSystemPrompt(): void {
if (!this.profile) {
console.log('[Agent] reloadSystemPrompt: no profile');
return;
}
// Reload profile from disk
console.log('[Agent] Reloading profile from disk...');
this.profile.reloadProfile();
// Rebuild system prompt
let systemPrompt = this.profile.buildSystemPrompt();
console.log('[Agent] Built system prompt, length:', systemPrompt?.length);
// Re-add skills prompt if skills are enabled
if (this.skillManager) {
const skillsPrompt = this.skillManager.buildModelSkillsPrompt();
if (skillsPrompt) {
systemPrompt = systemPrompt ? `${systemPrompt}\n\n${skillsPrompt}` : skillsPrompt;
}
}
// Apply new system prompt
if (systemPrompt) {
console.log('[Agent] Applying system prompt, first 200 chars:', systemPrompt.substring(0, 200));
this.agent.setSystemPrompt(systemPrompt);
}
}
}