Render error cause chains at every diagnostic seam
A TUI run against an unreachable endpoint failed with only 'fetch failed':
undici wraps transport failures in a bare TypeError whose diagnosis lives
on .cause, and every diagnostic seam rendered only error.message. The
readline front door additionally rendered failed turns as pure silence.
- dsh-llm: new errorChain(value) renders the full cause chain and
AggregateError members with circular/hostile-coercion containment.
- llm-deepseek: pre-response transport failures throw LlmError('NETWORK')
naming the endpoint and chaining the fetch TypeError; aborts keep their
DOMException so the loop still classifies them as cancellation.
- agent-loop: durable turn/end error messages and logger warnings render
through errorChain; local renderThrown copies removed.
- ui-stdio: failure turn/end reasons now render ([turn failed <code>],
[turn aborted], [turn rejected], output-token-limit); startup-failure
logs use errorChain.
- ui-tui: agent/error notices and the startup-failure line use errorChain.
This commit is contained in:
@@ -35,6 +35,7 @@ import type { Context } from 'cordis'
|
||||
import z from 'schemastery'
|
||||
import type { Agent, AgentStatus } from '@deepseek-ai/dsh-agent'
|
||||
import type {} from '@deepseek-ai/dsh-agent-loop'
|
||||
import { errorChain } from '@deepseek-ai/dsh-llm'
|
||||
import type { ContentBlock, StreamChunk } from '@deepseek-ai/dsh-llm'
|
||||
import { SessionId, type Session, type SessionEvent, type TodoItem } from '@deepseek-ai/dsh-session'
|
||||
import type {
|
||||
@@ -191,15 +192,6 @@ function displayText(text: string): string {
|
||||
`\\x${control.charCodeAt(0).toString(16).padStart(2, '0')}`)
|
||||
}
|
||||
|
||||
/** Render an arbitrary failure without allowing hostile coercion to escape the UI boundary. */
|
||||
function renderThrown(value: unknown): string {
|
||||
try {
|
||||
return String(value)
|
||||
} catch {
|
||||
return '<unrenderable thrown value>'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme-agnostic palette built from the standard 16-color ANSI set plus SGR
|
||||
* attributes, which every terminal remaps to its active color scheme. Body
|
||||
@@ -1263,7 +1255,9 @@ export function createTuiChat(
|
||||
const disposeError = ctx.on('agent/error', (subject, turn, step, error) => {
|
||||
if (subject !== agent) return
|
||||
liveErrors.add(`${turn}:${step}`)
|
||||
appendNotice(error.message, 'error')
|
||||
// Full cause chain: wrapper messages like `fetch failed` carry the
|
||||
// actionable transport detail on `cause`.
|
||||
appendNotice(errorChain(error), 'error')
|
||||
})
|
||||
const disposeAgent = ctx.on('agent/disposed', (subject) => {
|
||||
if (subject !== agent) return
|
||||
@@ -1330,7 +1324,7 @@ export function mountTui(ctx: Context, config: Config, runtime: TuiRuntime): voi
|
||||
if (settled || failedSessionId !== sessionId) return
|
||||
settled = true
|
||||
stopWaiting()
|
||||
runtime.terminal.write(displayText(`ui-tui: session "${sessionId}" failed to start: ${renderThrown(error)}\n`))
|
||||
runtime.terminal.write(displayText(`ui-tui: session "${sessionId}" failed to start: ${errorChain(error)}\n`))
|
||||
runtime.exit(1)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user