Skip to content

Commit 58a3ccf

Browse files
committed
refactor(chatRenderer.js)
No changes to the module's core logic, properties or functionality. Two 'private' methods were renamed and extracted as utility functions. - formatCompactNumber: Formats large numbers to K/M shorthand - previously named `_fmtCtx` inside of chatRenderer - toTrimmedString: Converts values to trimmed strings, handling null - previously named `modelValue` inside of chatRenderer Elements were factored out - none factored in. Exports not belonging to the remaining set of properties and functions were removed. Updates were applied downstream to importing modules so that they use the correct sources of truth moving forward. fix(test) Update frontend tests touching refactor Introduces `tests/helpers/valid_imports.py` to help ease the pain of rewriting exact-match import tests when refactoring, reording of modules lists, etc., occurs Updates tests where needed - Update stream render test to use rfind for try block detection - Update XSS test assertions to use new source of truth for safeDisplayImageSrc. Use valid_imports helper to survive refactors.
1 parent df2fad2 commit 58a3ccf

17 files changed

Lines changed: 459 additions & 242 deletions

static/js/chat.js

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ import slashCommands, { initSlashCommands, isCommand, handleSlashCommand, handle
2323
import createResearchSynapse from './researchSynapse.js';
2424
import { createStreamRenderer } from './streamingRenderer.js';
2525
import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composerArrowUpRecall.js';
26+
import { isSubscriptionEndpoint } from './model/endpoint.js';
27+
import { modelRouteLabel, replyModelPair, sameModelName, shortModel } from './model/models.js';
28+
import { getImageCost, getModelCost } from './model/pricing.js';
29+
import { safeDisplayImageSrc, safeToolScreenshotSrc } from './util/safeString.js';
2630

2731
const RESEARCH_TIMEOUT_MS = 360000;
2832
const DEFAULT_TIMEOUT_MS = 120000;
@@ -102,23 +106,19 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
102106
let _autoContinuePending = false; // marks the next submit as an auto-continue (don't reset the counter)
103107
const _AUTO_NUDGE_CAP = 3;
104108

105-
// shortModel and modelColor are now in chatRenderer.js
106-
var _shortModel = chatRenderer.shortModel;
107-
var _modelRouteLabel = chatRenderer.modelRouteLabel;
108-
var _sameModelName = chatRenderer.sameModelName;
109109
var _applyModelColor = chatRenderer.applyModelColor;
110110
function _setRoleModelLabel(roleEl, requestedModel, actualModel, opts) {
111111
if (!roleEl) return;
112112
opts = opts || {};
113113
const tsSpan = roleEl.querySelector('.role-timestamp');
114114
const req = requestedModel || actualModel || '';
115115
const actual = actualModel || requestedModel || '';
116-
let label = _modelRouteLabel(req, actual);
116+
let label = modelRouteLabel(req, actual);
117117
if (opts.suffix) label += ' (' + opts.suffix + ')';
118118
if (opts.characterName) label = opts.characterName;
119119
roleEl.textContent = label + ' ';
120120
_applyModelColor(roleEl, actual || req);
121-
if (req && actual && !_sameModelName(req, actual)) {
121+
if (req && actual && !sameModelName(req, actual)) {
122122
roleEl.title = req + ' -> ' + actual + (opts.reason ? ': ' + opts.reason : '');
123123
} else if (!opts.reason) {
124124
roleEl.removeAttribute('title');
@@ -285,8 +285,6 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
285285

286286
// Model/image pricing, _buildImageBubble now in chatRenderer.js
287287
var _buildImageBubble = chatRenderer.buildImageBubble;
288-
var getModelCost = chatRenderer.getModelCost;
289-
var getImageCost = chatRenderer.getImageCost;
290288

291289
// stripToolBlocks and roleTimestamp now in chatRenderer.js
292290
var stripToolBlocks = chatRenderer.stripToolBlocks;
@@ -420,7 +418,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
420418
if (window._updateSendBtnIcon) {
421419
setTimeout(window._updateSendBtnIcon, 50);
422420
} else {
423-
var icons = window._odysseusBtnIcons;
421+
var icons = window._odysseusBtnIcons;// already declared above (non-breaking)
424422
submitBtn.innerHTML = icons ? icons.send : '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19V5M5 12l7-7 7 7"/></svg>';
425423
submitBtn.title = 'Send message';
426424
submitBtn.classList.remove('mic-mode', 'newchat-mode');
@@ -584,7 +582,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
584582
clearTimeout(window._researchTimeoutTimer);
585583
window._researchTimeoutTimer = null;
586584
}
587-
// Get current session
585+
// Get current session (note: these two vars go UNUSED)
588586
const sessionId = sessionModule.getCurrentSessionId();
589587
const session = sessionModule.getSessions().find(s => s.id === sessionId);
590588

@@ -867,7 +865,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
867865

868866

869867
const messageInput = el('message');
870-
const originalBtnText = submitBtn ? submitBtn.innerHTML : '';
868+
const originalBtnText = submitBtn ? submitBtn.innerHTML : '';// note: UNUSED
871869

872870
// Re-enable the textarea now that we've handed off to the stream: the
873871
// user wants to compose the next message while the AI is still talking.
@@ -1278,7 +1276,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
12781276

12791277
const modelName = sessionModule.getCurrentModel() || null;
12801278

1281-
let loadingText = 'Initializing...';
1279+
let loadingText = 'Initializing...';//note: UNUSED despite being set below
12821280

12831281
if (el('web-toggle').checked && !_isAgent) {
12841282
const _searchLabel = searchModule ? searchModule.getProviderLabel() : 'web';
@@ -1292,7 +1290,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
12921290
loadingText = 'Processing request...';
12931291
}
12941292

1295-
var roleLabel = _modelRouteLabel(modelName, modelName);
1293+
var roleLabel = modelRouteLabel(modelName, modelName);
12961294
var _charNameInit = presetsModule.getCharacterName ? presetsModule.getCharacterName() : '';
12971295
if (_charNameInit) roleLabel = _charNameInit;
12981296
const roleTs = new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
@@ -1461,7 +1459,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
14611459
const metaS = sessionModule.getSessions().find(s => s.id === streamSessionId);
14621460
const requested = holder?._requestedModel || metaS?.model || modelName;
14631461
const actual = holder?._actualModel || requested;
1464-
newRole.textContent = _modelRouteLabel(requested, actual) || '';
1462+
newRole.textContent = modelRouteLabel(requested, actual) || '';
14651463
_applyModelColor(newRole, actual);
14661464
newWrap.appendChild(newRole);
14671465
const newBody = document.createElement('div');
@@ -2292,8 +2290,8 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
22922290
// it visible so a misconfigured provider is never silently
22932291
// masked under the selected model's name.
22942292
if (!_isBg) {
2295-
var _selM = _shortModel(json.selected_model || '');
2296-
var _ansM = _shortModel(json.answered_by || '');
2293+
var _selM = shortModel(json.selected_model || '');
2294+
var _ansM = shortModel(json.answered_by || '');
22972295
uiModule.showToast('⚠ ' + _selM + ' failed — answered by ' + _ansM, 6000);
22982296
if (holder) {
22992297
var _rEl = holder.querySelector('.role');
@@ -2305,7 +2303,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
23052303
_applyModelColor(_rEl, json.answered_by);
23062304
if (_tsS) _rEl.appendChild(_tsS);
23072305
holder._requestedModel = json.selected_model || holder._requestedModel || modelName;
2308-
const _hasResolvedActual = holder._actualModel && !_sameModelName(holder._actualModel, holder._requestedModel);
2306+
const _hasResolvedActual = holder._actualModel && !sameModelName(holder._actualModel, holder._requestedModel);
23092307
holder._actualModel = _hasResolvedActual ? holder._actualModel : (json.answered_by || holder._actualModel || holder._requestedModel);
23102308
_setRoleModelLabel(_rEl, holder._requestedModel, holder._actualModel, {
23112309
suffix: holder._roleSuffix,
@@ -2676,7 +2674,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
26762674
if (json.screenshot && currentToolBubble) {
26772675
const contentEl = currentToolBubble.querySelector('.agent-thread-content');
26782676
if (contentEl) {
2679-
const screenshotSrc = chatRenderer.safeToolScreenshotSrc(json.screenshot);
2677+
const screenshotSrc = safeToolScreenshotSrc(json.screenshot);
26802678
if (screenshotSrc) {
26812679
const details = document.createElement('details');
26822680
details.className = 'agent-tool-output';
@@ -2796,7 +2794,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
27962794
// Agent wrote back to the plan (ticked a step / revised). Update
27972795
// the stored plan + live-refresh the docked plan window.
27982796
const _pu = (json.data && json.data.plan) ? json.data.plan : '';
2799-
if (_pu) _setStoredPlan(_pu);
2797+
if (_pu) _setStoredPlan(_pu);// note: error - undeclared
28002798

28012799
} else if (json.type === 'agent_step') {
28022800
if (_isBg) continue;
@@ -2823,7 +2821,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
28232821
const metaS = sessionModule.getSessions().find(s => s.id === streamSessionId);
28242822
const _roundRequested = holder?._requestedModel || metaS?.model;
28252823
const _roundActual = holder?._actualModel || _roundRequested;
2826-
newRole.textContent = _modelRouteLabel(_roundRequested, _roundActual) || '';
2824+
newRole.textContent = modelRouteLabel(_roundRequested, _roundActual) || '';
28272825
_applyModelColor(newRole, _roundActual);
28282826
newWrap.appendChild(newRole);
28292827
const newBody = document.createElement('div');
@@ -3231,13 +3229,15 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
32313229
}
32323230
} else {
32333231
// Stop streaming TTS on any error/abort
3232+
// note - error: streamingTTS is undefined (try block), so window.aiTTSManager.stop() will NEVER be called
32343233
if (streamingTTS && window.aiTTSManager) window.aiTTSManager.stop();
32353234

32363235
if (currentAbort && currentAbort.signal.aborted) {
32373236
const abortReason = currentAbort._reason || '';
32383237
// Timeout-triggered aborts should remain visible instead of disappearing.
32393238
if (timedOut || abortReason === 'timeout') {
3240-
const timeoutMsg = _isAgent
3239+
// note - error: _isAgent is undefined (try block), so msg will ALWAYS be "Response timed out. Try again."
3240+
const timeoutMsg = _isAgent
32413241
? 'Agent response timed out. Try again, switch to a faster model, or reduce tool usage.'
32423242
: 'Response timed out. Try again.';
32433243

@@ -3781,7 +3781,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
37813781
const holder = document.createElement('div');
37823782
holder.className = 'msg msg-ai';
37833783
const meta = sessionModule.getSessions().find(s => s.id === sessionId);
3784-
const roleLabel = _shortModel(meta && meta.model);
3784+
const roleLabel = shortModel(meta && meta.model);
37853785
const roleTs = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
37863786
holder.innerHTML = '<div class="role">' + uiModule.esc(roleLabel) +
37873787
' <span class="role-timestamp">' + roleTs + '</span></div>' +
@@ -3948,7 +3948,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
39483948
var holder = document.createElement('div');
39493949
holder.className = 'msg msg-ai';
39503950
var meta = sessionModule.getSessions().find(function(s) { return s.id === sessionId; });
3951-
var roleLabel = _shortModel(meta && meta.model);
3951+
var roleLabel = shortModel(meta && meta.model);
39523952
var roleTs = new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
39533953
holder.innerHTML = '<div class="role">' + uiModule.esc(roleLabel) + ' <span class="role-timestamp">' + roleTs + '</span></div><div class="body"></div>';
39543954
_applyModelColor(holder.querySelector('.role'), meta && meta.model);
@@ -4725,7 +4725,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
47254725
var _role = document.createElement('div');
47264726
_role.className = 'role';
47274727
var _meta = sessionModule.getSessions().find(function(s) { return s.id === sessionId; });
4728-
_role.textContent = _shortModel(_meta?.model);
4728+
_role.textContent = shortModel(_meta?.model);
47294729
_applyModelColor(_role, _meta?.model);
47304730
_role.appendChild(chatRenderer.roleTimestamp());
47314731
var _body = document.createElement('div');
@@ -4761,7 +4761,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
47614761
holder.dataset.researchSession = sessionId;
47624762
const roleTs = new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
47634763
const agentMeta = sessionModule.getSessions().find(s => s.id === sessionModule.getCurrentSessionId());
4764-
const agentModelLabel = _shortModel(agentMeta?.model);
4764+
const agentModelLabel = shortModel(agentMeta?.model);
47654765
holder.innerHTML = `<div class="role">${uiModule.esc(agentModelLabel)} <span class="role-timestamp">${roleTs}</span></div><div class="body"></div>`;
47664766
_applyModelColor(holder.querySelector('.role'), agentMeta?.model);
47674767
box.appendChild(holder);
@@ -5412,7 +5412,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
54125412
hideWelcomeScreen: chatRenderer.hideWelcomeScreen,
54135413
showWelcomeScreen: chatRenderer.showWelcomeScreen,
54145414
checkPendingResearch,
5415-
getImageCost: chatRenderer.getImageCost,
5415+
getImageCost: getImageCost,
54165416
setDisplayOverride,
54175417
setHideUserBubble,
54185418
setPendingContinue,

0 commit comments

Comments
 (0)