Add debug tab with payload viewer

This commit is contained in:
Jordan Wages 2025-07-19 19:03:37 -05:00
commit db7ce49a5b
4 changed files with 39 additions and 2 deletions

View file

@ -16,6 +16,7 @@ message meets a specified criterion.
- **Advanced parameters** tune generation settings like temperature, topp and more from the options page.
- **Markdown conversion** optionally convert HTML bodies to Markdown before sending them to the AI service.
- **Debug logging** optional colorized logs help troubleshoot interactions with the AI service.
- **Debug tab** view the last request payload sent to the AI service.
- **Light/Dark themes** automatically match Thunderbird's appearance with optional manual override.
- **Automatic rules** create rules that tag, move, copy, forward, reply, delete, archive, mark read/unread or flag/unflag messages based on AI classification. Rules can optionally apply only to unread messages and can ignore messages outside a chosen age range.
- **Rule ordering** drag rules to prioritize them and optionally stop processing after a match.

View file

@ -308,6 +308,11 @@ async function classifyText(text, criterion, cacheKey = null) {
}
const payload = buildPayload(text, criterion);
try {
await storage.local.set({ lastPayload: JSON.parse(payload) });
} catch (e) {
aiLog('failed to save last payload', { level: 'warn' }, e);
}
aiLog(`[AiClassifier] Sending classification request to ${gEndpoint}`, {debug: true});
aiLog(`[AiClassifier] Classification request payload:`, { debug: true }, payload);

View file

@ -47,6 +47,7 @@
<li class="is-active" data-tab="settings"><a><span class="icon is-small"><img data-icon="settings" data-size="16" src="../resources/img/settings-light-16.png" alt=""></span><span>Settings</span></a></li>
<li data-tab="rules"><a><span class="icon is-small"><img data-icon="clipboarddata" data-size="16" src="../resources/img/clipboarddata-light-16.png" alt=""></span><span>Rules</span></a></li>
<li data-tab="maintenance"><a><span class="icon is-small"><img data-icon="gear" data-size="16" src="../resources/img/gear-light-16.png" alt=""></span><span>Maintenance</span></a></li>
<li id="debug-tab-button" class="is-hidden" data-tab="debug"><a><span class="icon is-small"><img data-icon="average" data-size="16" src="../resources/img/average-light-16.png" alt=""></span><span>Debug</span></a></li>
</ul>
</div>
</div>
@ -215,6 +216,11 @@
<input class="input" type="number" step="0.01" id="tfs">
</div>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" id="show-debug-tab"> Advanced Options
</label>
</div>
</div>
</div>
@ -273,6 +279,14 @@
</p>
</div>
</div>
<div id="debug-tab" class="tab-content is-hidden">
<h2 class="title is-4">
<span class="icon is-small"><img data-icon="average" data-size="16" src="../resources/img/average-light-16.png" alt=""></span>
<span>Debug</span>
</h2>
<pre id="payload-display"></pre>
</div>
</div>
</section>
<script src="options.js"></script>

View file

@ -19,7 +19,9 @@ document.addEventListener('DOMContentLoaded', async () => {
'tokenReduction',
'aiRules',
'aiCache',
'theme'
'theme',
'showDebugTab',
'lastPayload'
]);
const tabButtons = document.querySelectorAll('#main-tabs li');
const tabs = document.querySelectorAll('.tab-content');
@ -64,6 +66,10 @@ document.addEventListener('DOMContentLoaded', async () => {
}
await applyTheme(themeSelect.value);
const payloadDisplay = document.getElementById('payload-display');
if (defaults.lastPayload) {
payloadDisplay.textContent = JSON.stringify(defaults.lastPayload, null, 2);
}
themeSelect.addEventListener('change', async () => {
markDirty();
await applyTheme(themeSelect.value);
@ -119,6 +125,16 @@ document.addEventListener('DOMContentLoaded', async () => {
const tokenReductionToggle = document.getElementById('token-reduction');
tokenReductionToggle.checked = defaults.tokenReduction === true;
const debugTabToggle = document.getElementById('show-debug-tab');
const debugTabBtn = document.getElementById('debug-tab-button');
function updateDebugTab() {
const visible = debugTabToggle.checked;
debugTabBtn.classList.toggle('is-hidden', !visible);
}
debugTabToggle.checked = defaults.showDebugTab === true;
debugTabToggle.addEventListener('change', () => { updateDebugTab(); markDirty(); });
updateDebugTab();
const aiParams = Object.assign({}, DEFAULT_AI_PARAMS, defaults.aiParams || {});
for (const [key, val] of Object.entries(aiParams)) {
@ -797,8 +813,9 @@ document.addEventListener('DOMContentLoaded', async () => {
const altTextImages = altTextToggle.checked;
const collapseWhitespace = collapseWhitespaceToggle.checked;
const tokenReduction = tokenReductionToggle.checked;
const showDebugTab = debugTabToggle.checked;
const theme = themeSelect.value;
await storage.local.set({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging, htmlToMarkdown, stripUrlParams, altTextImages, collapseWhitespace, tokenReduction, aiRules: rules, theme });
await storage.local.set({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging, htmlToMarkdown, stripUrlParams, altTextImages, collapseWhitespace, tokenReduction, aiRules: rules, theme, showDebugTab });
await applyTheme(theme);
try {
await AiClassifier.setConfig({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging });