LLM: verbose [llm] logs + visible tweak progress

Tune appeared to do nothing — the 400's cause was buried, in-flight was
near-invisible, and dialog only appeared on success. Make every stage
observable and cheap to diagnose.

- src/llm/llmTweak.js (+ spec.js): provider.chat(model) + providerOptions
  strictJsonSchema:false fix (correct placement), edits nullable so strict
  requires all 7 keys; clamped, budget-aware. Now logs [llm] fetch target,
  messages/spec, raw vs clamped edits, rationale/confidence/usage,
  elapsed time, and diff summary. NO_EDITS refunded with console.warn.
- src/main.js: immediate OK toast "Contacting LLM (model)…" on click,
  console.group for handleLlmTweak start, post-result toast with
  rationale snippet + editsSummary before dialog, preview synthesis
  logged, catch logs stack once with toast.
- vite.config.js: /__llm dev proxy already in place from prior fix;
  retained for CORS-free dev.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Dejvino
2026-09-13 20:59:30 +02:00
co-authored by Claude
parent 82ab88e6b0
commit e2f56e3ce4
2 changed files with 48 additions and 3 deletions
+22 -1
View File
@@ -1053,6 +1053,14 @@ async function handleLlmTweak() {
const btn = document.getElementById('btn-llm-tweak');
const prevLabel = btn ? btn.textContent : '';
if (btn) btn.textContent = '… tuning';
// Immediate feedback — budget had a one-frame lag before, so show progress explicitly.
showToast(`Contacting LLM (${cfg.model})…`, { ok: true });
console.info('[llm] handleLlmTweak start', {
model: cfg.model, gateway: cfg.gatewayUrl,
remaining, hint: hint || '(none)',
specBefore, trackSummary: trackBefore && trackBefore.summary,
lookDirector: lookBefore && lookBefore.director,
});
try {
const result = await requestSongTweak({
@@ -1063,6 +1071,17 @@ async function handleLlmTweak() {
config: cfg,
});
// Log what came back before any synthesis — this is the audit trail.
console.groupCollapsed(`[llm] got result — ${Object.keys(result.edits).join(', ') || 'no edits'} · confidence ${String(result.confidence)}`);
console.log('[llm] rationale:', result.rationale);
console.log('[llm] edits:', result.edits);
console.log('[llm] raw:', result.raw, 'usage:', result.usage);
console.groupEnd();
const editsSummary = Object.keys(result.edits).length
? Object.entries(result.edits).map(([k, v]) => `${k}→${v == null ? '∅' : String(v)}`).join(' · ')
: '(no knobs changed)';
showToast(`LLM replied: ${result.rationale.slice(0, 160)} — edits: ${editsSummary}`, { ok: true, timeout: 5000 });
const specAfter = { ...specBefore, ...result.edits };
// Validate locally by re-synthesizing and measuring — show diff before applying.
// Do a lightweight preview synthesis so we can report section/agitation delta
@@ -1083,12 +1102,15 @@ async function handleLlmTweak() {
trackAfter = FeatureTrack.fromAudioBuffer(buf, { fps: state.show.fps });
const previewSeed = specAfter.seed != null ? (specAfter.seed >>> 0) : (specBefore.seed != null ? (specBefore.seed >>> 0) + 1 : 1);
lookAfter = generateLook(trackAfter, { seed: previewSeed });
console.info('[llm] preview look', lookAfter ? `${lookAfter.director} · ${lookAfter.sections.length} sections` : 'n/a',
trackAfter ? `sections ${trackAfter.sections.length}` : '');
} catch (e) {
console.warn('[llm] preview synthesis failed', e);
}
openLlmTweakDialog(result, specBefore, specAfter, trackBefore, trackAfter, lookBefore, lookAfter);
} catch (err) {
console.warn('[llm] request failed', err && err.stack ? err.stack : err);
const code = err && err.code;
if (code === 'NO_EDITS') {
showToast(err.message, { ok: true, timeout: 5000 });
@@ -1102,7 +1124,6 @@ async function handleLlmTweak() {
openLlmConfigDialog();
} else {
showToast(`LLM tweak failed: ${err.message}`);
console.error('[llm] request failed', err);
}
} finally {
llmTweakInFlight = false;