From c720a2163c38e7ac08cd130fbba84772ccb582b6 Mon Sep 17 00:00:00 2001
From: Adam <2363879+adamdotdevin@users.noreply.github.com>
Date: Mon, 19 Jan 2026 10:38:41 -0600
Subject: [PATCH 28/42] chore: cleanup
---
packages/ui/src/components/session-turn.css | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/packages/ui/src/components/session-turn.css b/packages/ui/src/components/session-turn.css
index a3c87c576d..556b357c3b 100644
--- a/packages/ui/src/components/session-turn.css
+++ b/packages/ui/src/components/session-turn.css
@@ -331,7 +331,11 @@
}
[data-component="sticky-accordion-header"] {
- position: static;
+ top: var(--sticky-header-height, 40px);
+ &[data-expanded]::before {
+ top: calc(-1 * var(--sticky-header-height, 40px));
+ }
+ /* position: static; */
}
[data-slot="session-turn-accordion-trigger-content"] {
From eb779a7cc5c1728471489a3304a6203716bd4d47 Mon Sep 17 00:00:00 2001
From: Adam <2363879+adamdotdevin@users.noreply.github.com>
Date: Mon, 19 Jan 2026 10:54:56 -0600
Subject: [PATCH 29/42] chore: cleanup
---
packages/ui/src/components/session-turn.css | 13 +++--
packages/ui/src/components/session-turn.tsx | 60 +++++++++++++++++++--
2 files changed, 67 insertions(+), 6 deletions(-)
diff --git a/packages/ui/src/components/session-turn.css b/packages/ui/src/components/session-turn.css
index 556b357c3b..5f8c0a16f6 100644
--- a/packages/ui/src/components/session-turn.css
+++ b/packages/ui/src/components/session-turn.css
@@ -1,4 +1,6 @@
[data-component="session-turn"] {
+ --session-turn-sticky-height: 0px;
+ --sticky-header-height: calc(var(--session-title-height, 0px) + var(--session-turn-sticky-height, 0px) + 12px);
/* flex: 1; */
height: 100%;
min-height: 0;
@@ -44,6 +46,12 @@
}
}
+ [data-slot="session-turn-attachments"] {
+ width: 100%;
+ min-width: 0;
+ align-self: stretch;
+ }
+
[data-slot="session-turn-sticky"] {
width: calc(100% + 9px);
position: sticky;
@@ -331,11 +339,10 @@
}
[data-component="sticky-accordion-header"] {
- top: var(--sticky-header-height, 40px);
+ top: var(--sticky-header-height, 0px);
&[data-expanded]::before {
- top: calc(-1 * var(--sticky-header-height, 40px));
+ top: calc(-1 * var(--sticky-header-height, 0px));
}
- /* position: static; */
}
[data-slot="session-turn-accordion-trigger-content"] {
diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx
index e5fe4ba1ce..a918f0ae4f 100644
--- a/packages/ui/src/components/session-turn.tsx
+++ b/packages/ui/src/components/session-turn.tsx
@@ -1,5 +1,6 @@
import {
AssistantMessage,
+ FilePart,
Message as MessageType,
Part as PartType,
type PermissionRequest,
@@ -29,6 +30,7 @@ import { Spinner } from "./spinner"
import { createStore } from "solid-js/store"
import { DateTime, DurationUnit, Interval } from "luxon"
import { createAutoScroll } from "../hooks"
+import { createResizeObserver } from "@solid-primitives/resize-observer"
function computeStatusFromPart(part: PartType | undefined): string | undefined {
if (!part) return undefined
@@ -75,6 +77,12 @@ function same
(a: readonly T[], b: readonly T[]) {
return a.every((x, i) => x === b[i])
}
+function isAttachment(part: PartType | undefined) {
+ if (part?.type !== "file") return false
+ const mime = (part as FilePart).mime ?? ""
+ return mime.startsWith("image/") || mime === "application/pdf"
+}
+
function AssistantMessageItem(props: {
message: AssistantMessage
responsePartId: string | undefined
@@ -133,6 +141,7 @@ export function SessionTurn(
const emptyMessages: MessageType[] = []
const emptyParts: PartType[] = []
+ const emptyFiles: FilePart[] = []
const emptyAssistant: AssistantMessage[] = []
const emptyPermissions: PermissionRequest[] = []
const emptyPermissionParts: { part: ToolPart; message: AssistantMessage }[] = []
@@ -180,6 +189,19 @@ export function SessionTurn(
return data.store.part[msg.id] ?? emptyParts
})
+ const attachmentParts = createMemo(() => {
+ const msgParts = parts()
+ if (msgParts.length === 0) return emptyFiles
+ return msgParts.filter((part) => isAttachment(part)) as FilePart[]
+ })
+
+ const stickyParts = createMemo(() => {
+ const msgParts = parts()
+ if (msgParts.length === 0) return emptyParts
+ if (attachmentParts().length === 0) return msgParts
+ return msgParts.filter((part) => !isAttachment(part))
+ })
+
const assistantMessages = createMemo(
() => {
const msg = message()
@@ -331,6 +353,15 @@ export function SessionTurn(
const hideResponsePart = createMemo(() => !working() && !!responsePartId())
const [responseCopied, setResponseCopied] = createSignal(false)
+ const [rootRef, setRootRef] = createSignal()
+ const [stickyRef, setStickyRef] = createSignal()
+
+ const updateStickyHeight = (height: number) => {
+ const root = rootRef()
+ if (!root) return
+ const next = Math.ceil(height)
+ root.style.setProperty("--session-turn-sticky-height", `${next}px`)
+ }
const handleCopyResponse = async () => {
const content = response()
if (!content) return
@@ -361,6 +392,24 @@ export function SessionTurn(
onUserInteracted: props.onUserInteracted,
})
+ createResizeObserver(
+ () => stickyRef(),
+ ({ height }) => {
+ updateStickyHeight(height)
+ },
+ )
+
+ createEffect(() => {
+ const root = rootRef()
+ if (!root) return
+ const sticky = stickyRef()
+ if (!sticky) {
+ root.style.setProperty("--session-turn-sticky-height", "0px")
+ return
+ }
+ updateStickyHeight(sticky.getBoundingClientRect().height)
+ })
+
const diffInit = 20
const diffBatch = 20
@@ -438,7 +487,7 @@ export function SessionTurn(
})
return (
-
+
-
+
0}>
+
+
+
+
+
{/* User Message */}
-
+
{/* Trigger (sticky) */}
From c7f0cb3d2d516e1a4673df1cf5be4ee983a78bfb Mon Sep 17 00:00:00 2001
From: David Hill
Date: Mon, 19 Jan 2026 15:20:28 +0000
Subject: [PATCH 30/42] fix: remove focus outline from dropdown menu
---
packages/ui/src/components/dropdown-menu.css | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/packages/ui/src/components/dropdown-menu.css b/packages/ui/src/components/dropdown-menu.css
index d2dc03c500..cba041613e 100644
--- a/packages/ui/src/components/dropdown-menu.css
+++ b/packages/ui/src/components/dropdown-menu.css
@@ -11,6 +11,11 @@
z-index: 50;
transform-origin: var(--kb-menu-content-transform-origin);
+ &:focus,
+ &:focus-visible {
+ outline: none;
+ }
+
&[data-closed] {
animation: dropdown-menu-close 0.15s ease-out;
}
From 89be504abcb74093342e1ead17d0b7bce5a44ba8 Mon Sep 17 00:00:00 2001
From: David Hill
Date: Mon, 19 Jan 2026 15:43:50 +0000
Subject: [PATCH 31/42] update: align edit project dialog padding and avatar
styles
---
.../app/src/components/dialog-edit-project.tsx | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/packages/app/src/components/dialog-edit-project.tsx b/packages/app/src/components/dialog-edit-project.tsx
index 2f0f7db1f6..8160821b22 100644
--- a/packages/app/src/components/dialog-edit-project.tsx
+++ b/packages/app/src/components/dialog-edit-project.tsx
@@ -78,7 +78,7 @@ export function DialogEditProject(props: { project: LocalProject }) {
return (
From 494e8d5be94c72950476027d08fc6a2faafb5f94 Mon Sep 17 00:00:00 2001
From: David Hill
Date: Mon, 19 Jan 2026 15:57:47 +0000
Subject: [PATCH 33/42] update: tweak edit project icon container
---
packages/app/src/components/dialog-edit-project.tsx | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/packages/app/src/components/dialog-edit-project.tsx b/packages/app/src/components/dialog-edit-project.tsx
index a2a0ba9db6..d47dd9dcc4 100644
--- a/packages/app/src/components/dialog-edit-project.tsx
+++ b/packages/app/src/components/dialog-edit-project.tsx
@@ -94,10 +94,11 @@ export function DialogEditProject(props: { project: LocalProject }) {
Date: Mon, 19 Jan 2026 15:59:11 +0000
Subject: [PATCH 34/42] update: constrain edit project dialog width
---
packages/app/src/components/dialog-edit-project.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/app/src/components/dialog-edit-project.tsx b/packages/app/src/components/dialog-edit-project.tsx
index d47dd9dcc4..81ceb305db 100644
--- a/packages/app/src/components/dialog-edit-project.tsx
+++ b/packages/app/src/components/dialog-edit-project.tsx
@@ -77,7 +77,7 @@ export function DialogEditProject(props: { project: LocalProject }) {
}
return (
-