Skip to content

Commit 37cdfba

Browse files
committed
Add default agent configuration for agentic search
- in CLI settings, add section 'Defaults', allow setting a default agent for 'Agentic Search', and respect user selection to skip the quick pick - on Agent, make 'name' and 'agent' required properties and skip redundant checks and Non-Null Assertion Operator - on agent, make 'name' and 'agent' required properties ├── apps │ └── editor │ ├── package.json │ └── src │ ├── commands │ │ └── agentic-search-command │ │ └── agentic-search-command.ts │ ├── constants │ │ ├── instructions.ts │ │ └── state-keys.ts │ ├── features │ │ └── agentic-search │ │ └── agentic-search.ts │ ├── services │ │ └── providers-manager.ts │ ├── types │ │ └── cli-configuration.ts │ ├── utils │ │ ├── agentic-cli-invocation │ │ │ └── invoke-agentic-cli.ts │ │ └── cli-configuration-format-converters.ts │ └── views │ ├── prompt │ │ ├── backend │ │ │ ├── message-handlers │ │ │ │ ├── handle-agentic-search │ │ │ │ │ └── handle-agentic-search.ts │ │ │ │ └── handle-voice-input.ts │ │ │ └── prompt-view-provider.ts │ │ ├── frontend │ │ │ └── Main │ │ │ ├── Main.tsx │ │ │ └── MainView │ │ │ ├── MainView.tsx │ │ │ └── hooks │ │ │ └── use-last-choice-tooltip.ts │ │ └── types │ │ └── messages.ts │ ├── settings │ │ ├── backend │ │ │ ├── message-handlers │ │ │ │ ├── handle-get-api-configurations.ts │ │ │ │ ├── handle-select-default-api-configuration.ts │ │ │ │ ├── handle-set-default-api-configuration.ts │ │ │ │ └── index.ts │ │ │ └── settings-view-provider.ts │ │ ├── frontend │ │ │ ├── Home │ │ │ │ ├── Home.tsx │ │ │ │ └── sections │ │ │ │ ├── ApiSection.tsx │ │ │ │ └── CliSection.tsx │ │ │ ├── Settings.tsx │ │ │ └── i18n │ │ │ ├── translations │ │ │ │ ├── actions.ts │ │ │ │ ├── agent.ts │ │ │ │ ├── api.ts │ │ │ │ ├── common.ts │ │ │ │ ├── edit-provider-form.ts │ │ │ │ ├── edit-template-form.ts │ │ │ │ ├── general.ts │ │ │ │ ├── index.ts │ │ │ │ ├── sections.ts │ │ │ │ └── web.ts │ │ │ └── use-translation.tsx │ │ └── types │ │ └── messages.ts │ └── shared │ ├── actions │ │ ├── agent │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ ├── reorder.ts │ │ │ └── update.ts │ │ └── api │ │ ├── create │ │ │ └── interactions │ │ │ └── verify-model.ts │ │ └── update │ │ └── update.ts │ ├── forms │ │ └── EditCliConfigurationForm │ │ └── EditCliConfigurationForm.tsx │ └── types │ └── api-features.ts └── packages └── ui └── src └── components └── editor └── settings └── DefaultConfigurationSelector └── DefaultConfigurationSelector.tsx
1 parent 1769eaa commit 37cdfba

16 files changed

Lines changed: 285 additions & 44 deletions

File tree

‎apps/editor/package.json‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1039,8 +1039,15 @@
10391039
},
10401040
"isPinned": {
10411041
"type": "boolean"
1042+
},
1043+
"isDefaultForAgenticSearch": {
1044+
"type": "boolean"
10421045
}
1043-
}
1046+
},
1047+
"required": [
1048+
"name",
1049+
"agent"
1050+
]
10441051
}
10451052
},
10461053
"codeWebChat.chatbots": {

‎apps/editor/src/features/agentic-search/agentic-search.ts‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ export const agentic_search = async (params: {
6262
}
6363
)
6464

65+
const config = vscode.workspace.getConfiguration('codeWebChat')
66+
const agent_configs = config.get<any[]>('agents', []) || []
67+
const default_agent = agent_configs.find(c => c.isDefaultForAgenticSearch)
68+
69+
const use_quick_pick = !default_agent
70+
const agent_configuration_name = default_agent ? default_agent.name : undefined
71+
6572
const last_used_agent_config_name =
6673
params.extension_context.workspaceState.get<string>(
6774
LAST_USED_AGENTIC_SEARCH_AGENT_STATE_KEY
@@ -78,6 +85,7 @@ export const agentic_search = async (params: {
7885
'utils.agentic-cli-invocation.agent.waiting-for-agent'
7986
),
8087
last_used_agent_config_name,
88+
agent_configuration_name,
8189
on_agent_selected: (name: string) => {
8290
params.extension_context.workspaceState.update(
8391
LAST_USED_AGENTIC_SEARCH_AGENT_STATE_KEY,
@@ -91,7 +99,7 @@ export const agentic_search = async (params: {
9199
last_selected_workspace_state_key:
92100
LAST_SELECTED_WORKSPACE_IN_AGENTIC_SEARCH_STATE_KEY,
93101
show_back_button: true,
94-
use_quick_pick: true,
102+
use_quick_pick,
95103
build_prompt: async () => {
96104
const { instructions: processed_query, skill_definitions } =
97105
await replace_symbols({
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export type CliConfiguration = {
2-
name?: string
3-
agent?: string
2+
name: string
3+
agent: string
44
flags?: string
55
is_pinned?: boolean
66
}

‎apps/editor/src/utils/cli-configuration-format-converters.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { AGENTS } from '@/constants/agents'
22
import { CliConfiguration } from '@/types/cli-configuration'
33

44
export type ConfigAgentConfigurationFormat = {
5-
name?: string
6-
agent?: keyof typeof AGENTS
5+
name: string
6+
agent: keyof typeof AGENTS
77
flags?: string
88
isPinned?: boolean
99
}
@@ -23,7 +23,7 @@ export const ui_agent_configuration_to_config_format = (
2323
agent_configuration: CliConfiguration
2424
): ConfigAgentConfigurationFormat => {
2525
return {
26-
name: agent_configuration.name || undefined,
26+
name: agent_configuration.name,
2727
agent: agent_configuration.agent as keyof typeof AGENTS,
2828
flags: agent_configuration.flags,
2929
isPinned: agent_configuration.is_pinned

‎apps/editor/src/views/prompt/backend/prompt-view-provider.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -941,7 +941,7 @@ export class PromptViewProvider implements vscode.WebviewViewProvider {
941941
this.extension_context.globalState.get<string>(key)
942942
if (last_selected) {
943943
if (
944-
agent_configurations_ui.some((p) => (p.name ?? '') == last_selected)
944+
agent_configurations_ui.some((p) => p.name == last_selected)
945945
) {
946946
selected_name = last_selected
947947
}

‎apps/editor/src/views/prompt/frontend/Main/MainView/MainView.tsx‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -278,22 +278,22 @@ export const MainView: React.FC<Props> = (props) => {
278278
})
279279

280280
const agent_configurations_ui: UiConfigurations.Configuration[] =
281-
props.agent_configurations.map((c, index) => {
282-
const is_unnamed = !c.name || /^\(\d+\)$/.test(c.name.trim())
281+
props.agent_configurations.map((c) => {
282+
const is_unnamed = /^\(\d+\)$/.test(c.name.trim())
283283
const display_name = is_unnamed
284-
? c.agent!
285-
: c.name!.replace(/ \(\d+\)$/, '')
284+
? c.agent
285+
: c.name.replace(/ \(\d+\)$/, '')
286286

287287
const details: string[] = []
288288
if (is_unnamed) {
289289
if (c.flags) details.push(c.flags)
290-
} else if (c.agent) {
290+
} else {
291291
details.push(c.agent)
292292
if (c.flags) details.push(c.flags)
293293
}
294294

295295
return {
296-
id: c.name ?? `unnamed-${index}`,
296+
id: c.name,
297297
title: display_name,
298298
details,
299299
is_pinned: c.is_pinned
@@ -753,7 +753,7 @@ export const MainView: React.FC<Props> = (props) => {
753753
on_reorder={(reordered) => {
754754
const new_agent_configurations = reordered.map((c) => {
755755
return props.agent_configurations.find(
756-
(p, i) => (p.name ?? `unnamed-${i}`) == c.id
756+
(p) => p.name == c.id
757757
)!
758758
})
759759
props.on_agent_configurations_reorder(new_agent_configurations)

‎apps/editor/src/views/prompt/frontend/Main/MainView/hooks/use-last-choice-tooltip.ts‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,12 @@ export const use_last_choice_tooltip = (params: {
9393
(c) => c.name == params.selected_agent_configuration_name
9494
)
9595
if (configuration) {
96-
const is_unnamed =
97-
!configuration.name ||
98-
/^\(\d+\)$/.test(configuration.name.trim())
96+
const is_unnamed = /^\(\d+\)$/.test(configuration.name.trim())
9997
const display_name = is_unnamed
100-
? configuration.agent!
101-
: configuration.name!.replace(/ \(\d+\)$/, '')
98+
? configuration.agent
99+
: configuration.name.replace(/ \(\d+\)$/, '')
102100
const details: string[] = []
103-
if (!is_unnamed && configuration.agent) {
101+
if (!is_unnamed) {
104102
details.push(configuration.agent)
105103
}
106104
if (configuration.flags) {

‎apps/editor/src/views/settings/backend/settings-view-provider.ts‎

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,10 @@ export class SettingsViewProvider {
116116
)
117117
.map((config: any) => {
118118
return config_agent_configuration_to_ui_format(config)
119-
})
119+
}),
120+
defaults: {
121+
'agentic-search': agent_configurations_config.find((c: any) => c.isDefaultForAgenticSearch)?.name || null
122+
}
120123
})
121124
}
122125

@@ -303,6 +306,78 @@ export class SettingsViewProvider {
303306
await handle_pick_api_model(this, message)
304307
} else if (message.command == 'PICK_API_REASONING_EFFORT') {
305308
await handle_pick_api_reasoning_effort(this, message)
309+
} else if (message.command == 'SET_DEFAULT_AGENT_CONFIGURATION') {
310+
const config = vscode.workspace.getConfiguration('codeWebChat')
311+
const agent_configs = config.get<any[]>('agents', []) || []
312+
const updated = agent_configs.map((c) => {
313+
const new_c = { ...c }
314+
if (message.cli_feature === 'agentic-search') {
315+
if (c.name === message.agent_configuration_name) {
316+
new_c.isDefaultForAgenticSearch = true
317+
} else {
318+
delete new_c.isDefaultForAgenticSearch
319+
}
320+
}
321+
return new_c
322+
})
323+
await config.update('agents', updated, vscode.ConfigurationTarget.Global)
324+
} else if (message.command == 'SELECT_DEFAULT_AGENT_CONFIGURATION') {
325+
const config = vscode.workspace.getConfiguration('codeWebChat')
326+
const agent_configs = config.get<any[]>('agents', []) || []
327+
if (agent_configs.length === 0) return
328+
329+
const items = agent_configs.map((c) => {
330+
const is_unnamed = /^\(\d+\)$/.test(c.name.trim())
331+
const display_name = is_unnamed ? c.agent : c.name.replace(/ \(\d+\)$/, '')
332+
333+
return {
334+
label: display_name,
335+
description: c.agent === display_name ? undefined : c.agent,
336+
agent_configuration_name: c.name
337+
}
338+
})
339+
340+
const quick_pick = vscode.window.createQuickPick<
341+
vscode.QuickPickItem & { agent_configuration_name: string }
342+
>()
343+
quick_pick.items = items
344+
quick_pick.title = 'Select default agent'
345+
quick_pick.placeholder = 'Select agent'
346+
347+
const close_button: vscode.QuickInputButton = {
348+
iconPath: new vscode.ThemeIcon('close'),
349+
tooltip: 'Close'
350+
}
351+
quick_pick.buttons = [close_button]
352+
353+
quick_pick.onDidTriggerButton((button) => {
354+
if (button === close_button) {
355+
quick_pick.hide()
356+
}
357+
})
358+
359+
quick_pick.onDidAccept(async () => {
360+
const selected = quick_pick.selectedItems[0]
361+
quick_pick.hide()
362+
363+
if (selected) {
364+
const updated = agent_configs.map((c) => {
365+
const new_c = { ...c }
366+
if (message.cli_feature === 'agentic-search') {
367+
if (c.name === selected.agent_configuration_name) {
368+
new_c.isDefaultForAgenticSearch = true
369+
} else {
370+
delete new_c.isDefaultForAgenticSearch
371+
}
372+
}
373+
return new_c
374+
})
375+
await config.update('agents', updated, vscode.ConfigurationTarget.Global)
376+
}
377+
})
378+
379+
quick_pick.onDidHide(() => quick_pick.dispose())
380+
quick_pick.show()
306381
} else if (message.command == 'GET_IS_MODERN_UI') {
307382
this._send_is_modern_ui()
308383
}

‎apps/editor/src/views/settings/frontend/Home/Home.tsx‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export type NavItem =
3131
| 'section:api:group:system-instructions'
3232
| 'section:cli'
3333
| 'section:cli:group:agents'
34+
| 'section:cli:group:agent-defaults'
3435

3536
export type NavConfigItem = { id: NavItem; label: TranslationKey }
3637

@@ -86,6 +87,10 @@ export const NAV_ITEMS_CONFIG: NavConfigItem[] = [
8687
{
8788
id: 'section:cli:group:agents',
8889
label: 'agents.configurations.title'
90+
},
91+
{
92+
id: 'section:cli:group:agent-defaults',
93+
label: 'cli.default-configurations.title'
8994
}
9095
]
9196

@@ -125,6 +130,9 @@ type Props = {
125130
on_edit_agent_configuration: (id: string) => void
126131
on_delete_agent_configuration: (name: string) => void
127132
on_toggle_pinned_agent_configuration: (config: CliConfiguration) => void
133+
agent_defaults: Record<string, string | null>
134+
on_set_default_agent_configuration: (cli_feature: string, name: string | null) => void
135+
on_select_default_agent_configuration: (cli_feature: string) => void
128136
on_commit_instructions_change: (instructions: string) => void
129137
on_attach_ascii_tree_of_context_change: (
130138
value: 'ask' | 'always' | 'never'
@@ -417,6 +425,9 @@ export const Home: React.FC<Props> = (props) => {
417425
on_toggle_pinned_agent_configuration={
418426
props.on_toggle_pinned_agent_configuration
419427
}
428+
agent_defaults={props.agent_defaults}
429+
on_set_default_agent_configuration={props.on_set_default_agent_configuration}
430+
on_select_default_agent_configuration={props.on_select_default_agent_configuration}
420431
/>
421432
</UiLayout>
422433
</div>

‎apps/editor/src/views/settings/frontend/Home/sections/CliSection.tsx‎

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@ import { Section as UiSection } from '@ui/components/editor/settings/Section'
33
import { Group as UiGroup } from '@ui/components/editor/settings/Group/Group'
44
import { SortableList } from '@ui/components/editor/settings/SortableList'
55
import { IconButton } from '@ui/components/editor/common/IconButton'
6+
import { DefaultConfigurationSelector } from '@ui/components/editor/settings/DefaultConfigurationSelector'
67
import { CliConfiguration } from '@/types/cli-configuration'
78
import { use_translation } from '../../i18n/use-translation'
89
import { NavItem } from '../Home'
910

1011
type Props = {
1112
agent_configurations: CliConfiguration[]
1213
set_agent_configurations: (configurations: CliConfiguration[]) => void
14+
agent_defaults: Record<string, string | null>
15+
on_set_default_agent_configuration: (cli_feature: string, name: string | null) => void
16+
on_select_default_agent_configuration: (cli_feature: string) => void
1317
on_reorder_agent_configurations: (reordered: CliConfiguration[]) => void
1418
on_add_agent_configuration: (params?: {
1519
insertion_index?: number
@@ -31,9 +35,9 @@ export const CliSection = forwardRef<HTMLDivElement, Props>((props, ref) => {
3135
>
3236
<UiGroup title={t('agents.configurations.title')}>
3337
<SortableList
34-
items={props.agent_configurations.map((c, index) => ({
38+
items={props.agent_configurations.map((c) => ({
3539
...c,
36-
id: c.name ?? `unnamed-${index}`
40+
id: c.name
3741
}))}
3842
on_reorder={(reordered) => {
3943
const restored = reordered.map(
@@ -50,18 +54,15 @@ export const CliSection = forwardRef<HTMLDivElement, Props>((props, ref) => {
5054
items_text_many: t('agents.configurations.items-many')
5155
}}
5256
render_content={(config) => {
53-
const is_unnamed =
54-
!config.name ||
55-
config.name.startsWith('unnamed-') ||
56-
/^\(\d+\)$/.test(config.name.trim())
57+
const is_unnamed = /^\(\d+\)$/.test(config.name.trim())
5758
const display_name = is_unnamed
58-
? config.agent!
59-
: config.name!.replace(/ \(\d+\)$/, '')
59+
? config.agent
60+
: config.name.replace(/ \(\d+\)$/, '')
6061

6162
const details: string[] = []
6263
if (is_unnamed) {
6364
// ...
64-
} else if (config.agent) {
65+
} else {
6566
details.push(config.agent)
6667
}
6768

@@ -132,6 +133,41 @@ export const CliSection = forwardRef<HTMLDivElement, Props>((props, ref) => {
132133
/>
133134
</UiGroup>
134135
</div>
136+
<div
137+
ref={(el) => props.set_section_ref('section:cli:group:agent-defaults', el)}
138+
>
139+
<UiGroup
140+
title={t('cli.default-configurations.title')}
141+
is_disabled={props.agent_configurations.length === 0}
142+
>
143+
<DefaultConfigurationSelector
144+
title={t('cli.default-configurations.tool.agentic-search')}
145+
value={props.agent_defaults['agentic-search'] || null}
146+
configurations={props.agent_configurations.map((config) => {
147+
const is_unnamed = /^\(\d+\)$/.test(config.name.trim())
148+
const display_name = is_unnamed
149+
? config.agent
150+
: config.name.replace(/ \(\d+\)$/, '')
151+
152+
return {
153+
id: config.name,
154+
model: display_name,
155+
description: config.agent
156+
}
157+
})}
158+
on_unset={() =>
159+
props.on_set_default_agent_configuration('agentic-search', null)
160+
}
161+
on_select={() =>
162+
props.on_select_default_agent_configuration('agentic-search')
163+
}
164+
translations={{
165+
select: t('agents.configurations.action.select-default'),
166+
unset: t('agents.configurations.action.unset-default')
167+
}}
168+
/>
169+
</UiGroup>
170+
</div>
135171
</UiSection>
136172
)
137173
})

0 commit comments

Comments
 (0)