diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/VscodeSessionTurn.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/VscodeSessionTurn.tsx
index c4de848fa2a..c667615beae 100644
--- a/packages/kilo-vscode/webview-ui/src/components/chat/VscodeSessionTurn.tsx
+++ b/packages/kilo-vscode/webview-ui/src/components/chat/VscodeSessionTurn.tsx
@@ -122,11 +122,9 @@ export const VscodeSessionTurn: Component
= (props) => {
0 && !session.revert() && session.status() !== "idle" ? "" : undefined
- }
+ data-revert-disabled={assistantMessages().length > 0 && session.status() !== "idle" ? "" : undefined}
title={
- assistantMessages().length > 0 && !session.revert() && session.status() !== "idle"
+ assistantMessages().length > 0 && session.status() !== "idle"
? language.t("revert.disabled.agentBusy")
: undefined
}
@@ -138,7 +136,7 @@ export const VscodeSessionTurn: Component
= (props) => {
queued={props.queued}
onFork={props.onForkMessage ? () => props.onForkMessage?.(msg().sessionID, msg().id) : undefined}
onRevert={
- assistantMessages().length > 0 && !session.revert()
+ assistantMessages().length > 0
? () => {
if (session.status() !== "idle") return
session.revertSession(msg().id)
diff --git a/packages/kilo-vscode/webview-ui/src/context/session-utils.ts b/packages/kilo-vscode/webview-ui/src/context/session-utils.ts
index 3506d2d07b9..2544246964a 100644
--- a/packages/kilo-vscode/webview-ui/src/context/session-utils.ts
+++ b/packages/kilo-vscode/webview-ui/src/context/session-utils.ts
@@ -121,13 +121,14 @@ export function buildFamilyCosts(
family: Set,
messages: Record>,
sessions: Record,
+ parents: Map = new Map(),
): Map {
const totals = new Map()
for (const sid of family) totals.set(sid, calcTotalCost(messages[sid] ?? []))
const own = new Map(totals)
for (const sid of family) {
- const parent = sessions[sid]?.parentID
+ const parent = sessions[sid]?.parentID ?? parents.get(sid)
if (!parent || !own.has(parent)) continue
own.set(parent, (own.get(parent) ?? 0) - (totals.get(sid) ?? 0))
}
@@ -139,6 +140,32 @@ export function buildFamilyCosts(
return costs
}
+/**
+ * Build child session ID -> parent session ID links from task tool metadata.
+ * This fills the gap when child messages are synced before their SessionInfo.
+ */
+export function buildFamilyParents(
+ family: Set,
+ messages: Record,
+ parts: Record,
+): Map {
+ const parents = new Map()
+ for (const sid of family) {
+ const msgs = messages[sid]
+ if (!msgs) continue
+ for (const msg of msgs) {
+ const list = parts[msg.id]
+ if (!list) continue
+ for (const p of list) {
+ const child = childID(p)
+ if (!child || !family.has(child) || parents.has(child)) continue
+ parents.set(child, sid)
+ }
+ }
+ }
+ return parents
+}
+
const LABEL_CAP = 24
/**
diff --git a/packages/kilo-vscode/webview-ui/src/context/session.tsx b/packages/kilo-vscode/webview-ui/src/context/session.tsx
index 77260855bf9..e47ef1834f1 100644
--- a/packages/kilo-vscode/webview-ui/src/context/session.tsx
+++ b/packages/kilo-vscode/webview-ui/src/context/session.tsx
@@ -39,6 +39,7 @@ import {
computeStatus,
calcContextUsage,
buildFamilyCosts,
+ buildFamilyParents,
buildFamilyLabels,
buildCostBreakdown,
childID,
@@ -1200,8 +1201,13 @@ export const SessionProvider: ParentComponent = (props) => {
// Append text delta to text or reasoning parts
;(existing as { text: string }).text += delta.textDelta
} else {
- // Replace entire part
- parts[effectiveMessageID][existingIndex] = part
+ // Preserve the proxy identity so Solid does not remount tool UI
+ // during streaming updates and restart pending animations.
+ const target = existing as unknown as Record
+ for (const key of Object.keys(target)) {
+ if (!(key in part)) delete target[key]
+ }
+ Object.assign(existing, part)
}
} else {
// Add new part
@@ -2205,14 +2211,16 @@ export const SessionProvider: ParentComponent = (props) => {
/**
* Per-session **own cost** — reads `store.messages` for per-session
- * propagated totals and `store.sessions` for parent links so each
+ * propagated totals and task metadata as a fallback for parent links so each
* session's entry excludes the cost already propagated up from its
* descendants by the CLI backend.
*/
const familyCosts = createMemo