Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
7af958f
feat(chat): render subagent activity inline as collapsible tool wrapper
michalkopanski Mar 29, 2026
880719c
fix(chat): add gradient fade-out and bottom padding to input footer
michalkopanski Mar 30, 2026
4cdc8ca
feat(ui): redesign ToolInput/ToolOutput/ToolHeader — compact, monospaced
michalkopanski Mar 30, 2026
40f9b8c
fix(ui): stop scroll anchor when clicking tool call triggers
michalkopanski Mar 30, 2026
130f677
feat(ui): add ToolCallRow and refactor tool components
michalkopanski Mar 30, 2026
f16d3c8
feat(desktop): refactor tool call components to use shared ToolCallRow
michalkopanski Mar 30, 2026
0c24828
feat(chat): replace inline question UI with footer overlay
michalkopanski Mar 30, 2026
8d49b00
feat(ui): replace tool call header indicators with braille spinner an…
michalkopanski Mar 30, 2026
4330a0b
feat(chat): hide Question tool row while active, show with descriptio…
michalkopanski Mar 30, 2026
255d90b
feat(chat): improve tool call UX and styling
michalkopanski Mar 30, 2026
4bd8e4f
fix(chat): keep answered question messages visible during active turn
michalkopanski Mar 30, 2026
db77831
fix(chat): refactor question tool call — answer bubble, skip badge, p…
michalkopanski Mar 30, 2026
5f94788
fix(chat): overlay freezes in place on submit, skip sends answer, scr…
michalkopanski Mar 30, 2026
1f646a9
feat(chat): question overlay max-height with scrollable options and p…
michalkopanski Mar 30, 2026
5318d6f
fix(chat): stabilize useFocusPromptOnPane effect dependency
michalkopanski Mar 30, 2026
cce5656
feat(chat): show question tool call with status and collapsible answer
michalkopanski Mar 30, 2026
84d3190
fix(chat): keep question tool calls visible during active assistant turn
michalkopanski Mar 30, 2026
81c5cf3
feat(chat): optimistically hide question overlay on answer submit
michalkopanski Mar 30, 2026
d7460fe
feat(chat): scroll to bottom on message send, question arrival, and a…
michalkopanski Mar 30, 2026
8cbffcf
feat(chat): show cancelled status when question is aborted
michalkopanski Mar 30, 2026
ac88901
fix(chat): keep bottom-pinned scroll when expanding a tool call
michalkopanski Mar 30, 2026
475bf66
fix(chat): exclude scrollbar column from input footer gradient
michalkopanski Mar 30, 2026
7d00430
fix(chat): stop scroll jump when expanding any tool call
michalkopanski Mar 30, 2026
5675dc9
feat(chat): always use ask_user tool for questions in Superset
michalkopanski Mar 30, 2026
7ee9874
feat(chat): pending question drives workspace nav status and native n…
michalkopanski Mar 30, 2026
9e376ca
fix(chat): clear orange dot on answer submit, focus prompt on dismiss…
michalkopanski Mar 30, 2026
17cd679
feat(chat): render subagent task prompt with markdown via MessageResp…
michalkopanski Mar 31, 2026
7bd9a27
fix(chat): scale down headings and fix list layout in subagent output
michalkopanski Mar 31, 2026
6142b82
feat(chat): render read file tool output with syntax-highlighted code…
michalkopanski Mar 31, 2026
55de0fb
feat(chat): improve tool call error and task_write UX
michalkopanski Mar 31, 2026
41015ef
fix(chat): add vertical padding to read file tool content area
michalkopanski Mar 31, 2026
ec717d6
feat(chat): add LspInspectToolCall with ActivityIcon and file subtitle
michalkopanski Mar 31, 2026
3eb1d85
fix(chat): handle mastra_workspace_lsp_inspect tool name alias
michalkopanski Mar 31, 2026
abd2f9e
fix(chat): use FileSearchIcon for LSP Inspect tool call
michalkopanski Mar 31, 2026
d35a014
feat(chat): show input/output content in LSP Inspect tool call
michalkopanski Mar 31, 2026
f475669
fix(chat): use SearchCheckIcon for LSP Inspect tool call
michalkopanski Mar 31, 2026
93606f4
fix(chat): extract TOOL_CALL_MD_CLASSNAME for global compact markdown…
michalkopanski Mar 31, 2026
f2fd66a
feat(chat): improve subagent tool call display and share read-file co…
michalkopanski Mar 31, 2026
14b3da8
fix(chat): forward workspace props to ReadOnlyToolCall in MessagePart…
michalkopanski Mar 31, 2026
a4b460c
fix(chat): remove dead code from MessageList
michalkopanski Mar 31, 2026
11f4cfa
fix(chat): fix type safety, path normalization, and memoize in Subage…
michalkopanski Mar 31, 2026
0c13932
fix(chat): add stale time and loading state to ReadOnlyToolCall file …
michalkopanski Mar 31, 2026
baea6f2
feat(chat): replace text input with Tiptap editor for slash commands …
michalkopanski Apr 2, 2026
0b03217
feat(chat): add skill preload — /command chips trigger skill tool cal…
michalkopanski Apr 2, 2026
0b1b54b
feat(ui): update shared AI element components for chat UX
michalkopanski Apr 2, 2026
95a415f
fix(chat): improve tool call display components
michalkopanski Apr 2, 2026
2bff60e
fix(chat): update message list and subagent execution display
michalkopanski Apr 2, 2026
fb535c5
fix(chat): suppress empty assistant message wrappers
michalkopanski Apr 11, 2026
7c5ed92
feat(chat): show styled "Not Configured" state for LSP inspect when L…
michalkopanski Apr 11, 2026
5613ce1
feat(chat): universal "not configured" warning on tool call rows
michalkopanski Apr 11, 2026
a1fc29d
fix(chat): move not-configured warning icon inline after description
michalkopanski Apr 11, 2026
1a6943c
feat(chat): clickable file names on file-related tool call rows
michalkopanski Apr 11, 2026
4c5e8ca
feat(ui): add ShowCode component with expand/collapse, copy, and star…
michalkopanski Apr 12, 2026
7aa6f90
refactor: replace legacy syntax highlighters with ShowCode
michalkopanski Apr 12, 2026
d5b8244
fix(chat): address PR review feedback
michalkopanski Apr 17, 2026
c304ca1
fix(chat): address second round of PR review feedback
michalkopanski Apr 17, 2026
43b1008
fix(chat): address third round of PR review feedback
michalkopanski Apr 17, 2026
fdd495b
fix(chat): address fourth round of PR review feedback
michalkopanski Apr 17, 2026
67a0910
chore: formatting and cleanup
michalkopanski Apr 17, 2026
b7b36d4
fix(chat): close mention popup before falling through Enter when resu…
michalkopanski Apr 17, 2026
ad85fd3
fix(chat): address fifth round of PR review feedback
michalkopanski Apr 17, 2026
41e644d
chore: rebuild bun.lock after rebase
michalkopanski Apr 17, 2026
e3ffd60
Merge main
Kitenite Apr 18, 2026
ba9cae4
Fix typecheck
Kitenite Apr 18, 2026
8159d2a
Merge remote-tracking branch 'origin/main' into chat-ux-enhancements
Kitenite Apr 18, 2026
d106a51
refactor(chat): align skill handling with upstream mastra
Kitenite Apr 18, 2026
8ee4d16
chore(deps): bump mastra to 0.15.0-alpha.3 / 1.26.0-alpha.3
Kitenite Apr 18, 2026
648ec0b
chore: alphabetize @tiptap/pm in desktop package.json
Kitenite Apr 18, 2026
a246c4b
fix(chat): cut display polling to 4fps and restore query cache defaul…
Kitenite Apr 18, 2026
5131e3b
feat(chat): slash command chip UX enhancements
michalkopanski Apr 18, 2026
1bece5c
chore: refresh bun.lock after pull
Kitenite Apr 18, 2026
6a2dc0e
Merge remote-tracking branch 'origin' into chat-ux-enhancements
Kitenite Apr 18, 2026
dbd7bdf
test(chat): drop shallow ChatMessageList snapshot tests
Kitenite Apr 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Superset Monorepo Guide

## Question Tool

When you need to ask the user ANY question — including simple yes/no, confirmations, and clarifications — ALWAYS use the `ask_user` tool. Never ask questions in plain text. The Superset UI renders `ask_user` calls as an interactive overlay with clickable option buttons; plain-text questions will not be surfaced to the user in the same way.

Guidelines for agents and developers working in this repository.

## Structure
Expand Down
6 changes: 4 additions & 2 deletions apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
"@hono/node-server": "^1.14.1",
"@hookform/resolvers": "^5.2.2",
"@lezer/highlight": "^1.2.3",
"@mastra/core": "1.25.0",
"@mastra/core": "1.26.0-alpha.3",
"@parcel/watcher": "^2.5.6",
"@pierre/diffs": "1.1.3",
"@radix-ui/react-dialog": "^1.1.15",
Expand Down Expand Up @@ -130,6 +130,7 @@
"@tiptap/extension-task-list": "^3.17.1",
"@tiptap/extension-text": "^3.17.1",
"@tiptap/extension-underline": "^3.17.1",
"@tiptap/pm": "^3.17.1",
"@tiptap/react": "^3.17.1",
"@tiptap/starter-kit": "^3.17.1",
"@tiptap/suggestion": "^3.17.1",
Expand Down Expand Up @@ -182,7 +183,7 @@
"lowdb": "^7.0.1",
"lowlight": "^3.3.0",
"lucide-react": "^0.563.0",
"mastracode": "0.14.0",
"mastracode": "0.15.0-alpha.3",
"nanoid": "^5.1.6",
"node-addon-api": "^7.1.0",
"node-pty": "1.1.0",
Expand All @@ -209,6 +210,7 @@
"semver": "^7.7.3",
"shell-env": "^4.0.3",
"shell-quote": "^1.8.3",
"shiki": "^3.21.0",
"simple-git": "^3.30.0",
"streamdown": "2.5.0",
"strip-ansi": "^7.1.2",
Expand Down
15 changes: 9 additions & 6 deletions apps/desktop/src/main/lib/notifications/notification-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,16 @@ export class NotificationManager {
const title = this.deps.getNotificationTitle(event);

const isPermissionRequest = event.eventType === "PermissionRequest";
const isPendingQuestion = event.eventType === "PendingQuestion";
const notification = this.deps.createNotification({
title: isPermissionRequest
? `Input Needed — ${workspaceName}`
: `Agent Complete — ${workspaceName}`,
body: isPermissionRequest
? `"${title}" needs your attention`
: `"${title}" has finished its task`,
title:
isPermissionRequest || isPendingQuestion
? `Awaiting Response — ${workspaceName}`
: `Agent Complete — ${workspaceName}`,
body:
isPermissionRequest || isPendingQuestion
? `"${title}" is waiting for your reply`
: `"${title}" has finished its task`,
silent: true,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,25 @@ import {
PromptInputAttachment,
PromptInputAttachments,
type PromptInputMessage,
PromptInputTextarea,
usePromptInputController,
} from "@superset/ui/ai-elements/prompt-input";
import type { ThinkingLevel } from "@superset/ui/ai-elements/thinking-toggle";
import type { ChatStatus, FileUIPart } from "ai";
import type React from "react";
import type { ReactNode } from "react";
import { useCallback, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { useFocusPromptOnPane } from "renderer/components/Chat/ChatInterface/hooks/useFocusPromptOnPane";
import { useHotkeyDisplay } from "renderer/hotkeys";
import type { SlashCommand } from "../../hooks/useSlashCommands";
import type { ModelOption, PermissionMode } from "../../types";
import { IssueLinkCommand } from "../IssueLinkCommand";
import { MentionAnchor, MentionProvider } from "../MentionPopover";
import { SlashCommandInput } from "../SlashCommandInput";
import { TiptapPromptEditor } from "../TiptapPromptEditor";
import { ChatComposerControls } from "./components/ChatComposerControls";
import { ChatInputDropZone } from "./components/ChatInputDropZone";
import { ChatShortcuts } from "./components/ChatShortcuts";
import { FileDropOverlay } from "./components/FileDropOverlay";
import { LinkedIssues } from "./components/LinkedIssues";
import { SlashCommandPreview } from "./components/SlashCommandPreview";
import { QuestionInputOverlay } from "./components/QuestionInputOverlay";
import type { LinkedIssue } from "./types";
import { getErrorMessage } from "./utils/getErrorMessage";

Expand All @@ -48,7 +47,14 @@ interface ChatInputFooterProps {
onSubmitEnd?: () => void;
onSend: (message: PromptInputMessage) => Promise<void> | void;
onStop: (e: React.MouseEvent) => void;
onSlashCommandSend: (command: SlashCommand) => void;
pendingQuestion?: {
questionId: string;
question: string;
options?: { label: string; description?: string }[];
} | null;
isQuestionSubmitting?: boolean;
onQuestionRespond?: (questionId: string, answer: string) => Promise<void>;
onQuestionCancel?: () => void;
}

export function ChatInputFooter({
Expand All @@ -73,9 +79,27 @@ export function ChatInputFooter({
onSubmitEnd,
onSend,
onStop,
onSlashCommandSend,
pendingQuestion,
isQuestionSubmitting,
onQuestionRespond,
onQuestionCancel,
}: ChatInputFooterProps) {
useFocusPromptOnPane(isFocused);

// Focus the prompt when the question overlay dismisses (pendingQuestion → null).
// Uses rAF so the editor has time to mount, register its ref, and browser
// focus-stealing from the unmounting overlay has settled.
const { textInput } = usePromptInputController();
const prevPendingQuestionRef = useRef(pendingQuestion);
useEffect(() => {
const prev = prevPendingQuestionRef.current;
prevPendingQuestionRef.current = pendingQuestion;
if (prev != null && pendingQuestion == null) {
const id = requestAnimationFrame(() => textInput.focus());
return () => cancelAnimationFrame(id);
}
}, [pendingQuestion, textInput]);

const [issueLinkOpen, setIssueLinkOpen] = useState(false);
const [linkedIssues, setLinkedIssues] = useState<LinkedIssue[]>([]);
const inputRootRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -115,7 +139,7 @@ export function ChatInputFooter({
);

return (
<ChatInputDropZone className="bg-background px-4 py-3">
<ChatInputDropZone className="relative bg-background px-4 pb-3 before:pointer-events-none before:absolute before:left-0 before:right-3 before:-top-8 before:h-8 before:bg-gradient-to-t before:from-background before:to-transparent">
{(dragType) => (
<div className="mx-auto w-full max-w-[680px]">
{errorMessage && (
Expand All @@ -126,82 +150,78 @@ export function ChatInputFooter({
{errorMessage}
</p>
)}
<SlashCommandInput
onCommandSend={onSlashCommandSend}
commands={slashCommands}
>
<MentionProvider cwd={cwd}>
<MentionAnchor>
<div
ref={inputRootRef}
className={
dragType === "path"
? "relative opacity-50 transition-opacity"
: "relative"
{pendingQuestion && onQuestionRespond && onQuestionCancel ? (
<QuestionInputOverlay
question={pendingQuestion}
isSubmitting={isQuestionSubmitting ?? false}
onRespond={onQuestionRespond}
onCancel={onQuestionCancel}
/>
) : (
<div
ref={inputRootRef}
className={
dragType === "path"
? "relative opacity-50 transition-opacity"
: "relative"
}
>
<PromptInput
className="[&>[data-slot=input-group]]:rounded-[13px] [&>[data-slot=input-group]]:border-[0.5px] [&>[data-slot=input-group]]:shadow-none [&>[data-slot=input-group]]:bg-foreground/[0.02]"
onSubmitStart={onSubmitStart}
onSubmitEnd={onSubmitEnd}
onSubmit={handleSend}
multiple
maxFiles={5}
maxFileSize={10 * 1024 * 1024}
globalDrop
>
<ChatShortcuts
isFocused={isFocused}
setIssueLinkOpen={setIssueLinkOpen}
/>
<IssueLinkCommand
open={issueLinkOpen}
onOpenChange={setIssueLinkOpen}
onSelect={addLinkedIssue}
/>
<FileDropOverlay visible={dragType === "files"} />
<PromptInputAttachments>
{renderAttachment ??
((file) => <PromptInputAttachment data={file} />)}
</PromptInputAttachments>
<LinkedIssues
issues={linkedIssues}
onRemove={removeLinkedIssue}
/>
<TiptapPromptEditor
cwd={cwd}
slashCommands={slashCommands}
availableModels={availableModels}
placeholder="Ask to make changes, @mention files, run /commands"
focusShortcutText={
showFocusHint ? focusShortcutText : undefined
}
>
{showFocusHint && (
<span className="pointer-events-none absolute top-3 right-3 z-10 text-xs text-muted-foreground/50 [:focus-within>&]:hidden">
{focusShortcutText} to focus
</span>
)}
<PromptInput
className="[&>[data-slot=input-group]]:rounded-[13px] [&>[data-slot=input-group]]:border-[0.5px] [&>[data-slot=input-group]]:shadow-none [&>[data-slot=input-group]]:bg-foreground/[0.02]"
onSubmitStart={onSubmitStart}
onSubmitEnd={onSubmitEnd}
onSubmit={handleSend}
multiple
maxFiles={5}
maxFileSize={10 * 1024 * 1024}
globalDrop
>
<ChatShortcuts
isFocused={isFocused}
setIssueLinkOpen={setIssueLinkOpen}
/>
<IssueLinkCommand
open={issueLinkOpen}
onOpenChange={setIssueLinkOpen}
onSelect={addLinkedIssue}
/>
<FileDropOverlay visible={dragType === "files"} />
<PromptInputAttachments>
{renderAttachment ??
((file) => <PromptInputAttachment data={file} />)}
</PromptInputAttachments>
<LinkedIssues
issues={linkedIssues}
onRemove={removeLinkedIssue}
/>
<SlashCommandPreview
cwd={cwd}
slashCommands={slashCommands}
/>
<PromptInputTextarea
placeholder="Ask to make changes, @mention files, run /commands"
className="min-h-10"
/>
<ChatComposerControls
availableModels={availableModels}
selectedModel={selectedModel}
setSelectedModel={setSelectedModel}
modelSelectorOpen={modelSelectorOpen}
setModelSelectorOpen={setModelSelectorOpen}
permissionMode={permissionMode}
setPermissionMode={setPermissionMode}
thinkingLevel={thinkingLevel}
setThinkingLevel={setThinkingLevel}
canAbort={canAbort}
submitStatus={submitStatus}
submitDisabled={submitDisabled}
onStop={onStop}
onLinkIssue={() => setIssueLinkOpen(true)}
/>
</PromptInput>
</div>
</MentionAnchor>
</MentionProvider>
</SlashCommandInput>
/>
<ChatComposerControls
availableModels={availableModels}
selectedModel={selectedModel}
setSelectedModel={setSelectedModel}
modelSelectorOpen={modelSelectorOpen}
setModelSelectorOpen={setModelSelectorOpen}
permissionMode={permissionMode}
setPermissionMode={setPermissionMode}
thinkingLevel={thinkingLevel}
setThinkingLevel={setThinkingLevel}
canAbort={canAbort}
submitStatus={submitStatus}
submitDisabled={submitDisabled}
onStop={onStop}
onLinkIssue={() => setIssueLinkOpen(true)}
/>
</PromptInput>
</div>
)}
<div className="py-1.5" />
</div>
)}
Expand Down
Loading
Loading