Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
932624b
fix(web): show reasoning summaries inline
Adamulek123 Sep 22, 2026
0309fd6
fix(web): restore thought styling for raw reasoning
Adamulek123 Sep 22, 2026
7145dec
fix(web): keep short reasoning chunks inline
Adamulek123 Sep 22, 2026
93c6a73
fix(opencode): preserve progress and fold settled reasoning
Adamulek123 Sep 23, 2026
322d393
fix(opencode): keep reasoning and final reports in one turn
Adamulek123 Sep 23, 2026
9ca3ae5
fix(server): settle OpenCode prompt admission after terminal response
Adamulek123 Sep 24, 2026
1f3b7ba
fix(chat): keep prior response folds closed during a new turn
Adamulek123 Sep 24, 2026
359a721
fix(mobile): classify OpenCode reasoning like web
Adamulek123 Sep 24, 2026
319aa03
fix(server): keep late OpenCode reports on their original turn
Adamulek123 Sep 24, 2026
81de145
fix(chat): clear assistant anchors when progress becomes reasoning
Adamulek123 Sep 24, 2026
5af33e4
fix(chat): keep live and failed reasoning visible
Adamulek123 Sep 24, 2026
cd78793
fix(web): retain and bound expanded reasoning summaries
Adamulek123 Sep 24, 2026
ab2e938
fix(chat): fold turnless reasoning with its answer
Adamulek123 Sep 24, 2026
5c711f7
fix(chat): place trailing reasoning fold before the answer
Adamulek123 Sep 24, 2026
1239421
fix(mobile): keep compaction visible beside folded work
Adamulek123 Sep 24, 2026
3e23db9
fix(server): finish OpenCode progress once per part
Adamulek123 Sep 24, 2026
425283e
fix(web): show settled empty assistant responses
Adamulek123 Sep 24, 2026
7bb25a6
test(web): remove vacuous reasoning markup check
Adamulek123 Sep 24, 2026
d698198
docs(chat): describe completed turn disclosure
Adamulek123 Sep 24, 2026
6630252
fix(mobile): read error tone from work entry
Adamulek123 Sep 24, 2026
69d0d0f
fix(chat): fold prior turns with stranded streams
Adamulek123 Sep 24, 2026
f39670c
fix(web): keep compaction visible beside folded work
Adamulek123 Sep 24, 2026
92a8ac4
fix(server): preserve completed OpenCode turns without an answer
Adamulek123 Sep 24, 2026
8d6f568
fix(mobile): show empty completed answers and fold prior work
Adamulek123 Sep 24, 2026
a0dbb27
fix(web): label whitespace-only completed responses
Adamulek123 Sep 24, 2026
e0a1820
fix(mobile): classify raw reasoning across separated runs
Adamulek123 Sep 24, 2026
9331e03
fix(opencode): keep length-limited replies visible
Adamulek123 Sep 24, 2026
b77e872
fix(mobile): bound unusually long reasoning summaries
Adamulek123 Sep 24, 2026
08e0afe
fix(server): buffer OpenCode progress text before projection
Adamulek123 Sep 24, 2026
bbc316b
test(opencode): cover length-limited reply without stop
Adamulek123 Sep 24, 2026
0f3f8ad
fix(web): keep streaming work visible before turn state arrives
Adamulek123 Sep 24, 2026
fe19b0b
fix(web): keep timeline activity helper private
Adamulek123 Sep 24, 2026
e067ac0
fix(mobile): preserve reasoning and failed work across turn states
Adamulek123 Sep 24, 2026
16142fe
fix(web): keep live reasoning and work visible during projection races
Adamulek123 Sep 24, 2026
1786b16
fix(opencode): bound recent message turn associations
Adamulek123 Sep 24, 2026
84ef2d8
fix(web): align reasoning rows with current React and lint rules
Adamulek123 Sep 24, 2026
48b4938
fix(chat): keep live reasoning visible and bound summaries
Adamulek123 Sep 24, 2026
87e3a89
fix(opencode): recover missed replies and keep reasoning live
Adamulek123 Sep 24, 2026
95f4358
fix(opencode): address remaining reasoning review findings
Adamulek123 Sep 25, 2026
a34a394
refactor(chat): share reasoning and turn presentation rules
Adamulek123 Sep 25, 2026
51558c4
fix(chat): avoid unrelated assistant anchors on reclassification
Adamulek123 Sep 25, 2026
4d5b30a
fix(opencode): isolate progress parts and omit empty replies
Adamulek123 Sep 25, 2026
3e4e64b
test(web): remove redundant reasoning markup assertions
Adamulek123 Sep 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 82 additions & 9 deletions apps/mobile/src/features/threads/ThreadFeed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ import {
} from "@t3tools/mobile-markdown-text/links";
import {
deriveThreadFeedPresentation,
deriveUnsettledTurnId,
deriveActiveFeedTurnId,
isContextCompactionActivityGroup,
type ThreadFeedEntry,
type ThreadFeedLatestTurn,
Expand Down Expand Up @@ -1486,13 +1486,71 @@ function renderFeedEntry(
const { message } = entry;
if (message.role === "reasoning") {
const messages = entry.reasoningMessages ?? [message];
if (entry.reasoningKind === "summary") {
const chunks = messages.map((item) => item.text.trim()).filter(Boolean);
const text = chunks.join(" ");
if (text.length === 0) return null;
const longSummary =
text.length > 2_000 ||
chunks.reduce((count, chunk) => count + chunk.split("\n").length, 0) > 25;
const expanded = props.expandedReasoningMessageIds.has(entry.id);
const preview = chunks
.slice(0, 25)
.join(" ")
.slice(0, 2_000)
.split("\n")
.slice(0, 25)
.join("\n");
const summaryContent = (
<MarkdownImageAvailableWidthContext value={props.markdownContentWidth}>
<View className="min-w-0 px-1 py-0.5">
<AssistantMarkdownContent
markdown={longSummary && !expanded ? preview : text}
markdownStyles={markdownStyles.assistant}
linkHandlers={props.markdownLinkHandlers}
renderImage={props.renderMarkdownImage}
skills={props.skills}
/>
</View>
</MarkdownImageAvailableWidthContext>
);
return (
<View>
{longSummary && expanded ? (
<ScrollView nestedScrollEnabled style={{ maxHeight: 384 }}>
{summaryContent}
</ScrollView>
) : (
summaryContent
)}
{longSummary ? (
<Pressable
accessibilityRole="button"
accessibilityState={{ expanded }}
onPress={() => props.onToggleReasoning(entry.id)}
className="min-h-11 justify-center px-1"
>
<Text className="text-xs text-foreground-muted">
{expanded ? "Show less" : "Show more"}
</Text>
</Pressable>
) : null}
</View>
);
}
return (
<ThreadReasoningRow
rowSizing={props.workRowSizing}
iconSubtleColor={iconSubtleColor}
expanded={props.expandedReasoningMessageIds.has(entry.id)}
label={`Thought${messages.length > 1 ? ` (×${messages.length})` : ""}`}
streaming={false}
streaming={messages.some(
(reasoningMessage) =>
reasoningMessage.streaming &&
(reasoningMessage.turnId
? reasoningMessage.turnId === props.unsettledTurnId
: props.isWorking),
)}
onToggle={() => props.onToggleReasoning(entry.id)}
>
<MarkdownImageAvailableWidthContext
Expand All @@ -1515,7 +1573,16 @@ function renderFeedEntry(
);
}
const isUser = message.role === "user";
const renderedText = renderAssistantCitationsAsText(message.text);
const assistantTurnStillInProgress =
message.role === "assistant" &&
(message.turnId !== null ? message.turnId === props.unsettledTurnId : props.isWorking);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
const renderedText = renderAssistantCitationsAsText(
message.role === "assistant" &&
!assistantTurnStillInProgress &&
message.text.trim().length === 0
? "(empty response)"
: message.text,
);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
const styles = isUser ? markdownStyles.user : markdownStyles.assistant;
const timestampLabel = formatMessageTime(isUser ? message.createdAt : message.updatedAt);
const attachments = message.attachments ?? [];
Expand All @@ -1526,10 +1593,6 @@ function renderFeedEntry(
// is clamped, so the paragraphs around the block end up drawn on top of
// each other. Pinning the width removes that pass.
const hasWideBlock = hasWideMarkdownBlock(renderedText, WIDE_MARKDOWN_BLOCK_OPTIONS);
const assistantTurnStillInProgress =
message.role === "assistant" &&
props.unsettledTurnId !== null &&
message.turnId === props.unsettledTurnId;
const showAssistantMeta =
message.role === "assistant" &&
props.terminalAssistantMessageIds.has(message.id) &&
Expand Down Expand Up @@ -2279,7 +2342,11 @@ export const ThreadFeed = memo(function ThreadFeed(props: ThreadFeedProps) {
const reviewCommentColors = useReviewCommentColors();
// One definition of "still live", shared with the fold derivation: two
// copies of this test are what let a row and the fold beside it disagree.
const unsettledTurnId = deriveUnsettledTurnId(props.latestTurn ?? null);
const unsettledTurnId = deriveActiveFeedTurnId(
props.feed,
props.latestTurn ?? null,
props.activeWorkStartedAt,
);
// LegendList does not invalidate visible rows when only the renderItem closure changes.
// Include turn completion so unchanged message rows reveal their footer and spacing
// even when the final message update arrives before the turn settles.
Expand All @@ -2289,6 +2356,7 @@ export const ThreadFeed = memo(function ThreadFeed(props: ThreadFeedProps) {
setupWorkingStartedAt: props.setupWorkingStartedAt,
dispatchingMessageId: props.dispatchingMessageId,
unsettledTurnId,
isWorking: props.activeWorkStartedAt !== null,
copiedRowId,
expandedWorkRows,
expandedReasoningMessageIds,
Expand All @@ -2305,6 +2373,7 @@ export const ThreadFeed = memo(function ThreadFeed(props: ThreadFeedProps) {
props.setupWorkingStartedAt,
props.dispatchingMessageId,
unsettledTurnId,
props.activeWorkStartedAt,
copiedRowId,
expandedWorkRows,
expandedReasoningMessageIds,
Expand Down Expand Up @@ -2457,6 +2526,7 @@ export const ThreadFeed = memo(function ThreadFeed(props: ThreadFeedProps) {
expandedTurnIds,
expandedWorkGroupIds,
props.activeWorkStartedAt,
unsettledTurnId,
),
props.feed,
props.queuedMessages,
Expand All @@ -2468,6 +2538,7 @@ export const ThreadFeed = memo(function ThreadFeed(props: ThreadFeedProps) {
props.activeWorkStartedAt,
props.feed,
props.latestTurn,
unsettledTurnId,
],
);
const setupAnchorIndex = presentedFeed.findIndex(
Expand Down Expand Up @@ -2717,7 +2788,9 @@ export const ThreadFeed = memo(function ThreadFeed(props: ThreadFeedProps) {
switch (entry.type) {
case "message":
// A collapsed reasoning row is the same chrome as a work toggle.
return entry.message.role === "reasoning" && !expandedReasoningMessageIds.has(entry.id)
return entry.message.role === "reasoning" &&
entry.reasoningKind !== "summary" &&
!expandedReasoningMessageIds.has(entry.id)
? WORK_GROUP_TOGGLE_HEIGHT
: undefined;
case "turn-fold":
Expand Down
Loading
Loading