diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx
index 6d29170081ab..197c55ada703 100644
--- a/packages/app/src/pages/session.tsx
+++ b/packages/app/src/pages/session.tsx
@@ -1732,6 +1732,16 @@ export default function Page() {
}}
renderedUserMessages={historyWindow.renderedUserMessages()}
anchor={anchor}
+ onRevert={(messageID) => {
+ const sessionID = params.id
+ if (!sessionID) return
+ void revert({ sessionID, messageID })
+ }}
+ onFork={(messageID) => {
+ const sessionID = params.id
+ if (!sessionID) return
+ void fork({ sessionID, messageID })
+ }}
/>
diff --git a/packages/app/src/pages/session/message-timeline.tsx b/packages/app/src/pages/session/message-timeline.tsx
index 74f2e8c2c12d..a98712263b8c 100644
--- a/packages/app/src/pages/session/message-timeline.tsx
+++ b/packages/app/src/pages/session/message-timeline.tsx
@@ -216,6 +216,8 @@ export function MessageTimeline(props: {
onLoadEarlier: () => void
renderedUserMessages: UserMessage[]
anchor: (id: string) => string
+ onRevert?: (messageID: string) => void
+ onFork?: (messageID: string) => void
}) {
let touchGesture: number | undefined
@@ -1007,6 +1009,8 @@ export function MessageTimeline(props: {
showReasoningSummaries={settings.general.showReasoningSummaries()}
shellToolDefaultOpen={settings.general.shellToolPartsExpanded()}
editToolDefaultOpen={settings.general.editToolPartsExpanded()}
+ onRevert={props.onRevert ? () => props.onRevert!(messageID) : undefined}
+ onFork={props.onFork ? () => props.onFork!(messageID) : undefined}
classes={{
root: "min-w-0 w-full relative",
content: "flex flex-col justify-between !overflow-visible",
diff --git a/packages/ui/src/components/session-turn.css b/packages/ui/src/components/session-turn.css
index 26d918050d7f..47f641b6400c 100644
--- a/packages/ui/src/components/session-turn.css
+++ b/packages/ui/src/components/session-turn.css
@@ -28,6 +28,51 @@
min-width: 0;
gap: 18px;
overflow-anchor: none;
+ position: relative;
+
+ [data-slot="session-turn-header"] {
+ position: absolute;
+ right: 0;
+ display: flex;
+ gap: 8px;
+ align-items: center;
+ padding-left: 16px;
+ background: linear-gradient(to right, transparent, var(--background-stronger) 12px);
+ opacity: 0;
+ transition: opacity 0.15s ease;
+ pointer-events: none;
+ }
+
+ &:hover [data-slot="session-turn-header"] {
+ opacity: 1;
+ pointer-events: auto;
+ }
+
+ [data-slot="session-turn-badge"] {
+ display: inline-flex;
+ align-items: center;
+ padding: 2px 6px;
+ border-radius: 4px;
+ font-family: var(--font-family-mono);
+ font-size: var(--font-size-x-small);
+ font-weight: var(--font-weight-medium);
+ line-height: var(--line-height-normal);
+ white-space: nowrap;
+ color: var(--text-base);
+ background: var(--surface-raised-base);
+ }
+ }
+
+ [data-slot="session-turn-user-badges"] {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ padding-left: 16px;
+ }
+
+ [data-slot="session-turn-message-actions"] {
+ display: flex;
+ gap: 4px;
}
[data-slot="session-turn-message-content"] {
diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx
index 8c9c1ffe4030..e4afaea42bce 100644
--- a/packages/ui/src/components/session-turn.tsx
+++ b/packages/ui/src/components/session-turn.tsx
@@ -1,4 +1,10 @@
-import { AssistantMessage, type FileDiff, Message as MessageType, Part as PartType } from "@opencode-ai/sdk/v2/client"
+import {
+ AssistantMessage,
+ type FileDiff,
+ Message as MessageType,
+ Part as PartType,
+ UserMessage,
+} from "@opencode-ai/sdk/v2/client"
import type { SessionStatus } from "@opencode-ai/sdk/v2"
import { useData } from "../context"
import { useFileComponent } from "../context/file"
@@ -18,6 +24,10 @@ import { Icon } from "./icon"
import { TextShimmer } from "./text-shimmer"
import { SessionRetry } from "./session-retry"
import { TextReveal } from "./text-reveal"
+import { ProviderIcon } from "./provider-icon"
+import type { IconName } from "./provider-icons/types"
+import { Tooltip } from "./tooltip"
+import { IconButton } from "./icon-button"
import { createAutoScroll } from "../hooks"
import { useI18n } from "../context/i18n"
@@ -149,6 +159,8 @@ export function SessionTurn(
active?: boolean
status?: SessionStatus
onUserInteracted?: () => void
+ onRevert?: () => void
+ onFork?: () => void
classes?: {
root?: string
content?: string
@@ -393,6 +405,36 @@ export function SessionTurn(
data-slot="session-turn-message-container"
class={props.classes?.container}
>
+