feat(kilo-ui): improve reasoning block styling

- Override PART_MAPPING["reasoning"] in kilo-ui with a collapsible component
- Collapsed by default with brain icon and localized "Reasoning" label
- Subtle background (--surface-inset-base) and left border accent (--border-weak-base)
- Italic, muted text to signal internal model thinking vs final output
- All colors via CSS custom properties for light/dark/HC theme compatibility
- Add ui.reasoning.label i18n key to all 16 kilo-i18n locale files
- Fix upstream margin-top: 24px on markdown wrapper inside reasoning block

Closes #6254
This commit is contained in:
Igor Šćekić
2026-03-04 14:15:00 +01:00
parent 3f8a0dff9e
commit 24a77465fb
18 changed files with 163 additions and 14 deletions
+4 -1
View File
@@ -11,4 +11,7 @@ export const dict = {
// Provider dialog translations
"dialog.provider.group.recommended": "موصى به",
"dialog.provider.kilo.note": "الوصول إلى أكثر من 500 نموذج ذكاء اصطناعي",
}
// Reasoning block label
"ui.reasoning.label": "الاستدلال",
}
+4 -1
View File
@@ -11,4 +11,7 @@ export const dict = {
// Provider dialog translations
"dialog.provider.group.recommended": "Recomendados",
"dialog.provider.kilo.note": "Acesso a mais de 500 modelos de IA",
}
// Reasoning block label
"ui.reasoning.label": "Raciocínio",
}
+4 -1
View File
@@ -16,4 +16,7 @@ export const dict = {
"desktop.menu.reloadWebview": "Ponovno učitavanje webview-a",
"desktop.updater.installFailed.message": "Neuspjelo instaliranje ažuriranja",
"desktop.cli.installed.message": "CLI je instaliran u {{path}}\n\nRestartuj terminal da bi koristio komandu 'kilo'.",
}
// Reasoning block label
"ui.reasoning.label": "Rezonovanje",
}
+4 -1
View File
@@ -11,4 +11,7 @@ export const dict = {
// Provider dialog translations
"dialog.provider.group.recommended": "Anbefalede",
"dialog.provider.kilo.note": "Adgang til 500+ AI-modeller",
}
// Reasoning block label
"ui.reasoning.label": "Ræsonnement",
}
+3
View File
@@ -11,4 +11,7 @@ export const dict = {
// Provider dialog translations
"dialog.provider.group.recommended": "Empfohlen",
"dialog.provider.kilo.note": "Zugriff auf 500+ KI-Modelle",
// Reasoning block label
"ui.reasoning.label": "Überlegung",
}
+3
View File
@@ -14,6 +14,9 @@ export const dict = {
"dialog.provider.group.recommended": "Recommended",
"dialog.provider.kilo.note": "Access 500+ AI models",
// Reasoning block label
"ui.reasoning.label": "Reasoning",
// Add any upstream overrides below this line
// Example: "some.upstream.key": "Kilo-specific override value",
}
+4 -1
View File
@@ -11,4 +11,7 @@ export const dict = {
// Provider dialog translations
"dialog.provider.group.recommended": "Recomendados",
"dialog.provider.kilo.note": "Acceso a más de 500 modelos de IA",
}
// Reasoning block label
"ui.reasoning.label": "Razonamiento",
}
+4 -1
View File
@@ -11,4 +11,7 @@ export const dict = {
// Provider dialog translations
"dialog.provider.group.recommended": "Recommandés",
"dialog.provider.kilo.note": "Accès à plus de 500 modèles d'IA",
}
// Reasoning block label
"ui.reasoning.label": "Raisonnement",
}
+4 -1
View File
@@ -10,4 +10,7 @@ export const dict = {
// Provider dialog translations
"dialog.provider.group.recommended": "おすすめ",
"dialog.provider.kilo.note": "500以上のAIモデルにアクセス",
}
// Reasoning block label
"ui.reasoning.label": "推論",
}
+4 -1
View File
@@ -10,4 +10,7 @@ export const dict = {
// Provider dialog translations
"dialog.provider.group.recommended": "추천",
"dialog.provider.kilo.note": "500개 이상의 AI 모델 이용 가능",
}
// Reasoning block label
"ui.reasoning.label": "추론",
}
+4 -1
View File
@@ -11,4 +11,7 @@ export const dict = {
// Provider dialog translations
"dialog.provider.group.recommended": "Anbefalt",
"dialog.provider.kilo.note": "Tilgang til 500+ AI-modeller",
}
// Reasoning block label
"ui.reasoning.label": "Resonnement",
}
+4 -1
View File
@@ -11,4 +11,7 @@ export const dict = {
// Provider dialog translations
"dialog.provider.group.recommended": "Polecane",
"dialog.provider.kilo.note": "Dostęp do ponad 500 modeli AI",
}
// Reasoning block label
"ui.reasoning.label": "Rozumowanie",
}
+4 -1
View File
@@ -11,4 +11,7 @@ export const dict = {
// Provider dialog translations
"dialog.provider.group.recommended": "Рекомендуемые",
"dialog.provider.kilo.note": "Доступ к 500+ моделям ИИ",
}
// Reasoning block label
"ui.reasoning.label": "Рассуждение",
}
+4 -1
View File
@@ -11,4 +11,7 @@ export const dict = {
// Provider dialog translations
"dialog.provider.group.recommended": "แนะนำ",
"dialog.provider.kilo.note": "เข้าถึงโมเดล AI มากกว่า 500 รายการ",
}
// Reasoning block label
"ui.reasoning.label": "การให้เหตุผล",
}
+4 -1
View File
@@ -9,4 +9,7 @@ export const dict = {
// Provider dialog translations
"dialog.provider.group.recommended": "推荐",
"dialog.provider.kilo.note": "访问 500+ AI 模型",
}
// Reasoning block label
"ui.reasoning.label": "推理",
}
+4 -1
View File
@@ -9,4 +9,7 @@ export const dict = {
// Provider dialog translations
"dialog.provider.group.recommended": "推薦",
"dialog.provider.kilo.note": "存取 500+ AI 模型",
}
// Reasoning block label
"ui.reasoning.label": "推理",
}
@@ -117,3 +117,64 @@ html[data-theme="kilo-vscode"] [data-component="bash-output"] {
[data-component="question-answers"] {
padding: 8px;
}
/* Reasoning block: visually distinct from normal agent output */
[data-component="reasoning-part"] {
width: 100%;
border-left: 2px solid var(--border-weak-base);
border-radius: var(--radius-sm);
overflow: hidden;
[data-component="collapsible"].tool-collapsible {
gap: 0;
}
[data-slot="collapsible-trigger"] {
height: 28px;
padding: 0 8px;
gap: 6px;
background: var(--surface-inset-base);
border-radius: 0;
cursor: pointer;
}
[data-slot="reasoning-header"] {
display: flex;
flex: 1 1 auto;
align-items: center;
gap: 6px;
color: var(--text-weaker);
font-size: var(--font-size-small);
font-weight: var(--font-weight-medium);
min-width: 0;
[data-component="icon"] {
flex-shrink: 0;
color: var(--icon-weak-base);
}
}
[data-slot="reasoning-label"] {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
[data-slot="reasoning-content"] {
padding: 8px 10px;
background: var(--surface-inset-base);
[data-component="markdown"] {
margin-top: 0;
font-style: italic;
font-size: var(--font-size-small);
color: var(--text-weak);
opacity: 0.9;
strong,
b {
color: var(--text-weak);
}
}
}
}
@@ -1 +1,41 @@
export * from "@opencode-ai/ui/message-part"
import { Show, createSignal } from "solid-js"
import { PART_MAPPING } from "@opencode-ai/ui/message-part"
import { Collapsible } from "@opencode-ai/ui/collapsible"
import { Icon } from "@opencode-ai/ui/icon"
import { Markdown } from "@opencode-ai/ui/markdown"
import { useI18n } from "@opencode-ai/ui/context/i18n"
import type { ReasoningPart } from "@kilocode/sdk/v2"
import type { MessagePartProps } from "@opencode-ai/ui/message-part"
// Override: collapsible reasoning block with brain icon + label
// Replaces the upstream flat markdown render with a clearly distinguished, collapsed-by-default block
PART_MAPPING["reasoning"] = function ReasoningPartDisplay(props: MessagePartProps) {
const part = props.part as unknown as ReasoningPart
const i18n = useI18n()
const [open, setOpen] = createSignal(false)
// Filter out redacted reasoning chunks from OpenRouter (encrypted reasoning data appears as [REDACTED])
const text = () => (part.text ?? "").replace("[REDACTED]", "").trim()
return (
<Show when={text()}>
<div data-component="reasoning-part">
<Collapsible open={open()} onOpenChange={setOpen}>
<Collapsible.Trigger>
<div data-slot="reasoning-header">
<Icon name="brain" size="small" />
<span data-slot="reasoning-label">{i18n.t("ui.reasoning.label" as never)}</span>
</div>
<Collapsible.Arrow />
</Collapsible.Trigger>
<Collapsible.Content>
<div data-slot="reasoning-content">
<Markdown text={text()} cacheKey={part.id} />
</div>
</Collapsible.Content>
</Collapsible>
</div>
</Show>
)
}