mirror of
https://github.com/EthanMarti/infio-copilot.git
synced 2026-01-18 17:22:52 +00:00
feat: custom prompt
This commit is contained in:
parent
b5a322df31
commit
5558c96aa1
1
src/core/prompts/constants.ts
Normal file
1
src/core/prompts/constants.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const ROOT_DIR = '_infio_prompts'
|
||||||
@ -1,25 +1,24 @@
|
|||||||
import fs from "fs/promises"
|
|
||||||
import path from "path"
|
|
||||||
|
|
||||||
async function safeReadFile(filePath: string): Promise<string> {
|
import * as path from 'path'
|
||||||
try {
|
|
||||||
const content = await fs.readFile(filePath, "utf-8")
|
import { App, normalizePath } from 'obsidian'
|
||||||
return content.trim()
|
|
||||||
} catch (err) {
|
import { ROOT_DIR } from '../constants'
|
||||||
const errorCode = (err as NodeJS.ErrnoException).code
|
|
||||||
if (!errorCode || !["ENOENT", "EISDIR"].includes(errorCode)) {
|
export async function loadRuleFiles(
|
||||||
throw err
|
app: App,
|
||||||
}
|
mode: string,
|
||||||
|
): Promise<string> {
|
||||||
|
const ruleFilesFolder = path.join(ROOT_DIR, `${mode}/rules/`)
|
||||||
|
if (!(await app.vault.adapter.exists(ruleFilesFolder))) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export async function loadRuleFiles(cwd: string): Promise<string> {
|
const ruleFiles = await app.vault.adapter.list(normalizePath(ruleFilesFolder))
|
||||||
const ruleFiles = [".clinerules", ".cursorrules", ".windsurfrules"]
|
|
||||||
let combinedRules = ""
|
let combinedRules = ""
|
||||||
|
for (const file of ruleFiles.files) {
|
||||||
for (const file of ruleFiles) {
|
const content = await app.vault.adapter.read(normalizePath(file))
|
||||||
const content = await safeReadFile(path.join(cwd, file))
|
|
||||||
if (content) {
|
if (content) {
|
||||||
combinedRules += `\n# Rules from ${file}:\n${content}\n`
|
combinedRules += `\n# Rules from ${file}:\n${content}\n`
|
||||||
}
|
}
|
||||||
@ -29,19 +28,23 @@ export async function loadRuleFiles(cwd: string): Promise<string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function addCustomInstructions(
|
export async function addCustomInstructions(
|
||||||
|
app: App,
|
||||||
modeCustomInstructions: string,
|
modeCustomInstructions: string,
|
||||||
globalCustomInstructions: string,
|
globalCustomInstructions: string,
|
||||||
cwd: string,
|
cwd: string,
|
||||||
mode: string,
|
mode: string,
|
||||||
options: { preferredLanguage?: string } = {},
|
options: { preferredLanguage?: string } = {},
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
|
console.log("addCustomInstructions this app, ", app)
|
||||||
const sections = []
|
const sections = []
|
||||||
|
|
||||||
// Load mode-specific rules if mode is provided
|
// Load mode-specific rules file if mode is provided
|
||||||
let modeRuleContent = ""
|
let modeRuleContent = ""
|
||||||
if (mode) {
|
if (mode) {
|
||||||
const modeRuleFile = `.clinerules-${mode}`
|
const modeRulesFile = path.join(ROOT_DIR, `${mode}/rules.md`)
|
||||||
modeRuleContent = await safeReadFile(path.join(cwd, modeRuleFile))
|
if (await app.vault.adapter.exists(modeRulesFile)) {
|
||||||
|
modeRuleContent = await app.vault.adapter.read(normalizePath(modeRulesFile))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add language preference if provided
|
// Add language preference if provided
|
||||||
@ -66,12 +69,12 @@ export async function addCustomInstructions(
|
|||||||
|
|
||||||
// Add mode-specific rules first if they exist
|
// Add mode-specific rules first if they exist
|
||||||
if (modeRuleContent && modeRuleContent.trim()) {
|
if (modeRuleContent && modeRuleContent.trim()) {
|
||||||
const modeRuleFile = `.clinerules-${mode}`
|
const modeRuleFile = `${mode}_rules.md`
|
||||||
rules.push(`# Rules from ${modeRuleFile}:\n${modeRuleContent}`)
|
rules.push(`# Rules from ${modeRuleFile}:\n${modeRuleContent}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add generic rules
|
// Add generic rules
|
||||||
const genericRuleContent = await loadRuleFiles(cwd)
|
const genericRuleContent = await loadRuleFiles(app, mode)
|
||||||
if (genericRuleContent && genericRuleContent.trim()) {
|
if (genericRuleContent && genericRuleContent.trim()) {
|
||||||
rules.push(genericRuleContent.trim())
|
rules.push(genericRuleContent.trim())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import path from "path"
|
|||||||
|
|
||||||
import { Mode } from "../../../shared/modes"
|
import { Mode } from "../../../shared/modes"
|
||||||
import { fileExistsAtPath } from "../../../utils/fs"
|
import { fileExistsAtPath } from "../../../utils/fs"
|
||||||
|
import { Mode } from "../../../utils/modes"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Safely reads a file, returning an empty string if the file doesn't exist
|
* Safely reads a file, returning an empty string if the file doesn't exist
|
||||||
@ -27,23 +28,26 @@ async function safeReadFile(filePath: string): Promise<string> {
|
|||||||
* Get the path to a system prompt file for a specific mode
|
* Get the path to a system prompt file for a specific mode
|
||||||
*/
|
*/
|
||||||
export function getSystemPromptFilePath(cwd: string, mode: Mode): string {
|
export function getSystemPromptFilePath(cwd: string, mode: Mode): string {
|
||||||
return path.join(cwd, ".roo", `system-prompt-${mode}`)
|
return path.join(cwd, "_infio_prompts", `${mode}_system_prompt`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads custom system prompt from a file at .roo/system-prompt-[mode slug]
|
* Loads custom system prompt from a file at _infio_prompts/system-prompt-[mode slug]
|
||||||
* If the file doesn't exist, returns an empty string
|
* If the file doesn't exist, returns an empty string
|
||||||
*/
|
*/
|
||||||
export async function loadSystemPromptFile(cwd: string, mode: Mode): Promise<string> {
|
export async function loadSystemPromptFile(cwd: string, mode: Mode): Promise<string> {
|
||||||
|
console.log("cwd", cwd)
|
||||||
|
console.log("mode", mode)
|
||||||
const filePath = getSystemPromptFilePath(cwd, mode)
|
const filePath = getSystemPromptFilePath(cwd, mode)
|
||||||
|
console.log("filePath", filePath)
|
||||||
return safeReadFile(filePath)
|
return safeReadFile(filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures the .roo directory exists, creating it if necessary
|
* Ensures the _infio_prompts directory exists, creating it if necessary
|
||||||
*/
|
*/
|
||||||
export async function ensureRooDirectory(cwd: string): Promise<void> {
|
export async function ensureInfioPromptsDirectory(cwd: string): Promise<void> {
|
||||||
const rooDir = path.join(cwd, ".roo")
|
const infioPromptsDir = path.join(cwd, "_infio_prompts")
|
||||||
|
|
||||||
// Check if directory already exists
|
// Check if directory already exists
|
||||||
if (await fileExistsAtPath(rooDir)) {
|
if (await fileExistsAtPath(rooDir)) {
|
||||||
@ -52,7 +56,7 @@ export async function ensureRooDirectory(cwd: string): Promise<void> {
|
|||||||
|
|
||||||
// Create the directory
|
// Create the directory
|
||||||
try {
|
try {
|
||||||
await fs.mkdir(rooDir, { recursive: true })
|
await fs.mkdir(infioPromptsDir, { recursive: true })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// If directory already exists (race condition), ignore the error
|
// If directory already exists (race condition), ignore the error
|
||||||
const errorCode = (err as NodeJS.ErrnoException).code
|
const errorCode = (err as NodeJS.ErrnoException).code
|
||||||
|
|||||||
220
src/core/prompts/system-prompts-manager.ts
Normal file
220
src/core/prompts/system-prompts-manager.ts
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
|
||||||
|
import * as path from 'path'
|
||||||
|
|
||||||
|
import { App, normalizePath } from 'obsidian'
|
||||||
|
|
||||||
|
import {
|
||||||
|
CustomModePrompts,
|
||||||
|
Mode,
|
||||||
|
ModeConfig,
|
||||||
|
PromptComponent,
|
||||||
|
defaultModeSlug,
|
||||||
|
getGroupName,
|
||||||
|
getModeBySlug,
|
||||||
|
modes
|
||||||
|
} from "../../utils/modes"
|
||||||
|
import { DiffStrategy } from "../diff/DiffStrategy"
|
||||||
|
import { McpHub } from "../mcp/McpHub"
|
||||||
|
|
||||||
|
|
||||||
|
import { ROOT_DIR } from './constants'
|
||||||
|
import {
|
||||||
|
addCustomInstructions,
|
||||||
|
getCapabilitiesSection,
|
||||||
|
getMcpServersSection,
|
||||||
|
getModesSection,
|
||||||
|
getObjectiveSection,
|
||||||
|
getRulesSection,
|
||||||
|
getSharedToolUseSection,
|
||||||
|
getSystemInfoSection,
|
||||||
|
getToolUseGuidelinesSection,
|
||||||
|
} from "./sections"
|
||||||
|
// import { loadSystemPromptFile } from "./sections/custom-system-prompt"
|
||||||
|
import { getToolDescriptionsForMode } from "./tools"
|
||||||
|
|
||||||
|
|
||||||
|
export class SystemPromptsManager {
|
||||||
|
protected dataDir: string
|
||||||
|
protected app: App
|
||||||
|
|
||||||
|
constructor(app: App) {
|
||||||
|
this.app = app
|
||||||
|
this.dataDir = normalizePath(`${ROOT_DIR}`)
|
||||||
|
this.ensureDirectory()
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ensureDirectory(): Promise<void> {
|
||||||
|
console.log("this.app, ", this.app)
|
||||||
|
if (!(await this.app.vault.adapter.exists(this.dataDir))) {
|
||||||
|
await this.app.vault.adapter.mkdir(this.dataDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSystemPromptFilePath(mode: Mode): string {
|
||||||
|
// Format: {mode slug}_system_prompt.md
|
||||||
|
return `${mode}/system_prompt.md`
|
||||||
|
}
|
||||||
|
|
||||||
|
private async loadSystemPromptFile(mode: Mode): Promise<string> {
|
||||||
|
const fileName = this.getSystemPromptFilePath(mode)
|
||||||
|
const filePath = normalizePath(path.join(this.dataDir, fileName))
|
||||||
|
if (!(await this.app.vault.adapter.exists(filePath))) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
const content = await this.app.vault.adapter.read(filePath)
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
|
||||||
|
private async generatePrompt(
|
||||||
|
cwd: string,
|
||||||
|
supportsComputerUse: boolean,
|
||||||
|
mode: Mode,
|
||||||
|
filesSearchMethod: string,
|
||||||
|
mcpHub?: McpHub,
|
||||||
|
diffStrategy?: DiffStrategy,
|
||||||
|
browserViewportSize?: string,
|
||||||
|
promptComponent?: PromptComponent,
|
||||||
|
customModeConfigs?: ModeConfig[],
|
||||||
|
globalCustomInstructions?: string,
|
||||||
|
preferredLanguage?: string,
|
||||||
|
diffEnabled?: boolean,
|
||||||
|
experiments?: Record<string, boolean>,
|
||||||
|
enableMcpServerCreation?: boolean,
|
||||||
|
): Promise<string> {
|
||||||
|
// if (!context) {
|
||||||
|
// throw new Error("Extension context is required for generating system prompt")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // If diff is disabled, don't pass the diffStrategy
|
||||||
|
// const effectiveDiffStrategy = diffEnabled ? diffStrategy : undefined
|
||||||
|
|
||||||
|
// Get the full mode config to ensure we have the role definition
|
||||||
|
const modeConfig = getModeBySlug(mode, customModeConfigs) || modes.find((m) => m.slug === mode) || modes[0]
|
||||||
|
const roleDefinition = promptComponent?.roleDefinition || modeConfig.roleDefinition
|
||||||
|
|
||||||
|
const [modesSection, mcpServersSection] = await Promise.all([
|
||||||
|
getModesSection(),
|
||||||
|
modeConfig.groups.some((groupEntry) => getGroupName(groupEntry) === "mcp")
|
||||||
|
? getMcpServersSection(mcpHub, diffStrategy, enableMcpServerCreation)
|
||||||
|
: Promise.resolve(""),
|
||||||
|
])
|
||||||
|
|
||||||
|
const basePrompt = `${roleDefinition}
|
||||||
|
|
||||||
|
${getSharedToolUseSection()}
|
||||||
|
|
||||||
|
${getToolDescriptionsForMode(
|
||||||
|
mode,
|
||||||
|
cwd,
|
||||||
|
filesSearchMethod,
|
||||||
|
supportsComputerUse,
|
||||||
|
diffStrategy,
|
||||||
|
browserViewportSize,
|
||||||
|
mcpHub,
|
||||||
|
customModeConfigs,
|
||||||
|
experiments,
|
||||||
|
)}
|
||||||
|
|
||||||
|
${getToolUseGuidelinesSection()}
|
||||||
|
|
||||||
|
${mcpServersSection}
|
||||||
|
|
||||||
|
${getCapabilitiesSection(
|
||||||
|
mode,
|
||||||
|
cwd,
|
||||||
|
filesSearchMethod,
|
||||||
|
)}
|
||||||
|
|
||||||
|
${modesSection}
|
||||||
|
|
||||||
|
${getRulesSection(
|
||||||
|
mode,
|
||||||
|
cwd,
|
||||||
|
filesSearchMethod,
|
||||||
|
supportsComputerUse,
|
||||||
|
diffStrategy,
|
||||||
|
experiments,
|
||||||
|
)}
|
||||||
|
|
||||||
|
${getSystemInfoSection(cwd)}
|
||||||
|
|
||||||
|
${getObjectiveSection(mode)}
|
||||||
|
|
||||||
|
${await addCustomInstructions(this.app, promptComponent?.customInstructions || modeConfig.customInstructions || "", globalCustomInstructions || "", cwd, mode, { preferredLanguage })}`
|
||||||
|
|
||||||
|
return basePrompt
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getSystemPrompt(
|
||||||
|
cwd: string,
|
||||||
|
supportsComputerUse: boolean,
|
||||||
|
mode: Mode = defaultModeSlug,
|
||||||
|
filesSearchMethod: string = 'regex',
|
||||||
|
preferredLanguage?: string,
|
||||||
|
diffStrategy?: DiffStrategy,
|
||||||
|
mcpHub?: McpHub,
|
||||||
|
browserViewportSize?: string,
|
||||||
|
customModePrompts?: CustomModePrompts,
|
||||||
|
customModes?: ModeConfig[],
|
||||||
|
globalCustomInstructions?: string,
|
||||||
|
diffEnabled?: boolean,
|
||||||
|
experiments?: Record<string, boolean>,
|
||||||
|
enableMcpServerCreation?: boolean,
|
||||||
|
): Promise<string> {
|
||||||
|
|
||||||
|
const getPromptComponent = (value: unknown): PromptComponent | undefined => {
|
||||||
|
if (typeof value === "object" && value !== null) {
|
||||||
|
return value as PromptComponent
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load custom system prompt from file
|
||||||
|
const fileCustomSystemPrompt = await this.loadSystemPromptFile(mode)
|
||||||
|
|
||||||
|
// Check if it's a custom mode
|
||||||
|
const promptComponent = getPromptComponent(customModePrompts?.[mode])
|
||||||
|
|
||||||
|
// Get full mode config from custom modes or fall back to built-in modes
|
||||||
|
const currentMode = getModeBySlug(mode, customModes) || modes.find((m) => m.slug === mode) || modes[0]
|
||||||
|
|
||||||
|
// If a file-based custom system prompt exists, use it
|
||||||
|
if (fileCustomSystemPrompt) {
|
||||||
|
const roleDefinition = promptComponent?.roleDefinition || currentMode.roleDefinition
|
||||||
|
const customInstructions = await addCustomInstructions(
|
||||||
|
this.app,
|
||||||
|
promptComponent?.customInstructions || currentMode.customInstructions || "",
|
||||||
|
globalCustomInstructions || "",
|
||||||
|
cwd,
|
||||||
|
mode,
|
||||||
|
{ preferredLanguage },
|
||||||
|
)
|
||||||
|
return `${roleDefinition}
|
||||||
|
|
||||||
|
${fileCustomSystemPrompt}
|
||||||
|
|
||||||
|
${customInstructions}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// // If diff is disabled, don't pass the diffStrategy
|
||||||
|
// const effectiveDiffStrategy = diffEnabled ? diffStrategy : undefined
|
||||||
|
|
||||||
|
return this.generatePrompt(
|
||||||
|
// context,
|
||||||
|
cwd,
|
||||||
|
supportsComputerUse,
|
||||||
|
currentMode.slug,
|
||||||
|
filesSearchMethod,
|
||||||
|
mcpHub,
|
||||||
|
diffStrategy,
|
||||||
|
browserViewportSize,
|
||||||
|
promptComponent,
|
||||||
|
customModes,
|
||||||
|
globalCustomInstructions,
|
||||||
|
preferredLanguage,
|
||||||
|
diffEnabled,
|
||||||
|
experiments,
|
||||||
|
enableMcpServerCreation,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,173 +0,0 @@
|
|||||||
import {
|
|
||||||
CustomModePrompts,
|
|
||||||
Mode,
|
|
||||||
ModeConfig,
|
|
||||||
PromptComponent,
|
|
||||||
defaultModeSlug,
|
|
||||||
getGroupName,
|
|
||||||
getModeBySlug,
|
|
||||||
modes
|
|
||||||
} from "../../utils/modes"
|
|
||||||
import { DiffStrategy } from "../diff/DiffStrategy"
|
|
||||||
import { McpHub } from "../mcp/McpHub"
|
|
||||||
|
|
||||||
import {
|
|
||||||
addCustomInstructions,
|
|
||||||
getCapabilitiesSection,
|
|
||||||
getMcpServersSection,
|
|
||||||
getModesSection,
|
|
||||||
getObjectiveSection,
|
|
||||||
getRulesSection,
|
|
||||||
getSharedToolUseSection,
|
|
||||||
getSystemInfoSection,
|
|
||||||
getToolUseGuidelinesSection,
|
|
||||||
} from "./sections"
|
|
||||||
import { getToolDescriptionsForMode } from "./tools"
|
|
||||||
|
|
||||||
async function generatePrompt(
|
|
||||||
cwd: string,
|
|
||||||
supportsComputerUse: boolean,
|
|
||||||
mode: Mode,
|
|
||||||
filesSearchMethod: string,
|
|
||||||
mcpHub?: McpHub,
|
|
||||||
diffStrategy?: DiffStrategy,
|
|
||||||
browserViewportSize?: string,
|
|
||||||
promptComponent?: PromptComponent,
|
|
||||||
customModeConfigs?: ModeConfig[],
|
|
||||||
globalCustomInstructions?: string,
|
|
||||||
preferredLanguage?: string,
|
|
||||||
diffEnabled?: boolean,
|
|
||||||
experiments?: Record<string, boolean>,
|
|
||||||
enableMcpServerCreation?: boolean,
|
|
||||||
): Promise<string> {
|
|
||||||
// if (!context) {
|
|
||||||
// throw new Error("Extension context is required for generating system prompt")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // If diff is disabled, don't pass the diffStrategy
|
|
||||||
// const effectiveDiffStrategy = diffEnabled ? diffStrategy : undefined
|
|
||||||
|
|
||||||
// Get the full mode config to ensure we have the role definition
|
|
||||||
const modeConfig = getModeBySlug(mode, customModeConfigs) || modes.find((m) => m.slug === mode) || modes[0]
|
|
||||||
const roleDefinition = promptComponent?.roleDefinition || modeConfig.roleDefinition
|
|
||||||
|
|
||||||
const [modesSection, mcpServersSection] = await Promise.all([
|
|
||||||
getModesSection(),
|
|
||||||
modeConfig.groups.some((groupEntry) => getGroupName(groupEntry) === "mcp")
|
|
||||||
? getMcpServersSection(mcpHub, diffStrategy, enableMcpServerCreation)
|
|
||||||
: Promise.resolve(""),
|
|
||||||
])
|
|
||||||
|
|
||||||
const basePrompt = `${roleDefinition}
|
|
||||||
|
|
||||||
${getSharedToolUseSection()}
|
|
||||||
|
|
||||||
${getToolDescriptionsForMode(
|
|
||||||
mode,
|
|
||||||
cwd,
|
|
||||||
filesSearchMethod,
|
|
||||||
supportsComputerUse,
|
|
||||||
diffStrategy,
|
|
||||||
browserViewportSize,
|
|
||||||
mcpHub,
|
|
||||||
customModeConfigs,
|
|
||||||
experiments,
|
|
||||||
)}
|
|
||||||
|
|
||||||
${getToolUseGuidelinesSection()}
|
|
||||||
|
|
||||||
${mcpServersSection}
|
|
||||||
|
|
||||||
${getCapabilitiesSection(
|
|
||||||
mode,
|
|
||||||
cwd,
|
|
||||||
filesSearchMethod,
|
|
||||||
)}
|
|
||||||
|
|
||||||
${modesSection}
|
|
||||||
|
|
||||||
${getRulesSection(
|
|
||||||
mode,
|
|
||||||
cwd,
|
|
||||||
filesSearchMethod,
|
|
||||||
supportsComputerUse,
|
|
||||||
diffStrategy,
|
|
||||||
experiments,
|
|
||||||
)}
|
|
||||||
|
|
||||||
${getSystemInfoSection(cwd)}
|
|
||||||
|
|
||||||
${getObjectiveSection(mode)}
|
|
||||||
|
|
||||||
${await addCustomInstructions(promptComponent?.customInstructions || modeConfig.customInstructions || "", globalCustomInstructions || "", cwd, mode, { preferredLanguage })}`
|
|
||||||
|
|
||||||
return basePrompt
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SYSTEM_PROMPT = async (
|
|
||||||
cwd: string,
|
|
||||||
supportsComputerUse: boolean,
|
|
||||||
mode: Mode = defaultModeSlug,
|
|
||||||
filesSearchMethod: string = 'regex',
|
|
||||||
preferredLanguage?: string,
|
|
||||||
diffStrategy?: DiffStrategy,
|
|
||||||
mcpHub?: McpHub,
|
|
||||||
browserViewportSize?: string,
|
|
||||||
customModePrompts?: CustomModePrompts,
|
|
||||||
customModes?: ModeConfig[],
|
|
||||||
globalCustomInstructions?: string,
|
|
||||||
diffEnabled?: boolean,
|
|
||||||
experiments?: Record<string, boolean>,
|
|
||||||
enableMcpServerCreation?: boolean,
|
|
||||||
): Promise<string> => {
|
|
||||||
// if (!context) {
|
|
||||||
// throw new Error("Extension context is required for generating system prompt")
|
|
||||||
// }
|
|
||||||
|
|
||||||
const getPromptComponent = (value: unknown) => {
|
|
||||||
if (typeof value === "object" && value !== null) {
|
|
||||||
return value as PromptComponent
|
|
||||||
}
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to load custom system prompt from file
|
|
||||||
// const fileCustomSystemPrompt = await loadSystemPromptFile(cwd, mode)
|
|
||||||
|
|
||||||
// Check if it's a custom mode
|
|
||||||
const promptComponent = getPromptComponent(customModePrompts?.[mode])
|
|
||||||
|
|
||||||
// Get full mode config from custom modes or fall back to built-in modes
|
|
||||||
const currentMode = getModeBySlug(mode, customModes) || modes.find((m) => m.slug === mode) || modes[0]
|
|
||||||
|
|
||||||
// If a file-based custom system prompt exists, use it
|
|
||||||
// if (fileCustomSystemPrompt) {
|
|
||||||
// const roleDefinition = promptComponent?.roleDefinition || currentMode.roleDefinition
|
|
||||||
// return `${roleDefinition}
|
|
||||||
|
|
||||||
// ${fileCustomSystemPrompt}
|
|
||||||
|
|
||||||
// ${await addCustomInstructions(promptComponent?.customInstructions || currentMode.customInstructions || "", globalCustomInstructions || "", cwd, mode, { preferredLanguage })}`
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // If diff is disabled, don't pass the diffStrategy
|
|
||||||
// const effectiveDiffStrategy = diffEnabled ? diffStrategy : undefined
|
|
||||||
|
|
||||||
return generatePrompt(
|
|
||||||
// context,
|
|
||||||
cwd,
|
|
||||||
supportsComputerUse,
|
|
||||||
currentMode.slug,
|
|
||||||
filesSearchMethod,
|
|
||||||
mcpHub,
|
|
||||||
diffStrategy,
|
|
||||||
browserViewportSize,
|
|
||||||
promptComponent,
|
|
||||||
customModes,
|
|
||||||
globalCustomInstructions,
|
|
||||||
preferredLanguage,
|
|
||||||
diffEnabled,
|
|
||||||
experiments,
|
|
||||||
enableMcpServerCreation,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
47
src/utils/fs.ts
Normal file
47
src/utils/fs.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import fs from "fs/promises"
|
||||||
|
import * as path from "path"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronously creates all non-existing subdirectories for a given file path
|
||||||
|
* and collects them in an array for later deletion.
|
||||||
|
*
|
||||||
|
* @param filePath - The full path to a file.
|
||||||
|
* @returns A promise that resolves to an array of newly created directories.
|
||||||
|
*/
|
||||||
|
export async function createDirectoriesForFile(filePath: string): Promise<string[]> {
|
||||||
|
const newDirectories: string[] = []
|
||||||
|
const normalizedFilePath = path.normalize(filePath) // Normalize path for cross-platform compatibility
|
||||||
|
const directoryPath = path.dirname(normalizedFilePath)
|
||||||
|
|
||||||
|
let currentPath = directoryPath
|
||||||
|
const dirsToCreate: string[] = []
|
||||||
|
|
||||||
|
// Traverse up the directory tree and collect missing directories
|
||||||
|
while (!(await fileExistsAtPath(currentPath))) {
|
||||||
|
dirsToCreate.push(currentPath)
|
||||||
|
currentPath = path.dirname(currentPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create directories from the topmost missing one down to the target directory
|
||||||
|
for (let i = dirsToCreate.length - 1; i >= 0; i--) {
|
||||||
|
await fs.mkdir(dirsToCreate[i])
|
||||||
|
newDirectories.push(dirsToCreate[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return newDirectories
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to check if a path exists.
|
||||||
|
*
|
||||||
|
* @param path - The path to check.
|
||||||
|
* @returns A promise that resolves to true if the path exists, false otherwise.
|
||||||
|
*/
|
||||||
|
export async function fileExistsAtPath(filePath: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
await fs.access(filePath)
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,6 +8,7 @@ import { RAGEngine } from '../core/rag/rag-engine'
|
|||||||
import { SelectVector } from '../database/schema'
|
import { SelectVector } from '../database/schema'
|
||||||
import { ChatMessage, ChatUserMessage } from '../types/chat'
|
import { ChatMessage, ChatUserMessage } from '../types/chat'
|
||||||
import { ContentPart, RequestMessage } from '../types/llm/request'
|
import { ContentPart, RequestMessage } from '../types/llm/request'
|
||||||
|
import { SystemPromptsManager } from '../core/prompts/system-prompts-manager'
|
||||||
import {
|
import {
|
||||||
MentionableBlock,
|
MentionableBlock,
|
||||||
MentionableFile,
|
MentionableFile,
|
||||||
@ -115,6 +116,7 @@ export class PromptGenerator {
|
|||||||
private app: App
|
private app: App
|
||||||
private settings: InfioSettings
|
private settings: InfioSettings
|
||||||
private diffStrategy: DiffStrategy
|
private diffStrategy: DiffStrategy
|
||||||
|
private systemPromptsManager: SystemPromptsManager
|
||||||
private static readonly EMPTY_ASSISTANT_MESSAGE: RequestMessage = {
|
private static readonly EMPTY_ASSISTANT_MESSAGE: RequestMessage = {
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: '',
|
content: '',
|
||||||
@ -130,6 +132,7 @@ export class PromptGenerator {
|
|||||||
this.app = app
|
this.app = app
|
||||||
this.settings = settings
|
this.settings = settings
|
||||||
this.diffStrategy = diffStrategy
|
this.diffStrategy = diffStrategy
|
||||||
|
this.systemPromptsManager = new SystemPromptsManager(this.app)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async generateRequestMessages({
|
public async generateRequestMessages({
|
||||||
@ -465,7 +468,7 @@ export class PromptGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async getSystemMessageNew(mode: Mode, filesSearchMethod: string, preferredLanguage: string): Promise<RequestMessage> {
|
private async getSystemMessageNew(mode: Mode, filesSearchMethod: string, preferredLanguage: string): Promise<RequestMessage> {
|
||||||
const systemPrompt = await SYSTEM_PROMPT(
|
const systemPrompt = await this.systemPromptsManager.getSystemPrompt(
|
||||||
this.app.vault.getRoot().path,
|
this.app.vault.getRoot().path,
|
||||||
false,
|
false,
|
||||||
mode,
|
mode,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user