✨ feat(vscode): 问 AI 和重写注释各用各的 profile,设置里加重写注释默认模型
This commit is contained in:
1 parent
925f1ed39a
commit
b83c445dd0
25 files changed
+363
-111
No files matched your search
@@ -606,6 +606,7 @@ export function App() {
|
||||
initialDefaultTestProfilePath={settings?.defaultTestProfilePath ?? ''}
|
||||
initialDefaultPrototypeProfilePath={settings?.defaultPrototypeProfilePath ?? ''}
|
||||
initialDefaultAskProfilePath={settings?.defaultAskProfilePath ?? ''}
|
||||
initialDefaultRewriteProfilePath={settings?.defaultRewriteProfilePath ?? ''}
|
||||
initialConflictResolutionProfilePath={settings?.conflictResolutionProfilePath ?? ''}
|
||||
initialCommitProfilePath={settings?.commitProfilePath ?? ''}
|
||||
initialPrDiffSummaryProfilePath={settings?.prDiffSummaryProfilePath ?? ''}
|
||||
|
||||
@@ -59,8 +59,8 @@ export function App(): ReactElement | null {
|
||||
const qa = useQa()
|
||||
/** 侧栏「问 AI」要聚焦顶部输入框时加一 */
|
||||
const [pathFocus, setPathFocus] = useState(0)
|
||||
/** 按注释规范重写:和问 AI 共用 profile 下拉 */
|
||||
const rewrite = useRewrite(qa.state.profiles, qa.onSelectProfile)
|
||||
/** 按注释规范重写 */
|
||||
const rewrite = useRewrite()
|
||||
const [doc, setDoc] = useState<DocumentMessage | null>(null)
|
||||
const [view, setView] = useState<BlockModes>(savedBlockModes)
|
||||
const [focusId, setFocusId] = useState<string | null>(null)
|
||||
|
||||
@@ -62,7 +62,7 @@ const CARD: BlockView = {
|
||||
|
||||
/** 重写注释的状态和动作:动作什么都不做 */
|
||||
function rewriteTree(state: ChatState): RewriteTree {
|
||||
return { state, profiles: { options: [], selected: '' }, onRewrite: () => {}, onAsk: () => {}, onStop: () => {}, onDelete: () => {}, onOpen: () => {}, onClose: () => {}, onSelectProfile: () => {} }
|
||||
return { state, onRewrite: () => {}, onAsk: () => {}, onStop: () => {}, onDelete: () => {}, onOpen: () => {}, onClose: () => {}, onSelectProfile: () => {} }
|
||||
}
|
||||
|
||||
function state(collapsed: ReadonlySet<string>, rewrite: ChatState = { ...EMPTY_CHAT, available: true }): BlockTreeState {
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { DiffTree, FoldedRuns, PlacedRemoved } from './diffView'
|
||||
import type { GridSlots } from './PropertyGrid'
|
||||
import type { ChatState, QaState } from './qa'
|
||||
import type { PendingImage } from './qaImages'
|
||||
import type { BlockMarks, BlockView, ProfileChoice } from './types'
|
||||
import type { BlockMarks, BlockView } from './types'
|
||||
import { ChevronDown, ChevronRight, ChevronsUpDown, EyeOff } from 'lucide-react'
|
||||
import { Fragment, useState } from 'react'
|
||||
import { AskThread, REWRITE_THREAD } from './AskThread'
|
||||
@@ -67,10 +67,9 @@ export interface BlockTreeState {
|
||||
onOpenRun: (id: string) => void
|
||||
}
|
||||
|
||||
/** 重写注释的状态和动作,块按自己的记号(anchor)取;profile 下拉和问 AI 共用 */
|
||||
/** 重写注释的状态和动作,块按自己的记号(anchor)取;profile 下拉是自己的,和问 AI 的互不影响 */
|
||||
export interface RewriteTree {
|
||||
state: ChatState
|
||||
profiles: ProfileChoice
|
||||
/** 点了块右上角的按钮:按技能命令重写这块(开新会话),展开它的重写记录 */
|
||||
onRewrite: (anchor: string) => void
|
||||
/** 在输入框里说的修改意见,接着这块最近一次重写的会话说;images 是贴的图片 */
|
||||
@@ -79,6 +78,7 @@ export interface RewriteTree {
|
||||
onDelete: (anchor: string, entryId: string) => void
|
||||
onOpen: (anchor: string) => void
|
||||
onClose: (anchor: string) => void
|
||||
/** 换重写注释用的 profile(所有块共用),`id` 同 [下拉项的 id](vscode/webview-ui/src/codeReader/types.ts#ProfileOption.id) */
|
||||
onSelectProfile: (id: string) => void
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ function BlockRewrite({ anchor, rewrite }: { anchor: string, rewrite: RewriteTre
|
||||
history={historyOf(rewrite.state, anchor)}
|
||||
asks={asksOf(rewrite.state, anchor)}
|
||||
open={rewrite.state.open.includes(anchor)}
|
||||
profiles={rewrite.profiles}
|
||||
profiles={rewrite.state.profiles}
|
||||
onSelectProfile={rewrite.onSelectProfile}
|
||||
onAsk={(request, images) => rewrite.onAsk(anchor, request, images)}
|
||||
onStop={rewrite.onStop}
|
||||
|
||||
@@ -34,12 +34,17 @@ describe('问 AI 的状态', () => {
|
||||
expect(historyOf(state, IF).map(entry => entry.id)).toEqual(['old'])
|
||||
})
|
||||
|
||||
it('profile 下拉:扩展端发来什么就显示什么,问答刷新不丢', () => {
|
||||
it('profile 下拉:问答、重写注释各记各的,扩展端发来什么就显示什么,记录刷新不丢', () => {
|
||||
const profiles = { options: [{ id: '', label: '默认' }, { id: 'sonnet', label: 'sonnet' }], selected: 'sonnet' }
|
||||
expect(EMPTY_QA.profiles).toEqual({ options: [], selected: '' })
|
||||
const state = run({ type: 'profiles', profiles }, qa([thread(IF, 'e1')]))
|
||||
expect(state.profiles).toEqual(profiles)
|
||||
expect(state.threads).toHaveLength(1)
|
||||
|
||||
expect(EMPTY_CHAT.profiles).toEqual({ options: [], selected: '' })
|
||||
const rewrite = chatReducer(chatReducer(EMPTY_CHAT, { type: 'profiles', profiles }), { type: 'sync', available: true, threads: [thread(IF, 'r1')], current: [] })
|
||||
expect(rewrite.profiles).toEqual(profiles)
|
||||
expect(rewrite.threads).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('顶部的问答记在路径上,不进任何一块的历史', () => {
|
||||
|
||||
@@ -37,6 +37,8 @@ export interface ChatState {
|
||||
asks: Ask[]
|
||||
/** 展开着对话区(历史、当前这一轮、输入框)的块 */
|
||||
open: string[]
|
||||
/** 这种对话输入框旁边的 profile 下拉,所有块共用 */
|
||||
profiles: ProfileChoice
|
||||
}
|
||||
|
||||
export interface QaState extends ChatState {
|
||||
@@ -44,8 +46,6 @@ export interface QaState extends ChatState {
|
||||
path: QaEntryView[]
|
||||
/** 顶部问的是这个文件、这个文件夹,还是「了解一块代码」找的一个功能 */
|
||||
subject: 'file' | 'folder' | 'feature'
|
||||
/** 输入框旁边的 profile 下拉,所有块共用 */
|
||||
profiles: ProfileChoice
|
||||
}
|
||||
|
||||
export const EMPTY_CHAT: ChatState = {
|
||||
@@ -53,17 +53,18 @@ export const EMPTY_CHAT: ChatState = {
|
||||
threads: [],
|
||||
asks: [],
|
||||
open: [],
|
||||
profiles: { options: [], selected: '' },
|
||||
}
|
||||
|
||||
export const EMPTY_QA: QaState = {
|
||||
...EMPTY_CHAT,
|
||||
path: [],
|
||||
subject: 'file',
|
||||
profiles: { options: [], selected: '' },
|
||||
}
|
||||
|
||||
/**
|
||||
* sync:扩展端发来的记录和它记着的当前一轮;answer:askId 那一轮的回答长了、排上队了(queued)或轮到了(question 是扩展端报上来的这一轮的话,点按钮那一轮开始时页面还不知道)
|
||||
* sync:扩展端发来的记录和它记着的当前一轮;answer:askId 那一轮的回答长了、排上队了(queued)或轮到了(question 是扩展端报上来的这一轮的话,点按钮那一轮开始时页面还不知道);
|
||||
* profiles:扩展端发来的这种对话的 profile 下拉
|
||||
*/
|
||||
export type ChatAction
|
||||
= | { type: 'sync', available: boolean, threads: QaThreadView[], current: AskRound[] }
|
||||
@@ -72,11 +73,11 @@ export type ChatAction
|
||||
| { type: 'ask', askId: string, anchor: string, question: string, images: string[] }
|
||||
| { type: 'open', anchor: string }
|
||||
| { type: 'close', anchor: string }
|
||||
| { type: 'profiles', profiles: ProfileChoice }
|
||||
|
||||
export type QaAction
|
||||
= | ChatAction
|
||||
| { type: 'qa', message: QaMessage }
|
||||
| { type: 'profiles', profiles: ProfileChoice }
|
||||
|
||||
function withOpen(open: string[], anchor: string): string[] {
|
||||
return open.includes(anchor) ? open : [...open, anchor]
|
||||
@@ -127,6 +128,8 @@ export function chatReducer<S extends ChatState>(state: S, action: ChatAction):
|
||||
asks: state.asks.filter(ask => ask.anchor !== action.anchor || unfinished(ask)),
|
||||
open: state.open.filter(anchor => anchor !== action.anchor),
|
||||
}
|
||||
case 'profiles':
|
||||
return { ...state, profiles: action.profiles }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,8 +139,6 @@ export function qaReducer(state: QaState, action: QaAction): QaState {
|
||||
const { available, threads, current, path, subject } = action.message
|
||||
return { ...chatReducer(state, { type: 'sync', available, threads, current }), path, subject }
|
||||
}
|
||||
case 'profiles':
|
||||
return { ...state, profiles: action.profiles }
|
||||
default:
|
||||
return chatReducer(state, action)
|
||||
}
|
||||
|
||||
@@ -316,13 +316,16 @@ export interface QaMessage {
|
||||
rewriteCurrent: AskRound[]
|
||||
}
|
||||
|
||||
/** 「问 AI」用的 Claude Code profile 的下拉一项:id 是 profile 名;「默认」(不带 `--settings`)的 id 是 '' */
|
||||
/** 预览里的两种对话:问 AI(ask,块下面和页面顶部)、重写注释(rewrite),各有各的记录和 profile 下拉 */
|
||||
export type ChatKind = 'ask' | 'rewrite'
|
||||
|
||||
/** Claude Code profile 下拉的一项:id 是 profile 名;「默认」(不带 `--settings`)的 id 是 '' */
|
||||
export interface ProfileOption {
|
||||
id: string
|
||||
label: string
|
||||
}
|
||||
|
||||
/** 「问 AI」输入框旁边的 profile 下拉:选项和选中的那项,所有预览共用、扩展端记着 */
|
||||
/** 一种对话输入框旁边的 profile 下拉:选项和选中的那项,所有预览共用、扩展端记着 */
|
||||
export interface ProfileChoice {
|
||||
options: ProfileOption[]
|
||||
selected: string
|
||||
@@ -460,7 +463,7 @@ export type OpenedFrom = 'uncommitted' | 'other'
|
||||
* occurrencesFound:id 那次 findOccurrences 的回答,语言扩展没答(或没装)就是空的
|
||||
* filter:整个工作区共用的块筛选和「只看改动」开关;ready 后先于第一份文档来一次,之后任何一个预览改了都会来
|
||||
* qa:这份文件的问答;ready 后来一次,问答、正在答的问题变了再来
|
||||
* askProfiles:「问 AI」的 profile 下拉;ready 后来一次,任何一个预览改了都会来
|
||||
* profiles:kind 那种对话的 profile 下拉;ready 后两种各来一次,任何一个预览改了哪种就来哪种
|
||||
* answer:askId 那个问题的回答长了(text 是到现在为止的全文)、或换了在做的事
|
||||
* answerEnd:askId 那个问题答完了,见 AnswerEnd
|
||||
* rewriteProgress:askId 那一轮重写排上队了(queued)、开始了、正文长了(text 是到现在为止写出来的)、或换了在做的事;question 是记在这一轮上的话(点按钮时是那句技能命令)
|
||||
@@ -528,7 +531,7 @@ export type ExtensionToWebview
|
||||
| { type: 'displayNames', version: number, names: ShownName[] }
|
||||
| { type: 'filter', excluded: Excluded, onlyChanges: boolean }
|
||||
| QaMessage
|
||||
| ({ type: 'askProfiles' } & ProfileChoice)
|
||||
| ({ type: 'profiles', kind: ChatKind } & ProfileChoice)
|
||||
| { type: 'answer', askId: string, text: string, activity?: string }
|
||||
| AnswerEnd
|
||||
| { type: 'rewriteProgress', askId: string, question: string, text: string, activity?: string, queued?: true }
|
||||
@@ -564,7 +567,7 @@ export type ExtensionToWebview
|
||||
* forgetRound:收起了 anchor 那块的问答(ask)或重写(rewrite),扩展端去掉这块留着的那一轮(出错、被叫停的),重新加载后不再画出来
|
||||
* stopAsk:叫停 askId 那个问题,这次不存
|
||||
* deleteQa:删掉 anchor 那块下面的一次问答(已经理解了)
|
||||
* selectAskProfile:「问 AI」换 profile;不在本地先改,等扩展端发回 askProfiles 再按它显示
|
||||
* selectProfile:kind 那种对话换 profile;不在本地先改,等扩展端发回这种的 profiles 再按它显示
|
||||
* occurrenceNavigation:眼下能不能用键盘在高亮着的名字的各处出现之间跳(有高亮、页面有焦点、焦点不在输入框里),变了才发
|
||||
* openRepoLink:点了注释里的仓库路径链接,打开 path(从仓库根算起)。symbol 是类名、函数名或「类名.成员名」,没有就只打开文件或在代码阅读侧栏的树上定位目录;
|
||||
* 没有 path 是不带路径的引用(`[Name]`、`[Class.member]`),扩展端按这份文件找 symbol
|
||||
@@ -581,7 +584,7 @@ export type WebviewToExtension
|
||||
| { type: 'rewriteComment', askId: string, anchor: string, request?: string, images: AskImage[] }
|
||||
| { type: 'stopRewrite', askId: string }
|
||||
| { type: 'deleteRewrite', anchor: string, entryId: string }
|
||||
| { type: 'forgetRound', kind: 'ask' | 'rewrite', anchor: string }
|
||||
| { type: 'forgetRound', kind: ChatKind, anchor: string }
|
||||
| { type: 'selectTranslator', id: string }
|
||||
| { type: 'visibleLine', line: number }
|
||||
| { type: 'probeDefinition', id: number, version: number, offset: number }
|
||||
@@ -592,7 +595,7 @@ export type WebviewToExtension
|
||||
| { type: 'ask', askId: string, anchor: string, question: string, images: AskImage[] }
|
||||
| { type: 'stopAsk', askId: string }
|
||||
| { type: 'deleteQa', anchor: string, entryId: string }
|
||||
| { type: 'selectAskProfile', id: string }
|
||||
| { type: 'selectProfile', kind: ChatKind, id: string }
|
||||
| { type: 'occurrenceNavigation', available: boolean }
|
||||
| { type: 'openRepoLink', path?: string, symbol?: string }
|
||||
| { type: 'checkRepoLinks', id: number, paths: string[], symbols: string[] }
|
||||
|
||||
@@ -30,8 +30,9 @@ export function useQa(): QaTree {
|
||||
case 'qa':
|
||||
dispatch({ type: 'qa', message: msg })
|
||||
return
|
||||
case 'askProfiles':
|
||||
dispatch({ type: 'profiles', profiles: { options: msg.options, selected: msg.selected } })
|
||||
case 'profiles':
|
||||
if (msg.kind === 'ask')
|
||||
dispatch({ type: 'profiles', profiles: { options: msg.options, selected: msg.selected } })
|
||||
return
|
||||
case 'answer':
|
||||
pending.set(msg.askId, { text: msg.text, activity: msg.activity })
|
||||
@@ -66,7 +67,7 @@ export function useQa(): QaTree {
|
||||
},
|
||||
onStop: askId => postMessage({ type: 'stopAsk', askId }),
|
||||
onDelete: (anchor, entryId) => postMessage({ type: 'deleteQa', anchor, entryId }),
|
||||
onSelectProfile: id => postMessage({ type: 'selectAskProfile', id }),
|
||||
onSelectProfile: id => postMessage({ type: 'selectProfile', kind: 'ask', id }),
|
||||
}
|
||||
}, [state])
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { RewriteTree } from './BlockTree'
|
||||
import type { ChatState } from './qa'
|
||||
import type { ProfileChoice } from './types'
|
||||
import { useEffect, useMemo, useReducer, useRef } from 'react'
|
||||
import { chatReducer, EMPTY_CHAT, newAskId, unfinished } from './qa'
|
||||
import { toAskImage } from './qaImages'
|
||||
@@ -9,9 +8,9 @@ import { onMessage, postMessage } from './vscode'
|
||||
|
||||
/**
|
||||
* 按注释规范重写:收扩展端的重写记录、当前一轮的进展,给块树用的状态和动作。和问 AI 同一套:
|
||||
* 排着队的、进行中的、出错被叫停留着的那一轮记在扩展端,页面重新加载后随 qa 消息的 rewriteCurrent 接上。profile 下拉和问 AI 共用。
|
||||
* 排着队的、进行中的、出错被叫停留着的那一轮记在扩展端,页面重新加载后随 qa 消息的 rewriteCurrent 接上。profile 下拉是自己的,和问 AI 的互不影响。
|
||||
*/
|
||||
export function useRewrite(profiles: ProfileChoice, onSelectProfile: (id: string) => void): RewriteTree {
|
||||
export function useRewrite(): RewriteTree {
|
||||
const [state, dispatch] = useReducer(chatReducer<ChatState>, EMPTY_CHAT)
|
||||
|
||||
useEffect(() => {
|
||||
@@ -29,6 +28,10 @@ export function useRewrite(profiles: ProfileChoice, onSelectProfile: (id: string
|
||||
case 'qa':
|
||||
dispatch({ type: 'sync', available: msg.available, threads: msg.rewrites, current: msg.rewriteCurrent })
|
||||
return
|
||||
case 'profiles':
|
||||
if (msg.kind === 'rewrite')
|
||||
dispatch({ type: 'profiles', profiles: { options: msg.options, selected: msg.selected } })
|
||||
return
|
||||
case 'rewriteProgress':
|
||||
pending.set(msg.askId, { question: msg.question, text: msg.text, ...(msg.activity !== undefined && { activity: msg.activity }), ...(msg.queued && { queued: true }) })
|
||||
timer ??= setTimeout(flush, ANSWER_FRAME_MS)
|
||||
@@ -51,8 +54,7 @@ export function useRewrite(profiles: ProfileChoice, onSelectProfile: (id: string
|
||||
|
||||
return useMemo((): RewriteTree => ({
|
||||
state,
|
||||
profiles,
|
||||
onSelectProfile,
|
||||
onSelectProfile: id => postMessage({ type: 'selectProfile', kind: 'rewrite', id }),
|
||||
onRewrite: (anchor) => {
|
||||
if (current.current.asks.some(ask => ask.anchor === anchor && unfinished(ask)))
|
||||
return
|
||||
@@ -73,5 +75,5 @@ export function useRewrite(profiles: ProfileChoice, onSelectProfile: (id: string
|
||||
dispatch({ type: 'close', anchor })
|
||||
postMessage({ type: 'forgetRound', kind: 'rewrite', anchor })
|
||||
},
|
||||
}), [state, profiles, onSelectProfile])
|
||||
}), [state])
|
||||
}
|
||||
@@ -32,6 +32,7 @@ const PROPS: SettingsModalProps = {
|
||||
initialDefaultTestProfilePath: '',
|
||||
initialDefaultPrototypeProfilePath: '',
|
||||
initialDefaultAskProfilePath: '/p/sonnet.json',
|
||||
initialDefaultRewriteProfilePath: '/p/dsflash.json',
|
||||
initialConflictResolutionProfilePath: '',
|
||||
initialCommitProfilePath: '',
|
||||
initialPrDiffSummaryProfilePath: '',
|
||||
@@ -42,30 +43,52 @@ const PROPS: SettingsModalProps = {
|
||||
initialYoutrackProjectShortName: '',
|
||||
initialYoutrackCloseCommand: '',
|
||||
initialYoutrackTokenSaved: false,
|
||||
profiles: [{ name: 'sonnet', path: '/p/sonnet.json' }],
|
||||
profiles: [{ name: 'sonnet', path: '/p/sonnet.json' }, { name: 'dsflash', path: '/p/dsflash.json' }],
|
||||
youtrackProjects: { status: 'idle', projects: [] },
|
||||
onListYouTrackProjects: () => {},
|
||||
onSubmit: () => {},
|
||||
}
|
||||
|
||||
function field(props: Partial<SettingsModalProps> = {}): string {
|
||||
/** 设置面板里 from 这一项到 to 那一项之间的那一段 */
|
||||
function between(props: Partial<SettingsModalProps>, from: string, to: string): string {
|
||||
const html = renderToStaticMarkup(<SettingsModal {...PROPS} {...props} />)
|
||||
expect(html).toContain('文件问答默认模型')
|
||||
return html.slice(html.indexOf('文件问答默认模型'), html.indexOf('冲突解决配置文件'))
|
||||
expect(html).toContain(from)
|
||||
return html.slice(html.indexOf(from), html.indexOf(to))
|
||||
}
|
||||
|
||||
describe('设置面板的文件问答默认模型', () => {
|
||||
const askField = (props: Partial<SettingsModalProps> = {}) => between(props, '问答默认模型', '重写注释默认模型')
|
||||
const rewriteField = (props: Partial<SettingsModalProps> = {}) => between(props, '重写注释默认模型', '冲突解决配置文件')
|
||||
|
||||
describe('设置面板的问答默认模型', () => {
|
||||
it('与其他默认配置在同一区域,显示保存的名称并说明临时切换不会改默认', () => {
|
||||
const html = field()
|
||||
const html = askField()
|
||||
expect(html).toContain('sonnet')
|
||||
expect(html).not.toContain('dsflash')
|
||||
expect(html).toContain('问这个文件')
|
||||
expect(html).toContain('了解一块代码')
|
||||
expect(html).toContain('临时切换')
|
||||
expect(html).toContain('不会修改这里的默认值')
|
||||
expect(html).toContain('aria-haspopup="listbox"')
|
||||
})
|
||||
|
||||
it('未配置时显示官方默认,失效路径不能伪装成默认', () => {
|
||||
expect(field({ initialDefaultAskProfilePath: '' })).toContain('(默认)')
|
||||
expect(field({ initialDefaultAskProfilePath: '/p/deleted.json' })).toContain('不可用:/p/deleted.json')
|
||||
expect(askField({ initialDefaultAskProfilePath: '' })).toContain('(默认)')
|
||||
expect(askField({ initialDefaultAskProfilePath: '/p/deleted.json' })).toContain('不可用:/p/deleted.json')
|
||||
})
|
||||
})
|
||||
|
||||
describe('设置面板的重写注释默认模型', () => {
|
||||
it('紧挨着问答默认模型,显示自己保存的名称,说明临时切换不会改默认', () => {
|
||||
const html = rewriteField()
|
||||
expect(html).toContain('dsflash')
|
||||
expect(html).toContain('重写')
|
||||
expect(html).toContain('临时切换')
|
||||
expect(html).toContain('不会修改这里的默认值')
|
||||
expect(html).toContain('aria-haspopup="listbox"')
|
||||
})
|
||||
|
||||
it('未配置时显示官方默认,失效路径不能伪装成默认', () => {
|
||||
expect(rewriteField({ initialDefaultRewriteProfilePath: '' })).toContain('(默认)')
|
||||
expect(rewriteField({ initialDefaultRewriteProfilePath: '/p/deleted.json' })).toContain('不可用:/p/deleted.json')
|
||||
})
|
||||
})
|
||||
@@ -43,6 +43,7 @@ interface SubmitValues {
|
||||
defaultTestProfilePath: string
|
||||
defaultPrototypeProfilePath: string
|
||||
defaultAskProfilePath: string
|
||||
defaultRewriteProfilePath: string
|
||||
conflictResolutionProfilePath: string
|
||||
commitProfilePath: string
|
||||
prDiffSummaryProfilePath: string
|
||||
@@ -99,6 +100,7 @@ export interface SettingsModalProps {
|
||||
initialDefaultTestProfilePath: string
|
||||
initialDefaultPrototypeProfilePath: string
|
||||
initialDefaultAskProfilePath: string
|
||||
initialDefaultRewriteProfilePath: string
|
||||
initialConflictResolutionProfilePath: string
|
||||
initialCommitProfilePath: string
|
||||
initialPrDiffSummaryProfilePath: string
|
||||
@@ -192,6 +194,7 @@ export function SettingsModal({
|
||||
initialDefaultTestProfilePath,
|
||||
initialDefaultPrototypeProfilePath,
|
||||
initialDefaultAskProfilePath,
|
||||
initialDefaultRewriteProfilePath,
|
||||
initialConflictResolutionProfilePath,
|
||||
initialCommitProfilePath,
|
||||
initialPrDiffSummaryProfilePath,
|
||||
@@ -236,6 +239,7 @@ export function SettingsModal({
|
||||
const [defaultTestProfilePath, setDefaultTestProfilePath] = useState(initialDefaultTestProfilePath)
|
||||
const [defaultPrototypeProfilePath, setDefaultPrototypeProfilePath] = useState(initialDefaultPrototypeProfilePath)
|
||||
const [defaultAskProfilePath, setDefaultAskProfilePath] = useState(initialDefaultAskProfilePath)
|
||||
const [defaultRewriteProfilePath, setDefaultRewriteProfilePath] = useState(initialDefaultRewriteProfilePath)
|
||||
const [conflictResolutionProfilePath, setConflictResolutionProfilePath] = useState(initialConflictResolutionProfilePath)
|
||||
const [commitProfilePath, setCommitProfilePath] = useState(initialCommitProfilePath)
|
||||
const [prDiffSummaryProfilePath, setPrDiffSummaryProfilePath] = useState(initialPrDiffSummaryProfilePath)
|
||||
@@ -282,6 +286,7 @@ export function SettingsModal({
|
||||
setDefaultTestProfilePath(initialDefaultTestProfilePath)
|
||||
setDefaultPrototypeProfilePath(initialDefaultPrototypeProfilePath)
|
||||
setDefaultAskProfilePath(initialDefaultAskProfilePath)
|
||||
setDefaultRewriteProfilePath(initialDefaultRewriteProfilePath)
|
||||
setConflictResolutionProfilePath(initialConflictResolutionProfilePath)
|
||||
setCommitProfilePath(initialCommitProfilePath)
|
||||
setPrDiffSummaryProfilePath(initialPrDiffSummaryProfilePath)
|
||||
@@ -380,6 +385,7 @@ export function SettingsModal({
|
||||
defaultTestProfilePath: defaultTestProfilePath.trim(),
|
||||
defaultPrototypeProfilePath: defaultPrototypeProfilePath.trim(),
|
||||
defaultAskProfilePath: defaultAskProfilePath.trim(),
|
||||
defaultRewriteProfilePath: defaultRewriteProfilePath.trim(),
|
||||
// 冲突解决 profile:空串 = 用 DEFAULT_PROFILE_PATH
|
||||
conflictResolutionProfilePath: conflictResolutionProfilePath.trim(),
|
||||
// 提交代码 profile:空串 = 未配置 → 提交严格失败
|
||||
@@ -663,8 +669,8 @@ export function SettingsModal({
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
label="文件问答默认模型"
|
||||
hint="代码阅读底部「问这个文件」默认使用此模型,也用于代码块和文件夹问答;留空沿用官方默认。输入框旁可临时切换,不会修改这里的默认值;重启或修改此设置后恢复默认。"
|
||||
label="问答默认模型"
|
||||
hint="代码阅读里问 AI 默认使用此模型:代码块下面的问答、预览顶部问这个文件或文件夹、「了解一块代码」都用它;留空沿用官方默认。输入框旁可临时切换,不会修改这里的默认值;重启或修改此设置后恢复默认。"
|
||||
>
|
||||
<SelectMenu
|
||||
value={defaultAskProfilePath}
|
||||
@@ -682,6 +688,26 @@ export function SettingsModal({
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
label="重写注释默认模型"
|
||||
hint="代码阅读里重写注释默认使用此模型:点按钮重写、在输入框里接着说都用它;留空沿用官方默认。输入框旁可临时切换,不会修改这里的默认值;重启或修改此设置后恢复默认。"
|
||||
>
|
||||
<SelectMenu
|
||||
value={defaultRewriteProfilePath}
|
||||
onChange={setDefaultRewriteProfilePath}
|
||||
variant="input"
|
||||
className={inputClass}
|
||||
options={[
|
||||
{ value: '', label: '(默认)' },
|
||||
...profiles.map(p => ({ value: p.path, label: p.name })),
|
||||
...(defaultRewriteProfilePath
|
||||
&& !profiles.some(p => p.path === defaultRewriteProfilePath)
|
||||
? [{ value: defaultRewriteProfilePath, label: `不可用:${defaultRewriteProfilePath}` }]
|
||||
: []),
|
||||
]}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
label="冲突解决配置文件"
|
||||
hint={(
|
||||
|
||||
@@ -53,6 +53,7 @@ export interface SettingsValues {
|
||||
defaultTestProfilePath: string
|
||||
defaultPrototypeProfilePath: string
|
||||
defaultAskProfilePath: string
|
||||
defaultRewriteProfilePath: string
|
||||
conflictResolutionProfilePath: string
|
||||
commitProfilePath: string
|
||||
prDiffSummaryProfilePath: string
|
||||
@@ -95,6 +96,7 @@ export interface SettingsOverlayState {
|
||||
defaultTestProfilePath: string
|
||||
defaultPrototypeProfilePath: string
|
||||
defaultAskProfilePath: string
|
||||
defaultRewriteProfilePath: string
|
||||
conflictResolutionProfilePath: string
|
||||
commitProfilePath: string
|
||||
prDiffSummaryProfilePath: string
|
||||
@@ -459,6 +461,7 @@ export function useIssues(): UseIssuesResult {
|
||||
defaultTestProfilePath: values.defaultTestProfilePath,
|
||||
defaultPrototypeProfilePath: values.defaultPrototypeProfilePath,
|
||||
defaultAskProfilePath: values.defaultAskProfilePath,
|
||||
defaultRewriteProfilePath: values.defaultRewriteProfilePath,
|
||||
conflictResolutionProfilePath: values.conflictResolutionProfilePath,
|
||||
commitProfilePath: values.commitProfilePath,
|
||||
prDiffSummaryProfilePath: values.prDiffSummaryProfilePath,
|
||||
@@ -981,6 +984,7 @@ export function useIssues(): UseIssuesResult {
|
||||
defaultTestProfilePath: msg.defaultTestProfilePath,
|
||||
defaultPrototypeProfilePath: msg.defaultPrototypeProfilePath,
|
||||
defaultAskProfilePath: msg.defaultAskProfilePath,
|
||||
defaultRewriteProfilePath: msg.defaultRewriteProfilePath,
|
||||
conflictResolutionProfilePath: msg.conflictResolutionProfilePath,
|
||||
commitProfilePath: msg.commitProfilePath,
|
||||
prDiffSummaryProfilePath: msg.prDiffSummaryProfilePath,
|
||||
|
||||
@@ -135,6 +135,7 @@ export type ExtensionToWebview
|
||||
defaultTestProfilePath: string
|
||||
defaultPrototypeProfilePath: string
|
||||
defaultAskProfilePath: string
|
||||
defaultRewriteProfilePath: string
|
||||
conflictResolutionProfilePath: string
|
||||
commitProfilePath: string
|
||||
prDiffSummaryProfilePath: string
|
||||
@@ -221,6 +222,7 @@ export type WebviewToExtension
|
||||
defaultTestProfilePath: string
|
||||
defaultPrototypeProfilePath: string
|
||||
defaultAskProfilePath: string
|
||||
defaultRewriteProfilePath: string
|
||||
conflictResolutionProfilePath: string
|
||||
commitProfilePath: string
|
||||
prDiffSummaryProfilePath: string
|
||||
|
||||
Reference in new issue
Block a user