diff --git a/.changeset/animate-tool-card-reveals.md b/.changeset/animate-tool-card-reveals.md
new file mode 100644
index 00000000000..a273d7ae45e
--- /dev/null
+++ b/.changeset/animate-tool-card-reveals.md
@@ -0,0 +1,5 @@
+---
+"kilo-code": patch
+---
+
+Animate tool-call and reasoning details when expanding and collapsing.
diff --git a/packages/kilo-ui/src/components/basic-tool.css b/packages/kilo-ui/src/components/basic-tool.css
index 0111b6381a9..49ed771af57 100644
--- a/packages/kilo-ui/src/components/basic-tool.css
+++ b/packages/kilo-ui/src/components/basic-tool.css
@@ -129,19 +129,62 @@ html[data-theme="kilo-vscode"] [data-component="tool-trigger"] {
}
}
+@keyframes tool-card-down {
+ from {
+ grid-template-rows: 0fr;
+ opacity: 0;
+ }
+
+ to {
+ grid-template-rows: 1fr;
+ opacity: 1;
+ }
+}
+
+@keyframes tool-card-up {
+ from {
+ grid-template-rows: 1fr;
+ opacity: 1;
+ }
+
+ to {
+ grid-template-rows: 0fr;
+ opacity: 0;
+ }
+}
+
/* Card styling for tool calls in the VS Code sidebar theme */
html[data-theme="kilo-vscode"] [data-component="tool-part-wrapper"][data-part-type="tool"] {
border-radius: 0;
border: 0;
overflow: visible;
- /* Header trigger — add bottom border when the collapsible is open */
[data-component="collapsible"].tool-collapsible {
gap: 0;
border-radius: 0;
- &:has([data-slot="collapsible-trigger"][aria-expanded="true"]) {
- gap: 6px;
+ > [data-slot="collapsible-content"] {
+ display: grid;
+ overflow: visible;
+ clip-path: inset(0 -6px);
+
+ > * {
+ min-height: 0;
+ }
+ }
+
+ > [data-slot="collapsible-content"][data-expanded] {
+ animation: tool-card-down 220ms cubic-bezier(0.23, 1, 0.32, 1);
+ }
+
+ > [data-slot="collapsible-content"][data-closed] {
+ animation: tool-card-up 160ms cubic-bezier(0.77, 0, 0.175, 1);
+ }
+
+ [data-slot="basic-tool-details"]::before {
+ display: block;
+ height: 6px;
+ content: "";
}
[data-slot="collapsible-trigger"] {
@@ -409,3 +452,12 @@ html[data-theme="kilo-vscode"] [data-component="tool-part-wrapper"][data-part-ty
}
}
}
+
+@media (prefers-reduced-motion: reduce) {
+ html[data-theme="kilo-vscode"] [data-component="tool-part-wrapper"][data-part-type="tool"] {
+ [data-component="collapsible"].tool-collapsible > [data-slot="collapsible-content"][data-expanded],
+ [data-component="collapsible"].tool-collapsible > [data-slot="collapsible-content"][data-closed] {
+ animation-duration: 0.01ms;
+ }
+ }
+}
diff --git a/packages/kilo-ui/src/components/basic-tool.tsx b/packages/kilo-ui/src/components/basic-tool.tsx
index 0f4234ad1a4..7ba072c7c44 100644
--- a/packages/kilo-ui/src/components/basic-tool.tsx
+++ b/packages/kilo-ui/src/components/basic-tool.tsx
@@ -20,14 +20,16 @@ export function initialOpen(props: OpenProps) {
export function BasicTool(props: BasicToolProps) {
const key = () => toolOpenKey(props)
const initial = () => initialOpen(props)
+ const change = (open: boolean) => {
+ writeToolOpen(key(), open)
+ props.onOpenChange?.(open)
+ }
+ if (!("children" in props)) {
+ return
+ }
return (
- {
- writeToolOpen(key(), open)
- props.onOpenChange?.(open)
- }}
- />
+
+
{props.children}
+
)
}
diff --git a/packages/kilo-ui/src/components/message-part.css b/packages/kilo-ui/src/components/message-part.css
index ffb4ae84ec4..5a3fd732da0 100644
--- a/packages/kilo-ui/src/components/message-part.css
+++ b/packages/kilo-ui/src/components/message-part.css
@@ -477,6 +477,30 @@ html[data-theme="kilo-vscode"] [data-component="todos"] {
padding: 8px;
}
+@keyframes reasoning-card-down {
+ from {
+ grid-template-rows: 0fr;
+ opacity: 0;
+ }
+
+ to {
+ grid-template-rows: 1fr;
+ opacity: 1;
+ }
+}
+
+@keyframes reasoning-card-up {
+ from {
+ grid-template-rows: 1fr;
+ opacity: 1;
+ }
+
+ to {
+ grid-template-rows: 0fr;
+ opacity: 0;
+ }
+}
+
/* Reasoning block: visually distinct from normal agent output.
Reasoning stays open unless the user explicitly collapses it. */
[data-component="reasoning-part"] {
@@ -550,22 +574,21 @@ html[data-theme="kilo-vscode"] [data-component="todos"] {
}
}
- /* Collapse/expand animation via Kobalte's CSS variable.
- Uses grid trick: the outer wrapper transitions grid-template-rows
- between 0fr (collapsed) and 1fr (expanded) so the content smoothly
- collapses without needing to know the pixel height up front. */
[data-slot="collapsible-content"] {
display: grid;
- grid-template-rows: 0fr;
- transition: grid-template-rows 250ms ease-out;
overflow: hidden;
> * {
+ min-height: 0;
overflow: hidden;
}
&[data-expanded] {
- grid-template-rows: 1fr;
+ animation: reasoning-card-down 220ms cubic-bezier(0.23, 1, 0.32, 1);
+ }
+
+ &[data-closed] {
+ animation: reasoning-card-up 160ms cubic-bezier(0.77, 0, 0.175, 1);
}
}
@@ -598,10 +621,6 @@ html[data-theme="kilo-vscode"] [data-component="reasoning-part"] {
[data-component="collapsible"].tool-collapsible {
gap: 0;
border-radius: 0;
-
- &:has([data-slot="collapsible-trigger"][aria-expanded="true"]) {
- gap: 6px;
- }
}
[data-slot="collapsible-trigger"] {
@@ -667,6 +686,12 @@ html[data-theme="kilo-vscode"] [data-component="reasoning-part"] {
width: calc(100% + 12px);
}
+ [data-slot="reasoning-details"]::before {
+ display: block;
+ height: 6px;
+ content: "";
+ }
+
[data-slot="reasoning-content"] {
padding: 8px 12px 10px;
border: 0;
@@ -712,3 +737,10 @@ html[data-theme="kilo-vscode"] [data-component="reasoning-part"] {
line-height: var(--line-height-large);
}
}
+
+@media (prefers-reduced-motion: reduce) {
+ [data-component="reasoning-part"] [data-slot="collapsible-content"][data-expanded],
+ [data-component="reasoning-part"] [data-slot="collapsible-content"][data-closed] {
+ animation-duration: 0.01ms;
+ }
+}
diff --git a/packages/kilo-ui/src/components/message-part.tsx b/packages/kilo-ui/src/components/message-part.tsx
index d8a448ed0ed..4fb2aab53bc 100644
--- a/packages/kilo-ui/src/components/message-part.tsx
+++ b/packages/kilo-ui/src/components/message-part.tsx
@@ -1591,8 +1591,10 @@ PART_MAPPING["reasoning"] = function ReasoningPartDisplay(props: MessagePartProp
-
-
+
diff --git a/packages/ui/src/components/basic-tool.tsx b/packages/ui/src/components/basic-tool.tsx
index 3dd1f37836f..9e713a12d64 100644
--- a/packages/ui/src/components/basic-tool.tsx
+++ b/packages/ui/src/components/basic-tool.tsx
@@ -31,6 +31,7 @@ export interface BasicToolProps {
defaultOpen?: boolean
forceOpen?: boolean
defer?: boolean
+ retainDetails?: boolean // kilocode_change
hasDetails?: boolean // kilocode_change
locked?: boolean
animated?: boolean
@@ -125,7 +126,7 @@ export function BasicTool(props: BasicToolProps) {
if (!props.defer) return
if (!value) {
cancel()
- setState("ready", false)
+ if (!props.retainDetails) setState("ready", false) // kilocode_change
return
}
@@ -175,6 +176,14 @@ export function BasicTool(props: BasicToolProps) {
props.onOpenChange?.(value) // kilocode_change
}
+ // kilocode_change start
+ const end = (event: AnimationEvent) => {
+ if (event.target !== event.currentTarget) return
+ if (!props.retainDetails || open()) return
+ setState("ready", false)
+ }
+ // kilocode_change end
+
const trigger = () => (
{/* kilocode_change start */}
-
+
{props.children}