fix(confidence-engine): preserve focused learning across turns
This commit is contained in:
@@ -167,6 +167,7 @@ function FocusedQuestionBody({
|
|||||||
setFocusedPresentationItemId,
|
setFocusedPresentationItemId,
|
||||||
setDoneForNowIds,
|
setDoneForNowIds,
|
||||||
setFollowUpQuestion,
|
setFollowUpQuestion,
|
||||||
|
focusedContributions,
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -199,22 +200,33 @@ function FocusedQuestionBody({
|
|||||||
|
|
||||||
{focused?.result && (
|
{focused?.result && (
|
||||||
<>
|
<>
|
||||||
|
{/* Prior accumulated learning (prior turns, current turn excluded — shown above) */}
|
||||||
|
<PriorContributionsSummary nodeId={nodeId} contributions={focusedContributions || []} />
|
||||||
|
|
||||||
<div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">What this tells us</h3><ul className="list-disc pl-5 space-y-1">{(focused.result.observations || []).map((o, i) => (<li key={i} className="text-sm leading-relaxed text-gray-700">{o}</li>))}</ul></div>
|
<div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">What this tells us</h3><ul className="list-disc pl-5 space-y-1">{(focused.result.observations || []).map((o, i) => (<li key={i} className="text-sm leading-relaxed text-gray-700">{o}</li>))}</ul></div>
|
||||||
<div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">Still unclear</h3><ul className="list-disc pl-5 space-y-1">{(focused.result.uncertainties || []).map((u, i) => (<li key={i} className="text-sm leading-relaxed text-gray-700">{u}</li>))}</ul></div>
|
<div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">Still unclear</h3><ul className="list-disc pl-5 space-y-1">{(focused.result.uncertainties || []).map((u, i) => (<li key={i} className="text-sm leading-relaxed text-gray-700">{u}</li>))}</ul></div>
|
||||||
<div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">Questions this raises</h3>
|
<div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">Questions this raises</h3>
|
||||||
{(focused.result.possibleFollowUpQuestions || []).length > 0 ? (
|
{(focused.result.possibleFollowUpQuestions || []).length > 0 ? (
|
||||||
<div className="space-y-1 mt-1">
|
<div className="space-y-1 mt-1">
|
||||||
{focused.result.possibleFollowUpQuestions.map((q, i) => (
|
{focused.result.possibleFollowUpQuestions.map((q, i) => {
|
||||||
<button
|
const isCurrentQuestion = q === focused?.question;
|
||||||
key={i}
|
return (
|
||||||
onClick={(e) => { e.stopPropagation(); setFollowUpQuestion(q); }}
|
<button
|
||||||
style={{ cursor: "pointer" }}
|
key={i}
|
||||||
className="w-full text-left rounded-lg border border-blue-200/60 bg-blue-50/40 px-3 py-2.5 text-sm leading-relaxed text-gray-800 hover:border-blue-300 hover:bg-blue-100/60 transition"
|
onClick={(e) => { if (!isCurrentQuestion) { e.stopPropagation(); setFollowUpQuestion(q); } }}
|
||||||
data-testid="follow-up-question"
|
style={{ cursor: isCurrentQuestion ? "default" : "pointer" }}
|
||||||
>
|
className={`w-full text-left rounded-lg border px-3 py-2.5 text-sm leading-relaxed transition ${
|
||||||
{q} → pick this question
|
isCurrentQuestion
|
||||||
</button>
|
? "border-gray-200 bg-gray-100/60 text-gray-400 cursor-default"
|
||||||
))}
|
: "border-blue-200/60 bg-blue-50/40 text-gray-800 hover:border-blue-300 hover:bg-blue-100/60"
|
||||||
|
}`}
|
||||||
|
data-testid="follow-up-question"
|
||||||
|
>
|
||||||
|
{q}
|
||||||
|
{isCurrentQuestion ? " (current question)" : " → pick this question"}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-xs text-gray-400">None yet</p>
|
<p className="text-xs text-gray-400">None yet</p>
|
||||||
@@ -403,7 +415,55 @@ function EvidenceLimitCard({ summary }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Per-thread contribution badge (compact indicator) ──────────────
|
// ── Prior contribution summary (embedded within FocusedQuestionBody) ───
|
||||||
|
|
||||||
|
function PriorContributionsSummary({ nodeId, contributions }) {
|
||||||
|
const threadContribs = contributions.filter((c) => c.targetNodeId === nodeId);
|
||||||
|
if (!threadContribs.length) return null;
|
||||||
|
|
||||||
|
// Exclude the most recent contribution — it is already shown as the current result above.
|
||||||
|
const priorContribs = threadContribs.slice(0, -1);
|
||||||
|
if (!priorContribs.length) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="rounded-lg border border-gray-200/60 bg-gray-50/40 px-4 py-3">
|
||||||
|
<h4 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">
|
||||||
|
Previous learning
|
||||||
|
</h4>
|
||||||
|
{priorContribs.map((c, idx) => (
|
||||||
|
<details key={c.id || idx} className="mb-2 border-b border-gray-200/40 last:border-0 pb-2 last:pb-0" open={idx === 0}>
|
||||||
|
<summary className="cursor-pointer text-xs font-medium text-gray-500 hover:text-gray-700 select-none py-1">
|
||||||
|
Turn {c.sequence || idx + 1} — contribution ({c.observations?.length ?? 0} observations, {c.uncertainties?.length ?? 0} unclear)
|
||||||
|
</summary>
|
||||||
|
<div className="pt-2 space-y-3">
|
||||||
|
{c.observations?.length ? (
|
||||||
|
<div>
|
||||||
|
<h5 className="text-[10px] font-semibold tracking-widest uppercase text-gray-500">What this tells us</h5>
|
||||||
|
<ul className="list-disc pl-5 space-y-0.5">
|
||||||
|
{c.observations.map((o, i) => (
|
||||||
|
<li key={i} className="text-xs leading-relaxed text-gray-700">{o}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{c.uncertainties?.length ? (
|
||||||
|
<div>
|
||||||
|
<h5 className="text-[10px] font-semibold tracking-widest uppercase text-gray-500">Still unclear</h5>
|
||||||
|
<ul className="list-disc pl-5 space-y-0.5">
|
||||||
|
{c.uncertainties.map((u, i) => (
|
||||||
|
<li key={i} className="text-xs leading-relaxed text-gray-700">{u}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Thread contributions badge (standalone — used outside focused body) ───
|
||||||
|
|
||||||
function ThreadContributionsBadge({ nodeId, contributions }) {
|
function ThreadContributionsBadge({ nodeId, contributions }) {
|
||||||
const threadContribs = contributions.filter((c) => c.targetNodeId === nodeId);
|
const threadContribs = contributions.filter((c) => c.targetNodeId === nodeId);
|
||||||
@@ -965,6 +1025,7 @@ function OpenQuestionsPanel({
|
|||||||
setFocusedPresentationItemId={setFocusedPresentationItemId}
|
setFocusedPresentationItemId={setFocusedPresentationItemId}
|
||||||
setDoneForNowIds={setDoneForNowIds}
|
setDoneForNowIds={setDoneForNowIds}
|
||||||
setFollowUpQuestion={setFollowUpQuestion}
|
setFollowUpQuestion={setFollowUpQuestion}
|
||||||
|
focusedContributions={focusedContributions}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Thread contributions for this node */}
|
{/* Thread contributions for this node */}
|
||||||
@@ -1575,6 +1636,7 @@ export default function ReasoningWorkspace({
|
|||||||
setFocusedPresentationItemId={setFocusedPresentationItemId}
|
setFocusedPresentationItemId={setFocusedPresentationItemId}
|
||||||
setDoneForNowIds={setDoneForNowIds}
|
setDoneForNowIds={setDoneForNowIds}
|
||||||
setFollowUpQuestion={setFollowUpQuestion}
|
setFollowUpQuestion={setFollowUpQuestion}
|
||||||
|
focusedContributions={focusedContributions}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
|
|||||||
Reference in New Issue
Block a user