Files
superwork/vscode/src/codeReader/qa/pathAskPrompt.ts
T

75 lines
3.6 KiB
TypeScript

/**
* 侧栏问一个路径时发给模型的话:写明是文件还是文件夹、相对工作区的路径(工作区外的库文件写绝对路径)。
* 文件附上开头若干行;文件夹只列这一层的名字,不把里面的代码贴进去。
*/
/** 文件开头最多贴这么多行,剩下的让模型自己去读。 */
export const PATH_ASK_HEAD_LINES = 80
export interface PathChild {
name: string
kind: 'file' | 'folder'
}
/** 文件开头:贴得下的行,或者为什么没附上。 */
export type PathHead
= | { lines: string[], truncated: boolean }
| { unavailable: string }
/** 问的这条路径在哪:工作区里的 [path] 是相对所在工作区文件夹的路径;[outside] 时在工作区外(比如库源码),[path] 是绝对路径 */
interface PathAskWhere {
path: string
outside?: true
}
export interface PathAskFile extends PathAskWhere {
kind: 'file'
head: PathHead
}
export interface PathAskFolder extends PathAskWhere {
kind: 'folder'
/** 这一层的子文件和子文件夹,调用方排好序;列不出来时是原因 */
children: PathChild[] | { unavailable: string }
}
export type PathAskSubject = PathAskFile | PathAskFolder
const LEAD = '我在看项目里的一个路径,想问它。请用中文、大白话、简洁地回答,不绕弯子。需要时可以自己去读、搜项目里的文件,但只读,不要改任何东西。提到文件时写相对项目根目录的路径。'
/** 一次提问的全文。不写进某一块代码的问答记录。 */
export function pathAskPrompt(subject: PathAskSubject, question: string): string {
const noun = subject.kind === 'folder' ? '文件夹' : '文件'
const where = subject.outside
? `这是项目外的一个${noun}(比如依赖库的源码),绝对路径:${subject.path}`
: `这是一个${noun},相对路径:${subject.path}`
const detail = subject.kind === 'file' ? fileHead(subject.head) : folderList(subject.children)
return [LEAD, where, detail, `问题:${question}`].join('\n\n')
}
/** 这条路径已经问过、接着上一次会话问时发的话:只说还是这个文件或文件夹(`path` 同 [PathAskSubject] 的),材料在会话里。 */
export function pathAskFollowUp(path: string, kind: 'file' | 'folder', question: string): string {
const noun = kind === 'folder' ? '文件夹' : '文件'
return `接着问(还是 ${path} 这个${noun},需要时重新读):${question}`
}
function fileHead(head: PathHead): string {
if ('unavailable' in head)
return `文件开头没附上:${head.unavailable}`
if (head.lines.length === 0)
return head.truncated ? '文件开头一行都没读全,需要时自己读这个文件。' : '文件是空的。'
const width = String(head.lines.length).length
const body = head.lines.map((line, index) => `${String(index + 1).padStart(width)} | ${line}`).join('\n')
const rest = head.truncated ? `\n(上面只贴了开头 ${head.lines.length} 行,剩下的需要时自己读这个文件)` : ''
return `文件开头:\n${body}${rest}`
}
function folderList(children: PathAskFolder['children']): string {
if (!Array.isArray(children))
return `这一层没列出来:${children.unavailable}`
if (children.length === 0)
return '里面这一层是空的。'
const lines = children.map(child => `- ${child.kind === 'folder' ? '文件夹' : '文件'} ${child.name}`)
return `里面这一层有:\n${lines.join('\n')}\n只列了这一层的名字,没有把里面的代码贴进来。侧栏里不显示的名字这里也没列。需要时自己去读这些文件。`
}