Refactor chat file-link opens to a single disposition seam (#1038)

* Open chat file links in a side pane on cmd-click

* Add hover tooltips to file links showing cmd-click hint

* Collapse file-link open path to a single disposition seam

Replace the parallel "open in side" callback that was threaded
alongside the normal open callback at every layer between the chat
click handler and the workspace router. One callback now carries a
`OpenFileDisposition` ("main" | "side") so the modifier-key decision
lives at the leaf and the routing decision lives at the workspace
screen, with no branching in between.

* Give assistant file links a home
This commit is contained in:
Mohamed Boudra
2026-05-16 17:27:20 +08:00
committed by GitHub
parent 4b02daed8a
commit 618b4a30b1
15 changed files with 684 additions and 227 deletions
@@ -75,6 +75,7 @@ import {
type BottomAnchorRouteRequest,
} from "./use-bottom-anchor-controller";
import { normalizeInlinePathTarget } from "@/utils/inline-path";
import type { OpenFileDisposition } from "@/utils/workspace-file-open";
import { resolveWorkspaceIdByExecutionDirectory } from "@/utils/workspace-execution";
import { navigateToPreparedWorkspaceTab } from "@/utils/workspace-navigation";
import { useStableEvent } from "@/hooks/use-stable-event";
@@ -242,7 +243,7 @@ export interface AgentStreamViewProps {
routeBottomAnchorRequest?: BottomAnchorRouteRequest | null;
isAuthoritativeHistoryReady?: boolean;
toast?: ToastApi | null;
onOpenWorkspaceFile?: (input: { filePath: string }) => void;
onOpenWorkspaceFile?: (input: { filePath: string; disposition: OpenFileDisposition }) => void;
}
const EMPTY_STREAM_HEAD: StreamItem[] = [];
@@ -304,6 +305,7 @@ const AgentStreamViewComponent = forwardRef<AgentStreamViewHandle, AgentStreamVi
});
const openWorkspaceFile = useStableEvent(function openWorkspaceFile(input: {
filePath: string;
disposition: OpenFileDisposition;
}) {
onOpenWorkspaceFile?.(input);
});
@@ -323,7 +325,7 @@ const AgentStreamViewComponent = forwardRef<AgentStreamViewHandle, AgentStreamVi
}, [agentId]);
const handleInlinePathPress = useCallback(
(target: InlinePathTarget) => {
(target: InlinePathTarget, disposition: OpenFileDisposition) => {
if (!target.path) {
return;
}
@@ -335,7 +337,7 @@ const AgentStreamViewComponent = forwardRef<AgentStreamViewHandle, AgentStreamVi
if (normalized.file) {
if (onOpenWorkspaceFile) {
openWorkspaceFile({ filePath: normalized.file });
openWorkspaceFile({ filePath: normalized.file, disposition });
return;
}
@@ -381,7 +383,7 @@ const AgentStreamViewComponent = forwardRef<AgentStreamViewHandle, AgentStreamVi
const handleToolCallOpenFile = useCallback(
(filePath: string) => {
handleInlinePathPress({ raw: filePath, path: filePath });
handleInlinePathPress({ raw: filePath, path: filePath }, "main");
},
[handleInlinePathPress],
);