Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions packages/app/src/i18n/ar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ export const dict = {
"command.session.undo.description": "تراجع عن الرسالة الأخيرة",
"command.session.redo": "إعادة",
"command.session.redo.description": "إعادة الرسالة التي تم التراجع عنها",
"session.revert.active": "تم الرجوع إلى نقطة سابقة",
"session.revert.cancel": "استعادة",
"command.session.compact": "ضغط الجلسة",
"command.session.compact.description": "تلخيص الجلسة لتقليل حجم السياق",
"command.session.fork": "تشعب من الرسالة",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/br.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ export const dict = {
"command.session.undo.description": "Desfazer a última mensagem",
"command.session.redo": "Refazer",
"command.session.redo.description": "Refazer a última mensagem desfeita",
"session.revert.active": "Revertido para um ponto anterior",
"session.revert.cancel": "Restaurar",
"command.session.compact": "Compactar sessão",
"command.session.compact.description": "Resumir a sessão para reduzir o tamanho do contexto",
"command.session.fork": "Bifurcar da mensagem",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/bs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export const dict = {
"command.session.undo.description": "Poništi posljednju poruku",
"command.session.redo": "Vrati",
"command.session.redo.description": "Vrati posljednju poništenu poruku",
"session.revert.active": "Vraćeno na raniju tačku",
"session.revert.cancel": "Vrati",
"command.session.compact": "Sažmi sesiju",
"command.session.compact.description": "Sažmi sesiju kako bi se smanjio kontekst",
"command.session.fork": "Fork iz poruke",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/da.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export const dict = {
"command.session.undo.description": "Fortryd den sidste besked",
"command.session.redo": "Omgør",
"command.session.redo.description": "Omgør den sidste fortrudte besked",
"session.revert.active": "Gendannet til et tidligere punkt",
"session.revert.cancel": "Gendan",
"command.session.compact": "Komprimér session",
"command.session.compact.description": "Opsummer sessionen for at reducere kontekststørrelsen",
"command.session.fork": "Forgren fra besked",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ export const dict = {
"command.session.undo.description": "Letzte Nachricht rückgängig machen",
"command.session.redo": "Wiederherstellen",
"command.session.redo.description": "Letzte rückgängig gemachte Nachricht wiederherstellen",
"session.revert.active": "Zu einem früheren Punkt zurückgesetzt",
"session.revert.cancel": "Wiederherstellen",
"command.session.compact": "Sitzung komprimieren",
"command.session.compact.description": "Sitzung zusammenfassen, um die Kontextgröße zu reduzieren",
"command.session.fork": "Von Nachricht abzweigen",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export const dict = {
"command.session.undo.description": "Undo the last message",
"command.session.redo": "Redo",
"command.session.redo.description": "Redo the last undone message",
"session.revert.active": "Reverted to an earlier point",
"session.revert.cancel": "Restore",
"command.session.compact": "Compact session",
"command.session.compact.description": "Summarize the session to reduce context size",
"command.session.fork": "Fork from message",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export const dict = {
"command.session.undo.description": "Deshacer el último mensaje",
"command.session.redo": "Rehacer",
"command.session.redo.description": "Rehacer el último mensaje deshecho",
"session.revert.active": "Se revirtió a un punto anterior",
"session.revert.cancel": "Restaurar",
"command.session.compact": "Compactar sesión",
"command.session.compact.description": "Resumir la sesión para reducir el tamaño del contexto",
"command.session.fork": "Bifurcar desde mensaje",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ export const dict = {
"command.session.undo.description": "Annuler le dernier message",
"command.session.redo": "Rétablir",
"command.session.redo.description": "Rétablir le dernier message annulé",
"session.revert.active": "Revenu à un point antérieur",
"session.revert.cancel": "Restaurer",
"command.session.compact": "Compacter la session",
"command.session.compact.description": "Résumer la session pour réduire la taille du contexte",
"command.session.fork": "Bifurquer à partir du message",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ export const dict = {
"command.session.undo.description": "最後のメッセージを元に戻す",
"command.session.redo": "やり直す",
"command.session.redo.description": "元に戻したメッセージをやり直す",
"session.revert.active": "前の時点に戻しました",
"session.revert.cancel": "復元",
"command.session.compact": "セッションを圧縮",
"command.session.compact.description": "セッションを要約してコンテキストサイズを削減",
"command.session.fork": "メッセージからフォーク",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ export const dict = {
"command.session.undo.description": "마지막 메시지 실행 취소",
"command.session.redo": "다시 실행",
"command.session.redo.description": "마지막 실행 취소된 메시지 다시 실행",
"session.revert.active": "이전 지점으로 되돌렸습니다",
"session.revert.cancel": "복원",
"command.session.compact": "세션 압축",
"command.session.compact.description": "컨텍스트 크기를 줄이기 위해 세션 요약",
"command.session.fork": "메시지에서 분기",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/no.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ export const dict = {
"command.session.undo.description": "Angre siste melding",
"command.session.redo": "Gjør om",
"command.session.redo.description": "Gjør om siste angrede melding",
"session.revert.active": "Tilbakestilt til et tidligere punkt",
"session.revert.cancel": "Gjenopprett",
"command.session.compact": "Komprimer sesjon",
"command.session.compact.description": "Oppsummer sesjonen for å redusere kontekststørrelsen",
"command.session.fork": "Forgren fra melding",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ export const dict = {
"command.session.undo.description": "Cofnij ostatnią wiadomość",
"command.session.redo": "Ponów",
"command.session.redo.description": "Ponów ostatnią cofniętą wiadomość",
"session.revert.active": "Przywrócono do wcześniejszego punktu",
"session.revert.cancel": "Przywróć",
"command.session.compact": "Kompaktuj sesję",
"command.session.compact.description": "Podsumuj sesję, aby zmniejszyć rozmiar kontekstu",
"command.session.fork": "Rozwidlij od wiadomości",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export const dict = {
"command.session.undo.description": "Отменить последнее сообщение",
"command.session.redo": "Повторить",
"command.session.redo.description": "Повторить отменённое сообщение",
"session.revert.active": "Возврат к более ранней точке",
"session.revert.cancel": "Восстановить",
"command.session.compact": "Сжать сессию",
"command.session.compact.description": "Сократить сессию для уменьшения размера контекста",
"command.session.fork": "Создать ответвление",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/th.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export const dict = {
"command.session.undo.description": "ยกเลิกข้อความล่าสุด",
"command.session.redo": "ทำซ้ำ",
"command.session.redo.description": "ทำซ้ำข้อความที่ถูกยกเลิกล่าสุด",
"session.revert.active": "ย้อนกลับไปยังจุดก่อนหน้าแล้ว",
"session.revert.cancel": "กู้คืน",
"command.session.compact": "บีบอัดเซสชัน",
"command.session.compact.description": "สรุปเซสชันเพื่อลดขนาดบริบท",
"command.session.fork": "แตกแขนงจากข้อความ",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ export const dict = {
"command.session.undo.description": "撤销上一条消息",
"command.session.redo": "重做",
"command.session.redo.description": "重做上一条撤销的消息",
"session.revert.active": "已回退到较早位置",
"session.revert.cancel": "恢复",
"command.session.compact": "精简会话",
"command.session.compact.description": "总结会话以减少上下文大小",
"command.session.fork": "从消息分叉",
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/zht.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ export const dict = {
"command.session.undo.description": "復原上一則訊息",
"command.session.redo": "重做",
"command.session.redo.description": "重做上一則復原的訊息",
"session.revert.active": "已回退到較早位置",
"session.revert.cancel": "還原",
"command.session.compact": "精簡工作階段",
"command.session.compact.description": "總結工作階段以減少上下文大小",
"command.session.fork": "從訊息分支",
Expand Down
61 changes: 61 additions & 0 deletions packages/app/src/pages/session.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import { SessionPromptDock } from "@/pages/session/session-prompt-dock"
import { SessionMobileTabs } from "@/pages/session/session-mobile-tabs"
import { SessionSidePanel } from "@/pages/session/session-side-panel"
import { useSessionHashScroll } from "@/pages/session/use-session-hash-scroll"
import { extractPromptFromParts } from "@/utils/prompt"

type HandoffSession = {
prompt: string
Expand Down Expand Up @@ -616,6 +617,59 @@ export default function Page() {
scrollToMessage(msgs[targetIndex], "auto")
}

async function revertMessage(messageID: string) {
const sessionID = params.id
if (!sessionID) return
const msg = userMessages().find((item) => item.id === messageID)
if (!msg) return

if (status().type !== "idle") {
await sdk.client.session.abort({ sessionID }).catch(() => {})
}

const reverted = await sdk.client.session.revert({ sessionID, messageID: msg.id }).catch((err) => {
showToast({
title: language.t("common.requestFailed"),
description: errorMessage(err),
})
return undefined
})
if (!reverted) return

const parts = sync.data.part[msg.id]
if (parts) {
const restored = extractPromptFromParts(parts, { directory: sdk.directory })
prompt.set(restored)
}

const prior = findLast(userMessages(), (item) => item.id < msg.id)
setActiveMessage(prior)
}

async function cancelRevert() {
const sessionID = params.id
if (!sessionID) return
const revertMsgID = info()?.revert?.messageID
if (!revertMsgID) return

if (status().type !== "idle") {
await sdk.client.session.abort({ sessionID }).catch(() => {})
}

const restored = await sdk.client.session.unrevert({ sessionID }).catch((err) => {
showToast({
title: language.t("common.requestFailed"),
description: errorMessage(err),
})
return undefined
})
if (!restored) return

prompt.reset()
const lastMsg = findLast(userMessages(), (item) => item.id >= revertMsgID)
setActiveMessage(lastMsg)
}

const kinds = createMemo(() => {
const merge = (a: "add" | "del" | "mix" | undefined, b: "add" | "del" | "mix") => {
if (!a) return b
Expand Down Expand Up @@ -1656,6 +1710,9 @@ export default function Page() {
lastUserMessageID={lastUserMessage()?.id}
expanded={store.expanded}
onToggleExpanded={(id) => setStore("expanded", id, (open: boolean | undefined) => !open)}
onRevertMessage={(messageID) => {
void revertMessage(messageID)
}}
/>
</Show>
</Match>
Expand Down Expand Up @@ -1690,7 +1747,11 @@ export default function Page() {
handoffPrompt={handoff.session.get(sessionKey())?.prompt}
t={language.t as (key: string, vars?: Record<string, string | number | boolean>) => string}
responding={ui.responding}
reverted={!!revertMessageID()}
onDecide={decide}
onCancelRevert={() => {
void cancelRevert()
}}
inputRef={(el) => {
inputRef = el
}}
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/pages/session/message-timeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export function MessageTimeline(props: {
lastUserMessageID?: string
expanded: Record<string, boolean>
onToggleExpanded: (id: string) => void
onRevertMessage?: (messageID: string) => void
}) {
let touchGesture: number | undefined

Expand Down Expand Up @@ -315,6 +316,7 @@ export function MessageTimeline(props: {
<SessionTurn
sessionID={props.sessionID}
messageID={message.id}
onRevert={props.onRevertMessage}
lastUserMessageID={props.lastUserMessageID}
stepsExpanded={props.expanded[message.id] ?? false}
onStepsExpandedToggle={() => props.onToggleExpanded(message.id)}
Expand Down
18 changes: 18 additions & 0 deletions packages/app/src/pages/session/session-prompt-dock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ export function SessionPromptDock(props: {
handoffPrompt?: string
t: (key: string, vars?: Record<string, string | number | boolean>) => string
responding: boolean
reverted: boolean
onDecide: (response: "once" | "always" | "reject") => void
onCancelRevert: () => void
inputRef: (el: HTMLDivElement) => void
newSessionWorktree: string
onNewSessionWorktreeReset: () => void
Expand Down Expand Up @@ -114,6 +116,22 @@ export function SessionPromptDock(props: {
</Show>

<Show when={!props.blocked}>
<Show when={props.reverted}>
<div data-component="tool-part-wrapper" data-revert="true" class="mb-3">
<BasicTool
icon="undo"
locked
trigger={{
title: props.t("session.revert.active"),
action: (
<Button variant="ghost" size="small" onClick={props.onCancelRevert} disabled={props.responding}>
{props.t("session.revert.cancel")}
</Button>
),
}}
/>
</div>
</Show>
<Show
when={props.promptReady}
fallback={
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/components/icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const icons = {
"align-right": `<path d="M12.292 6.04167L16.2503 9.99998L12.292 13.9583M2.91699 9.99998H15.6253M17.0837 3.75V16.25" stroke="currentColor" stroke-linecap="square"/>`,
"arrow-up": `<path fill-rule="evenodd" clip-rule="evenodd" d="M9.99991 2.24121L16.0921 8.33343L15.2083 9.21731L10.6249 4.63397V17.5001H9.37492V4.63398L4.7916 9.21731L3.90771 8.33343L9.99991 2.24121Z" fill="currentColor"/>`,
"arrow-left": `<path d="M8.33464 4.58398L2.91797 10.0007L8.33464 15.4173M3.33464 10.0007H17.0846" stroke="currentColor" stroke-linecap="square"/>`,
undo: `<path d="M4.16667 7.5H12.0833C14.3845 7.5 16.25 9.36548 16.25 11.6667C16.25 13.9679 14.3845 15.8333 12.0833 15.8333H10" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/><path d="M7.5 4.16667L4.16667 7.5L7.5 10.8333" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>`,
"arrow-right": `<path d="M11.6654 4.58398L17.082 10.0007L11.6654 15.4173M16.6654 10.0007H2.91536" stroke="currentColor" stroke-linecap="square"/>`,
archive: `<path d="M16.8747 6.24935H17.3747V5.74935H16.8747V6.24935ZM16.8747 16.8743V17.3743H17.3747V16.8743H16.8747ZM3.12467 16.8743H2.62467V17.3743H3.12467V16.8743ZM3.12467 6.24935V5.74935H2.62467V6.24935H3.12467ZM2.08301 2.91602V2.41602H1.58301V2.91602H2.08301ZM17.9163 2.91602H18.4163V2.41602H17.9163V2.91602ZM17.9163 6.24935V6.74935H18.4163V6.24935H17.9163ZM2.08301 6.24935H1.58301V6.74935H2.08301V6.24935ZM8.33301 9.08268H7.83301V10.0827H8.33301V9.58268V9.08268ZM11.6663 10.0827H12.1663V9.08268H11.6663V9.58268V10.0827ZM16.8747 6.24935H16.3747V16.8743H16.8747H17.3747V6.24935H16.8747ZM16.8747 16.8743V16.3743H3.12467V16.8743V17.3743H16.8747V16.8743ZM3.12467 16.8743H3.62467V6.24935H3.12467H2.62467V16.8743H3.12467ZM3.12467 6.24935V6.74935H16.8747V6.24935V5.74935H3.12467V6.24935ZM2.08301 2.91602V3.41602H17.9163V2.91602V2.41602H2.08301V2.91602ZM17.9163 2.91602H17.4163V6.24935H17.9163H18.4163V2.91602H17.9163ZM17.9163 6.24935V5.74935H2.08301V6.24935V6.74935H17.9163V6.24935ZM2.08301 6.24935H2.58301V2.91602H2.08301H1.58301V6.24935H2.08301ZM8.33301 9.58268V10.0827H11.6663V9.58268V9.08268H8.33301V9.58268Z" fill="currentColor"/>`,
"bubble-5": `<path d="M18.3327 9.99935C18.3327 5.57227 15.0919 2.91602 9.99935 2.91602C4.90676 2.91602 1.66602 5.57227 1.66602 9.99935C1.66602 11.1487 2.45505 13.1006 2.57637 13.3939C2.58707 13.4197 2.59766 13.4434 2.60729 13.4697C2.69121 13.6987 3.04209 14.9354 1.66602 16.7674C3.51787 17.6528 5.48453 16.1973 5.48453 16.1973C6.84518 16.9193 8.46417 17.0827 9.99935 17.0827C15.0919 17.0827 18.3327 14.4264 18.3327 9.99935Z" stroke="currentColor" stroke-linecap="square"/>`,
Expand Down
13 changes: 9 additions & 4 deletions packages/ui/src/components/message-part.css
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,18 @@
color: var(--syntax-type);
}

[data-slot="user-message-copy-wrapper"] {
[data-slot="user-message-actions-wrapper"] {
position: absolute;
top: 7px;
right: 7px;
display: inline-flex;
gap: 6px;
opacity: 0;
transition: opacity 0.15s ease;
}

&:hover [data-slot="user-message-copy-wrapper"] {
&:hover [data-slot="user-message-actions-wrapper"],
&:focus-within [data-slot="user-message-actions-wrapper"] {
opacity: 1;
}
}
Expand Down Expand Up @@ -454,7 +457,8 @@
width: 100%;

&[data-permission="true"],
&[data-question="true"] {
&[data-question="true"],
&[data-revert="true"] {
position: sticky;
top: calc(2px + var(--sticky-header-height, 40px));
bottom: 0px;
Expand Down Expand Up @@ -511,7 +515,8 @@
}
}

&[data-question="true"] {
&[data-question="true"],
&[data-revert="true"] {
background: var(--background-base);
border: 1px solid var(--border-weak-base);
}
Expand Down
Loading
Loading