mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-17 02:05:22 -04:00
Chat: show Chat/Agent tag next to message timestamp
Sometimes the user lands in chat mode without realizing — surface the mode the message went out on as a small uppercase pill right after the timestamp in the role header. - roleTimestamp(when, mode) gains an optional mode arg. Agent renders in accent; Chat renders in muted/neutral. Other values render nothing (back-compat for older history without the field). - The three roleTimestamp call sites pass metadata?.mode through. - chat.js writes mode into the user-message metadata at send time and into the assistant metadata when the active-stream render lands, reading toggleState.mode so research/agent overrides upstream still flow through correctly. Historical messages from before this change just don't show the pill — graceful fallback, no migration needed.
This commit is contained in:
+9
-1
@@ -628,8 +628,13 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let _userMsgEl = null;
|
let _userMsgEl = null;
|
||||||
|
// Capture which mode the user picked at send time so the message
|
||||||
|
// header can show "Chat" or "Agent" next to the timestamp.
|
||||||
|
const _sendMode = (toggleState.mode || 'chat') === 'agent' ? 'agent' : 'chat';
|
||||||
if (!skipBubble) {
|
if (!skipBubble) {
|
||||||
_userMsgEl = addMessage('user', userDisplay, null, _pendingAttachInfo ? { attachments: _pendingAttachInfo } : null);
|
const _userMeta = { mode: _sendMode };
|
||||||
|
if (_pendingAttachInfo) _userMeta.attachments = _pendingAttachInfo;
|
||||||
|
_userMsgEl = addMessage('user', userDisplay, null, _userMeta);
|
||||||
}
|
}
|
||||||
messageInput.value = '';
|
messageInput.value = '';
|
||||||
messageInput.style.height = '';
|
messageInput.style.height = '';
|
||||||
@@ -3423,6 +3428,9 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
|
|||||||
if (holder.parentNode) holder.remove();
|
if (holder.parentNode) holder.remove();
|
||||||
const model = meta && meta.model;
|
const model = meta && meta.model;
|
||||||
const meta_ = metricsData ? Object.assign({ model }, metricsData) : { model };
|
const meta_ = metricsData ? Object.assign({ model }, metricsData) : { model };
|
||||||
|
// Carry the send-time mode through so the assistant header gets
|
||||||
|
// the same Chat/Agent tag next to its timestamp.
|
||||||
|
meta_.mode = (toggleState.mode || 'chat') === 'agent' ? 'agent' : 'chat';
|
||||||
chatRenderer.addMessage('assistant', roundText, model, meta_);
|
chatRenderer.addMessage('assistant', roundText, model, meta_);
|
||||||
uiModule.scrollHistory();
|
uiModule.scrollHistory();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -832,8 +832,10 @@ export function updateSessionCostUI() {
|
|||||||
|
|
||||||
/** Create a timestamp span for role labels.
|
/** Create a timestamp span for role labels.
|
||||||
* Pass an ISO string / Date / epoch-ms to render the message's own time
|
* Pass an ISO string / Date / epoch-ms to render the message's own time
|
||||||
* (used when replaying history). Falls back to "now" when no value is given. */
|
* (used when replaying history). Falls back to "now" when no value is given.
|
||||||
export function roleTimestamp(when) {
|
* Optionally pass `mode` ('chat' | 'agent') to append a small badge so the
|
||||||
|
* reader can tell at a glance which path the message went through. */
|
||||||
|
export function roleTimestamp(when, mode) {
|
||||||
const ts = document.createElement('span');
|
const ts = document.createElement('span');
|
||||||
ts.className = 'role-timestamp';
|
ts.className = 'role-timestamp';
|
||||||
let d;
|
let d;
|
||||||
@@ -844,6 +846,12 @@ export function roleTimestamp(when) {
|
|||||||
if (isNaN(d.getTime())) d = new Date();
|
if (isNaN(d.getTime())) d = new Date();
|
||||||
ts.textContent = d.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
|
ts.textContent = d.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
|
||||||
ts.title = d.toLocaleString();
|
ts.title = d.toLocaleString();
|
||||||
|
if (mode === 'agent' || mode === 'chat') {
|
||||||
|
const tag = document.createElement('span');
|
||||||
|
tag.className = 'role-mode-tag role-mode-' + mode;
|
||||||
|
tag.textContent = mode === 'agent' ? 'Agent' : 'Chat';
|
||||||
|
ts.appendChild(tag);
|
||||||
|
}
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2005,7 +2013,7 @@ export function addMessage(role, content, modelName, metadata) {
|
|||||||
roleEl.title = pair.requestedModel + ' -> ' + contModel;
|
roleEl.title = pair.requestedModel + ' -> ' + contModel;
|
||||||
}
|
}
|
||||||
applyModelColor(roleEl, contModel);
|
applyModelColor(roleEl, contModel);
|
||||||
if (r === 0) roleEl.appendChild(roleTimestamp(metadata?.timestamp));
|
if (r === 0) roleEl.appendChild(roleTimestamp(metadata?.timestamp, metadata?.mode));
|
||||||
wrap.appendChild(roleEl);
|
wrap.appendChild(roleEl);
|
||||||
const body = document.createElement('div');
|
const body = document.createElement('div');
|
||||||
body.className = 'body';
|
body.className = 'body';
|
||||||
@@ -2165,7 +2173,7 @@ export function addMessage(role, content, modelName, metadata) {
|
|||||||
r.title = replyModels.requestedModel + ' -> ' + resolvedModel;
|
r.title = replyModels.requestedModel + ' -> ' + resolvedModel;
|
||||||
}
|
}
|
||||||
if (!isSlash && !isCompacted) applyModelColor(r, resolvedModel);
|
if (!isSlash && !isCompacted) applyModelColor(r, resolvedModel);
|
||||||
r.appendChild(roleTimestamp(metadata?.timestamp));
|
r.appendChild(roleTimestamp(metadata?.timestamp, metadata?.mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
const b = document.createElement('div');
|
const b = document.createElement('div');
|
||||||
@@ -2410,7 +2418,7 @@ export function addMessage(role, content, modelName, metadata) {
|
|||||||
if (metadata) displayMetrics(wrap, metadata);
|
if (metadata) displayMetrics(wrap, metadata);
|
||||||
} else {
|
} else {
|
||||||
// Add timestamp to user header (like AI messages)
|
// Add timestamp to user header (like AI messages)
|
||||||
r.appendChild(roleTimestamp(metadata?.timestamp));
|
r.appendChild(roleTimestamp(metadata?.timestamp, metadata?.mode));
|
||||||
|
|
||||||
wrap.appendChild(createUserMsgFooter(wrap));
|
wrap.appendChild(createUserMsgFooter(wrap));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3247,6 +3247,26 @@ body.bg-pattern-sparkles {
|
|||||||
.role-timestamp {
|
.role-timestamp {
|
||||||
font-size:0.7rem; color:var(--color-muted-alt); font-weight:normal; margin-left:6px;
|
font-size:0.7rem; color:var(--color-muted-alt); font-weight:normal; margin-left:6px;
|
||||||
}
|
}
|
||||||
|
/* Mode tag (Chat / Agent) sits right after the timestamp so users
|
||||||
|
can tell at a glance which path a message took. Subtle pill —
|
||||||
|
no accent background, just text + thin border. */
|
||||||
|
.role-mode-tag {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 6px;
|
||||||
|
padding: 0 5px;
|
||||||
|
font-size: 0.62rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.4px;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid color-mix(in srgb, var(--fg) 18%, transparent);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
.role-mode-tag.role-mode-agent {
|
||||||
|
color: var(--accent, var(--red));
|
||||||
|
border-color: color-mix(in srgb, var(--accent, var(--red)) 35%, transparent);
|
||||||
|
}
|
||||||
.msg-footer {
|
.msg-footer {
|
||||||
display:flex; align-items:center; gap:6px;
|
display:flex; align-items:center; gap:6px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
Reference in New Issue
Block a user