fix(opencode): forward provider retries instead of swallowing them

OpenCode subproviders (e.g. opencode/kimi-k2.6 on OpenCode Zen) emit
session.status:retry events with messages like "Internal server error"
when the upstream provider returns 5xx. opencode itself retries
indefinitely with backoff and never emits a terminal event for these.

Previously the adapter only surfaced retry messages on a small allowlist
of "fatal" tokens (insufficient balance, invalid api key, etc.) and
silently dropped everything else. The agent appeared hung from the
user's perspective — no message, no spinner update, nothing — until the
upstream eventually recovered or the user manually interrupted.

Forward every session.status:retry as a non-terminal timeline error
item so the user can see what opencode is doing, mirroring opencode's
own TUI. Drop the fatal-token allowlist: classifying which retries are
"really" terminal is opencode's job, and synthesizing turn_failed for
ones we guess at is misleading anyway because opencode keeps spending
upstream while we tell the user the agent is done.

Also a small design pass on the timeline error rendering:
- drop the redundant "Agent error" prefix (the message is descriptive)
- drop the colored box background (visual weight too high for a retry)
- align the icon vertically to the first text line (height+center)
- make the message text selectable so users can copy errors
This commit is contained in:
Mohamed Boudra
2026-05-05 19:56:51 +07:00
parent 0775f59a6f
commit 4d31cd4013
5 changed files with 65 additions and 86 deletions
+6 -4
View File
@@ -1810,9 +1810,7 @@ const activityLogStylesheet = StyleSheet.create((theme) => ({
successBg: {
backgroundColor: "rgba(20, 83, 45, 0.3)",
},
errorBg: {
backgroundColor: "rgba(127, 29, 29, 0.3)",
},
errorBg: {},
artifactBg: {
backgroundColor: "rgba(30, 58, 138, 0.4)",
},
@@ -1827,6 +1825,8 @@ const activityLogStylesheet = StyleSheet.create((theme) => ({
},
iconContainer: {
flexShrink: 0,
height: 20,
justifyContent: "center",
},
textContainer: {
flex: 1,
@@ -1936,7 +1936,9 @@ export const ActivityLog = memo(function ActivityLog({
<IconComponent size={16} color={config.color} />
</View>
<View style={activityLogStylesheet.textContainer}>
<Text style={messageTextStyle}>{displayMessage}</Text>
<Text style={messageTextStyle} selectable>
{displayMessage}
</Text>
{metadata && (
<View style={activityLogStylesheet.detailsRow}>
<Text style={activityLogStylesheet.detailsText}>Details</Text>
+1 -5
View File
@@ -543,10 +543,6 @@ function appendTodoList(
return [...state, entry];
}
function formatErrorMessage(message: string): string {
return `Agent error\n${message}`;
}
function reduceTimelineToolCall(
state: StreamItem[],
event: Extract<AgentStreamEventPayload, { type: "timeline" }>,
@@ -672,7 +668,7 @@ function reduceTimelineEvent(
id: createTimelineId("error", item.message ?? "", timestamp),
timestamp,
activityType: "error",
message: formatErrorMessage(item.message ?? "Unknown error"),
message: item.message ?? "Unknown error",
};
return finalizeActiveThoughts(appendActivityLog(state, activity));
}