mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
promp and clear command
This commit is contained in:
@@ -12,7 +12,7 @@ Rules:
|
|||||||
- Don't respond or use tools every cycle unless the context calls for it.
|
- Don't respond or use tools every cycle unless the context calls for it.
|
||||||
- `STATE_UPDATE`, `MEMORY_UPDATE`, and `tool_constraints` are context.
|
- `STATE_UPDATE`, `MEMORY_UPDATE`, and `tool_constraints` are context.
|
||||||
- Use tool calls for actions and memory updates.
|
- Use tool calls for actions and memory updates.
|
||||||
- If an action is needed, call tools directly; do not describe tool calls in chat.
|
- NEVER put tool calls in your chat output.
|
||||||
- When a chaos opportunity exists, take one tool action this cycle instead of only commenting.
|
- When a chaos opportunity exists, take one tool action this cycle instead of only commenting.
|
||||||
- Respect lock policies, cooldowns, and blocked tools.
|
- Respect lock policies, cooldowns, and blocked tools.
|
||||||
- Do not invent tools.
|
- Do not invent tools.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Chat Service Orchestrator
|
// Chat Service Orchestrator
|
||||||
// Purpose: Composes chat submodules into the public service API and boots socket/event wiring.
|
// Purpose: Composes chat submodules into the public service API and boots socket/event wiring.
|
||||||
// Scope: Keeps external chat contracts stable while delegating logic to focused modules.
|
// Scope: Keeps external chat contracts stable while delegating logic to focused modules.
|
||||||
const { history } = require('./state');
|
const { history, clearHistory } = require('./state');
|
||||||
const { normalizeUserText } = require('./contentFilters');
|
const { normalizeUserText } = require('./contentFilters');
|
||||||
const { buildMessage, buildTypingPayload } = require('./contextBuilders');
|
const { buildMessage, buildTypingPayload } = require('./contextBuilders');
|
||||||
const { broadcastMessage, getRecentMessages } = require('./broadcast');
|
const { broadcastMessage, getRecentMessages } = require('./broadcast');
|
||||||
@@ -37,4 +37,5 @@ module.exports = {
|
|||||||
buildTypingPayload,
|
buildTypingPayload,
|
||||||
sendSystemMessage,
|
sendSystemMessage,
|
||||||
getRecentMessages,
|
getRecentMessages,
|
||||||
|
clearHistory,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ function setLastAccessNoticeAt(ts) {
|
|||||||
lastAccessNoticeAt = ts;
|
lastAccessNoticeAt = ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearHistory() {
|
||||||
|
history.length = 0;
|
||||||
|
lastMessageBySocket.clear();
|
||||||
|
typingBySocket.clear();
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
rateBuckets,
|
rateBuckets,
|
||||||
history,
|
history,
|
||||||
@@ -50,4 +56,5 @@ module.exports = {
|
|||||||
getRecentMessages,
|
getRecentMessages,
|
||||||
getLastAccessNoticeAt,
|
getLastAccessNoticeAt,
|
||||||
setLastAccessNoticeAt,
|
setLastAccessNoticeAt,
|
||||||
|
clearHistory,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ const { getState: getHomeAssistantState, homeAssistantEvents } = homeAssistantSe
|
|||||||
const { getState: getNeatoState, neatoEvents } = neatoService;
|
const { getState: getNeatoState, neatoEvents } = neatoService;
|
||||||
const { getState: getLiftState, liftEvents } = liftService;
|
const { getState: getLiftState, liftEvents } = liftService;
|
||||||
const roverManager = require('../roverManager');
|
const roverManager = require('../roverManager');
|
||||||
const { getRecentMessages, sendSystemMessage } = require('../chatService');
|
const { getRecentMessages, sendSystemMessage, clearHistory: clearChatHistory } = require('../chatService');
|
||||||
|
const { subscribe } = require('../eventBus');
|
||||||
const {
|
const {
|
||||||
PROMPT_PATH,
|
PROMPT_PATH,
|
||||||
DEFAULT_NAME,
|
DEFAULT_NAME,
|
||||||
@@ -53,6 +54,7 @@ const runtime = {
|
|||||||
runHistory: [],
|
runHistory: [],
|
||||||
liveToolCalls: [],
|
liveToolCalls: [],
|
||||||
memoryStore: loadMemory(),
|
memoryStore: loadMemory(),
|
||||||
|
contextResetAt: Date.now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let status = {
|
let status = {
|
||||||
@@ -104,15 +106,28 @@ function buildVoteStatus() {
|
|||||||
const sockets = Array.from(io.sockets.sockets.values());
|
const sockets = Array.from(io.sockets.sockets.values());
|
||||||
let yesCount = 0;
|
let yesCount = 0;
|
||||||
let noCount = 0;
|
let noCount = 0;
|
||||||
let eligibleCount = 0;
|
const votesByIdentity = new Map();
|
||||||
const isEligibleVoter = (socket) => getRole(socket) !== 'spectator';
|
const isEligibleVoter = (socket) => getRole(socket) !== 'spectator';
|
||||||
|
|
||||||
sockets.forEach((socket) => {
|
sockets.forEach((socket) => {
|
||||||
if (!isEligibleVoter(socket)) return;
|
if (!isEligibleVoter(socket)) return;
|
||||||
eligibleCount += 1;
|
const identityKey = String(socket?.data?.cookieUserId || '').trim() || `socket:${socket.id}`;
|
||||||
const pref = socket?.data?.overseerEnabled;
|
const pref = typeof socket?.data?.overseerEnabled === 'boolean' ? socket.data.overseerEnabled : true;
|
||||||
if (typeof pref === 'boolean' ? pref : true) yesCount += 1;
|
const prev = votesByIdentity.get(identityKey);
|
||||||
|
if (typeof prev === 'boolean') {
|
||||||
|
// If one tab says "no", treat that user as "no" to avoid accidental override by stale tabs.
|
||||||
|
votesByIdentity.set(identityKey, prev && pref);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
votesByIdentity.set(identityKey, pref);
|
||||||
|
});
|
||||||
|
|
||||||
|
votesByIdentity.forEach((pref) => {
|
||||||
|
if (pref) yesCount += 1;
|
||||||
else noCount += 1;
|
else noCount += 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const eligibleCount = votesByIdentity.size;
|
||||||
const onlineCount = yesCount + noCount;
|
const onlineCount = yesCount + noCount;
|
||||||
const gatePassed = eligibleCount === 0 ? true : yesCount > noCount;
|
const gatePassed = eligibleCount === 0 ? true : yesCount > noCount;
|
||||||
return {
|
return {
|
||||||
@@ -188,6 +203,7 @@ function computeTriggerReason() {
|
|||||||
if (alwaysRunModel) return 'loop_tick';
|
if (alwaysRunModel) return 'loop_tick';
|
||||||
const recent = getRecentMessages(1, { includeSystem: false });
|
const recent = getRecentMessages(1, { includeSystem: false });
|
||||||
const last = recent[recent.length - 1];
|
const last = recent[recent.length - 1];
|
||||||
|
if (last && Number(last.ts || 0) < runtime.contextResetAt) return null;
|
||||||
if (last && Date.now() - Number(last.ts || 0) < 5000) {
|
if (last && Date.now() - Number(last.ts || 0) < 5000) {
|
||||||
const txt = String(last.text || '').toLowerCase();
|
const txt = String(last.text || '').toLowerCase();
|
||||||
if (txt.includes(name.toLowerCase()) || txt.includes('overseer') || txt.includes('bot')) return 'direct_address';
|
if (txt.includes(name.toLowerCase()) || txt.includes('overseer') || txt.includes('bot')) return 'direct_address';
|
||||||
@@ -286,6 +302,7 @@ async function runDecision(triggerReason) {
|
|||||||
const toolState = buildToolState({ mode, homeAssistantState, neatoState, liftState });
|
const toolState = buildToolState({ mode, homeAssistantState, neatoState, liftState });
|
||||||
|
|
||||||
const recentConversation = getRecentMessages(MAX_CHAT_CONTEXT + MAX_BOT_CONTEXT + 20, { includeSystem: true })
|
const recentConversation = getRecentMessages(MAX_CHAT_CONTEXT + MAX_BOT_CONTEXT + 20, { includeSystem: true })
|
||||||
|
.filter((entry) => Number(entry?.ts || 0) >= runtime.contextResetAt)
|
||||||
.filter((entry) => {
|
.filter((entry) => {
|
||||||
if (!entry?.roverId) return true;
|
if (!entry?.roverId) return true;
|
||||||
return roverManager.canReplayRoverId(entry.roverId);
|
return roverManager.canReplayRoverId(entry.roverId);
|
||||||
@@ -456,13 +473,39 @@ function emitStateToSocket(socket) {
|
|||||||
socket.emit('overseer:state', buildAdminState(status, runtime.runHistory));
|
socket.emit('overseer:state', buildAdminState(status, runtime.runHistory));
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearHistory() {
|
function clearHistory(reason = 'admin requested clear history') {
|
||||||
|
runtime.contextResetAt = Date.now();
|
||||||
runtime.runHistory = [];
|
runtime.runHistory = [];
|
||||||
runtime.liveToolCalls = [];
|
runtime.liveToolCalls = [];
|
||||||
runtime.generationCount = 0;
|
runtime.generationCount = 0;
|
||||||
runtime.generationTotalMs = 0;
|
runtime.generationTotalMs = 0;
|
||||||
|
runtime.lastModelAt = 0;
|
||||||
runtime.memoryStore = saveMemory(createDefaultMemory());
|
runtime.memoryStore = saveMemory(createDefaultMemory());
|
||||||
updateStatus({ lastReason: 'admin requested clear history', lastOutcome: 'cleared', lastLiveToolCalls: [] });
|
try {
|
||||||
|
clearChatHistory();
|
||||||
|
} catch (err) {
|
||||||
|
logger.warn('Failed to clear chat history during overseer clear', err.message);
|
||||||
|
}
|
||||||
|
updateStatus({
|
||||||
|
phase: 'idle',
|
||||||
|
currentRunId: null,
|
||||||
|
lastSystemPrompt: null,
|
||||||
|
lastStateUpdate: null,
|
||||||
|
lastTranscript: null,
|
||||||
|
lastAvailableTools: null,
|
||||||
|
lastBlockedTools: null,
|
||||||
|
lastModelMessages: null,
|
||||||
|
lastModelInputAt: null,
|
||||||
|
lastModelOutputAt: null,
|
||||||
|
lastModelRawOutput: null,
|
||||||
|
lastDecision: null,
|
||||||
|
lastChatDraft: null,
|
||||||
|
lastRequestedActions: null,
|
||||||
|
lastActionResults: null,
|
||||||
|
lastLiveToolCalls: [],
|
||||||
|
lastOutcome: 'cleared',
|
||||||
|
lastReason: reason,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopScheduler(reason = 'paused') {
|
function stopScheduler(reason = 'paused') {
|
||||||
@@ -525,6 +568,12 @@ roleEvents.on('change', ({ socket }) => {
|
|||||||
emitStateToSocket(socket);
|
emitStateToSocket(socket);
|
||||||
evaluateSchedulerGate('online vote update');
|
evaluateSchedulerGate('online vote update');
|
||||||
});
|
});
|
||||||
|
subscribe('chat:message', ({ payload } = {}) => {
|
||||||
|
const text = String(payload?.text || '').trim();
|
||||||
|
if (text !== 'CLEAR') return;
|
||||||
|
if (payload?.bot) return;
|
||||||
|
clearHistory('chat CLEAR command');
|
||||||
|
});
|
||||||
verificationEvents.on('change', () => evaluateSchedulerGate('online vote update'));
|
verificationEvents.on('change', () => evaluateSchedulerGate('online vote update'));
|
||||||
homeAssistantEvents.on('update', () => updateStatus({ phase: status.phase }));
|
homeAssistantEvents.on('update', () => updateStatus({ phase: status.phase }));
|
||||||
neatoEvents.on('update', () => updateStatus({ phase: status.phase }));
|
neatoEvents.on('update', () => updateStatus({ phase: status.phase }));
|
||||||
|
|||||||
Reference in New Issue
Block a user