mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
wording and overseer tool embeds
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -11,8 +11,8 @@
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-title" content="Roomba Rover" />
|
||||
<title>Roomba Rover</title>
|
||||
<script type="module" crossorigin src="/assets/index-3_2nPjxD.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-LJWnKvT4.css">
|
||||
<script type="module" crossorigin src="/assets/index-BWk3SALU.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BtUMEmG6.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -100,6 +100,21 @@ function buildRoverCtxSnapshot(roverId) {
|
||||
function buildMessage(socket, text, meta = {}) {
|
||||
const roverId = meta.roverId || resolveRoverId(socket?.id);
|
||||
const roverColor = meta.roverColor ?? resolveRoverColor(roverId);
|
||||
const toolCalls = Array.isArray(meta.toolCalls)
|
||||
? meta.toolCalls
|
||||
.map((entry) => {
|
||||
if (!entry || typeof entry !== 'object') return null;
|
||||
return {
|
||||
tool: String(entry.tool || '').trim() || 'unknown',
|
||||
status: String(entry.status || '').trim() || 'unknown',
|
||||
args: entry.args && typeof entry.args === 'object' ? entry.args : {},
|
||||
result: entry.result && typeof entry.result === 'object' ? entry.result : null,
|
||||
error: entry.error ? String(entry.error) : null,
|
||||
durationMs: Number.isFinite(entry.durationMs) ? Math.max(0, Math.round(entry.durationMs)) : null,
|
||||
};
|
||||
})
|
||||
.filter(Boolean)
|
||||
: null;
|
||||
return {
|
||||
id: uuidv4(),
|
||||
ts: Date.now(),
|
||||
@@ -119,6 +134,7 @@ function buildMessage(socket, text, meta = {}) {
|
||||
profileImage: normalizeProfileImageUrl(meta.profileImage),
|
||||
roverCtx: meta.roverCtx || null,
|
||||
text,
|
||||
toolCalls,
|
||||
tts: meta.tts || null,
|
||||
bot: Boolean(meta.bot),
|
||||
};
|
||||
|
||||
@@ -11,7 +11,8 @@ const { registerChatSocketHooks } = require('./socketHooks');
|
||||
function sendSystemMessage(text, options = {}) {
|
||||
const normalized = normalizeUserText(text);
|
||||
const clean = normalized.trim();
|
||||
if (!clean) return null;
|
||||
const hasToolCalls = Array.isArray(options.toolCalls) && options.toolCalls.length > 0;
|
||||
if (!clean && !hasToolCalls) return null;
|
||||
const safe = clean;
|
||||
const message = buildMessage(null, safe, {
|
||||
nickname: String(options.nickname || 'The Overseer'),
|
||||
@@ -19,6 +20,7 @@ function sendSystemMessage(text, options = {}) {
|
||||
fromDiscord: false,
|
||||
bot: options.bot !== false,
|
||||
profileImage: options.profileImage || null,
|
||||
toolCalls: hasToolCalls ? options.toolCalls : null,
|
||||
});
|
||||
broadcastMessage(message);
|
||||
return message;
|
||||
|
||||
@@ -3,6 +3,21 @@
|
||||
// Scope: Handles inbound Discord messages plus outbound webhook and typing relay.
|
||||
const { WebhookClient } = require('discord.js');
|
||||
|
||||
function summarizeToolCall(entry = {}) {
|
||||
const tool = String(entry?.tool || 'unknown');
|
||||
const status = String(entry?.status || 'unknown').toLowerCase();
|
||||
if (status === 'ok') return `✅ ${tool}`;
|
||||
if (status === 'blocked') return `⛔ ${tool} — ${String(entry?.error || 'blocked')}`;
|
||||
if (status === 'error') return `❌ ${tool} — ${String(entry?.error || 'failed')}`;
|
||||
return `• ${tool}`;
|
||||
}
|
||||
|
||||
function formatToolCallsCodeBlock(toolCalls = []) {
|
||||
const rows = (toolCalls || []).map((entry) => summarizeToolCall(entry));
|
||||
if (!rows.length) return '';
|
||||
return `\`\`\`txt\nTool calls:\n${rows.join('\n')}\n\`\`\``;
|
||||
}
|
||||
|
||||
function createChatBridgeHandlers(deps) {
|
||||
const {
|
||||
logger,
|
||||
@@ -48,7 +63,15 @@ function createChatBridgeHandlers(deps) {
|
||||
const guildConfigs = listGuildConfigs();
|
||||
if (!guildConfigs.length) return;
|
||||
|
||||
const text = payload.text?.length > 1900 ? `${payload.text.slice(0, 1897)}...` : payload.text;
|
||||
const baseText = String(payload.text || '');
|
||||
const toolCalls = Array.isArray(payload.toolCalls) ? payload.toolCalls : [];
|
||||
const toolsBlock = formatToolCallsCodeBlock(toolCalls);
|
||||
let text = baseText;
|
||||
if (toolsBlock) {
|
||||
text = text ? `${text}\n\n${toolsBlock}` : `Overseer ran tools (no chat line).\n\n${toolsBlock}`;
|
||||
}
|
||||
if (text.length > 1900) text = `${text.slice(0, 1897)}...`;
|
||||
if (!text.trim()) return;
|
||||
const username = formatWebhookUsername(payload);
|
||||
const avatarURL = payload.profileImage || (payload.fromDiscord ? payload.discordUserAvatarUrl || null : client.user?.displayAvatarURL?.({ extension: 'png', size: 128 }) || null);
|
||||
const typingId = getTypingId(payload);
|
||||
|
||||
@@ -207,6 +207,44 @@ function normalizeChatDraft(text) {
|
||||
return next;
|
||||
}
|
||||
|
||||
function summarizeResult(result) {
|
||||
if (!result || typeof result !== 'object') return null;
|
||||
if (Object.prototype.hasOwnProperty.call(result, 'ok')) return { ok: Boolean(result.ok) };
|
||||
return null;
|
||||
}
|
||||
|
||||
function buildToolCallFeedEntries(requestedActions = [], actionResults = []) {
|
||||
const resultsByTool = new Map();
|
||||
(actionResults || []).forEach((entry) => {
|
||||
if (!entry || entry.kind !== 'tool') return;
|
||||
const key = String(entry.tool || '');
|
||||
if (!key) return;
|
||||
if (!resultsByTool.has(key)) resultsByTool.set(key, []);
|
||||
resultsByTool.get(key).push(entry);
|
||||
});
|
||||
return (requestedActions || []).map((action) => {
|
||||
const tool = String(action?.tool || '').trim() || 'unknown';
|
||||
const bucket = resultsByTool.get(tool) || [];
|
||||
const resultEntry = bucket.length ? bucket.shift() : null;
|
||||
const ok = Boolean(resultEntry?.ok);
|
||||
const errText = resultEntry?.error ? String(resultEntry.error) : '';
|
||||
const status = resultEntry
|
||||
? ok
|
||||
? 'ok'
|
||||
: errText.includes('blocked') || errText.includes('unavailable')
|
||||
? 'blocked'
|
||||
: 'error'
|
||||
: 'started';
|
||||
return {
|
||||
tool,
|
||||
status,
|
||||
args: action?.args && typeof action.args === 'object' ? action.args : {},
|
||||
result: summarizeResult(resultEntry?.result),
|
||||
error: errText || null,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async function runDecision(triggerReason) {
|
||||
const runId = runtime.tickCount;
|
||||
updateStatus({ phase: 'context_build', currentRunId: runId, lastTriggerReason: triggerReason, lastError: null, lastErrorDetails: null });
|
||||
@@ -280,11 +318,6 @@ async function runDecision(triggerReason) {
|
||||
const reason = observeOnly ? 'observe-only mode' : null;
|
||||
|
||||
if (!observeOnly) {
|
||||
if ((decision === 'CHAT' || decision === 'ACTION+CHAT') && chatDraft) {
|
||||
sendSystemMessage(chatDraft, { nickname: name, bot: true, profileImage: profileImageUrl });
|
||||
actionResults.push({ kind: 'chat', ok: true });
|
||||
}
|
||||
|
||||
if (decision === 'ACTION' || decision === 'ACTION+CHAT') {
|
||||
for (const action of requestedActions) {
|
||||
pushLiveToolCall({ phase: 'start', tool: action.tool, args: action.args });
|
||||
@@ -315,6 +348,17 @@ async function runDecision(triggerReason) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const toolCallFeed = buildToolCallFeedEntries(requestedActions, actionResults);
|
||||
if (toolCallFeed.length > 0) {
|
||||
if ((decision === 'CHAT' || decision === 'ACTION+CHAT') && chatDraft) {
|
||||
sendSystemMessage(chatDraft, { nickname: name, bot: true, profileImage: profileImageUrl, toolCalls: toolCallFeed });
|
||||
} else {
|
||||
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 });
|
||||
}
|
||||
}
|
||||
|
||||
updateStatus({
|
||||
|
||||
Reference in New Issue
Block a user