From 46213dcebda653c1575b67ef93fc8aab065a9db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Uruchurtu?= Date: Tue, 26 May 2026 20:48:18 -0600 Subject: [PATCH 1/3] fix(vscode): improve chat error styling --- .changeset/polite-errors-glow.md | 6 ++ packages/kilo-ui/src/components/card.css | 7 ++ .../kilo-ui/src/components/error-details.css | 70 ++++++++++-- .../kilo-ui/src/components/error-details.tsx | 2 +- packages/kilo-ui/src/styles/vscode-bridge.css | 28 ++--- .../src/components/chat/ErrorDisplay.tsx | 8 +- .../webview-ui/src/stories/chat.stories.tsx | 102 ++++++++++++++++++ 7 files changed, 196 insertions(+), 27 deletions(-) create mode 100644 .changeset/polite-errors-glow.md diff --git a/.changeset/polite-errors-glow.md b/.changeset/polite-errors-glow.md new file mode 100644 index 00000000000..bc37608e936 --- /dev/null +++ b/.changeset/polite-errors-glow.md @@ -0,0 +1,6 @@ +--- +"@kilocode/kilo-ui": patch +"kilo-code": patch +--- + +Improve chat error styling in the VS Code extension. diff --git a/packages/kilo-ui/src/components/card.css b/packages/kilo-ui/src/components/card.css index 6ae4d7d2693..360d1028608 100644 --- a/packages/kilo-ui/src/components/card.css +++ b/packages/kilo-ui/src/components/card.css @@ -5,6 +5,13 @@ padding: 8px; border: 1px solid var(--border-weak-base); + &[data-variant="error"] { + padding: 12px; + background-color: color-mix(in srgb, var(--surface-critical-strong) 10%, var(--surface-inset-base)); + border-color: color-mix(in srgb, var(--border-critical-selected) 55%, var(--border-weaker-base)); + color: var(--text-base); + } + &[data-variant="warning"] { padding: 12px 14px; } diff --git a/packages/kilo-ui/src/components/error-details.css b/packages/kilo-ui/src/components/error-details.css index 259150984e0..88f97120a2e 100644 --- a/packages/kilo-ui/src/components/error-details.css +++ b/packages/kilo-ui/src/components/error-details.css @@ -1,42 +1,92 @@ .error-card { - padding-bottom: 0; - background-color: var(--surface-critical-base); + gap: 8px; + padding-bottom: 12px; + --error-card-accent: var(--text-on-critical-base); +} + +.error-card-body { + display: flex; + align-items: flex-start; + gap: 8px; +} + +.error-card-body [data-component="icon"] { + color: var(--error-card-accent); + margin-top: 2px; +} + +.error-card-message { + flex: 1; + min-width: 0; + color: var(--text-strong); + font-size: var(--font-size-base); + line-height: var(--line-height-large); + overflow-wrap: anywhere; } .error-card [data-component="collapsible"] { - margin-top: 8px; + margin-top: 0; + padding-left: 24px; } -.error-details-trigger { +.error-card .error-details-trigger[data-slot="collapsible-trigger"] { display: inline-flex; align-items: center; - gap: 4px; + align-self: flex-start; + gap: 2px; + width: auto; + height: 22px; font-size: var(--font-size-small); + font-weight: var(--font-weight-medium); opacity: 0.85; cursor: pointer; background: none; border: none; - color: inherit; - padding: 0; + border-radius: var(--radius-sm); + color: var(--error-card-accent); + padding: 0 6px; } -.error-details-trigger:hover { +.error-card .error-details-trigger[data-slot="collapsible-trigger"]:hover { + background-color: color-mix(in srgb, var(--error-card-accent) 12%, transparent); opacity: 1; } +.error-card .error-details-trigger[data-slot="collapsible-trigger"]:focus-visible { + background-color: color-mix(in srgb, var(--error-card-accent) 12%, transparent); + outline: 1px solid var(--border-focus); + outline-offset: 2px; +} + +.error-card .error-details-trigger [data-slot="collapsible-arrow"] { + width: 16px; + height: 16px; + opacity: 1; +} + +.error-card .error-details-trigger [data-slot="collapsible-arrow-icon"] { + color: currentColor; +} + .error-details { display: flex; flex-direction: column; - gap: 4px; + gap: 6px; font-size: var(--font-size-small); - margin-top: 4px; + margin-top: 8px; } .error-detail-pre { margin: 0; max-height: 120px; overflow-y: auto; + background-color: color-mix(in srgb, var(--surface-inset-base) 82%, var(--background-base)); + border: 1px solid color-mix(in srgb, var(--border-critical-base) 30%, var(--border-weaker-base)); + border-radius: var(--radius-sm); + color: var(--text-base); font-size: var(--font-size-small); + line-height: var(--line-height-large); + padding: 8px; white-space: pre-wrap; word-break: break-all; flex: 1; diff --git a/packages/kilo-ui/src/components/error-details.tsx b/packages/kilo-ui/src/components/error-details.tsx index c720bd80f8c..1a306385865 100644 --- a/packages/kilo-ui/src/components/error-details.tsx +++ b/packages/kilo-ui/src/components/error-details.tsx @@ -11,7 +11,7 @@ export function ErrorDetails(props: ErrorDetailsProps) { return (
-
{raw()}
+
{raw()}
) } diff --git a/packages/kilo-ui/src/styles/vscode-bridge.css b/packages/kilo-ui/src/styles/vscode-bridge.css index 5ad8a6a6920..534aea426c0 100644 --- a/packages/kilo-ui/src/styles/vscode-bridge.css +++ b/packages/kilo-ui/src/styles/vscode-bridge.css @@ -68,7 +68,7 @@ html[data-theme="kilo-vscode"] { --surface-critical-base: var(--vscode-editorMarkerNavigationError-headerBackground); --surface-critical-weak: var(--vscode-editorMarkerNavigationError-headerBackground); - --surface-critical-strong: var(--vscode-charts-red); + --surface-critical-strong: var(--vscode-errorForeground, var(--vscode-charts-red)); --surface-info-base: var(--vscode-editorMarkerNavigationInfo-headerBackground); --surface-info-weak: var(--vscode-editorMarkerNavigationInfo-headerBackground); @@ -116,9 +116,9 @@ html[data-theme="kilo-vscode"] { --text-on-success-base: var(--vscode-charts-green); --text-on-success-weak: var(--vscode-charts-green); --text-on-success-strong: var(--vscode-charts-green); - --text-on-critical-base: var(--vscode-charts-red); - --text-on-critical-weak: var(--vscode-charts-red); - --text-on-critical-strong: var(--vscode-charts-red); + --text-on-critical-base: var(--vscode-errorForeground, var(--vscode-charts-red)); + --text-on-critical-weak: var(--vscode-errorForeground, var(--vscode-charts-red)); + --text-on-critical-strong: var(--vscode-errorForeground, var(--vscode-charts-red)); --text-on-warning-base: var(--vscode-charts-yellow); --text-on-warning-weak: var(--vscode-charts-yellow); --text-on-warning-strong: var(--vscode-charts-yellow); @@ -183,9 +183,9 @@ html[data-theme="kilo-vscode"] { --border-warning-base: var(--vscode-charts-yellow); --border-warning-hover: var(--vscode-charts-yellow); --border-warning-selected: var(--vscode-charts-yellow); - --border-critical-base: var(--vscode-charts-red); - --border-critical-hover: var(--vscode-charts-red); - --border-critical-selected: var(--vscode-charts-red); + --border-critical-base: var(--vscode-inputValidation-errorBorder, var(--vscode-errorForeground, var(--vscode-charts-red))); + --border-critical-hover: var(--vscode-inputValidation-errorBorder, var(--vscode-errorForeground, var(--vscode-charts-red))); + --border-critical-selected: var(--vscode-inputValidation-errorBorder, var(--vscode-errorForeground, var(--vscode-charts-red))); --border-info-base: var(--vscode-charts-blue); --border-info-hover: var(--vscode-charts-blue); --border-info-selected: var(--vscode-charts-blue); @@ -221,9 +221,9 @@ html[data-theme="kilo-vscode"] { --icon-warning-base: var(--vscode-charts-yellow); --icon-warning-hover: var(--vscode-charts-yellow); --icon-warning-active: var(--vscode-charts-yellow); - --icon-critical-base: var(--vscode-charts-red); - --icon-critical-hover: var(--vscode-charts-red); - --icon-critical-active: var(--vscode-charts-red); + --icon-critical-base: var(--vscode-errorForeground, var(--vscode-charts-red)); + --icon-critical-hover: var(--vscode-errorForeground, var(--vscode-charts-red)); + --icon-critical-active: var(--vscode-errorForeground, var(--vscode-charts-red)); --icon-info-base: var(--vscode-charts-blue); --icon-info-hover: var(--vscode-charts-blue); --icon-info-active: var(--vscode-charts-blue); @@ -239,9 +239,9 @@ html[data-theme="kilo-vscode"] { --icon-on-warning-base: var(--vscode-charts-yellow); --icon-on-warning-hover: var(--vscode-charts-yellow); --icon-on-warning-selected: var(--vscode-charts-yellow); - --icon-on-critical-base: var(--vscode-charts-red); - --icon-on-critical-hover: var(--vscode-charts-red); - --icon-on-critical-selected: var(--vscode-charts-red); + --icon-on-critical-base: var(--vscode-errorForeground, var(--vscode-charts-red)); + --icon-on-critical-hover: var(--vscode-errorForeground, var(--vscode-charts-red)); + --icon-on-critical-selected: var(--vscode-errorForeground, var(--vscode-charts-red)); --icon-on-info-base: var(--vscode-charts-blue); --icon-on-info-hover: var(--vscode-charts-blue); --icon-on-info-selected: var(--vscode-charts-blue); @@ -273,7 +273,7 @@ html[data-theme="kilo-vscode"] { --syntax-object: var(--vscode-editor-foreground); --syntax-success: var(--vscode-charts-green); --syntax-warning: var(--vscode-charts-yellow); - --syntax-critical: var(--vscode-charts-red); + --syntax-critical: var(--vscode-errorForeground, var(--vscode-charts-red)); --syntax-info: var(--vscode-charts-blue); --syntax-diff-add: var(--vscode-gitDecoration-addedResourceForeground); --syntax-diff-delete: var(--vscode-gitDecoration-deletedResourceForeground); diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/ErrorDisplay.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/ErrorDisplay.tsx index ef600bccfc3..52ae08d88e6 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/ErrorDisplay.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/ErrorDisplay.tsx @@ -3,6 +3,7 @@ import { Card } from "@kilocode/kilo-ui/card" import { Collapsible } from "@kilocode/kilo-ui/collapsible" import { useDialog } from "@kilocode/kilo-ui/context/dialog" import { ErrorDetails } from "@kilocode/kilo-ui/error-details" +import { Icon } from "@kilocode/kilo-ui/icon" import { Button } from "@kilocode/kilo-ui/button" import type { AssistantMessage } from "@kilocode/sdk/v2" import { useLanguage } from "../../context/language" @@ -62,8 +63,11 @@ export const ErrorDisplay: Component = (props) => { return ( - {errorText()} + +
+ +
{errorText()}
+
{t("error.details.show")} diff --git a/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx b/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx index b8b41bcaf92..692960c8e2d 100644 --- a/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx +++ b/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx @@ -8,8 +8,10 @@ */ import type { Meta, StoryObj } from "storybook-solidjs-vite" +import type { AssistantMessage } from "@kilocode/sdk/v2" import { StoryProviders, defaultMockData, mockSessionValue } from "./StoryProviders" import { ChatView } from "../components/chat/ChatView" +import { ErrorDisplay } from "../components/chat/ErrorDisplay" import { TaskHeader } from "../components/chat/TaskHeader" import { QuestionDock } from "../components/chat/QuestionDock" import { SuggestBar } from "../components/chat/SuggestBar" @@ -76,6 +78,72 @@ const reviewSuggestion: SuggestionRequest = { tool: { messageID: "asst-msg-002", callID: "call-suggest-001" }, } +const policyMessage = + "No endpoints found matching your data policy (Free model training). Configure: https://openrouter.ai/settings/privacy" + +const policyError: NonNullable = { + name: "APIError", + data: { + message: policyMessage, + statusCode: 400, + isRetryable: false, + responseBody: JSON.stringify( + { + error: { + type: "Bad Request", + message: "Data collection is required for this model. Please enable data collection to use this model.", + }, + }, + null, + 2, + ), + }, +} + +function BeforeErrorDisplay() { + return ( +
+
{policyMessage}
+
+ +
+
+ ) +} + // --------------------------------------------------------------------------- // Meta // --------------------------------------------------------------------------- @@ -231,6 +299,40 @@ export const SuggestBarReview: Story = { ), } +export const ErrorDisplayDataPolicy: Story = { + name: "ErrorDisplay — data policy", + render: () => ( + +
+ +
+
+ ), +} + +export const ErrorDisplayBeforeAfter: Story = { + name: "ErrorDisplay — before / after", + render: () => ( + +
+
+ Compare the previous error treatment reconstructed from pre-change CSS with the updated readable card. +
+
+
+

Before

+ +
+
+

After

+ +
+
+
+
+ ), +} + const toolUserID = "user-msg-spacing-001" const toolAssistantID = "asst-msg-spacing-001" const queuedUserID = "user-msg-spacing-002" From d02c3a6bf31f2a696363d136d8b4cffd57dc6aba Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 27 May 2026 02:51:48 +0000 Subject: [PATCH 2/3] chore: update kilo-vscode visual regression baselines --- .../chat/error-display-before-after-chromium-linux.png | 3 +++ .../chat/error-display-data-policy-chromium-linux.png | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/error-display-before-after-chromium-linux.png create mode 100644 packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/error-display-data-policy-chromium-linux.png diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/error-display-before-after-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/error-display-before-after-chromium-linux.png new file mode 100644 index 00000000000..7ff28e5ac05 --- /dev/null +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/error-display-before-after-chromium-linux.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de207e3a717fe43dbb297ebebf018b14b010cee02fb060135c41bf8f5a599c68 +size 24422 diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/error-display-data-policy-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/error-display-data-policy-chromium-linux.png new file mode 100644 index 00000000000..010968eb6a0 --- /dev/null +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/error-display-data-policy-chromium-linux.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e3050c782d797be7dad951b76199df2c87195415e699d3e8481bbf40ad0dfccf +size 10073 From 7d2dbb0ae206f5cc3d39a06c2a3dbe3c631373ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Uruchurtu?= Date: Tue, 26 May 2026 20:56:07 -0600 Subject: [PATCH 3/3] chore(vscode): trim error story coverage --- ...or-display-before-after-chromium-linux.png | 3 - .../webview-ui/src/stories/chat.stories.tsx | 67 ------------------- 2 files changed, 70 deletions(-) delete mode 100644 packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/error-display-before-after-chromium-linux.png diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/error-display-before-after-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/error-display-before-after-chromium-linux.png deleted file mode 100644 index 7ff28e5ac05..00000000000 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/error-display-before-after-chromium-linux.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:de207e3a717fe43dbb297ebebf018b14b010cee02fb060135c41bf8f5a599c68 -size 24422 diff --git a/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx b/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx index 692960c8e2d..4d966d9d116 100644 --- a/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx +++ b/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx @@ -100,50 +100,6 @@ const policyError: NonNullable = { }, } -function BeforeErrorDisplay() { - return ( -
-
{policyMessage}
-
- -
-
- ) -} - // --------------------------------------------------------------------------- // Meta // --------------------------------------------------------------------------- @@ -310,29 +266,6 @@ export const ErrorDisplayDataPolicy: Story = { ), } -export const ErrorDisplayBeforeAfter: Story = { - name: "ErrorDisplay — before / after", - render: () => ( - -
-
- Compare the previous error treatment reconstructed from pre-change CSS with the updated readable card. -
-
-
-

Before

- -
-
-

After

- -
-
-
-
- ), -} - const toolUserID = "user-msg-spacing-001" const toolAssistantID = "asst-msg-spacing-001" const queuedUserID = "user-msg-spacing-002"