mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
feat: add api-error event support with folding for retry messages
Introduces support for displaying API error system messages in the web UI with automatic folding of consecutive retry messages to show only the latest state.
This commit is contained in:
@@ -216,6 +216,22 @@ export function normalizeAgentRecord(
|
||||
meta
|
||||
}
|
||||
}
|
||||
if (data.type === 'system' && data.subtype === 'api_error') {
|
||||
return {
|
||||
id: messageId,
|
||||
localId,
|
||||
createdAt,
|
||||
role: 'event',
|
||||
content: {
|
||||
type: 'api-error',
|
||||
retryAttempt: asNumber(data.retryAttempt) ?? 0,
|
||||
maxRetries: asNumber(data.maxRetries) ?? 0,
|
||||
error: data.error
|
||||
},
|
||||
isSidechain: false,
|
||||
meta
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,19 @@ export type EventPresentation = {
|
||||
}
|
||||
|
||||
export function getEventPresentation(event: AgentEvent): EventPresentation {
|
||||
if (event.type === 'api-error') {
|
||||
const { retryAttempt, maxRetries } = event as { retryAttempt: number; maxRetries: number }
|
||||
if (maxRetries > 0 && retryAttempt >= maxRetries) {
|
||||
return { icon: '⚠️', text: 'API error: Max retries reached' }
|
||||
}
|
||||
if (maxRetries > 0) {
|
||||
return { icon: '⏳', text: `API error: Retrying (${retryAttempt}/${maxRetries})` }
|
||||
}
|
||||
if (retryAttempt > 0) {
|
||||
return { icon: '⏳', text: 'API error: Retrying...' }
|
||||
}
|
||||
return { icon: '⚠️', text: 'API error' }
|
||||
}
|
||||
if (event.type === 'switch') {
|
||||
const mode = event.mode === 'local' ? 'local' : 'remote'
|
||||
return { icon: '🔄', text: `Switched to ${mode}` }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { AgentState } from '@/types/api'
|
||||
import type { ChatBlock, NormalizedMessage, UsageData } from '@/chat/types'
|
||||
import { traceMessages, type TracedMessage } from '@/chat/tracer'
|
||||
import { dedupeAgentEvents } from '@/chat/reducerEvents'
|
||||
import { dedupeAgentEvents, foldApiErrorEvents } from '@/chat/reducerEvents'
|
||||
import { collectTitleChanges, collectToolIdsFromMessages, ensureToolBlock, getPermissions } from '@/chat/reducerTools'
|
||||
import { reduceTimeline } from '@/chat/reducerTimeline'
|
||||
|
||||
@@ -94,5 +94,5 @@ export function reduceChatBlocks(
|
||||
}
|
||||
}
|
||||
|
||||
return { blocks: dedupeAgentEvents(rootResult.blocks), hasReadyEvent, latestUsage }
|
||||
return { blocks: dedupeAgentEvents(foldApiErrorEvents(rootResult.blocks)), hasReadyEvent, latestUsage }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { AgentEvent, ChatBlock, NormalizedMessage } from '@/chat/types'
|
||||
import type { AgentEvent, AgentEventBlock, ChatBlock, NormalizedMessage } from '@/chat/types'
|
||||
|
||||
function parseClaudeUsageLimit(text: string): number | null {
|
||||
const match = text.match(/^Claude AI usage limit reached\|(\d+)$/)
|
||||
@@ -83,3 +83,32 @@ export function dedupeAgentEvents(blocks: ChatBlock[]): ChatBlock[] {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Fold consecutive api-error events, keeping only the latest state.
|
||||
*/
|
||||
export function foldApiErrorEvents(blocks: ChatBlock[]): ChatBlock[] {
|
||||
const result: ChatBlock[] = []
|
||||
|
||||
for (const block of blocks) {
|
||||
if (block.kind !== 'agent-event') {
|
||||
result.push(block)
|
||||
continue
|
||||
}
|
||||
|
||||
const event = block.event as { type: string }
|
||||
if (event.type !== 'api-error') {
|
||||
result.push(block)
|
||||
continue
|
||||
}
|
||||
|
||||
const prev = result[result.length - 1] as AgentEventBlock | undefined
|
||||
if (prev?.kind === 'agent-event' && (prev.event as { type: string }).type === 'api-error') {
|
||||
result[result.length - 1] = block
|
||||
} else {
|
||||
result.push(block)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ export type AgentEvent =
|
||||
| { type: 'title-changed'; title: string }
|
||||
| { type: 'limit-reached'; endsAt: number }
|
||||
| { type: 'ready' }
|
||||
| { type: 'api-error'; retryAttempt: number; maxRetries: number; error: unknown }
|
||||
| ({ type: string } & Record<string, unknown>)
|
||||
|
||||
export type ToolResultPermission = {
|
||||
|
||||
Reference in New Issue
Block a user