Skip to content

Commit da578d4

Browse files
committed
Implement invocation count selection and support for multiple parallel AI requests per prompt
1 parent c7242eb commit da578d4

15 files changed

Lines changed: 363 additions & 158 deletions

File tree

‎packages/ui/src/components/editor/common/DropdownMenu/DropdownMenu.module.scss‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
z-index: 2;
77
width: max-content;
88
text-align: left;
9-
min-width: 100%;
9+
min-width: max(100%, 80px);
1010

1111
&__inner {
1212
background-color: var(--vscode-quickInput-background);
@@ -35,6 +35,12 @@
3535
white-space: nowrap;
3636
}
3737

38+
&__right {
39+
display: flex;
40+
align-items: center;
41+
gap: 8px;
42+
}
43+
3844
&:hover,
3945
&[data-selected='true'] {
4046
background-color: var(--vscode-list-activeSelectionBackground);

‎packages/ui/src/components/editor/common/DropdownMenu/DropdownMenu.tsx‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export namespace DropdownMenu {
66
label: string
77
shortcut?: string
88
on_click: () => void
9+
checked?: boolean
910
is_selected?: boolean
1011
}
1112

@@ -50,8 +51,13 @@ export const DropdownMenu: React.FC<DropdownMenu.Props> = (props) => {
5051
item.label
5152
)}
5253
</span>
53-
{item.shortcut && (
54-
<span className={styles.shortcut}>{item.shortcut}</span>
54+
{(item.shortcut || item.checked) && (
55+
<div className={styles.item__right}>
56+
{item.checked && <span className="codicon codicon-check" />}
57+
{item.shortcut && (
58+
<span className={styles.shortcut}>{item.shortcut}</span>
59+
)}
60+
</div>
5561
)}
5662
</div>
5763
)

‎packages/ui/src/components/editor/panel/PromptField/PromptField.module.scss‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@
274274
display: flex;
275275
align-items: center;
276276
justify-content: flex-end;
277-
gap: 8px;
277+
gap: 5px;
278278
pointer-events: none;
279279

280280
&__edit-format {
@@ -321,6 +321,18 @@
321321
}
322322
}
323323

324+
&__invocation-count {
325+
position: relative;
326+
pointer-events: all;
327+
display: flex;
328+
align-items: center;
329+
330+
&__button {
331+
font-size: 11px !important;
332+
padding: 0 4px !important;
333+
}
334+
}
335+
324336
&__submit {
325337
display: flex;
326338
align-items: center;

‎packages/ui/src/components/editor/panel/PromptField/PromptField.stories.tsx‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ export const Empty = () => (
2424
on_submit_with_control={() => console.log('Submitted with control')}
2525
context_file_paths={[]}
2626
on_curly_braces_click={() => {}}
27+
invocation_count={1}
28+
on_invocation_count_change={(count) =>
29+
console.log('Invocation count changed:', count)
30+
}
2731
/>
2832
)
2933

@@ -46,6 +50,10 @@ export const WithText = () => (
4650
on_submit_with_control={() => console.log('Submitted with control')}
4751
context_file_paths={[]}
4852
on_curly_braces_click={() => {}}
53+
invocation_count={1}
54+
on_invocation_count_change={(count) =>
55+
console.log('Invocation count changed:', count)
56+
}
4957
/>
5058
)
5159

@@ -68,6 +76,10 @@ export const LongText = () => (
6876
on_submit_with_control={() => console.log('Submitted with control')}
6977
context_file_paths={[]}
7078
on_curly_braces_click={() => {}}
79+
invocation_count={1}
80+
on_invocation_count_change={(count) =>
81+
console.log('Invocation count changed:', count)
82+
}
7183
/>
7284
)
7385

@@ -89,6 +101,10 @@ export const WithPlaceholderSavedContext = () => (
89101
is_web_mode={false}
90102
on_submit_with_control={() => console.log('Submitted with control')}
91103
context_file_paths={[]}
104+
invocation_count={1}
105+
on_invocation_count_change={(count) =>
106+
console.log('Invocation count changed:', count)
107+
}
92108
on_curly_braces_click={() => {}}
93109
/>
94110
)
@@ -111,6 +127,10 @@ export const WithPlaceholderSelection = () => (
111127
is_web_mode={false}
112128
on_submit_with_control={() => console.log('Submitted with control')}
113129
context_file_paths={[]}
130+
invocation_count={1}
131+
on_invocation_count_change={(count) =>
132+
console.log('Invocation count changed:', count)
133+
}
114134
on_curly_braces_click={() => {}}
115135
/>
116136
)
@@ -133,6 +153,10 @@ export const WithCommit = () => (
133153
is_web_mode={false}
134154
on_submit_with_control={() => console.log('Submitted with control')}
135155
context_file_paths={[]}
156+
invocation_count={1}
157+
on_invocation_count_change={(count) =>
158+
console.log('Invocation count changed:', count)
159+
}
136160
on_curly_braces_click={() => {}}
137161
/>
138162
)
@@ -155,6 +179,10 @@ export const WithCommitWithQuotes = () => (
155179
is_web_mode={false}
156180
on_submit_with_control={() => console.log('Submitted with control')}
157181
context_file_paths={[]}
182+
invocation_count={1}
183+
on_invocation_count_change={(count) =>
184+
console.log('Invocation count changed:', count)
185+
}
158186
on_curly_braces_click={() => {}}
159187
/>
160188
)
@@ -176,6 +204,10 @@ export const WithContextAtCommit = () => (
176204
is_web_mode={false}
177205
on_submit_with_control={() => console.log('Submitted with control')}
178206
context_file_paths={[]}
207+
invocation_count={1}
208+
on_invocation_count_change={(count) =>
209+
console.log('Invocation count changed:', count)
210+
}
179211
on_curly_braces_click={() => {}}
180212
/>
181213
)
@@ -210,6 +242,8 @@ export const WithEditFormatSelector = () => {
210242
diff: 'Use diff...'
211243
}}
212244
context_file_paths={[]}
245+
invocation_count={1}
246+
on_invocation_count_change={set_edit_format as any} // Mocking for demo
213247
/>
214248
)
215249
}
@@ -234,5 +268,9 @@ export const WithFilePaths = () => (
234268
on_curly_braces_click={() => {}}
235269
on_go_to_file={(path) => console.log('Go to file:', path)}
236270
context_file_paths={['path/to/my/file.ts']}
271+
invocation_count={1}
272+
on_invocation_count_change={(count) =>
273+
console.log('Invocation count changed:', count)
274+
}
237275
/>
238276
)

‎packages/ui/src/components/editor/panel/PromptField/PromptField.tsx‎

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ export type PromptFieldProps = {
5252
edit_format_instructions?: Record<EditFormat, string>
5353
context_file_paths?: string[]
5454
currently_open_file_text?: string
55+
invocation_count: number
56+
on_invocation_count_change: (count: number) => void
5557
on_go_to_file?: (file_path: string) => void
5658
}
5759

@@ -62,6 +64,8 @@ export const PromptField: React.FC<PromptFieldProps> = (props) => {
6264
const [show_submit_tooltip, set_show_submit_tooltip] = useState(false)
6365
const [is_text_selecting, set_is_text_selecting] = useState(false)
6466
const [is_focused, set_is_focused] = useState(false)
67+
const [is_invocation_dropdown_open, set_is_invocation_dropdown_open] =
68+
useState(false)
6569
const [hovered_edit_format, set_hovered_edit_format] =
6670
useState<EditFormat | null>(null)
6771
const { is_alt_pressed, handle_container_key_down } = use_keyboard_shortcuts({
@@ -73,10 +77,12 @@ export const PromptField: React.FC<PromptFieldProps> = (props) => {
7377
const {
7478
is_dropdown_open,
7579
toggle_dropdown,
80+
close_dropdown,
7681
dropdown_ref,
7782
handle_copy_click,
7883
handle_select_click
7984
} = use_dropdown(props)
85+
const invocation_dropdown_ref = useRef<HTMLDivElement>(null)
8086
const { ghost_text, handle_accept_ghost_text } = use_ghost_text({
8187
value: props.value,
8288
input_ref,
@@ -207,6 +213,26 @@ export const PromptField: React.FC<PromptFieldProps> = (props) => {
207213
}
208214
}, [props.focus_key])
209215

216+
useEffect(() => {
217+
if (input_ref.current) {
218+
const handle_click_outside = (event: MouseEvent) => {
219+
if (
220+
invocation_dropdown_ref.current &&
221+
!invocation_dropdown_ref.current.contains(event.target as Node)
222+
) {
223+
set_is_invocation_dropdown_open(false)
224+
}
225+
}
226+
227+
if (is_invocation_dropdown_open) {
228+
document.addEventListener('mousedown', handle_click_outside)
229+
}
230+
return () => {
231+
document.removeEventListener('mousedown', handle_click_outside)
232+
}
233+
}
234+
}, [is_invocation_dropdown_open])
235+
210236
useEffect(() => {
211237
if (input_ref.current) {
212238
input_ref.current.focus()
@@ -493,6 +519,37 @@ export const PromptField: React.FC<PromptFieldProps> = (props) => {
493519
{(!props.is_web_mode ||
494520
(props.is_web_mode && props.is_connected)) && (
495521
<>
522+
<div
523+
className={styles['footer__right__invocation-count']}
524+
ref={invocation_dropdown_ref}
525+
>
526+
<button
527+
className={cn(
528+
styles['footer__right__submit__button'],
529+
styles['footer__right__invocation-count__button']
530+
)}
531+
onClick={(e) => {
532+
e.stopPropagation()
533+
set_is_invocation_dropdown_open((prev) => !prev)
534+
close_dropdown()
535+
}}
536+
title="Invocation count"
537+
>
538+
{props.invocation_count}×
539+
</button>
540+
{is_invocation_dropdown_open && (
541+
<DropdownMenu
542+
items={[1, 2, 3, 4, 5].map((count) => ({
543+
label: `${count}×`,
544+
checked: count == props.invocation_count,
545+
on_click: () => {
546+
props.on_invocation_count_change(count)
547+
set_is_invocation_dropdown_open(false)
548+
}
549+
}))}
550+
/>
551+
)}
552+
</div>
496553
<button
497554
className={cn(
498555
styles['footer__right__submit__button'],
@@ -509,7 +566,10 @@ export const PromptField: React.FC<PromptFieldProps> = (props) => {
509566
styles['footer__right__submit__button'],
510567
styles['footer__right__submit__button--chevron']
511568
)}
512-
onClick={toggle_dropdown}
569+
onClick={() => {
570+
toggle_dropdown()
571+
set_is_invocation_dropdown_open(false)
572+
}}
513573
title="More actions"
514574
>
515575
<span

‎packages/ui/src/components/editor/panel/PromptField/hooks/use-dropdown.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export const use_dropdown = ({
5050
return {
5151
is_dropdown_open,
5252
toggle_dropdown,
53+
close_dropdown,
5354
dropdown_ref,
5455
handle_copy_click,
5556
handle_select_click

‎packages/vscode/src/commands/apply-chat-response-command/response-processor.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { parse_response, FileItem, DiffItem } from './utils/clipboard-parser'
66
import { create_safe_path } from '@/utils/path-sanitizer'
77
import { dictionary } from '@shared/constants/dictionary'
88
import { Logger } from '@shared/utils/logger'
9-
import { Diff } from './utils/clipboard-parser/extract-diff-patches'
109
import { apply_git_patch } from './handlers/diff-handler'
1110
import { apply_file_relocations } from './utils/file-operations'
1211
import { ModelProvidersManager } from '@/services/model-providers-manager'
@@ -23,6 +22,7 @@ import {
2322
handle_truncated_edit,
2423
is_truncation_line
2524
} from './handlers/truncated-handler'
25+
import { Diff } from 'diff'
2626

2727
export type PreviewData = {
2828
original_states: OriginalFileState[]
@@ -197,7 +197,7 @@ export const process_chat_response = async (
197197

198198
let all_original_states: OriginalFileState[] = []
199199
const applied_patches: {
200-
patch: Diff
200+
patch: DiffItem
201201
original_states: OriginalFileState[]
202202
diff_application_method?: 'recount' | 'search_and_replace'
203203
}[] = []

0 commit comments

Comments
 (0)