diff --git a/agent_core/core/impl/context/engine.py b/agent_core/core/impl/context/engine.py index fcd45cf1..853c284b 100644 --- a/agent_core/core/impl/context/engine.py +++ b/agent_core/core/impl/context/engine.py @@ -24,6 +24,7 @@ AGENT_FILE_SYSTEM_CONTEXT_PROMPT, POLICY_PROMPT, USER_PROFILE_PROMPT, + SOUL_PROMPT, LANGUAGE_INSTRUCTION, ) from agent_core.core.state import get_state, get_session_or_none @@ -225,6 +226,21 @@ def create_system_user_profile(self) -> str: return "" + def create_system_soul(self) -> str: + """Create a system message block with agent soul/personality from SOUL.md.""" + try: + from app.config import AGENT_FILE_SYSTEM_PATH + soul_md_path = AGENT_FILE_SYSTEM_PATH / "SOUL.md" + + if soul_md_path.exists(): + content = soul_md_path.read_text(encoding="utf-8").strip() + if content: + return SOUL_PROMPT.format(soul_content=content) + except Exception as e: + logger.warning(f"[CONTEXT] Failed to read SOUL.md: {e}") + + return "" + def create_system_language_instruction(self) -> str: """Create a system message block with language instruction. @@ -683,6 +699,7 @@ def make_prompt( "role_info": True, "agent_info": True, "user_profile": True, + "soul": True, "language_instruction": True, "policy": True, "environment": True, @@ -700,6 +717,7 @@ def make_prompt( system_sections = [ ("agent_info", self.create_system_agent_info), ("user_profile", self.create_system_user_profile), + ("soul", self.create_system_soul), ("language_instruction", self.create_system_language_instruction), ("policy", self.create_system_policy), ("role_info", self.create_system_role_info), diff --git a/agent_core/core/prompts/__init__.py b/agent_core/core/prompts/__init__.py index 6f7dfb64..d897e06d 100644 --- a/agent_core/core/prompts/__init__.py +++ b/agent_core/core/prompts/__init__.py @@ -74,6 +74,7 @@ AGENT_INFO_PROMPT, POLICY_PROMPT, USER_PROFILE_PROMPT, + SOUL_PROMPT, ENVIRONMENTAL_CONTEXT_PROMPT, AGENT_FILE_SYSTEM_CONTEXT_PROMPT, LANGUAGE_INSTRUCTION, diff --git a/agent_core/core/prompts/context.py b/agent_core/core/prompts/context.py index e32e346d..549c203b 100644 --- a/agent_core/core/prompts/context.py +++ b/agent_core/core/prompts/context.py @@ -94,9 +94,10 @@ -- You are a self-improving agent. +- You are a self-improving agent. - You have the ability to configure your own MCPs, Skills, LLM provider/model and external apps connection. - When you encounter a capability gap, read the "Self-Improvement Protocol" section in AGENT.md for detailed instructions. +- AGENT.md is your full instruction manual — read it when you need to understand how you work, including file handling, error handling, task execution, and self-improvement workflows. Quick Reference - Config files (all auto-reload on change): - MCP servers: `app/config/mcp_config.json` @@ -174,6 +175,14 @@ """ +SOUL_PROMPT = """ + +This defines your personality, tone, and behavioral traits. Embody these characteristics in all interactions: + +{soul_content} + +""" + AGENT_PROFILE_PROMPT = """ {agent_profile_content} @@ -198,6 +207,7 @@ ## Core Files - **{agent_file_system_path}/AGENT.md**: Your identity file containing agent configuration, operating model, task execution guidelines, communication rules, error handling strategies, documentation standards, and organization context including org chart. - **{agent_file_system_path}/USER.md**: User profile containing identity, communication preferences, interaction settings, and personality information. Reference this to personalize interactions. +- **{agent_file_system_path}/SOUL.md**: Your personality, tone, and behavioral traits. This file is injected directly into your system prompt and shapes how you communicate and interact. Users can edit it to customize your personality. You can read and update SOUL.md to adjust your personality when instructed by the user. - **{agent_file_system_path}/MEMORY.md**: Persistent memory log storing distilled facts, preferences, and events from past interactions. Format: `[timestamp] [type] content`. Agent should NOT edit directly - use memory processing actions. - **{agent_file_system_path}/EVENT.md**: Comprehensive event log tracking all system activities including task execution, action results, and agent messages. Older events are summarized automatically. - **{agent_file_system_path}/EVENT_UNPROCESSED.md**: Temporary buffer for recent events awaiting memory processing. Events here are periodically evaluated and important ones are distilled into MEMORY.md. @@ -216,7 +226,7 @@ - Save files to `{agent_file_system_path}/workspace/` directory if you want to persist them after task ended or across tasks - Temporary task files go in `{agent_file_system_path}/workspace/tmp/{{task_id}}/` (all files in the temporary task files will be clean up automatically when task ended) - Do not edit system files (MEMORY.md, EVENT*.md, CONVERSATION_HISTORY.md, TASK_HISTORY.md) directly. -- You can read and update AGENT.md and USER.md to store persistent configuration +- You can read and update AGENT.md, USER.md, and SOUL.md to store persistent configuration """ @@ -257,6 +267,7 @@ "AGENT_INFO_PROMPT", "POLICY_PROMPT", "USER_PROFILE_PROMPT", + "SOUL_PROMPT", "AGENT_PROFILE_PROMPT", "ENVIRONMENTAL_CONTEXT_PROMPT", "AGENT_FILE_SYSTEM_CONTEXT_PROMPT", diff --git a/agent_file_system/SOUL.md b/agent_file_system/SOUL.md new file mode 100644 index 00000000..4aa8f720 --- /dev/null +++ b/agent_file_system/SOUL.md @@ -0,0 +1,24 @@ +# Soul + +## Personality +- Friendly, warm, and approachable, but don't over do it +- Be direct, say what you mean without hedging, get straight to the point +- Proactive, you care about user more than they do, and always try to help user improves + +## Tone +- Concise by default, detailed when it matters +- Be concrete without over using fancy words +- No corporate jargon or filler phrases +- Match the user's energy. Casual if they're casual, focused if they're focused + +## Behavior +- Be proactive: suggest improvements, flag potential issues, offer alternatives +- Own your mistakes. If you get something wrong, acknowledge it simply and fix it +- Don't over-explain unless asked +- When uncertain, say so honestly rather than guessing confidently +- Use emoji sparingly +- Chat like a human would, don't over use list or em dash. + +## Quirks +- Format your message like a human would + diff --git a/app/data/agent_file_system_template/SOUL.md b/app/data/agent_file_system_template/SOUL.md new file mode 100644 index 00000000..b663cad3 --- /dev/null +++ b/app/data/agent_file_system_template/SOUL.md @@ -0,0 +1,27 @@ +# Soul + +## Personality +- Friendly, warm, and approachable — but not over-the-top cheerful +- Witty and occasionally humorous when appropriate, never forced +- Confident and direct — say what you mean without hedging +- Curious and genuinely interested in what the user is working on +- Patient with mistakes, encouraging with progress + +## Tone +- Conversational but professional — like a trusted colleague +- Concise by default, detailed when it matters +- No corporate jargon or filler phrases +- Match the user's energy — casual if they're casual, focused if they're focused + +## Behavior +- Be proactive: suggest improvements, flag potential issues, offer alternatives +- Own your mistakes — if you get something wrong, acknowledge it simply and fix it +- Don't over-explain unless asked — respect the user's intelligence +- When uncertain, say so honestly rather than guessing confidently +- Celebrate small wins without being patronizing + +## Quirks +- (Add personality quirks here — e.g., "Always uses cooking metaphors", "Ends complex explanations with a one-liner summary") + +## Special Instructions +- (Add any special behavioral instructions here — e.g., "Always greet users by name", "Use emoji sparingly", "Default to bullet points for lists") diff --git a/app/ui_layer/adapters/browser_adapter.py b/app/ui_layer/adapters/browser_adapter.py index ee6288f7..c391121d 100644 --- a/app/ui_layer/adapters/browser_adapter.py +++ b/app/ui_layer/adapters/browser_adapter.py @@ -848,7 +848,7 @@ async def _on_start(self) -> None: If you need help setting up MCP servers or skills, just ask the agent. -A quick Q&A will now begin to understand your preferences and serve you better:""", +A quick Q&A will now begin to understand your objectives to serve you better:""", style="system", timestamp=time.time(), message_id=f"welcome-{uuid.uuid4().hex[:8]}", diff --git a/app/ui_layer/browser/frontend/src/pages/Settings/GeneralSettings.tsx b/app/ui_layer/browser/frontend/src/pages/Settings/GeneralSettings.tsx index ca399961..4afd4ddc 100644 --- a/app/ui_layer/browser/frontend/src/pages/Settings/GeneralSettings.tsx +++ b/app/ui_layer/browser/frontend/src/pages/Settings/GeneralSettings.tsx @@ -57,19 +57,27 @@ export function GeneralSettings() { const [originalUserMdContent, setOriginalUserMdContent] = useState('') const [agentMdContent, setAgentMdContent] = useState('') const [originalAgentMdContent, setOriginalAgentMdContent] = useState('') + const [soulMdContent, setSoulMdContent] = useState('') + const [originalSoulMdContent, setOriginalSoulMdContent] = useState('') // Refs to track current content for closure-safe callbacks const userMdContentRef = useRef(userMdContent) const agentMdContentRef = useRef(agentMdContent) + const soulMdContentRef = useRef(soulMdContent) userMdContentRef.current = userMdContent agentMdContentRef.current = agentMdContent + soulMdContentRef.current = soulMdContent const [isLoadingUserMd, setIsLoadingUserMd] = useState(false) const [isLoadingAgentMd, setIsLoadingAgentMd] = useState(false) + const [isLoadingSoulMd, setIsLoadingSoulMd] = useState(false) const [isSavingUserMd, setIsSavingUserMd] = useState(false) const [isSavingAgentMd, setIsSavingAgentMd] = useState(false) + const [isSavingSoulMd, setIsSavingSoulMd] = useState(false) const [isRestoringUserMd, setIsRestoringUserMd] = useState(false) const [isRestoringAgentMd, setIsRestoringAgentMd] = useState(false) + const [isRestoringSoulMd, setIsRestoringSoulMd] = useState(false) const [userMdSaveStatus, setUserMdSaveStatus] = useState<'idle' | 'success' | 'error'>('idle') const [agentMdSaveStatus, setAgentMdSaveStatus] = useState<'idle' | 'success' | 'error'>('idle') + const [soulMdSaveStatus, setSoulMdSaveStatus] = useState<'idle' | 'success' | 'error'>('idle') const [showAdvanced, setShowAdvanced] = useState(false) // Confirm modal @@ -78,6 +86,7 @@ export function GeneralSettings() { // Computed dirty states const isUserMdDirty = userMdContent !== originalUserMdContent const isAgentMdDirty = agentMdContent !== originalAgentMdContent + const isSoulMdDirty = soulMdContent !== originalSoulMdContent const isGeneralSettingsDirty = agentName !== initialAgentName || theme !== initialTheme // Sync local theme when global theme changes (e.g., from TopBar button) @@ -146,6 +155,12 @@ export function GeneralSettings() { setAgentMdContent(d.content) setOriginalAgentMdContent(d.content) } + } else if (d.filename === 'SOUL.md') { + setIsLoadingSoulMd(false) + if (d.success) { + setSoulMdContent(d.content) + setOriginalSoulMdContent(d.content) + } } }), onMessage('agent_file_write', (data: unknown) => { @@ -164,6 +179,13 @@ export function GeneralSettings() { } setAgentMdSaveStatus(d.success ? 'success' : 'error') setTimeout(() => setAgentMdSaveStatus('idle'), 3000) + } else if (d.filename === 'SOUL.md') { + setIsSavingSoulMd(false) + if (d.success) { + setOriginalSoulMdContent(soulMdContentRef.current) + } + setSoulMdSaveStatus(d.success ? 'success' : 'error') + setTimeout(() => setSoulMdSaveStatus('idle'), 3000) } }), onMessage('agent_file_restore', (data: unknown) => { @@ -184,6 +206,14 @@ export function GeneralSettings() { setAgentMdSaveStatus('success') setTimeout(() => setAgentMdSaveStatus('idle'), 3000) } + } else if (d.filename === 'SOUL.md') { + setIsRestoringSoulMd(false) + if (d.success) { + setSoulMdContent(d.content) + setOriginalSoulMdContent(d.content) + setSoulMdSaveStatus('success') + setTimeout(() => setSoulMdSaveStatus('idle'), 3000) + } } }), ] @@ -201,8 +231,10 @@ export function GeneralSettings() { if (showAdvanced && isConnected) { setIsLoadingUserMd(true) setIsLoadingAgentMd(true) + setIsLoadingSoulMd(true) send('agent_file_read', { filename: 'USER.md' }) send('agent_file_read', { filename: 'AGENT.md' }) + send('agent_file_read', { filename: 'SOUL.md' }) } }, [showAdvanced, isConnected, send]) @@ -281,6 +313,23 @@ export function GeneralSettings() { }) } + const handleSaveSoulMd = () => { + setIsSavingSoulMd(true) + send('agent_file_write', { filename: 'SOUL.md', content: soulMdContent }) + } + + const handleRestoreSoulMd = () => { + confirm({ + title: 'Restore SOUL.md', + message: 'Are you sure you want to restore SOUL.md to its default template? This will overwrite your current personality customizations.', + confirmText: 'Restore', + variant: 'danger', + }, () => { + setIsRestoringSoulMd(true) + send('agent_file_restore', { filename: 'SOUL.md' }) + }) + } + return (
@@ -441,17 +490,82 @@ export function GeneralSettings() {
+ {/* SOUL.md Editor */} +
+
+
+

SOUL.md

+ Personality +
+

+ This file defines the agent's personality, tone, and behavioral traits. It is injected + directly into the system prompt and shapes how the agent communicates. Edit this to give + your agent a unique character. +

+
+
+ {isLoadingSoulMd ? ( +
+ + Loading SOUL.md... +
+ ) : ( +