File size: 2,867 Bytes
0dbc9de | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | import { createEffect, createMemo, createSignal, on, onCleanup, Show } from "solid-js"
import type { SessionStatus } from "@opencode-ai/sdk/v2/client"
import { useI18n } from "@opencode-ai/ui/context/i18n"
import { Card } from "@opencode-ai/ui/card"
import { Tooltip } from "@opencode-ai/ui/tooltip"
import { Spinner } from "@opencode-ai/ui/spinner"
export function SessionRetry(props: { status: SessionStatus; show?: boolean }) {
const i18n = useI18n()
const retry = createMemo(() => {
if (props.status.type !== "retry") return
return props.status
})
const [seconds, setSeconds] = createSignal(0)
createEffect(
on(retry, (current) => {
if (!current) return
const update = () => {
const next = retry()?.next
if (!next) return
setSeconds(Math.round((next - Date.now()) / 1000))
}
update()
const timer = setInterval(update, 1000)
onCleanup(() => clearInterval(timer))
}),
)
const message = createMemo(() => {
const current = retry()
if (!current) return ""
if (current.message.includes("exceeded your current quota") && current.message.includes("gemini")) {
return i18n.t("ui.sessionTurn.retry.geminiHot")
}
if (current.message.length > 80) return current.message.slice(0, 80) + "..."
return current.message
})
const truncated = createMemo(() => {
const current = retry()
if (!current) return false
return current.message.length > 80
})
const info = createMemo(() => {
const current = retry()
if (!current) return ""
const count = Math.max(0, seconds())
const delay = count > 0 ? i18n.t("ui.sessionTurn.retry.inSeconds", { seconds: count }) : ""
const retrying = i18n.t("ui.sessionTurn.retry.retrying")
const line = [retrying, delay].filter(Boolean).join(" ")
if (!line) return i18n.t("ui.sessionTurn.retry.attempt", { attempt: current.attempt })
return i18n.t("ui.sessionTurn.retry.attemptLine", { line, attempt: current.attempt })
})
return (
<Show when={retry() && (props.show ?? true)}>
<div data-slot="session-turn-retry">
<Card variant="error" class="error-card">
<div class="flex items-start gap-2">
<Spinner class="size-4 mt-0.5" />
<div class="min-w-0">
<Show when={truncated()} fallback={<div data-slot="session-turn-retry-message">{message()}</div>}>
<Tooltip value={retry()?.message ?? ""} placement="top">
<div data-slot="session-turn-retry-message" class="cursor-help truncate">
{message()}
</div>
</Tooltip>
</Show>
<Show when={info()}>{(line) => <div data-slot="session-turn-retry-info">{line()}</div>}</Show>
</div>
</div>
</Card>
</div>
</Show>
)
}
|