From 15fedc7c774849950cf0617dd6045b54120a83ff Mon Sep 17 00:00:00 2001 From: legop3 Date: Mon, 4 May 2026 00:14:32 -0400 Subject: [PATCH] overseer v2 6 (tool actions, text chat) --- server/config.example.yaml | 1 + server/src/services/chatService/index.js | 2 +- .../overseerControlService/contextBuilder.js | 2 +- server/src/services/overseerControlService/index.js | 12 +++++++++++- .../overseerControlService/runtimeHelpers.js | 1 + .../services/overseerControlService/tools/chatSay.js | 2 +- .../services/overseerControlService/tools/index.js | 2 -- 7 files changed, 16 insertions(+), 6 deletions(-) diff --git a/server/config.example.yaml b/server/config.example.yaml index 898b58a3..c5a255a6 100644 --- a/server/config.example.yaml +++ b/server/config.example.yaml @@ -16,6 +16,7 @@ llmCommentary: overseerControl: enabled: false observeOnly: true + alwaysRunModel: false name: "The Overseer" model: "qwen2.5:7b-instruct" ollamaServer: "http://127.0.0.1:11434" diff --git a/server/src/services/chatService/index.js b/server/src/services/chatService/index.js index a0f42f5c..8d515327 100644 --- a/server/src/services/chatService/index.js +++ b/server/src/services/chatService/index.js @@ -12,7 +12,7 @@ function sendSystemMessage(text, options = {}) { const normalized = normalizeUserText(text); const clean = normalized.trim(); if (!clean) return null; - const safe = clean.length > 256 ? `${clean.slice(0, 253)}...` : clean; + const safe = clean; const message = buildMessage(null, safe, { nickname: String(options.nickname || 'The Overseer'), role: 'user', diff --git a/server/src/services/overseerControlService/contextBuilder.js b/server/src/services/overseerControlService/contextBuilder.js index c71e0d14..c0a8fc48 100644 --- a/server/src/services/overseerControlService/contextBuilder.js +++ b/server/src/services/overseerControlService/contextBuilder.js @@ -67,7 +67,7 @@ function buildModelMessages({ systemPrompt, stateUpdate, conversationMessages, a messages.push({ role: 'user', content: - 'Use tool calls when needed. If no tool is needed, either respond with one short chat line or SKIP.', + 'Use tool calls when needed. If no tool is needed, respond with one short in-character chat line.', }); return messages; } diff --git a/server/src/services/overseerControlService/index.js b/server/src/services/overseerControlService/index.js index 10e56de5..3309d1c3 100644 --- a/server/src/services/overseerControlService/index.js +++ b/server/src/services/overseerControlService/index.js @@ -38,6 +38,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 alwaysRunModel = Boolean(overseerConfig.alwaysRunModel); const ollamaClient = ollamaUrl ? new Ollama({ host: ollamaUrl }) : null; const runtime = { @@ -60,6 +61,7 @@ let status = { promptPath: PROMPT_PATH, gateIntervalMs, heartbeatMs, + alwaysRunModel, running: false, inFlight: false, phase: 'idle', @@ -125,6 +127,7 @@ function buildRosterSummary() { } function computeTriggerReason() { + if (alwaysRunModel) return 'loop_tick'; const recent = getRecentMessages(1, { includeSystem: false }); const last = recent[recent.length - 1]; if (last && Date.now() - Number(last.ts || 0) < 5000) { @@ -166,6 +169,13 @@ function inferDecision({ toolCalls, chatText }) { return 'SKIP'; } +function normalizeChatDraft(text) { + const next = String(text || '').trim(); + if (!next) return null; + if (next.toUpperCase() === 'SKIP') return null; + return next; +} + async function runDecision(triggerReason) { const runId = runtime.tickCount; updateStatus({ phase: 'context_build', currentRunId: runId, lastTriggerReason: triggerReason, lastError: null, lastErrorDetails: null }); @@ -223,7 +233,7 @@ async function runDecision(triggerReason) { const rawOutput = String(payload?.message?.content || ''); const toolCalls = normalizeToolCalls(payload); - const chatDraft = rawOutput.trim() || null; + const chatDraft = normalizeChatDraft(rawOutput); const decision = inferDecision({ toolCalls, chatText: chatDraft }); const generationMs = Math.max(0, Date.now() - generationStart); diff --git a/server/src/services/overseerControlService/runtimeHelpers.js b/server/src/services/overseerControlService/runtimeHelpers.js index 5d81c242..5fa605a7 100644 --- a/server/src/services/overseerControlService/runtimeHelpers.js +++ b/server/src/services/overseerControlService/runtimeHelpers.js @@ -22,6 +22,7 @@ function buildAdminState(status, runHistory) { ollamaUrl: status.ollamaUrl, gateIntervalMs: status.gateIntervalMs, heartbeatMs: status.heartbeatMs, + alwaysRunModel: status.alwaysRunModel, observeOnly: status.observeOnly, promptPath: status.promptPath, }, diff --git a/server/src/services/overseerControlService/tools/chatSay.js b/server/src/services/overseerControlService/tools/chatSay.js index cd1af4f7..b698535a 100644 --- a/server/src/services/overseerControlService/tools/chatSay.js +++ b/server/src/services/overseerControlService/tools/chatSay.js @@ -5,7 +5,7 @@ module.exports = { parameters: { type: 'object', properties: { - text: { type: 'string', minLength: 1, maxLength: 220 }, + text: { type: 'string', minLength: 1 }, }, required: ['text'], additionalProperties: false, diff --git a/server/src/services/overseerControlService/tools/index.js b/server/src/services/overseerControlService/tools/index.js index fe1afdbd..ed387b8d 100644 --- a/server/src/services/overseerControlService/tools/index.js +++ b/server/src/services/overseerControlService/tools/index.js @@ -1,4 +1,3 @@ -const chatSay = require('./chatSay'); const memoryRead = require('./memoryRead'); const memoryWrite = require('./memoryWrite'); const liftUp = require('./liftUp'); @@ -11,7 +10,6 @@ const haSetEntity = require('./haSetEntity'); const buttonBoxAddCount = require('./buttonBoxAddCount'); const TOOL_DEFINITIONS = [ - chatSay, memoryRead, memoryWrite, liftUp,