fix(app): retry error unwrapping (#12462)
This commit is contained in:
@@ -501,6 +501,7 @@
|
|||||||
|
|
||||||
[data-slot="session-turn-collapsible-trigger-content"] {
|
[data-slot="session-turn-collapsible-trigger-content"] {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
min-width: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
@@ -525,6 +526,10 @@
|
|||||||
[data-slot="session-turn-retry-message"] {
|
[data-slot="session-turn-retry-message"] {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--syntax-critical);
|
color: var(--syntax-critical);
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-slot="session-turn-retry-seconds"] {
|
[data-slot="session-turn-retry-seconds"] {
|
||||||
@@ -549,6 +554,9 @@
|
|||||||
.error-card {
|
.error-card {
|
||||||
color: var(--text-on-critical-base);
|
color: var(--text-on-critical-base);
|
||||||
max-height: 240px;
|
max-height: 240px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
word-break: break-word;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,59 @@ import { createResizeObserver } from "@solid-primitives/resize-observer"
|
|||||||
|
|
||||||
type Translator = (key: UiI18nKey, params?: UiI18nParams) => string
|
type Translator = (key: UiI18nKey, params?: UiI18nParams) => string
|
||||||
|
|
||||||
|
function record(value: unknown): value is Record<string, unknown> {
|
||||||
|
return !!value && typeof value === "object" && !Array.isArray(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
function unwrap(message: string) {
|
||||||
|
const text = message.replace(/^Error:\s*/, "").trim()
|
||||||
|
|
||||||
|
const parse = (value: string) => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(value) as unknown
|
||||||
|
} catch {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const read = (value: string) => {
|
||||||
|
const first = parse(value)
|
||||||
|
if (typeof first !== "string") return first
|
||||||
|
return parse(first.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
let json = read(text)
|
||||||
|
|
||||||
|
if (json === undefined) {
|
||||||
|
const start = text.indexOf("{")
|
||||||
|
const end = text.lastIndexOf("}")
|
||||||
|
if (start !== -1 && end > start) {
|
||||||
|
json = read(text.slice(start, end + 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!record(json)) return message
|
||||||
|
|
||||||
|
const err = record(json.error) ? json.error : undefined
|
||||||
|
if (err) {
|
||||||
|
const type = typeof err.type === "string" ? err.type : undefined
|
||||||
|
const msg = typeof err.message === "string" ? err.message : undefined
|
||||||
|
if (type && msg) return `${type}: ${msg}`
|
||||||
|
if (msg) return msg
|
||||||
|
if (type) return type
|
||||||
|
const code = typeof err.code === "string" ? err.code : undefined
|
||||||
|
if (code) return code
|
||||||
|
}
|
||||||
|
|
||||||
|
const msg = typeof json.message === "string" ? json.message : undefined
|
||||||
|
if (msg) return msg
|
||||||
|
|
||||||
|
const reason = typeof json.error === "string" ? json.error : undefined
|
||||||
|
if (reason) return reason
|
||||||
|
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
function computeStatusFromPart(part: PartType | undefined, t: Translator): string | undefined {
|
function computeStatusFromPart(part: PartType | undefined, t: Translator): string | undefined {
|
||||||
if (!part) return undefined
|
if (!part) return undefined
|
||||||
|
|
||||||
@@ -236,6 +289,12 @@ export function SessionTurn(
|
|||||||
const lastAssistantMessage = createMemo(() => assistantMessages().at(-1))
|
const lastAssistantMessage = createMemo(() => assistantMessages().at(-1))
|
||||||
|
|
||||||
const error = createMemo(() => assistantMessages().find((m) => m.error)?.error)
|
const error = createMemo(() => assistantMessages().find((m) => m.error)?.error)
|
||||||
|
const errorText = createMemo(() => {
|
||||||
|
const msg = error()?.data?.message
|
||||||
|
if (typeof msg === "string") return unwrap(msg)
|
||||||
|
if (msg === undefined || msg === null) return ""
|
||||||
|
return unwrap(String(msg))
|
||||||
|
})
|
||||||
|
|
||||||
const lastTextPart = createMemo(() => {
|
const lastTextPart = createMemo(() => {
|
||||||
const msgs = assistantMessages()
|
const msgs = assistantMessages()
|
||||||
@@ -463,6 +522,39 @@ export function SessionTurn(
|
|||||||
onCleanup(() => clearInterval(timer))
|
onCleanup(() => clearInterval(timer))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let retryLog = ""
|
||||||
|
createEffect(() => {
|
||||||
|
const r = retry()
|
||||||
|
if (!r) return
|
||||||
|
const key = `${r.attempt}:${r.next}:${r.message}`
|
||||||
|
if (key === retryLog) return
|
||||||
|
retryLog = key
|
||||||
|
console.warn("[session-turn] retry", {
|
||||||
|
sessionID: props.sessionID,
|
||||||
|
messageID: props.messageID,
|
||||||
|
attempt: r.attempt,
|
||||||
|
next: r.next,
|
||||||
|
raw: r.message,
|
||||||
|
parsed: unwrap(r.message),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
let errorLog = ""
|
||||||
|
createEffect(() => {
|
||||||
|
const value = error()?.data?.message
|
||||||
|
if (value === undefined || value === null) return
|
||||||
|
const raw = typeof value === "string" ? value : String(value)
|
||||||
|
if (!raw) return
|
||||||
|
if (raw === errorLog) return
|
||||||
|
errorLog = raw
|
||||||
|
console.warn("[session-turn] assistant-error", {
|
||||||
|
sessionID: props.sessionID,
|
||||||
|
messageID: props.messageID,
|
||||||
|
raw,
|
||||||
|
parsed: unwrap(raw),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
const update = () => {
|
const update = () => {
|
||||||
setStore("duration", duration())
|
setStore("duration", duration())
|
||||||
@@ -595,7 +687,8 @@ export function SessionTurn(
|
|||||||
{(() => {
|
{(() => {
|
||||||
const r = retry()
|
const r = retry()
|
||||||
if (!r) return ""
|
if (!r) return ""
|
||||||
return r.message.length > 60 ? r.message.slice(0, 60) + "..." : r.message
|
const msg = unwrap(r.message)
|
||||||
|
return msg.length > 60 ? msg.slice(0, 60) + "..." : msg
|
||||||
})()}
|
})()}
|
||||||
</span>
|
</span>
|
||||||
<span data-slot="session-turn-retry-seconds">
|
<span data-slot="session-turn-retry-seconds">
|
||||||
@@ -640,7 +733,7 @@ export function SessionTurn(
|
|||||||
</For>
|
</For>
|
||||||
<Show when={error()}>
|
<Show when={error()}>
|
||||||
<Card variant="error" class="error-card">
|
<Card variant="error" class="error-card">
|
||||||
{error()?.data?.message as string}
|
{errorText()}
|
||||||
</Card>
|
</Card>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
@@ -696,7 +789,7 @@ export function SessionTurn(
|
|||||||
</Show>
|
</Show>
|
||||||
<Show when={error() && !props.stepsExpanded}>
|
<Show when={error() && !props.stepsExpanded}>
|
||||||
<Card variant="error" class="error-card">
|
<Card variant="error" class="error-card">
|
||||||
{error()?.data?.message as string}
|
{errorText()}
|
||||||
</Card>
|
</Card>
|
||||||
</Show>
|
</Show>
|
||||||
</Match>
|
</Match>
|
||||||
|
|||||||
Reference in New Issue
Block a user