overseer improvements and new social buttones

This commit is contained in:
legop3
2026-05-26 23:58:23 -04:00
parent f56d865c8e
commit 742232b882
15 changed files with 253 additions and 297 deletions
@@ -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 });
}