mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
new chat style minotiring
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-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-BzJGyAyM.js"></script>
|
<script type="module" crossorigin src="/assets/index-Djoi30hN.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-D2M34pit.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-CgR-sTcr.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ let status = {
|
|||||||
lastPromptChars: 0,
|
lastPromptChars: 0,
|
||||||
lastSystemPrompt: null,
|
lastSystemPrompt: null,
|
||||||
lastInfoSnapshot: null,
|
lastInfoSnapshot: null,
|
||||||
|
lastModelMessages: null,
|
||||||
|
lastModelRawOutput: null,
|
||||||
lastSnapshotSummary: null,
|
lastSnapshotSummary: null,
|
||||||
lastClearedAt: contextResetAt,
|
lastClearedAt: contextResetAt,
|
||||||
clearCount,
|
clearCount,
|
||||||
@@ -186,6 +188,8 @@ function clearRuntimeHistory() {
|
|||||||
lastClearedAt: contextResetAt,
|
lastClearedAt: contextResetAt,
|
||||||
clearCount,
|
clearCount,
|
||||||
lastInfoSnapshot: null,
|
lastInfoSnapshot: null,
|
||||||
|
lastModelMessages: null,
|
||||||
|
lastModelRawOutput: null,
|
||||||
lastSnapshotSummary: null,
|
lastSnapshotSummary: null,
|
||||||
lastGeneratedText: null,
|
lastGeneratedText: null,
|
||||||
lastPostedText: null,
|
lastPostedText: null,
|
||||||
@@ -413,6 +417,16 @@ function normalizeCommentary(rawText) {
|
|||||||
return `${normalized.slice(0, MAX_OUTPUT_CHARS - 3)}...`;
|
return `${normalized.slice(0, MAX_OUTPUT_CHARS - 3)}...`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseModelOutput(rawContent) {
|
||||||
|
const raw = typeof rawContent === 'string' ? rawContent : '';
|
||||||
|
const normalized = normalizeCommentary(raw);
|
||||||
|
return {
|
||||||
|
raw,
|
||||||
|
normalized,
|
||||||
|
skipped: normalized == null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async function readSystemPrompt() {
|
async function readSystemPrompt() {
|
||||||
const prompt = await fsp.readFile(PROMPT_PATH, 'utf8');
|
const prompt = await fsp.readFile(PROMPT_PATH, 'utf8');
|
||||||
const trimmed = prompt.trim();
|
const trimmed = prompt.trim();
|
||||||
@@ -482,6 +496,9 @@ async function generateCommentary(systemPrompt, snapshot) {
|
|||||||
current_snapshot: snapshot?.current_snapshot || {},
|
current_snapshot: snapshot?.current_snapshot || {},
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
updateStatus({
|
||||||
|
lastModelMessages: messages,
|
||||||
|
});
|
||||||
|
|
||||||
const payload = await ollamaClient.chat({
|
const payload = await ollamaClient.chat({
|
||||||
model,
|
model,
|
||||||
@@ -494,7 +511,7 @@ async function generateCommentary(systemPrompt, snapshot) {
|
|||||||
},
|
},
|
||||||
messages,
|
messages,
|
||||||
});
|
});
|
||||||
return normalizeCommentary(payload?.message?.content);
|
return parseModelOutput(payload?.message?.content);
|
||||||
}
|
}
|
||||||
|
|
||||||
function defaultTickDelayMs() {
|
function defaultTickDelayMs() {
|
||||||
@@ -576,12 +593,16 @@ async function runTick() {
|
|||||||
lastInfoSnapshot: snapshot,
|
lastInfoSnapshot: snapshot,
|
||||||
});
|
});
|
||||||
const systemPrompt = await readSystemPrompt();
|
const systemPrompt = await readSystemPrompt();
|
||||||
const text = await generateCommentary(systemPrompt, snapshot);
|
const modelResult = await generateCommentary(systemPrompt, snapshot);
|
||||||
|
updateStatus({
|
||||||
|
lastModelRawOutput: modelResult?.raw || '',
|
||||||
|
});
|
||||||
|
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 });
|
||||||
updateStatus({
|
updateStatus({
|
||||||
lastOutcome: 'skipped',
|
lastOutcome: 'skipped',
|
||||||
lastReason: 'model returned SKIP/empty',
|
lastReason: modelResult?.raw?.trim() ? 'model returned SKIP' : 'model returned empty',
|
||||||
lastGeneratedText: null,
|
lastGeneratedText: null,
|
||||||
});
|
});
|
||||||
// Immediate retry after model skip.
|
// Immediate retry after model skip.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { useSession } from '../context/SessionContext.jsx';
|
import { useSession } from '../context/SessionContext.jsx';
|
||||||
import RoverRoster from './RoverRoster.jsx';
|
import RoverRoster from './RoverRoster.jsx';
|
||||||
|
import ChatMessageRow from './ChatMessageRow.jsx';
|
||||||
|
|
||||||
const MODES = [
|
const MODES = [
|
||||||
{ key: 'open', label: 'Open' },
|
{ key: 'open', label: 'Open' },
|
||||||
@@ -284,6 +285,7 @@ function LlmCommentaryPanel({ status, onClearHistory, clearingHistory }) {
|
|||||||
: status.lastOutcome === 'posted'
|
: status.lastOutcome === 'posted'
|
||||||
? 'text-emerald-300'
|
? 'text-emerald-300'
|
||||||
: 'text-slate-300';
|
: 'text-slate-300';
|
||||||
|
const conversationRows = buildLlmConversationRows(status);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-0.5">
|
<div className="space-y-0.5">
|
||||||
@@ -405,10 +407,62 @@ function LlmCommentaryPanel({ status, onClearHistory, clearingHistory }) {
|
|||||||
: 'No snapshot captured yet.'}
|
: 'No snapshot captured yet.'}
|
||||||
</pre>
|
</pre>
|
||||||
</details>
|
</details>
|
||||||
|
<div className="space-y-0.5">
|
||||||
|
<div className="panel-muted text-xs uppercase">Most recent LLM conversation</div>
|
||||||
|
<div className="surface max-h-72 space-y-0.5 overflow-y-auto">
|
||||||
|
{conversationRows.length ? (
|
||||||
|
conversationRows.map((row) => <ChatMessageRow key={row.id} message={row.message} />)
|
||||||
|
) : (
|
||||||
|
<div className="text-xs text-slate-300">No model conversation captured yet.</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildLlmConversationRows(status) {
|
||||||
|
const now = Date.now();
|
||||||
|
const modelMessages = Array.isArray(status?.lastModelMessages) ? status.lastModelMessages : [];
|
||||||
|
const rows = modelMessages.map((entry, index) => {
|
||||||
|
const role = String(entry?.role || '').toLowerCase();
|
||||||
|
const content =
|
||||||
|
typeof entry?.content === 'string' ? entry.content : JSON.stringify(entry?.content ?? null, null, 2);
|
||||||
|
const nickname =
|
||||||
|
role === 'system'
|
||||||
|
? 'LLM System'
|
||||||
|
: role === 'assistant'
|
||||||
|
? 'LLM Context'
|
||||||
|
: role === 'user'
|
||||||
|
? 'LLM Input'
|
||||||
|
: 'LLM Message';
|
||||||
|
return {
|
||||||
|
id: `llm-msg-${index}`,
|
||||||
|
message: {
|
||||||
|
ts: now + index,
|
||||||
|
nickname,
|
||||||
|
text: content,
|
||||||
|
role: 'spectator',
|
||||||
|
system: role === 'system',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
if (status?.lastModelRawOutput != null) {
|
||||||
|
const raw = String(status.lastModelRawOutput);
|
||||||
|
rows.push({
|
||||||
|
id: 'llm-output',
|
||||||
|
message: {
|
||||||
|
ts: now + rows.length + 1,
|
||||||
|
nickname: 'LLM Output',
|
||||||
|
text: raw.trim() ? raw : '<empty>',
|
||||||
|
role: 'spectator',
|
||||||
|
system: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
function ReplaySnapshotHealth({ health }) {
|
function ReplaySnapshotHealth({ health }) {
|
||||||
if (!health) return null;
|
if (!health) return null;
|
||||||
const replay = health.replay || { sources: [], readyCount: 0, totalCount: 0 };
|
const replay = health.replay || { sources: [], readyCount: 0, totalCount: 0 };
|
||||||
|
|||||||
Reference in New Issue
Block a user