mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 17:40:46 -04:00
overseer improvements and new social buttones
This commit is contained in:
@@ -4,6 +4,7 @@ const PROMPT_PATH = path.join(__dirname, '..', '..', '..', 'prompts', 'overseer_
|
||||
const DEFAULT_NAME = 'The Overseer';
|
||||
const DEFAULT_GATE_INTERVAL_MS = 2000;
|
||||
const DEFAULT_HEARTBEAT_MS = 30000;
|
||||
const DEFAULT_POST_CHAT_DELAY_MS = 20000;
|
||||
const MIN_INTERVAL_MS = 250;
|
||||
const MAX_RUN_HISTORY = 100;
|
||||
const MAX_CHAT_CONTEXT = 12;
|
||||
@@ -19,6 +20,7 @@ module.exports = {
|
||||
DEFAULT_NAME,
|
||||
DEFAULT_GATE_INTERVAL_MS,
|
||||
DEFAULT_HEARTBEAT_MS,
|
||||
DEFAULT_POST_CHAT_DELAY_MS,
|
||||
MAX_RUN_HISTORY,
|
||||
MAX_CHAT_CONTEXT,
|
||||
MAX_BOT_CONTEXT,
|
||||
|
||||
@@ -60,16 +60,28 @@ function buildConversation({ recentMessages, name }) {
|
||||
return messages;
|
||||
}
|
||||
|
||||
function buildModelMessages({ systemPrompt, stateUpdate, memorySummary, conversationMessages, availableTools, blockedTools }) {
|
||||
function buildModelMessages({
|
||||
systemPrompt,
|
||||
stateUpdate,
|
||||
memorySummary,
|
||||
recentEvents,
|
||||
conversationMessages,
|
||||
availableTools,
|
||||
blockedTools,
|
||||
}) {
|
||||
const messages = [];
|
||||
messages.push({ role: 'system', content: systemPrompt });
|
||||
const metadataSections = [];
|
||||
metadataSections.push(`STATE_UPDATE\n${stateUpdate}`);
|
||||
if (memorySummary) metadataSections.push(`MEMORY_UPDATE\n${memorySummary}`);
|
||||
metadataSections.push(
|
||||
`tool_constraints:\n${blockedTools.map((entry) => `- blocked: ${entry.tool} reason=${entry.reason}`).join('\n') || '- none'}`,
|
||||
);
|
||||
messages.push({ role: 'user', content: metadataSections.join('\n\n') });
|
||||
messages.push({ role: 'system', content: `ROOM_SNAPSHOT\n${stateUpdate}` });
|
||||
if (memorySummary) {
|
||||
messages.push({ role: 'system', content: `MEMORY_SUMMARY\n${memorySummary}` });
|
||||
}
|
||||
if (recentEvents) {
|
||||
messages.push({ role: 'system', content: `RECENT_EVENTS\n${recentEvents}` });
|
||||
}
|
||||
messages.push({
|
||||
role: 'system',
|
||||
content: `TOOL_CONSTRAINTS\n${blockedTools.map((entry) => `- blocked: ${entry.tool} reason=${entry.reason}`).join('\n') || '- none'}`,
|
||||
});
|
||||
(conversationMessages || []).forEach((message) => {
|
||||
if (!message || !message.role || !message.content) return;
|
||||
messages.push(message);
|
||||
|
||||
@@ -21,6 +21,7 @@ const {
|
||||
DEFAULT_NAME,
|
||||
DEFAULT_GATE_INTERVAL_MS,
|
||||
DEFAULT_HEARTBEAT_MS,
|
||||
DEFAULT_POST_CHAT_DELAY_MS,
|
||||
MAX_RUN_HISTORY,
|
||||
MAX_CHAT_CONTEXT,
|
||||
MAX_BOT_CONTEXT,
|
||||
@@ -40,6 +41,7 @@ const model = String(overseerConfig.model || '').trim();
|
||||
const ollamaUrl = String(overseerConfig.ollamaUrl || overseerConfig.ollamaServer || '').trim();
|
||||
const gateIntervalMs = normalizeMs(Number(overseerConfig.gateIntervalMs), DEFAULT_GATE_INTERVAL_MS);
|
||||
const heartbeatMs = normalizeMs(Number(overseerConfig.heartbeatMs), DEFAULT_HEARTBEAT_MS);
|
||||
const postChatDelayMs = normalizeMs(Number(overseerConfig.postChatDelayMs), DEFAULT_POST_CHAT_DELAY_MS);
|
||||
const alwaysRunModel = Boolean(overseerConfig.alwaysRunModel);
|
||||
const postToolsOnlyMessages = Boolean(overseerConfig.postToolsOnlyMessages);
|
||||
const profileImageUrl = String(overseerConfig.profileImageUrl || '').trim() || null;
|
||||
@@ -67,6 +69,7 @@ let status = {
|
||||
promptPath: PROMPT_PATH,
|
||||
gateIntervalMs,
|
||||
heartbeatMs,
|
||||
postChatDelayMs,
|
||||
alwaysRunModel,
|
||||
postToolsOnlyMessages,
|
||||
running: false,
|
||||
@@ -290,6 +293,20 @@ function buildToolCallFeedEntries(requestedActions = [], actionResults = []) {
|
||||
});
|
||||
}
|
||||
|
||||
function buildRecentEventsSummary() {
|
||||
const events = (runtime.liveToolCalls || [])
|
||||
.filter((entry) => entry && (entry.phase === 'ok' || entry.phase === 'error' || entry.phase === 'blocked'))
|
||||
.slice(-3)
|
||||
.map((entry) => {
|
||||
const tool = String(entry.tool || 'unknown');
|
||||
const phase = String(entry.phase || 'unknown');
|
||||
const err = entry.error ? ` error=${String(entry.error).slice(0, 60)}` : '';
|
||||
return `- tool=${tool} phase=${phase}${err}`;
|
||||
});
|
||||
if (!events.length) return '- none';
|
||||
return events.join('\n');
|
||||
}
|
||||
|
||||
async function runDecision(triggerReason) {
|
||||
const runId = runtime.tickCount;
|
||||
updateStatus({ phase: 'context_build', currentRunId: runId, lastTriggerReason: triggerReason, lastError: null, lastErrorDetails: null });
|
||||
@@ -317,6 +334,7 @@ async function runDecision(triggerReason) {
|
||||
systemPrompt,
|
||||
stateUpdate,
|
||||
memorySummary: summarizeMemory(runtime.memoryStore),
|
||||
recentEvents: buildRecentEventsSummary(),
|
||||
conversationMessages,
|
||||
availableTools: toolState.available,
|
||||
blockedTools: toolState.blocked,
|
||||
@@ -360,6 +378,7 @@ async function runDecision(triggerReason) {
|
||||
|
||||
const actionResults = [];
|
||||
const requestedActions = toolCalls;
|
||||
let postedChat = false;
|
||||
let outcome = observeOnly ? 'observed' : 'executed';
|
||||
const reason = observeOnly ? 'observe-only mode' : null;
|
||||
|
||||
@@ -399,11 +418,13 @@ async function runDecision(triggerReason) {
|
||||
if (toolCallFeed.length > 0) {
|
||||
if ((decision === 'CHAT' || decision === 'ACTION+CHAT') && chatDraft) {
|
||||
sendSystemMessage(chatDraft, { nickname: name, bot: true, profileImage: profileImageUrl, toolCalls: toolCallFeed });
|
||||
postedChat = true;
|
||||
} else if (postToolsOnlyMessages) {
|
||||
sendSystemMessage('', { nickname: name, bot: true, profileImage: profileImageUrl, toolCalls: toolCallFeed });
|
||||
}
|
||||
} else if ((decision === 'CHAT' || decision === 'ACTION+CHAT') && chatDraft) {
|
||||
sendSystemMessage(chatDraft, { nickname: name, bot: true, profileImage: profileImageUrl });
|
||||
postedChat = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,6 +456,8 @@ async function runDecision(triggerReason) {
|
||||
generationMs,
|
||||
blockedTools: toolState.blocked,
|
||||
});
|
||||
|
||||
return { postedChat };
|
||||
}
|
||||
|
||||
async function tick() {
|
||||
@@ -442,12 +465,16 @@ async function tick() {
|
||||
runtime.inFlight = true;
|
||||
updateStatus({ inFlight: true, tickCount: runtime.tickCount, lastTickAt: Date.now(), phase: 'gate_check' });
|
||||
|
||||
let nextDelayMs = gateIntervalMs;
|
||||
try {
|
||||
const triggerReason = computeTriggerReason();
|
||||
if (!triggerReason) {
|
||||
updateStatus({ phase: 'idle', lastOutcome: 'skipped', lastReason: 'gate not triggered' });
|
||||
} else {
|
||||
await runDecision(triggerReason);
|
||||
const runResult = await runDecision(triggerReason);
|
||||
if (runResult?.postedChat) {
|
||||
nextDelayMs = postChatDelayMs;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
const failure = buildFailureInfo(err);
|
||||
@@ -462,8 +489,8 @@ async function tick() {
|
||||
} finally {
|
||||
runtime.inFlight = false;
|
||||
if (status.running) {
|
||||
updateStatus({ inFlight: false, currentRunId: null, phase: 'idle', nextRunAt: Date.now() + gateIntervalMs });
|
||||
runtime.timer = setTimeout(tick, gateIntervalMs);
|
||||
updateStatus({ inFlight: false, currentRunId: null, phase: 'idle', nextRunAt: Date.now() + nextDelayMs });
|
||||
runtime.timer = setTimeout(tick, nextDelayMs);
|
||||
} else {
|
||||
updateStatus({ inFlight: false, currentRunId: null, nextRunAt: null });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user