Skip to content

Commit 178803f

Browse files
authored
refactor sending prompt to agent from UI (#1539)
## Problem trying to add more things that prompt the agent automatically, and more annotations to the review panel, was getting messy <!-- Who is this for and what problem does it solve? --> <!-- Closes #ISSUE_ID --> ## Changes small refactor: - adds `sendPromptToAgent` util that: - takes in a prompt+task - puts the review panel back to split view if it's open in full view - focuses the main session tab - sends the prompt to the agent - broke out the prompt builders into a new util `reviewPrompts.ts` - made `CommentAnnotation`self-contained -- now it handles building prompt and sending to agent -- so we don't have to thread a million things through a million components - also updated the comment box to match new font styles i still don't like how `task`/`taskId` are getting drilled a million levels deep everywhere, but that happens throughout the whole codebase... i considered a small task context, but it's pretty deeps, i'll revisit that later... for now this just avoids drilling _allll_ the annotation stuff <!-- What did you change and why? --> <!-- If there are frontend changes, include screenshots. --> ## How did you test this? manually <!-- Describe what you tested -- manual steps, automated tests, or both. --> <!-- If you're an agent, only list tests you actually ran. -->
1 parent 1f73cb4 commit 178803f

File tree

9 files changed

+136
-149
lines changed

9 files changed

+136
-149
lines changed

apps/code/src/renderer/features/code-review/components/CloudReviewPage.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import { Flex, Spinner, Text } from "@radix-ui/themes";
55
import { useReviewNavigationStore } from "@renderer/features/code-review/stores/reviewNavigationStore";
66
import type { ChangedFile, Task } from "@shared/types";
77
import { useMemo } from "react";
8-
import { useReviewComment } from "../hooks/useReviewComment";
9-
import type { DiffOptions, OnCommentCallback } from "../types";
8+
import type { DiffOptions } from "../types";
109
import { InteractiveFileDiff } from "./InteractiveFileDiff";
1110
import {
1211
DeferredDiffPlaceholder,
@@ -26,7 +25,6 @@ export function CloudReviewPage({ task }: CloudReviewPageProps) {
2625
);
2726
const { effectiveBranch, prUrl, isRunActive, remoteFiles, isLoading } =
2827
useCloudChangedFiles(taskId, task, isReviewOpen);
29-
const onComment = useReviewComment(taskId);
3028

3129
const allPaths = useMemo(() => remoteFiles.map((f) => f.path), [remoteFiles]);
3230

@@ -102,11 +100,11 @@ export function CloudReviewPage({ task }: CloudReviewPageProps) {
102100
<div key={file.path} data-file-path={file.path}>
103101
<CloudFileDiff
104102
file={file}
103+
taskId={taskId}
105104
prUrl={prUrl}
106105
options={diffOptions}
107106
collapsed={isCollapsed}
108107
onToggle={() => toggleFile(file.path)}
109-
onComment={onComment}
110108
/>
111109
</div>
112110
);
@@ -117,18 +115,18 @@ export function CloudReviewPage({ task }: CloudReviewPageProps) {
117115

118116
function CloudFileDiff({
119117
file,
118+
taskId,
120119
prUrl,
121120
options,
122121
collapsed,
123122
onToggle,
124-
onComment,
125123
}: {
126124
file: ChangedFile;
125+
taskId: string;
127126
prUrl: string | null;
128127
options: DiffOptions;
129128
collapsed: boolean;
130129
onToggle: () => void;
131-
onComment: OnCommentCallback;
132130
}) {
133131
const fileDiff = useMemo((): FileDiffMetadata | undefined => {
134132
if (!file.patch) return undefined;
@@ -158,7 +156,7 @@ function CloudFileDiff({
158156
<InteractiveFileDiff
159157
fileDiff={fileDiff}
160158
options={{ ...options, collapsed }}
161-
onComment={onComment}
159+
taskId={taskId}
162160
renderCustomHeader={(fd) => (
163161
<DiffFileHeader
164162
fileDiff={fd}

apps/code/src/renderer/features/code-review/components/CommentAnnotation.tsx

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
1+
import { sendPromptToAgent } from "@features/sessions/utils/sendPromptToAgent";
2+
import { PaperPlaneTilt, X } from "@phosphor-icons/react";
3+
import type { AnnotationSide } from "@pierre/diffs";
4+
import { Button, IconButton } from "@radix-ui/themes";
15
import { useCallback, useRef } from "react";
6+
import { buildInlineCommentPrompt } from "../utils/reviewPrompts";
27

38
interface CommentAnnotationProps {
4-
onSubmit: (text: string) => void;
5-
onCancel: () => void;
9+
taskId: string;
10+
filePath: string;
11+
startLine: number;
12+
endLine: number;
13+
side: AnnotationSide;
14+
onDismiss: () => void;
615
}
716

817
export function CommentAnnotation({
9-
onSubmit,
10-
onCancel,
18+
taskId,
19+
filePath,
20+
startLine,
21+
endLine,
22+
side,
23+
onDismiss,
1124
}: CommentAnnotationProps) {
1225
const textareaRef = useRef<HTMLTextAreaElement>(null);
1326

@@ -23,9 +36,13 @@ export function CommentAnnotation({
2336
const handleSubmit = useCallback(() => {
2437
const text = textareaRef.current?.value?.trim();
2538
if (text) {
26-
onSubmit(text);
39+
onDismiss();
40+
sendPromptToAgent(
41+
taskId,
42+
buildInlineCommentPrompt(filePath, startLine, endLine, side, text),
43+
);
2744
}
28-
}, [onSubmit]);
45+
}, [taskId, filePath, startLine, endLine, side, onDismiss]);
2946

3047
const handleKeyDown = useCallback(
3148
(e: React.KeyboardEvent) => {
@@ -35,39 +52,34 @@ export function CommentAnnotation({
3552
}
3653
if (e.key === "Escape") {
3754
e.preventDefault();
38-
onCancel();
55+
onDismiss();
3956
}
4057
},
41-
[handleSubmit, onCancel],
58+
[handleSubmit, onDismiss],
4259
);
4360

4461
return (
45-
<div
46-
data-comment-annotation=""
47-
className="whitespace-normal rounded-md border border-[var(--gray-5)] bg-[var(--gray-2)] px-2 py-2.5"
48-
>
49-
<textarea
50-
ref={setTextareaRef}
51-
placeholder="Describe the changes you'd like..."
52-
onKeyDown={handleKeyDown}
53-
className="w-full resize-none rounded border border-[var(--gray-6)] bg-[var(--color-background)] p-1.5 font-inherit text-[13px] text-[var(--gray-12)] leading-normal outline-none"
54-
style={{ minHeight: 48 }}
55-
/>
56-
<div className="mt-1.5 flex items-center gap-1.5">
57-
<button
58-
type="button"
59-
onClick={handleSubmit}
60-
className="cursor-pointer rounded border-none bg-[var(--accent-9)] px-2.5 py-0.5 font-medium text-[var(--gray-1)] text-xs leading-[18px]"
61-
>
62-
Send to agent
63-
</button>
64-
<button
65-
type="button"
66-
onClick={onCancel}
67-
className="cursor-pointer border-none bg-transparent px-2 py-0.5 text-[var(--gray-9)] text-xs leading-[18px]"
68-
>
69-
Cancel
70-
</button>
62+
<div className="px-3 py-1.5">
63+
<div
64+
data-comment-annotation=""
65+
className="whitespace-normal rounded-md border border-[var(--gray-5)] bg-[var(--gray-2)] px-2.5 py-2 font-sans"
66+
>
67+
<textarea
68+
ref={setTextareaRef}
69+
placeholder="Describe the changes you'd like..."
70+
onKeyDown={handleKeyDown}
71+
className="w-full resize-none rounded border border-[var(--gray-6)] bg-[var(--color-background)] p-1.5 text-[13px] text-[var(--gray-12)] leading-normal outline-none"
72+
style={{ minHeight: 48 }}
73+
/>
74+
<div className="mt-1.5 flex items-center gap-3">
75+
<Button size="1" onClick={handleSubmit}>
76+
<PaperPlaneTilt size={12} weight="fill" />
77+
Send to agent
78+
</Button>
79+
<IconButton size="1" variant="ghost" color="gray" onClick={onDismiss}>
80+
<X size={12} />
81+
</IconButton>
82+
</div>
7183
</div>
7284
</div>
7385
);

apps/code/src/renderer/features/code-review/components/InteractiveFileDiff.tsx

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ function PatchDiffView({
3737
repoPath,
3838
options,
3939
renderCustomHeader,
40-
onComment,
40+
taskId,
4141
}: PatchDiffProps) {
4242
const trpc = useTRPC();
4343
const queryClient = useQueryClient();
@@ -78,22 +78,6 @@ function PatchDiffView({
7878
[hunkAnnotations, commentAnnotation],
7979
);
8080

81-
const handleCommentSubmit = useCallback(
82-
(text: string) => {
83-
const meta = commentAnnotation?.metadata;
84-
if (!currentFilePath || !meta || meta.kind !== "comment") return;
85-
reset();
86-
onComment?.(
87-
currentFilePath,
88-
meta.startLine,
89-
meta.endLine,
90-
meta.side,
91-
text,
92-
);
93-
},
94-
[currentFilePath, commentAnnotation, reset, onComment],
95-
);
96-
9781
const handleRevert = useCallback(
9882
async (hunkIndex: number) => {
9983
const filePath = filePathRef.current;
@@ -150,8 +134,16 @@ function PatchDiffView({
150134
const renderAnnotation = useCallback(
151135
(annotation: DiffLineAnnotation<AnnotationMetadata>) => {
152136
if (annotation.metadata.kind === "comment") {
137+
const { startLine, endLine, side } = annotation.metadata;
153138
return (
154-
<CommentAnnotation onSubmit={handleCommentSubmit} onCancel={reset} />
139+
<CommentAnnotation
140+
taskId={taskId ?? ""}
141+
filePath={currentFilePath}
142+
startLine={startLine}
143+
endLine={endLine}
144+
side={side}
145+
onDismiss={reset}
146+
/>
155147
);
156148
}
157149

@@ -184,7 +176,7 @@ function PatchDiffView({
184176
</div>
185177
);
186178
},
187-
[handleRevert, handleCommentSubmit, reset, revertingHunks],
179+
[handleRevert, reset, revertingHunks, taskId, currentFilePath],
188180
);
189181

190182
const mergedOptions = useMemo(
@@ -214,7 +206,7 @@ function FilesDiffView({
214206
newFile,
215207
options,
216208
renderCustomHeader,
217-
onComment,
209+
taskId,
218210
}: FilesDiffProps) {
219211
const {
220212
selectedRange,
@@ -231,24 +223,22 @@ function FilesDiffView({
231223
[commentAnnotation],
232224
);
233225

234-
const handleCommentSubmit = useCallback(
235-
(text: string) => {
236-
const meta = commentAnnotation?.metadata;
237-
if (!filePath || !meta || meta.kind !== "comment") return;
238-
reset();
239-
onComment?.(filePath, meta.startLine, meta.endLine, meta.side, text);
240-
},
241-
[filePath, commentAnnotation, reset, onComment],
242-
);
243-
244226
const renderAnnotation = useCallback(
245227
(annotation: DiffLineAnnotation<AnnotationMetadata>) => {
246228
if (annotation.metadata.kind !== "comment") return null;
229+
const { startLine, endLine, side } = annotation.metadata;
247230
return (
248-
<CommentAnnotation onSubmit={handleCommentSubmit} onCancel={reset} />
231+
<CommentAnnotation
232+
taskId={taskId ?? ""}
233+
filePath={filePath}
234+
startLine={startLine}
235+
endLine={endLine}
236+
side={side}
237+
onDismiss={reset}
238+
/>
249239
);
250240
},
251-
[handleCommentSubmit, reset],
241+
[reset, taskId, filePath],
252242
);
253243

254244
const mergedOptions = useMemo(

apps/code/src/renderer/features/code-review/components/ReviewPage.tsx

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ import { useTRPC } from "@renderer/trpc/client";
88
import type { ChangedFile, Task } from "@shared/types";
99
import { useQuery } from "@tanstack/react-query";
1010
import { useMemo } from "react";
11-
import { useReviewComment } from "../hooks/useReviewComment";
1211
import { useReviewDiffs } from "../hooks/useReviewDiffs";
13-
import type { DiffOptions, OnCommentCallback } from "../types";
12+
import type { DiffOptions } from "../types";
1413
import { InteractiveFileDiff } from "./InteractiveFileDiff";
1514
import {
1615
DeferredDiffPlaceholder,
@@ -32,8 +31,6 @@ export function ReviewPage({ task }: ReviewPageProps) {
3231
const isReviewOpen = useReviewNavigationStore(
3332
(s) => (s.reviewModes[taskId] ?? "closed") !== "closed",
3433
);
35-
const onComment = useReviewComment(taskId);
36-
3734
const {
3835
changedFiles,
3936
changesLoading,
@@ -79,7 +76,6 @@ export function ReviewPage({ task }: ReviewPageProps) {
7976
revealFile,
8077
getDeferredReason,
8178
openFile,
82-
onComment,
8379
};
8480

8581
return (
@@ -118,7 +114,7 @@ export function ReviewPage({ task }: ReviewPageProps) {
118114
options={diffOptions}
119115
collapsed={isCollapsed}
120116
onToggle={() => toggleFile(key)}
121-
onComment={onComment}
117+
taskId={taskId}
122118
/>
123119
</div>
124120
);
@@ -148,7 +144,6 @@ interface FileDiffListProps {
148144
revealFile: (key: string) => void;
149145
getDeferredReason: (key: string) => DeferredReason | null;
150146
openFile: (taskId: string, path: string, preview: boolean) => void;
151-
onComment: OnCommentCallback;
152147
}
153148

154149
function FileDiffList({
@@ -162,7 +157,6 @@ function FileDiffList({
162157
revealFile,
163158
getDeferredReason,
164159
openFile,
165-
onComment,
166160
}: FileDiffListProps) {
167161
return files.map((fileDiff) => {
168162
const filePath = fileDiff.name ?? fileDiff.prevName ?? "";
@@ -193,7 +187,7 @@ function FileDiffList({
193187
fileDiff={fileDiff}
194188
repoPath={repoPath}
195189
options={{ ...diffOptions, collapsed: isCollapsed }}
196-
onComment={onComment}
190+
taskId={taskId}
197191
renderCustomHeader={(fd) => (
198192
<DiffFileHeader
199193
fileDiff={fd}
@@ -213,17 +207,17 @@ function FileDiffList({
213207
function UntrackedFileDiff({
214208
file,
215209
repoPath,
210+
taskId,
216211
options,
217212
collapsed,
218213
onToggle,
219-
onComment,
220214
}: {
221215
file: ChangedFile;
222216
repoPath: string;
217+
taskId: string;
223218
options: DiffOptions;
224219
collapsed: boolean;
225220
onToggle: () => void;
226-
onComment: OnCommentCallback;
227221
}) {
228222
const trpc = useTRPC();
229223
const { data: content } = useQuery(
@@ -245,7 +239,7 @@ function UntrackedFileDiff({
245239
oldFile={oldFile}
246240
newFile={newFile}
247241
options={{ ...options, collapsed }}
248-
onComment={onComment}
242+
taskId={taskId}
249243
renderCustomHeader={(fd) => (
250244
<DiffFileHeader
251245
fileDiff={fd}

0 commit comments

Comments
 (0)