This commit is contained in:
legop3
2026-02-26 03:32:31 -05:00
parent 5a575aeab4
commit d34c107b1a
2 changed files with 88 additions and 9 deletions
+63 -1
View File
@@ -105,12 +105,68 @@ function buildMessage(socket, text, meta = {}) {
discordUserId: meta.discordUserId || null, discordUserId: meta.discordUserId || null,
discordUserName: meta.discordUserName || null, discordUserName: meta.discordUserName || null,
discordUserAvatarUrl: meta.discordUserAvatarUrl || null, discordUserAvatarUrl: meta.discordUserAvatarUrl || null,
roverCtx: meta.roverCtx || null,
text, text,
tts: meta.tts || null, tts: meta.tts || null,
system: Boolean(meta.system), system: Boolean(meta.system),
}; };
} }
function isChargingFromSensors(sensors = {}) {
const label = String(sensors?.chargingState?.label || '').toLowerCase();
if (label === 'waiting' || label === 'full charging' || label === 'trickle charging') {
return true;
}
const code = sensors?.chargingState?.code;
return code === 2 || code === 3 || code === 4;
}
function buildRoverCtxSnapshot(roverId) {
if (!roverId) return null;
const key = String(roverId);
const record = roverManager.rovers.get(key);
if (!record) return null;
const sensors = record?.lastSensor?.decoded || {};
const batteryState = record?.batteryState || null;
const { getActiveDrivers } = require('./turnService');
const activeDrivers = getActiveDrivers();
const driverSocketId = activeDrivers[key] || record?.drivers?.values?.().next?.().value || null;
const charging = isChargingFromSensors(sensors);
const docked = Boolean(sensors?.chargingSources?.homeBase);
const wheelsOffGround = Boolean(
sensors?.bumpsAndWheelDrops?.wheelDropLeft && sensors?.bumpsAndWheelDrops?.wheelDropRight,
);
const latestDistanceM = Math.round((Math.abs(Number(sensors?.distanceMm) || 0) / 1000) * 10) / 10;
const latestTurnDeg = Math.round(Math.abs(Number(sensors?.angleDeg) || 0));
const latestBumps =
(sensors?.bumpsAndWheelDrops?.bumpLeft ? 0.5 : 0) +
(sensors?.bumpsAndWheelDrops?.bumpRight ? 0.5 : 0);
const moving = latestDistanceM > 0.05 || latestTurnDeg > 10;
let statusTag = 'idle';
if (charging) {
statusTag = 'charging';
} else if (docked) {
statusTag = 'docked';
} else if (driverSocketId && moving) {
statusTag = 'driving';
} else if (driverSocketId) {
statusTag = 'active-idle';
}
return {
id: key,
status_tag: statusTag,
battery_low: Boolean(batteryState?.warnActive || batteryState?.urgentActive),
docked,
charging,
wheels_off_ground: wheelsOffGround,
activity_30s: {
distance_m: latestDistanceM,
turn_deg: latestTurnDeg,
bumps: latestBumps,
},
};
}
function buildTypingPayload(socket, meta = {}) { function buildTypingPayload(socket, meta = {}) {
const roverId = meta.roverId || resolveRoverId(socket?.id); const roverId = meta.roverId || resolveRoverId(socket?.id);
const socketId = socket?.id || null; const socketId = socket?.id || null;
@@ -282,7 +338,12 @@ function handleIncoming({ text, tts } = {}, socket, cb = () => {}) {
// } // }
const roverId = resolveRoverId(socket?.id); const roverId = resolveRoverId(socket?.id);
const ttsOptions = normalizeTtsOptions(tts); const ttsOptions = normalizeTtsOptions(tts);
const message = buildMessage(socket, clean, { fromDiscord: false, roverId, tts: ttsOptions }); const message = buildMessage(socket, clean, {
fromDiscord: false,
roverId,
roverCtx: buildRoverCtxSnapshot(roverId),
tts: ttsOptions,
});
logger.info('Chat message', { socket: socket.id, roverId: message.roverId }); logger.info('Chat message', { socket: socket.id, roverId: message.roverId });
playTypingNote(roverId, TYPING_SEND_NOTE, socket?.id); playTypingNote(roverId, TYPING_SEND_NOTE, socket?.id);
broadcastMessage(message); broadcastMessage(message);
@@ -349,6 +410,7 @@ function sendExternalMessage({
nickname, nickname,
role, role,
roverId, roverId,
roverCtx: buildRoverCtxSnapshot(roverId),
fromDiscord: true, fromDiscord: true,
discordGuildId, discordGuildId,
discordGuildName, discordGuildName,
+25 -8
View File
@@ -477,12 +477,8 @@ function compactRoverForContext(rover) {
}; };
} }
function buildSnapshot() { function buildRoversNow(nowMs = Date.now()) {
const now = new Date();
const nowMs = now.getTime();
const activeDrivers = getActiveDrivers(); const activeDrivers = getActiveDrivers();
const driverEntries = collectActiveDriverEntries();
const roster = roverManager.getRoster().slice(0, MAX_ROVERS); const roster = roverManager.getRoster().slice(0, MAX_ROVERS);
const nextRoverStateById = new Map(); const nextRoverStateById = new Map();
const rovers = roster.map((entry) => { const rovers = roster.map((entry) => {
@@ -537,6 +533,14 @@ function buildSnapshot() {
nextRoverStateById.forEach((value, roverId) => { nextRoverStateById.forEach((value, roverId) => {
lastRoverStateById.set(roverId, value); lastRoverStateById.set(roverId, value);
}); });
return { rovers, activeDrivers, roster };
}
function buildSnapshot() {
const now = new Date();
const nowMs = now.getTime();
const driverEntries = collectActiveDriverEntries();
const { rovers } = buildRoversNow(nowMs);
const roverById = new Map(rovers.map((rover) => [String(rover.id), rover])); const roverById = new Map(rovers.map((rover) => [String(rover.id), rover]));
const allRecentMessages = getRecentMessages(300, { includeSystem: true }) const allRecentMessages = getRecentMessages(300, { includeSystem: true })
.filter((entry) => Number(entry?.ts) >= contextResetAt); .filter((entry) => Number(entry?.ts) >= contextResetAt);
@@ -571,7 +575,7 @@ function buildSnapshot() {
nickname: entry.nickname || entry.socketId?.slice(0, 6) || 'unknown', nickname: entry.nickname || entry.socketId?.slice(0, 6) || 'unknown',
text: entry.text || '', text: entry.text || '',
rover_id: roverId, rover_id: roverId,
rover_ctx: compactRoverForContext(rover), rover_ctx: entry?.roverCtx || entry?.rover_ctx || compactRoverForContext(rover),
}; };
}); });
const hasRecentChat = eventStream.some((event) => event.type === 'chat'); const hasRecentChat = eventStream.some((event) => event.type === 'chat');
@@ -604,6 +608,17 @@ function buildSnapshot() {
}; };
} }
function refreshFinalSnapshotForSend(snapshot) {
const { rovers } = buildRoversNow(Date.now());
return {
...(snapshot || {}),
current_snapshot: {
...(snapshot?.current_snapshot || {}),
rovers,
},
};
}
function normalizeCommentary(rawText) { function normalizeCommentary(rawText) {
if (typeof rawText !== 'string') return null; if (typeof rawText !== 'string') return null;
const trimmed = rawText.trim(); const trimmed = rawText.trim();
@@ -832,14 +847,15 @@ async function runTick() {
lastInfoSnapshot: snapshot, lastInfoSnapshot: snapshot,
}); });
const systemPrompt = await readSystemPrompt(); const systemPrompt = await readSystemPrompt();
const modelMessages = buildModelMessages(systemPrompt, snapshot); const snapshotForSend = refreshFinalSnapshotForSend(snapshot);
const modelMessages = buildModelMessages(systemPrompt, snapshotForSend);
const modelInputAt = Date.now(); const modelInputAt = Date.now();
patchCurrentRun({ patchCurrentRun({
phase: 'input_ready', phase: 'input_ready',
input: { input: {
...(currentRun?.input || {}), ...(currentRun?.input || {}),
systemPrompt, systemPrompt,
infoSnapshot: snapshot, infoSnapshot: snapshotForSend,
modelMessages, modelMessages,
modelInputAt, modelInputAt,
}, },
@@ -848,6 +864,7 @@ async function runTick() {
lastModelMessages: modelMessages, lastModelMessages: modelMessages,
lastModelInputAt: modelInputAt, lastModelInputAt: modelInputAt,
lastModelInputTickId: tickId, lastModelInputTickId: tickId,
lastInfoSnapshot: snapshotForSend,
lastModelRawOutput: null, lastModelRawOutput: null,
lastModelOutputAt: null, lastModelOutputAt: null,
lastModelOutputTickId: null, lastModelOutputTickId: null,