/** * 五个会话入口(头脑风暴 / 实施 / 审查 / 测试 / 原型)的首个提示词。 * 模板正文在 `prompts/*.md`,用户改过的副本落在设置里,这里只负责 * 「读设置 + 灌上下文 + 渲染」。 * * 上下文一律是「工单 state JSON 全量字段 + 调用方补的几个变量」,所以模板里 * 想用 `{{branch}}`、`{{specFile}}` 这类字段不必改扩展代码。 */ import type { ExtensionContext } from 'vscode' import type { PromptContext } from './promptTemplate' import { logger } from '../logging/logger' import { getSettings } from '../settings/store' import { buildPromptContext, renderPromptTemplate } from './promptTemplate' /** 调用方补进模板上下文的变量;state 之外的都放这儿。 */ export interface PromptVars { /** `readIssueState` 的结果,读失败时给 undefined(模板里条件块自然走 else)。 */ state?: PromptContext /** 工单号;youtrack 卡片传可读 id(LXF-12),别传看板的合成号。 */ issueNumber?: string userRequest?: string nonce?: string planFile?: string prNumber?: string prRef?: string } /** * 模板语法错误不该把会话卡死:记 error 日志后原样把模板正文当提示词发出去, * 用户在终端里一眼能看到没被替换的 `{{...}}`,知道是自己模板写坏了。 */ function render(name: string, tpl: string, vars: PromptVars): string { const { state, ...extra } = vars try { return renderPromptTemplate(tpl, buildPromptContext(state, extra)) } catch (err) { logger.add({ level: 'error', source: 'prompts', message: `${name}提示词模板有语法错误,已原样发出未渲染的模板`, details: err instanceof Error ? err.message : String(err), }) return tpl } } /** * 头脑风暴提示词。模板用 `{{#if issueNumber}}` 分叉:有工单号 = 续聊已有工单, * 没有 = 新建工单(用 userRequest / nonce)。 * * 粘贴的参考图片不进模板——它是会话级附加信息,不是模板变量。 */ export function renderBrainstormPrompt( ctx: ExtensionContext, vars: PromptVars & { imagePaths?: string[] }, ): string { const { imagePaths, ...rest } = vars const out = render('头脑风暴', getSettings(ctx).brainstormPrompt, rest) if (!imagePaths || imagePaths.length === 0) return out const lines = imagePaths.map(p => `- ${p}`).join('\n') return `${out}\n\n参考图片(请用 Read 工具查看):\n${lines}` } export function renderImplementPlanPrompt(ctx: ExtensionContext, vars: PromptVars): string { return render('实施', getSettings(ctx).implementPlanPrompt, vars) } /** * 测试会话首个提示词。`prRef` 是给验收技能的定位线索:主 worktree 上是 * 已合并的 PR,worktree 里就是那条分支。 */ export function renderTestPrompt(ctx: ExtensionContext, vars: PromptVars): string { return render('测试', getSettings(ctx).testPrompt, vars) } /** 原型会话首个提示词。只认工单号——原型照工单正文画界面,与 PR / 分支无关。 */ export function renderPrototypePrompt(ctx: ExtensionContext, vars: PromptVars): string { return render('原型', getSettings(ctx).prototypePrompt, vars) } export function renderReviewPrompt(ctx: ExtensionContext, vars: PromptVars): string { return render('审查', getSettings(ctx).reviewPrompt, vars) }