Skip to content

Commit 71ce963

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 d88c8cb commit 71ce963

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');
@@ -3215,13 +3213,15 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
32153213
}
32163214
} else {
32173215
// Stop streaming TTS on any error/abort
3216+
// note - error: streamingTTS is undefined (try block), so window.aiTTSManager.stop() will NEVER be called
32183217
if (streamingTTS && window.aiTTSManager) window.aiTTSManager.stop();
32193218

32203219
if (currentAbort && currentAbort.signal.aborted) {
32213220
const abortReason = currentAbort._reason || '';
32223221
// Timeout-triggered aborts should remain visible instead of disappearing.
32233222
if (timedOut || abortReason === 'timeout') {
3224-
const timeoutMsg = _isAgent
3223+
// note - error: _isAgent is undefined (try block), so msg will ALWAYS be "Response timed out. Try again."
3224+
const timeoutMsg = _isAgent
32253225
? 'Agent response timed out. Try again, switch to a faster model, or reduce tool usage.'
32263226
: 'Response timed out. Try again.';
32273227

@@ -3765,7 +3765,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
37653765
const holder = document.createElement('div');
37663766
holder.className = 'msg msg-ai';
37673767
const meta = sessionModule.getSessions().find(s => s.id === sessionId);
3768-
const roleLabel = _shortModel(meta && meta.model);
3768+
const roleLabel = shortModel(meta && meta.model);
37693769
const roleTs = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
37703770
holder.innerHTML = '<div class="role">' + uiModule.esc(roleLabel) +
37713771
' <span class="role-timestamp">' + roleTs + '</span></div>' +
@@ -3932,7 +3932,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
39323932
var holder = document.createElement('div');
39333933
holder.className = 'msg msg-ai';
39343934
var meta = sessionModule.getSessions().find(function(s) { return s.id === sessionId; });
3935-
var roleLabel = _shortModel(meta && meta.model);
3935+
var roleLabel = shortModel(meta && meta.model);
39363936
var roleTs = new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
39373937
holder.innerHTML = '<div class="role">' + uiModule.esc(roleLabel) + ' <span class="role-timestamp">' + roleTs + '</span></div><div class="body"></div>';
39383938
_applyModelColor(holder.querySelector('.role'), meta && meta.model);
@@ -4709,7 +4709,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
47094709
var _role = document.createElement('div');
47104710
_role.className = 'role';
47114711
var _meta = sessionModule.getSessions().find(function(s) { return s.id === sessionId; });
4712-
_role.textContent = _shortModel(_meta?.model);
4712+
_role.textContent = shortModel(_meta?.model);
47134713
_applyModelColor(_role, _meta?.model);
47144714
_role.appendChild(chatRenderer.roleTimestamp());
47154715
var _body = document.createElement('div');
@@ -4745,7 +4745,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
47454745
holder.dataset.researchSession = sessionId;
47464746
const roleTs = new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
47474747
const agentMeta = sessionModule.getSessions().find(s => s.id === sessionModule.getCurrentSessionId());
4748-
const agentModelLabel = _shortModel(agentMeta?.model);
4748+
const agentModelLabel = shortModel(agentMeta?.model);
47494749
holder.innerHTML = `<div class="role">${uiModule.esc(agentModelLabel)} <span class="role-timestamp">${roleTs}</span></div><div class="body"></div>`;
47504750
_applyModelColor(holder.querySelector('.role'), agentMeta?.model);
47514751
box.appendChild(holder);
@@ -5396,7 +5396,7 @@ import { wireArrowUpRecall, getLastUserMessageFromChatHistory } from './composer
53965396
hideWelcomeScreen: chatRenderer.hideWelcomeScreen,
53975397
showWelcomeScreen: chatRenderer.showWelcomeScreen,
53985398
checkPendingResearch,
5399-
getImageCost: chatRenderer.getImageCost,
5399+
getImageCost: getImageCost,
54005400
setDisplayOverride,
54015401
setHideUserBubble,
54025402
setPendingContinue,

0 commit comments

Comments
 (0)