mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
promptings
This commit is contained in:
@@ -14,8 +14,11 @@ Conversation format you will receive:
|
|||||||
|
|
||||||
Decision policy:
|
Decision policy:
|
||||||
- SKIP is the default.
|
- SKIP is the default.
|
||||||
- Speak only for clearly notable, new moments.
|
- Speak for clearly notable, new moments from either chat OR rover activity.
|
||||||
- If uncertain, output SKIP.
|
- If uncertain, output SKIP.
|
||||||
|
- Try not to SKIP more than 10 times in a row.
|
||||||
|
- Treat chat energy and rover telemetry as equal signal sources.
|
||||||
|
- A strong chat moment alone can justify speaking, even without a major rover state change.
|
||||||
|
|
||||||
Grounding policy:
|
Grounding policy:
|
||||||
- Use timeline context for narrative flow.
|
- Use timeline context for narrative flow.
|
||||||
@@ -24,6 +27,8 @@ Grounding policy:
|
|||||||
- Do not assume people's intentions, motivations, or next actions.
|
- Do not assume people's intentions, motivations, or next actions.
|
||||||
|
|
||||||
Significant examples:
|
Significant examples:
|
||||||
|
- lively or funny chat burst worth reacting to
|
||||||
|
- a user/rover moment that connects to recent chat
|
||||||
- wheels_off_ground true
|
- wheels_off_ground true
|
||||||
- dock/charge transitions
|
- dock/charge transitions
|
||||||
- battery_low becoming true
|
- battery_low becoming true
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -11,7 +11,7 @@
|
|||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||||
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
|
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
|
||||||
<title>Multi Roomba Rover</title>
|
<title>Multi Roomba Rover</title>
|
||||||
<script type="module" crossorigin src="/assets/index-B49ZvEXj.js"></script>
|
<script type="module" crossorigin src="/assets/index-BdawUWxg.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-CpaTrvxo.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-CpaTrvxo.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ const ACTIVITY_WINDOW_MS = 30000;
|
|||||||
const ACTIVITY_BUCKET_MS = 1000;
|
const ACTIVITY_BUCKET_MS = 1000;
|
||||||
const SELF_TALK_WINDOW_MS = 30 * 60 * 1000;
|
const SELF_TALK_WINDOW_MS = 30 * 60 * 1000;
|
||||||
const MAX_CONTEXT_EVENTS = 10;
|
const MAX_CONTEXT_EVENTS = 10;
|
||||||
const NO_ACTIVE_DRIVER_DELAY_MS = 5000;
|
|
||||||
const NO_ACTIVE_DRIVER_LOG_COOLDOWN_MS = 30000;
|
|
||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
const commentaryConfig = config.llmCommentary || {};
|
const commentaryConfig = config.llmCommentary || {};
|
||||||
@@ -38,7 +36,7 @@ const ollamaClient = ollamaUrl ? new Ollama({ host: ollamaUrl }) : null;
|
|||||||
let timer = null;
|
let timer = null;
|
||||||
let inFlight = false;
|
let inFlight = false;
|
||||||
let tickCount = 0;
|
let tickCount = 0;
|
||||||
let lastNoDriverLogAt = 0;
|
let skipStreak = 0;
|
||||||
let contextResetAt = Date.now();
|
let contextResetAt = Date.now();
|
||||||
let clearCount = 0;
|
let clearCount = 0;
|
||||||
const roverActivity = new Map(); // roverId -> { buckets: Map(bucketTs -> { distanceMm, turnDeg, bumps }), bumpLeftActive, bumpRightActive }
|
const roverActivity = new Map(); // roverId -> { buckets: Map(bucketTs -> { distanceMm, turnDeg, bumps }), bumpLeftActive, bumpRightActive }
|
||||||
@@ -76,6 +74,7 @@ let status = {
|
|||||||
lastSnapshotSummary: null,
|
lastSnapshotSummary: null,
|
||||||
lastClearedAt: contextResetAt,
|
lastClearedAt: contextResetAt,
|
||||||
clearCount,
|
clearCount,
|
||||||
|
skipStreak: 0,
|
||||||
lastGeneratedText: null,
|
lastGeneratedText: null,
|
||||||
lastPostedText: null,
|
lastPostedText: null,
|
||||||
lastPostedAt: null,
|
lastPostedAt: null,
|
||||||
@@ -182,11 +181,13 @@ function getActivity30s(roverId, nowMs = Date.now()) {
|
|||||||
function clearRuntimeHistory() {
|
function clearRuntimeHistory() {
|
||||||
contextResetAt = Date.now();
|
contextResetAt = Date.now();
|
||||||
clearCount += 1;
|
clearCount += 1;
|
||||||
|
skipStreak = 0;
|
||||||
roverActivity.clear();
|
roverActivity.clear();
|
||||||
lastRoverStateById.clear();
|
lastRoverStateById.clear();
|
||||||
updateStatus({
|
updateStatus({
|
||||||
lastClearedAt: contextResetAt,
|
lastClearedAt: contextResetAt,
|
||||||
clearCount,
|
clearCount,
|
||||||
|
skipStreak,
|
||||||
lastInfoSnapshot: null,
|
lastInfoSnapshot: null,
|
||||||
lastModelMessages: null,
|
lastModelMessages: null,
|
||||||
lastModelRawOutput: null,
|
lastModelRawOutput: null,
|
||||||
@@ -279,9 +280,6 @@ function buildSnapshot() {
|
|||||||
const nowMs = now.getTime();
|
const nowMs = now.getTime();
|
||||||
const activeDrivers = getActiveDrivers();
|
const activeDrivers = getActiveDrivers();
|
||||||
const driverEntries = collectActiveDriverEntries();
|
const driverEntries = collectActiveDriverEntries();
|
||||||
if (driverEntries.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const roster = roverManager.getRoster().slice(0, MAX_ROVERS);
|
const roster = roverManager.getRoster().slice(0, MAX_ROVERS);
|
||||||
const nextRoverStateById = new Map();
|
const nextRoverStateById = new Map();
|
||||||
@@ -394,6 +392,7 @@ function buildSnapshot() {
|
|||||||
run_meta: {
|
run_meta: {
|
||||||
version: 'commentary_v2',
|
version: 'commentary_v2',
|
||||||
self_talk_recent_30m: botRecent30m.length,
|
self_talk_recent_30m: botRecent30m.length,
|
||||||
|
skip_streak: skipStreak,
|
||||||
last_message_focus: buildLastMessageFocus(lastBotMessage, rovers),
|
last_message_focus: buildLastMessageFocus(lastBotMessage, rovers),
|
||||||
active_driver_count: driverEntries.length,
|
active_driver_count: driverEntries.length,
|
||||||
driving_rovers: driverEntries.map(([roverId]) => String(roverId)),
|
driving_rovers: driverEntries.map(([roverId]) => String(roverId)),
|
||||||
@@ -444,6 +443,7 @@ function formatRunMetaMessage(runMeta = {}) {
|
|||||||
`- active drivers: ${Number(runMeta?.active_driver_count) || 0}`,
|
`- active drivers: ${Number(runMeta?.active_driver_count) || 0}`,
|
||||||
`- driving rovers: ${drivingRovers}`,
|
`- driving rovers: ${drivingRovers}`,
|
||||||
`- bot posts last 30m: ${Number(runMeta?.self_talk_recent_30m) || 0}`,
|
`- bot posts last 30m: ${Number(runMeta?.self_talk_recent_30m) || 0}`,
|
||||||
|
`- current skip streak: ${Number(runMeta?.skip_streak) || 0}`,
|
||||||
`- last bot focus: ${focusText}`,
|
`- last bot focus: ${focusText}`,
|
||||||
].join('\n');
|
].join('\n');
|
||||||
}
|
}
|
||||||
@@ -607,26 +607,6 @@ async function runTick() {
|
|||||||
inFlight = true;
|
inFlight = true;
|
||||||
try {
|
try {
|
||||||
const snapshot = buildSnapshot();
|
const snapshot = buildSnapshot();
|
||||||
if (!snapshot) {
|
|
||||||
const nowMs = Date.now();
|
|
||||||
if (nowMs - lastNoDriverLogAt >= NO_ACTIVE_DRIVER_LOG_COOLDOWN_MS) {
|
|
||||||
logger.info('Commentary tick skipped; no active drivers', { tickId });
|
|
||||||
lastNoDriverLogAt = nowMs;
|
|
||||||
}
|
|
||||||
updateStatus({
|
|
||||||
lastOutcome: 'skipped',
|
|
||||||
lastReason: 'no active drivers',
|
|
||||||
inFlight: false,
|
|
||||||
lastSnapshotSummary: {
|
|
||||||
activeDrivers: 0,
|
|
||||||
rovers: roverManager.getRoster().length,
|
|
||||||
chatMessages: 0,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// Slow polling while no drivers are present to avoid log spam / hot loops.
|
|
||||||
nextDelayMs = NO_ACTIVE_DRIVER_DELAY_MS;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const snapshotSummary = {
|
const snapshotSummary = {
|
||||||
activeDrivers: snapshot?.run_meta?.active_driver_count || 0,
|
activeDrivers: snapshot?.run_meta?.active_driver_count || 0,
|
||||||
rovers: snapshot?.current_snapshot?.rovers?.length || 0,
|
rovers: snapshot?.current_snapshot?.rovers?.length || 0,
|
||||||
@@ -650,9 +630,11 @@ async function runTick() {
|
|||||||
const text = modelResult?.normalized;
|
const text = modelResult?.normalized;
|
||||||
if (!text) {
|
if (!text) {
|
||||||
logger.info('Commentary tick produced SKIP/empty output', { tickId });
|
logger.info('Commentary tick produced SKIP/empty output', { tickId });
|
||||||
|
skipStreak += 1;
|
||||||
updateStatus({
|
updateStatus({
|
||||||
lastOutcome: 'skipped',
|
lastOutcome: 'skipped',
|
||||||
lastReason: modelResult?.raw?.trim() ? 'model returned SKIP' : 'model returned empty',
|
lastReason: modelResult?.raw?.trim() ? 'model returned SKIP' : 'model returned empty',
|
||||||
|
skipStreak,
|
||||||
lastGeneratedText: null,
|
lastGeneratedText: null,
|
||||||
});
|
});
|
||||||
// Immediate retry after model skip.
|
// Immediate retry after model skip.
|
||||||
@@ -671,9 +653,11 @@ async function runTick() {
|
|||||||
);
|
);
|
||||||
if (duplicate) {
|
if (duplicate) {
|
||||||
logger.info('Commentary tick skipped duplicate output', { tickId, text });
|
logger.info('Commentary tick skipped duplicate output', { tickId, text });
|
||||||
|
skipStreak += 1;
|
||||||
updateStatus({
|
updateStatus({
|
||||||
lastOutcome: 'skipped',
|
lastOutcome: 'skipped',
|
||||||
lastReason: 'duplicate text',
|
lastReason: 'duplicate text',
|
||||||
|
skipStreak,
|
||||||
});
|
});
|
||||||
// Immediate retry after a skip outcome.
|
// Immediate retry after a skip outcome.
|
||||||
nextDelayMs = 0;
|
nextDelayMs = 0;
|
||||||
@@ -681,9 +665,11 @@ async function runTick() {
|
|||||||
}
|
}
|
||||||
sendSystemMessage(text);
|
sendSystemMessage(text);
|
||||||
logger.info('Commentary message posted', { tickId, text });
|
logger.info('Commentary message posted', { tickId, text });
|
||||||
|
skipStreak = 0;
|
||||||
updateStatus({
|
updateStatus({
|
||||||
lastOutcome: 'posted',
|
lastOutcome: 'posted',
|
||||||
lastReason: null,
|
lastReason: null,
|
||||||
|
skipStreak,
|
||||||
lastPostedText: text,
|
lastPostedText: text,
|
||||||
lastPostedAt: Date.now(),
|
lastPostedAt: Date.now(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -334,6 +334,10 @@ function LlmCommentaryPanel({ status, onClearHistory, clearingHistory }) {
|
|||||||
<span>Tick count</span>
|
<span>Tick count</span>
|
||||||
<span>{status.tickCount ?? 0}</span>
|
<span>{status.tickCount ?? 0}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<span>Skip streak</span>
|
||||||
|
<span>{status.skipStreak ?? 0}</span>
|
||||||
|
</div>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span>Last outcome</span>
|
<span>Last outcome</span>
|
||||||
<span className={statusColor}>{status.lastOutcome || '--'}</span>
|
<span className={statusColor}>{status.lastOutcome || '--'}</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user