Skip to content

Commit 3e31dbc

Browse files
author
Chris Scott
committed
Fix parent/child session navigation for task tool calls
1 parent d61da27 commit 3e31dbc

2 files changed

Lines changed: 44 additions & 28 deletions

File tree

frontend/src/components/message/ToolCallPart.tsx

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,15 @@ import type { components } from '@/api/opencode-types'
33
import { useSettings } from '@/hooks/useSettings'
44
import { useUserBash } from '@/stores/userBashStore'
55
import { detectFileReferences } from '@/lib/fileReferences'
6-
import { Copy } from 'lucide-react'
7-
8-
function CopyButton({ content, title, className = "" }: { content: string; title: string; className?: string }) {
9-
const handleCopy = async () => {
10-
try {
11-
await navigator.clipboard.writeText(content)
12-
} catch (error) {
13-
console.error('Failed to copy content:', error)
14-
}
15-
}
16-
17-
if (!content.trim()) {
18-
return null
19-
}
20-
21-
return (
22-
<button
23-
onClick={handleCopy}
24-
className={`p-1.5 rounded bg-card hover:bg-card-hover text-muted-foreground hover:text-foreground ${className}`}
25-
title={title}
26-
>
27-
<Copy className="w-4 h-4" />
28-
</button>
29-
)
30-
}
6+
import { ExternalLink } from 'lucide-react'
7+
import { CopyButton } from '@/components/ui/copy-button'
318

329
type ToolPart = components['schemas']['ToolPart']
3310

3411
interface ToolCallPartProps {
3512
part: ToolPart
3613
onFileClick?: (filePath: string, lineNumber?: number) => void
14+
onChildSessionClick?: (sessionId: string) => void
3715
}
3816

3917
function ClickableJson({ json, onFileClick }: { json: unknown; onFileClick?: (filePath: string) => void }) {
@@ -76,7 +54,7 @@ function ClickableJson({ json, onFileClick }: { json: unknown; onFileClick?: (fi
7654
return <pre className="bg-accent p-2 rounded text-xs overflow-x-auto">{parts}</pre>
7755
}
7856

79-
export function ToolCallPart({ part, onFileClick }: ToolCallPartProps) {
57+
export function ToolCallPart({ part, onFileClick, onChildSessionClick }: ToolCallPartProps) {
8058
const { preferences } = useSettings()
8159
const { userBashCommands } = useUserBash()
8260
const outputRef = useRef<HTMLDivElement>(null)
@@ -196,6 +174,22 @@ export function ToolCallPart({ part, onFileClick }: ToolCallPartProps) {
196174
) : previewText ? (
197175
<span className="text-muted-foreground text-xs truncate">{previewText}</span>
198176
) : null}
177+
{part.tool === 'task' && (() => {
178+
const sessionId = (part.metadata?.sessionId ?? (part.state.status !== 'pending' && part.state.metadata?.sessionId)) as string | undefined
179+
return sessionId ? (
180+
<span
181+
onClick={(e) => {
182+
e.stopPropagation()
183+
onChildSessionClick?.(sessionId)
184+
}}
185+
className="text-purple-600 dark:text-purple-400 text-xs hover:text-purple-700 dark:hover:text-purple-300 cursor-pointer underline decoration-dotted flex items-center gap-1"
186+
title="View subagent session"
187+
>
188+
<ExternalLink className="w-3 h-3" />
189+
View Session
190+
</span>
191+
) : null
192+
})()}
199193
<span className="text-muted-foreground text-xs ml-auto">({part.state.status})</span>
200194
</button>
201195

frontend/src/components/session/SessionDetailHeader.tsx

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { BackButton } from "@/components/ui/back-button";
22
import { ContextUsageIndicator } from "@/components/session/ContextUsageIndicator";
33
import { BranchSwitcher } from "@/components/repo/BranchSwitcher";
44
import { Button } from "@/components/ui/button";
5-
import { Loader2, Settings, FolderOpen } from "lucide-react";
5+
import { Loader2, Settings, FolderOpen, CornerUpLeft } from "lucide-react";
66
import { useState } from "react";
77

88
interface Repo {
@@ -25,9 +25,11 @@ interface SessionDetailHeaderProps {
2525
isReconnecting?: boolean;
2626
opcodeUrl: string | null;
2727
repoDirectory: string | undefined;
28+
parentSessionId?: string;
2829
onFileBrowserOpen: () => void;
2930
onSettingsOpen: () => void;
3031
onSessionTitleUpdate: (newTitle: string) => void;
32+
onParentSessionClick?: () => void;
3133
}
3234

3335
export function SessionDetailHeader({
@@ -39,9 +41,11 @@ export function SessionDetailHeader({
3941
isReconnecting,
4042
opcodeUrl,
4143
repoDirectory,
44+
parentSessionId,
4245
onFileBrowserOpen,
4346
onSettingsOpen,
4447
onSessionTitleUpdate,
48+
onParentSessionClick,
4549
}: SessionDetailHeaderProps) {
4650
const [isEditing, setIsEditing] = useState(false);
4751
const [editTitle, setEditTitle] = useState(sessionTitle);
@@ -95,7 +99,25 @@ export function SessionDetailHeader({
9599
<div className="sticky top-0 z-10 border-b border-border bg-gradient-to-b from-background via-background to-background backdrop-blur-sm px-2 sm:px-4 py-1.5 sm:py-2">
96100
<div className="flex items-center justify-between gap-2">
97101
<div className="flex items-center gap-1.5 sm:gap-3 min-w-0 flex-1">
98-
<BackButton to={`/repos/${repoId}`} className="text-xs sm:text-sm" />
102+
{parentSessionId ? (
103+
<>
104+
<Button
105+
variant="ghost"
106+
size="sm"
107+
onClick={onParentSessionClick}
108+
className="text-purple-600 dark:text-purple-400 hover:text-purple-700 dark:hover:text-purple-300 hover:bg-purple-100 dark:hover:bg-purple-900/20 h-7 px-2 gap-1"
109+
title="Back to parent session"
110+
>
111+
<CornerUpLeft className="w-3.5 h-3.5" />
112+
<span className="hidden sm:inline text-xs">Parent</span>
113+
</Button>
114+
<div className="hidden sm:block">
115+
<BackButton to={`/repos/${repoId}`} className="text-xs sm:text-sm" />
116+
</div>
117+
</>
118+
) : (
119+
<BackButton to={`/repos/${repoId}`} className="text-xs sm:text-sm" />
120+
)}
99121
<div className="min-w-0 flex-1">
100122
{isEditing ? (
101123
<form onSubmit={handleTitleSubmit} className="min-w-0">

0 commit comments

Comments
 (0)