* Fold a run's step messages behind its latest message Long tool runs posted every step as its own bubble, so the answer drowned in narration and a summary written before saving a file appeared twice. Web and mobile now fold a run's text-only step messages behind one "N steps" line above the run's latest message. The thread snapshot also stops replaying live narration that was already posted, which showed steps again after a refresh. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tgvrj34NMnaqvtgvruYQZZ * Keep a run's last step visible above a card A card such as the peer-message receipt has no words of its own, so folding the narration into it hid everything the bot said. Steps now fold only into a written answer or the live row; before a card the last step stays visible. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tgvrj34NMnaqvtgvruYQZZ --------- Co-authored-by: Claude <noreply@anthropic.com>
53 lines
1.8 KiB
TypeScript
53 lines
1.8 KiB
TypeScript
import { useState } from "react";
|
|
import { Pressable, Text, View } from "react-native";
|
|
import type { MobileMessage } from "../lib/api";
|
|
import { useI18n } from "../lib/i18n";
|
|
import { useMobileTokens } from "../lib/native";
|
|
import { NativeSymbol } from "./native-symbol";
|
|
|
|
/** A run's earlier step messages, folded behind one line above its latest message. */
|
|
export function RunSteps({ steps }: { steps: readonly MobileMessage[] }) {
|
|
const tokens = useMobileTokens();
|
|
const { t } = useI18n();
|
|
const [open, setOpen] = useState(false);
|
|
const label = steps.length === 1 ? t("1 step") : t("{count} steps", { count: steps.length });
|
|
return (
|
|
<View style={{ marginBottom: 6 }}>
|
|
<Pressable
|
|
accessibilityRole="button"
|
|
accessibilityState={{ expanded: open }}
|
|
onPress={() => setOpen((current) => !current)}
|
|
hitSlop={8}
|
|
style={{ flexDirection: "row", alignItems: "center", gap: 4, alignSelf: "flex-start" }}
|
|
>
|
|
<NativeSymbol
|
|
ios={open ? "chevron.down" : "chevron.right"}
|
|
android={open ? "chevron-down" : "chevron-forward"}
|
|
size={12}
|
|
color={tokens.mutedForeground}
|
|
/>
|
|
<Text style={{ color: tokens.mutedForeground, fontSize: 13.5 }}>{label}</Text>
|
|
</Pressable>
|
|
{open ? (
|
|
<View
|
|
style={{
|
|
marginTop: 4,
|
|
gap: 6,
|
|
borderLeftWidth: 1,
|
|
borderLeftColor: tokens.border,
|
|
paddingLeft: 10,
|
|
}}
|
|
>
|
|
{steps.map((step) => (
|
|
<Text key={step.id} style={{ color: tokens.mutedForeground, fontSize: 14 }}>
|
|
{step.blocks
|
|
.flatMap((block) => (block.kind === "text" ? [block.text] : []))
|
|
.join("\n")}
|
|
</Text>
|
|
))}
|
|
</View>
|
|
) : null}
|
|
</View>
|
|
);
|
|
}
|