Persist MoA intermediate layers so they survive reload

Previously only the final proposer layer was persisted, so after a reload
the intermediate MoA rounds and their "Runde k/N" dividers were gone — the
history showed only the last refined round, not the full live view. Persist
every proposer round instead, tagging each member's JSON transcript with
its layer index, and rebuild the round structure on reload.

- AnthropicService.Panel.cs: persist every round unconditionally; drop the
  now-dead persist parameter and isFinalLayer local; write layer/totalLayers
  into the transcript; iteration = layer*100+index+1 so DB rows are
  layer-aware (no UNIQUE constraint on chain_id/iteration, id-based ordering)
- history.js: group panel bubbles by layer on reload and insert the
  "Runde k / N" divider on round change for MoA (totalLayers > 1), matching
  the live startPanelLayer view; back-compat for old format (default layer 1)
- TODO.md: check off the MoA persistence item

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MelekiandClaude Opus 4.8 committed 2026-06-18 18:03:37 +02:00
1 parent 1641bf11b6
commit 0f87ccdcab
3 files changed
+54 -28

No files matched your search

+27 -1
View File
@@ -231,14 +231,40 @@ function _renderMessagesIntoFragment(fragment, msgs, imageMessageIds, opts) {
continue;
}
// ── Panel (Fusion): je Member eine eigene Bubble ──
// ── Panel (Fusion/MoA): je Member eine eigene Bubble; bei MoA nach Runden gruppiert mit Divider ──
if (msg.tag === 'panel') {
const panelGroup = [msg];
while (_msgIdx + 1 < msgs.length && msgs[_msgIdx + 1].tag === 'panel') {
_msgIdx++;
panelGroup.push(msgs[_msgIdx]);
}
// Layer-Info aus dem JSON-Transkript lesen (Alt-Format / kein layer → Runde 1).
var _panelMaxLayers = 1;
var _panelLayers = [];
for (var _pli = 0; _pli < panelGroup.length; _pli++) {
var _pLayer = 1;
var _pContent = panelGroup[_pli].content || '';
if (_pContent.charAt(0) === '{') {
try {
var _pData = JSON.parse(_pContent);
if (_pData.layer) _pLayer = _pData.layer;
if (_pData.totalLayers > _panelMaxLayers) _panelMaxLayers = _pData.totalLayers;
} catch (e) {}
}
_panelLayers.push(_pLayer);
}
// In id-Reihenfolge rendern; bei MoA (>1 Runde) einen Divider beim Runden-Wechsel einfügen
// (spiegelt startPanelLayer aus stream-ui.js). Da die Runden SEQUENZIELL persistiert werden,
// ist panelGroup bereits nach Runde geordnet (Layer-1-ids < Layer-2-ids).
var _pLastLayer = null;
for (var _pi = 0; _pi < panelGroup.length; _pi++) {
if (_panelMaxLayers > 1 && _panelLayers[_pi] !== _pLastLayer) {
var _pDiv = document.createElement('div');
_pDiv.className = 'panel-layer-divider';
_pDiv.innerHTML = '<span><i class="fa fa-clone"></i> Runde ' + _panelLayers[_pi] + ' / ' + _panelMaxLayers + '</span>';
fragment.appendChild(_pDiv);
_pLastLayer = _panelLayers[_pi];
}
fragment.appendChild(_renderPanelMemberBubble(panelGroup[_pi], archived));
}
continue;