add timeline tool visibility toggle

This commit is contained in:
Shantur Rathore
2025-12-08 18:32:23 +00:00
parent 8fcf757c5c
commit 7aba3c1221
14 changed files with 48 additions and 14 deletions

12
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "codenomad-workspace", "name": "codenomad-workspace",
"version": "0.2.8", "version": "0.2.9",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "codenomad-workspace", "name": "codenomad-workspace",
"version": "0.2.8", "version": "0.2.9",
"dependencies": { "dependencies": {
"7zip-bin": "^5.2.0", "7zip-bin": "^5.2.0",
"google-auth-library": "^10.5.0" "google-auth-library": "^10.5.0"
@@ -8815,7 +8815,7 @@
}, },
"packages/electron-app": { "packages/electron-app": {
"name": "@neuralnomads/codenomad-electron-app", "name": "@neuralnomads/codenomad-electron-app",
"version": "0.2.8", "version": "0.2.9",
"dependencies": { "dependencies": {
"@codenomad/ui": "file:../ui", "@codenomad/ui": "file:../ui",
"@neuralnomads/codenomad": "file:../server" "@neuralnomads/codenomad": "file:../server"
@@ -8843,7 +8843,7 @@
}, },
"packages/server": { "packages/server": {
"name": "@neuralnomads/codenomad", "name": "@neuralnomads/codenomad",
"version": "0.2.8", "version": "0.2.9",
"dependencies": { "dependencies": {
"@fastify/cors": "^8.5.0", "@fastify/cors": "^8.5.0",
"@fastify/reply-from": "^9.8.0", "@fastify/reply-from": "^9.8.0",
@@ -8882,14 +8882,14 @@
}, },
"packages/tauri-app": { "packages/tauri-app": {
"name": "@codenomad/tauri-app", "name": "@codenomad/tauri-app",
"version": "0.2.8", "version": "0.2.9",
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": "^2.9.4" "@tauri-apps/cli": "^2.9.4"
} }
}, },
"packages/ui": { "packages/ui": {
"name": "@codenomad/ui", "name": "@codenomad/ui",
"version": "0.2.8", "version": "0.2.9",
"dependencies": { "dependencies": {
"@git-diff-view/solid": "^0.0.8", "@git-diff-view/solid": "^0.0.8",
"@kobalte/core": "0.13.11", "@kobalte/core": "0.13.11",

View File

@@ -1,6 +1,6 @@
{ {
"name": "codenomad-workspace", "name": "codenomad-workspace",
"version": "0.2.8", "version": "0.2.9",
"private": true, "private": true,
"description": "CodeNomad monorepo workspace", "description": "CodeNomad monorepo workspace",
"workspaces": { "workspaces": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "@neuralnomads/codenomad-electron-app", "name": "@neuralnomads/codenomad-electron-app",
"version": "0.2.8", "version": "0.2.9",
"description": "CodeNomad - AI coding assistant", "description": "CodeNomad - AI coding assistant",
"author": { "author": {
"name": "Neural Nomads", "name": "Neural Nomads",

View File

@@ -1,12 +1,12 @@
{ {
"name": "@neuralnomads/codenomad", "name": "@neuralnomads/codenomad",
"version": "0.2.8", "version": "0.2.9",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@neuralnomads/codenomad", "name": "@neuralnomads/codenomad",
"version": "0.2.8", "version": "0.2.9",
"dependencies": { "dependencies": {
"@fastify/cors": "^8.5.0", "@fastify/cors": "^8.5.0",
"commander": "^12.1.0", "commander": "^12.1.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@neuralnomads/codenomad", "name": "@neuralnomads/codenomad",
"version": "0.2.8", "version": "0.2.9",
"description": "CodeNomad Server", "description": "CodeNomad Server",
"author": { "author": {
"name": "Neural Nomads", "name": "Neural Nomads",

View File

@@ -11,6 +11,7 @@ const AgentModelSelectionsSchema = z.record(z.string(), AgentModelSelectionSchem
const PreferencesSchema = z.object({ const PreferencesSchema = z.object({
showThinkingBlocks: z.boolean().default(false), showThinkingBlocks: z.boolean().default(false),
thinkingBlocksExpansion: z.enum(["expanded", "collapsed"]).default("expanded"), thinkingBlocksExpansion: z.enum(["expanded", "collapsed"]).default("expanded"),
showTimelineTools: z.boolean().default(true),
lastUsedBinary: z.string().optional(), lastUsedBinary: z.string().optional(),
environmentVariables: z.record(z.string()).default({}), environmentVariables: z.record(z.string()).default({}),
modelRecents: z.array(ModelPreferenceSchema).default([]), modelRecents: z.array(ModelPreferenceSchema).default([]),

View File

@@ -1,6 +1,6 @@
{ {
"name": "@codenomad/tauri-app", "name": "@codenomad/tauri-app",
"version": "0.2.8", "version": "0.2.9",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "npx --yes @tauri-apps/cli@^2.9.4 dev", "dev": "npx --yes @tauri-apps/cli@^2.9.4 dev",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@codenomad/ui", "name": "@codenomad/ui",
"version": "0.2.8", "version": "0.2.9",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {

View File

@@ -52,6 +52,7 @@ const App: Component = () => {
preferences, preferences,
recordWorkspaceLaunch, recordWorkspaceLaunch,
toggleShowThinkingBlocks, toggleShowThinkingBlocks,
toggleShowTimelineTools,
toggleAutoCleanupBlankSessions, toggleAutoCleanupBlankSessions,
toggleUsageMetrics, toggleUsageMetrics,
setDiffViewMode, setDiffViewMode,
@@ -222,6 +223,7 @@ const App: Component = () => {
preferences, preferences,
toggleAutoCleanupBlankSessions, toggleAutoCleanupBlankSessions,
toggleShowThinkingBlocks, toggleShowThinkingBlocks,
toggleShowTimelineTools,
toggleUsageMetrics, toggleUsageMetrics,
setDiffViewMode, setDiffViewMode,
setToolOutputExpansion, setToolOutputExpansion,

View File

@@ -39,6 +39,7 @@ export interface MessageSectionProps {
export default function MessageSection(props: MessageSectionProps) { export default function MessageSection(props: MessageSectionProps) {
const { preferences } = useConfig() const { preferences } = useConfig()
const showUsagePreference = () => preferences().showUsageMetrics ?? true const showUsagePreference = () => preferences().showUsageMetrics ?? true
const showTimelineToolsPreference = () => preferences().showTimelineTools ?? true
const store = createMemo<InstanceMessageStore>(() => messageStoreBus.getOrCreate(props.instanceId)) const store = createMemo<InstanceMessageStore>(() => messageStoreBus.getOrCreate(props.instanceId))
const messageIds = createMemo(() => store().getSessionMessageIds(props.sessionId)) const messageIds = createMemo(() => store().getSessionMessageIds(props.sessionId))
@@ -639,6 +640,7 @@ export default function MessageSection(props: MessageSectionProps) {
activeMessageId={activeMessageId()} activeMessageId={activeMessageId()}
instanceId={props.instanceId} instanceId={props.instanceId}
sessionId={props.sessionId} sessionId={props.sessionId}
showToolSegments={showTimelineToolsPreference()}
/> />
</div> </div>
</Show> </Show>

View File

@@ -24,6 +24,7 @@ interface MessageTimelineProps {
activeMessageId?: string | null activeMessageId?: string | null
instanceId: string instanceId: string
sessionId: string sessionId: string
showToolSegments?: boolean
} }
const SEGMENT_LABELS: Record<TimelineSegmentType, string> = { const SEGMENT_LABELS: Record<TimelineSegmentType, string> = {
@@ -239,6 +240,7 @@ const MessageTimeline: Component<MessageTimelineProps> = (props) => {
const [hoveredSegment, setHoveredSegment] = createSignal<TimelineSegment | null>(null) const [hoveredSegment, setHoveredSegment] = createSignal<TimelineSegment | null>(null)
const [tooltipCoords, setTooltipCoords] = createSignal<{ top: number; left: number }>({ top: 0, left: 0 }) const [tooltipCoords, setTooltipCoords] = createSignal<{ top: number; left: number }>({ top: 0, left: 0 })
let hoverTimer: number | null = null let hoverTimer: number | null = null
const showTools = () => props.showToolSegments ?? true
const registerButtonRef = (segmentId: string, element: HTMLButtonElement | null) => { const registerButtonRef = (segmentId: string, element: HTMLButtonElement | null) => {
if (element) { if (element) {
@@ -313,6 +315,7 @@ const MessageTimeline: Component<MessageTimelineProps> = (props) => {
{(segment) => { {(segment) => {
onCleanup(() => buttonRefs.delete(segment.id)) onCleanup(() => buttonRefs.delete(segment.id))
const isActive = () => props.activeMessageId === segment.messageId const isActive = () => props.activeMessageId === segment.messageId
const isHidden = () => segment.type === "tool" && !(showTools() || isActive())
const shortLabelContent = () => { const shortLabelContent = () => {
if (segment.type === "tool") { if (segment.type === "tool") {
return segment.shortLabel ?? getToolIcon("tool") return segment.shortLabel ?? getToolIcon("tool")
@@ -326,8 +329,9 @@ const MessageTimeline: Component<MessageTimelineProps> = (props) => {
<button <button
ref={(el) => registerButtonRef(segment.id, el)} ref={(el) => registerButtonRef(segment.id, el)}
type="button" type="button"
class={`message-timeline-segment message-timeline-${segment.type} ${isActive() ? "message-timeline-segment-active" : ""}`} class={`message-timeline-segment message-timeline-${segment.type} ${isActive() ? "message-timeline-segment-active" : ""} ${isHidden() ? "message-timeline-segment-hidden" : ""}`}
aria-current={isActive() ? "true" : undefined} aria-current={isActive() ? "true" : undefined}
aria-hidden={isHidden() ? "true" : undefined}
onClick={() => props.onSegmentClick?.(segment)} onClick={() => props.onSegmentClick?.(segment)}
onMouseEnter={(event) => handleMouseEnter(segment, event)} onMouseEnter={(event) => handleMouseEnter(segment, event)}
onMouseLeave={handleMouseLeave} onMouseLeave={handleMouseLeave}

View File

@@ -24,6 +24,7 @@ const log = getLogger("actions")
export interface UseCommandsOptions { export interface UseCommandsOptions {
preferences: Accessor<Preferences> preferences: Accessor<Preferences>
toggleShowThinkingBlocks: () => void toggleShowThinkingBlocks: () => void
toggleShowTimelineTools: () => void
toggleUsageMetrics: () => void toggleUsageMetrics: () => void
toggleAutoCleanupBlankSessions: () => void toggleAutoCleanupBlankSessions: () => void
setDiffViewMode: (mode: "split" | "unified") => void setDiffViewMode: (mode: "split" | "unified") => void
@@ -410,6 +411,15 @@ export function useCommands(options: UseCommandsOptions) {
action: options.toggleShowThinkingBlocks, action: options.toggleShowThinkingBlocks,
}) })
commandRegistry.register({
id: "timeline-tools",
label: () => `${options.preferences().showTimelineTools ? "Hide" : "Show"} Timeline Tool Calls`,
description: "Toggle tool call entries in the message timeline",
category: "System",
keywords: ["timeline", "tool", "toggle"],
action: options.toggleShowTimelineTools,
})
commandRegistry.register({ commandRegistry.register({
id: "thinking-default-visibility", id: "thinking-default-visibility",
label: () => { label: () => {

View File

@@ -35,6 +35,7 @@ export type ListeningMode = "local" | "all"
export interface Preferences { export interface Preferences {
showThinkingBlocks: boolean showThinkingBlocks: boolean
thinkingBlocksExpansion: ExpansionPreference thinkingBlocksExpansion: ExpansionPreference
showTimelineTools: boolean
lastUsedBinary?: string lastUsedBinary?: string
environmentVariables: Record<string, string> environmentVariables: Record<string, string>
modelRecents: ModelPreference[] modelRecents: ModelPreference[]
@@ -67,6 +68,7 @@ const MAX_RECENT_MODELS = 5
const defaultPreferences: Preferences = { const defaultPreferences: Preferences = {
showThinkingBlocks: false, showThinkingBlocks: false,
thinkingBlocksExpansion: "expanded", thinkingBlocksExpansion: "expanded",
showTimelineTools: true,
environmentVariables: {}, environmentVariables: {},
modelRecents: [], modelRecents: [],
diffViewMode: "split", diffViewMode: "split",
@@ -103,6 +105,7 @@ function normalizePreferences(pref?: Partial<Preferences> & { agentModelSelectio
return { return {
showThinkingBlocks: sanitized.showThinkingBlocks ?? defaultPreferences.showThinkingBlocks, showThinkingBlocks: sanitized.showThinkingBlocks ?? defaultPreferences.showThinkingBlocks,
thinkingBlocksExpansion: sanitized.thinkingBlocksExpansion ?? defaultPreferences.thinkingBlocksExpansion, thinkingBlocksExpansion: sanitized.thinkingBlocksExpansion ?? defaultPreferences.thinkingBlocksExpansion,
showTimelineTools: sanitized.showTimelineTools ?? defaultPreferences.showTimelineTools,
lastUsedBinary: sanitized.lastUsedBinary ?? defaultPreferences.lastUsedBinary, lastUsedBinary: sanitized.lastUsedBinary ?? defaultPreferences.lastUsedBinary,
environmentVariables, environmentVariables,
modelRecents, modelRecents,
@@ -301,6 +304,10 @@ function toggleShowThinkingBlocks(): void {
updatePreferences({ showThinkingBlocks: !preferences().showThinkingBlocks }) updatePreferences({ showThinkingBlocks: !preferences().showThinkingBlocks })
} }
function toggleShowTimelineTools(): void {
updatePreferences({ showTimelineTools: !preferences().showTimelineTools })
}
function toggleUsageMetrics(): void { function toggleUsageMetrics(): void {
updatePreferences({ showUsageMetrics: !preferences().showUsageMetrics }) updatePreferences({ showUsageMetrics: !preferences().showUsageMetrics })
} }
@@ -411,8 +418,10 @@ interface ConfigContextValue {
setThemePreference: typeof setThemePreference setThemePreference: typeof setThemePreference
updateConfig: typeof updateConfig updateConfig: typeof updateConfig
toggleShowThinkingBlocks: typeof toggleShowThinkingBlocks toggleShowThinkingBlocks: typeof toggleShowThinkingBlocks
toggleShowTimelineTools: typeof toggleShowTimelineTools
toggleUsageMetrics: typeof toggleUsageMetrics toggleUsageMetrics: typeof toggleUsageMetrics
toggleAutoCleanupBlankSessions: typeof toggleAutoCleanupBlankSessions toggleAutoCleanupBlankSessions: typeof toggleAutoCleanupBlankSessions
setDiffViewMode: typeof setDiffViewMode setDiffViewMode: typeof setDiffViewMode
setToolOutputExpansion: typeof setToolOutputExpansion setToolOutputExpansion: typeof setToolOutputExpansion
setDiagnosticsExpansion: typeof setDiagnosticsExpansion setDiagnosticsExpansion: typeof setDiagnosticsExpansion
@@ -445,6 +454,7 @@ const configContextValue: ConfigContextValue = {
setThemePreference, setThemePreference,
updateConfig, updateConfig,
toggleShowThinkingBlocks, toggleShowThinkingBlocks,
toggleShowTimelineTools,
toggleUsageMetrics, toggleUsageMetrics,
toggleAutoCleanupBlankSessions, toggleAutoCleanupBlankSessions,
setDiffViewMode, setDiffViewMode,
@@ -503,6 +513,7 @@ export {
updateConfig, updateConfig,
updatePreferences, updatePreferences,
toggleShowThinkingBlocks, toggleShowThinkingBlocks,
toggleShowTimelineTools,
toggleAutoCleanupBlankSessions, toggleAutoCleanupBlankSessions,
toggleUsageMetrics, toggleUsageMetrics,
recentFolders, recentFolders,

View File

@@ -80,6 +80,10 @@
transition: transform 0.15s ease, background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease; transition: transform 0.15s ease, background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
} }
.message-timeline-segment.message-timeline-segment-hidden {
display: none !important;
}
.message-timeline-segment-active { .message-timeline-segment-active {
border-color: transparent; border-color: transparent;
background-color: #0f5b44; background-color: #0f5b44;