mirror of
https://github.com/wahyd4/links.git
synced 2026-08-08 21:04:53 +10:00
jbot: disable local memory in Hermes Agent mode
In Hermes mode JBOT is a pure voice UI — memory is owned by the Agent: - Backend: sys prompt excludes local memories when backend_mode=hermes - Backend: config_view now returns backendMode so the frontend can adapt - Frontend: App.jsx loads backendMode on mount via apiConfig() - Frontend: memories not passed to apiChat() when isHermesMode - Frontend: memory extraction (apiExtractMemory) skipped when isHermesMode - Frontend: MemoryPanel hidden in Hermes mode; replaced by subtle '🧠 Hermes Agent 模式 · 记忆由 Agent 管理' badge Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
+3
-1
@@ -547,7 +547,8 @@ def chat_view(request):
|
|||||||
settings = data.get('settings', {})
|
settings = data.get('settings', {})
|
||||||
mode = cfg.get('backend_mode', 'openrouter')
|
mode = cfg.get('backend_mode', 'openrouter')
|
||||||
|
|
||||||
sys_content = _build_sys_prompt(settings, memories)
|
# In Hermes mode, don't inject local memories — Hermes manages its own memory
|
||||||
|
sys_content = _build_sys_prompt(settings, [] if mode == 'hermes' else memories)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if mode == 'hermes':
|
if mode == 'hermes':
|
||||||
@@ -626,4 +627,5 @@ def config_view(request):
|
|||||||
'volcengine': bool(cfg['volc_app_id'] and cfg['volc_access_token']),
|
'volcengine': bool(cfg['volc_app_id'] and cfg['volc_access_token']),
|
||||||
'llm': bool(cfg['openrouter_api_key']),
|
'llm': bool(cfg['openrouter_api_key']),
|
||||||
'ttsVoice': cfg['volc_tts_voice'],
|
'ttsVoice': cfg['volc_tts_voice'],
|
||||||
|
'backendMode': cfg.get('backend_mode', 'openrouter'),
|
||||||
})
|
})
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+3
-3
File diff suppressed because one or more lines are too long
@@ -663,6 +663,14 @@ kbd {
|
|||||||
border-bottom: 1px solid var(--border);
|
border-bottom: 1px solid var(--border);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
.hermes-mode-badge {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
padding: 6px 14px;
|
||||||
|
font-size: 0.72rem;
|
||||||
|
color: var(--accent);
|
||||||
|
background: color-mix(in srgb, var(--accent) 10%, transparent);
|
||||||
|
border-bottom: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
|
||||||
|
}
|
||||||
.memory-toggle {
|
.memory-toggle {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
+25
-9
@@ -4,7 +4,7 @@ import RobotFace from './components/RobotFace';
|
|||||||
import ChatPanel from './components/ChatPanel';
|
import ChatPanel from './components/ChatPanel';
|
||||||
import MemoryPanel from './components/MemoryPanel';
|
import MemoryPanel from './components/MemoryPanel';
|
||||||
import { EXPRESSIONS, ALL_AUTO_IDS, byId } from './data/expressions';
|
import { EXPRESSIONS, ALL_AUTO_IDS, byId } from './data/expressions';
|
||||||
import { apiChat, apiTts, apiAsr, apiExtractMemory } from './services/api';
|
import { apiChat, apiTts, apiAsr, apiExtractMemory, apiConfig } from './services/api';
|
||||||
import { usePushToTalk } from './hooks/usePushToTalk';
|
import { usePushToTalk } from './hooks/usePushToTalk';
|
||||||
import { addEntry } from './store/historyStore';
|
import { addEntry } from './store/historyStore';
|
||||||
import { getMemories, addMemory } from './store/memoryStore';
|
import { getMemories, addMemory } from './store/memoryStore';
|
||||||
@@ -134,11 +134,19 @@ export default function App() {
|
|||||||
const [chatMessages, setChatMessages] = useState([]);
|
const [chatMessages, setChatMessages] = useState([]);
|
||||||
const [llmHistory, setLlmHistory] = useState([]); // last N {role,content} for context
|
const [llmHistory, setLlmHistory] = useState([]); // last N {role,content} for context
|
||||||
const [memories, setMemories] = useState(() => getMemories());
|
const [memories, setMemories] = useState(() => getMemories());
|
||||||
|
const [isHermesMode, setIsHermesMode] = useState(false);
|
||||||
const voicePhaseRef = useRef('idle');
|
const voicePhaseRef = useRef('idle');
|
||||||
const isSpaceDownRef = useRef(false);
|
const isSpaceDownRef = useRef(false);
|
||||||
|
|
||||||
const refreshMemories = useCallback(() => setMemories(getMemories()), []);
|
const refreshMemories = useCallback(() => setMemories(getMemories()), []);
|
||||||
|
|
||||||
|
// Load backend mode from server config on mount
|
||||||
|
useEffect(() => {
|
||||||
|
apiConfig().then(cfg => {
|
||||||
|
if (cfg?.backendMode === 'hermes') setIsHermesMode(true);
|
||||||
|
}).catch(() => {});
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => { voicePhaseRef.current = voicePhase; }, [voicePhase]);
|
useEffect(() => { voicePhaseRef.current = voicePhase; }, [voicePhase]);
|
||||||
|
|
||||||
const appendMsg = (role, text, audioBase64, audioMime, toolCalls) => {
|
const appendMsg = (role, text, audioBase64, audioMime, toolCalls) => {
|
||||||
@@ -220,7 +228,8 @@ export default function App() {
|
|||||||
let botText = '';
|
let botText = '';
|
||||||
let toolCalls = [];
|
let toolCalls = [];
|
||||||
try {
|
try {
|
||||||
const currentMemories = getMemories().map(m => m.text);
|
// In Hermes mode don't pass local memories — Hermes owns its own memory
|
||||||
|
const currentMemories = isHermesMode ? [] : getMemories().map(m => m.text);
|
||||||
const currentSettings = getSettings();
|
const currentSettings = getSettings();
|
||||||
const newHistory = [...llmHistory, { role: 'user', content: userText }];
|
const newHistory = [...llmHistory, { role: 'user', content: userText }];
|
||||||
const result = await apiChat(newHistory.slice(-10), currentMemories, currentSettings);
|
const result = await apiChat(newHistory.slice(-10), currentMemories, currentSettings);
|
||||||
@@ -263,12 +272,14 @@ export default function App() {
|
|||||||
botAudioMime: 'audio/mp3',
|
botAudioMime: 'audio/mp3',
|
||||||
});
|
});
|
||||||
|
|
||||||
// Background memory extraction — never blocks the voice pipeline
|
// Background memory extraction — skip in Hermes mode (Hermes owns its memory)
|
||||||
apiExtractMemory(userText, botText).then(facts => {
|
if (!isHermesMode) {
|
||||||
let added = false;
|
apiExtractMemory(userText, botText).then(facts => {
|
||||||
facts.forEach(f => { if (addMemory(f)) added = true; });
|
let added = false;
|
||||||
if (added) refreshMemories();
|
facts.forEach(f => { if (addMemory(f)) added = true; });
|
||||||
}).catch(() => {});
|
if (added) refreshMemories();
|
||||||
|
}).catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
// Play audio
|
// Play audio
|
||||||
if (botAudio) {
|
if (botAudio) {
|
||||||
@@ -379,7 +390,12 @@ export default function App() {
|
|||||||
|
|
||||||
{/* ── Right column: memory + chat + bottom bar ── */}
|
{/* ── Right column: memory + chat + bottom bar ── */}
|
||||||
<div className="right-col">
|
<div className="right-col">
|
||||||
<MemoryPanel memories={memories} onMemoriesChange={refreshMemories} />
|
{!isHermesMode && (
|
||||||
|
<MemoryPanel memories={memories} onMemoriesChange={refreshMemories} />
|
||||||
|
)}
|
||||||
|
{isHermesMode && (
|
||||||
|
<div className="hermes-mode-badge">🧠 Hermes Agent 模式 · 记忆由 Agent 管理</div>
|
||||||
|
)}
|
||||||
<ChatPanel messages={chatMessages} voiceStatus={voiceStatus} />
|
<ChatPanel messages={chatMessages} voiceStatus={voiceStatus} />
|
||||||
<VoiceButton phase={voicePhase} onStart={handleSpaceDown} onEnd={handleSpaceUp} />
|
<VoiceButton phase={voicePhase} onStart={handleSpaceDown} onEnd={handleSpaceUp} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user