From 8e6040e90c8118e2d55fdc2b521f59933db1c8aa Mon Sep 17 00:00:00 2001 From: OpenClaw Bot Date: Wed, 27 May 2026 14:51:20 +0200 Subject: [PATCH] Add source citation copy for Ranker handoff --- public/app.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/public/app.js b/public/app.js index 336c052..78414b6 100644 --- a/public/app.js +++ b/public/app.js @@ -197,10 +197,29 @@ function renderLane(ranked, laneId) { `; } +function sourceCitation(data) { + const brief = data.brief || {}; + const source = brief.source || data.handoff?.source || data.input?.provenance || {}; + const trace = brief.quickGlance?.sourceTrace || {}; + const parts = [ + source.artifactId ? `Artifact: ${source.artifactId}` : '', + source.conceptMapId ? `Concept Map: ${source.conceptMapId}` : '', + source.snapshotTitle ? `Title: ${source.snapshotTitle}` : '', + trace.sourceSection ? `Source section: ${trace.sourceSection}` : '', + trace.sourceId ? `Source item: ${trace.sourceId}` : '', + trace.sourceTitle ? `Source title: ${trace.sourceTitle}` : '', + trace.sourceQuote ? `Source quote: ${trace.sourceQuote}` : '', + source.originalPromptExcerpt ? `Original prompt: ${source.originalPromptExcerpt}` : '', + ].filter(Boolean); + return parts.length ? parts.join('\n') : 'No source citation was carried into this result.'; +} + function markdownBrief(data) { const brief = data.brief || {}; const glance = brief.quickGlance || {}; const ranked = data.ranked || []; + const citation = sourceCitation(data); + const hasCitation = !citation.startsWith('No source citation'); const lanes = ['do', 'test', 'defer', 'park']; const laneTitles = { do: 'Do first', test: 'Validate next', defer: 'Defer', park: 'Park / cut' }; return [ @@ -215,6 +234,7 @@ function markdownBrief(data) { `- Evidence question: ${glance.evidenceQuestion || 'n/a'}`, `- Biggest trap: ${glance.biggestTrap || 'n/a'}`, `- Confidence: ${data.rankConfidence?.level || 'n/a'} — ${data.rankConfidence?.reason || ''}`, + ...(hasCitation ? ['', '## Source citation', citation] : []), '', ...lanes.flatMap((lane) => { const items = ranked.filter((item) => item.lane?.id === lane); @@ -238,6 +258,7 @@ function attachResultActions(data) { document.querySelector('#copyBrief')?.addEventListener('click', () => copyText(markdownBrief(data), 'Decision brief')); document.querySelector('#copyActions')?.addEventListener('click', () => copyText((data.brief?.next48Hours || []).map((step, index) => `${index + 1}. ${step}`).join('\n'), '48h actions')); document.querySelector('#copyJson')?.addEventListener('click', () => copyText(JSON.stringify({ brief: data.brief, ranked: data.ranked, buildOrder: data.buildOrderDetails, handoff: data.handoff }, null, 2), 'JSON handoff')); + document.querySelector('#copySource')?.addEventListener('click', () => copyText(sourceCitation(data), 'Source citation')); } function renderResults(data) { @@ -266,6 +287,7 @@ function renderResults(data) { +