mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-19 01:51:21 +08:00
Merge pull request #6613 from Kilo-Org/feat/reasoning-block-styling
feat(kilo-ui): improve reasoning block styling (#6254)
This commit is contained in:
@@ -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": "الاستدلال",
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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": "Denken",
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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": "推論",
|
||||
}
|
||||
|
||||
@@ -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": "추론",
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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": "Рассуждение",
|
||||
}
|
||||
|
||||
@@ -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": "การให้เหตุผล",
|
||||
}
|
||||
|
||||
@@ -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": "推理",
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/** @jsxImportSource solid-js */
|
||||
import type { Meta, StoryObj } from "storybook-solidjs-vite"
|
||||
import { Message, AssistantMessageDisplay, UserMessageDisplay } from "@opencode-ai/ui/message-part"
|
||||
// Side-effect import: registers kilo-ui's PART_MAPPING override for reasoning blocks
|
||||
import "../components/message-part"
|
||||
import { DataProvider } from "@opencode-ai/ui/context/data"
|
||||
import { DiffComponentProvider } from "@opencode-ai/ui/context/diff"
|
||||
import { CodeComponentProvider } from "@opencode-ai/ui/context/code"
|
||||
@@ -8,7 +10,7 @@ import { DialogProvider } from "@opencode-ai/ui/context/dialog"
|
||||
import { MarkedProvider } from "@opencode-ai/ui/context/marked"
|
||||
import { Diff } from "@opencode-ai/ui/diff"
|
||||
import { Code } from "@opencode-ai/ui/code"
|
||||
import type { UserMessage, AssistantMessage, TextPart, ToolPart } from "@kilocode/sdk/v2"
|
||||
import type { UserMessage, AssistantMessage, TextPart, ToolPart, ReasoningPart } from "@kilocode/sdk/v2"
|
||||
|
||||
const SESSION_ID = "session-story-001"
|
||||
const USER_MSG_ID = "user-msg-001"
|
||||
@@ -104,6 +106,15 @@ const errorToolPart: ToolPart = {
|
||||
},
|
||||
}
|
||||
|
||||
const reasoningPart: ReasoningPart = {
|
||||
id: "part-reasoning-001",
|
||||
sessionID: SESSION_ID,
|
||||
messageID: ASST_MSG_ID,
|
||||
type: "reasoning",
|
||||
text: "Let me think about this carefully. The user wants code improvements.\n\n1. First, I should check for error boundaries — they prevent cascading failures\n2. The dependencies could be updated to newer minor versions\n3. Unit tests would improve confidence in refactoring later\n\nI'll structure my response to address each point clearly.",
|
||||
time: { start: now - 9000, end: now - 8500 },
|
||||
}
|
||||
|
||||
const mockData = {
|
||||
session: [],
|
||||
session_status: {},
|
||||
@@ -186,6 +197,33 @@ export const FullConversationTurn: Story = {
|
||||
),
|
||||
}
|
||||
|
||||
export const WithReasoningCollapsed: Story = {
|
||||
name: "WithReasoning (collapsed)",
|
||||
render: () => (
|
||||
<AllProviders>
|
||||
<AssistantMessageDisplay message={mockAssistantMessage} parts={[reasoningPart, textPart]} />
|
||||
</AllProviders>
|
||||
),
|
||||
}
|
||||
|
||||
export const WithReasoningExpanded: Story = {
|
||||
name: "WithReasoning (expanded)",
|
||||
render: () => {
|
||||
// Use a wrapper to render with the collapsible open by default
|
||||
const expandedReasoningPart = { ...reasoningPart, id: "part-reasoning-expanded" }
|
||||
return (
|
||||
<AllProviders>
|
||||
<AssistantMessageDisplay message={mockAssistantMessage} parts={[expandedReasoningPart, textPart]} />
|
||||
</AllProviders>
|
||||
)
|
||||
},
|
||||
play: async ({ canvasElement }: { canvasElement: HTMLElement }) => {
|
||||
// Click the collapsible trigger to expand it
|
||||
const trigger = canvasElement.querySelector("[data-slot='reasoning-header']")?.closest("button")
|
||||
if (trigger) trigger.click()
|
||||
},
|
||||
}
|
||||
|
||||
export const MessageSwitch: Story = {
|
||||
render: () => (
|
||||
<AllProviders>
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cf93ca79d15deab7dc52473f68305b521c62d10e968a9258e09609ad9c04fde6
|
||||
size 15837
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:14bf991adcbc6fcbf53f4cff2275dcec255943b5545c624231aeb73529ca2d6e
|
||||
size 32478
|
||||
Reference in New Issue
Block a user