fix inline edit can't up error

This commit is contained in:
duanfuxiang 2025-04-30 18:47:14 +08:00
parent dfdb21e832
commit 92b5c8fe61
6 changed files with 97 additions and 39 deletions

View File

@ -7,7 +7,7 @@ import { APPLY_VIEW_TYPE } from './constants'
import { AppProvider } from './contexts/AppContext'
export type ApplyViewState = {
file: TFile
file: string
oldContent: string
newContent: string
onClose: (applied: boolean) => void

View File

@ -53,8 +53,11 @@ export default function ApplyViewRoot({
}
return result;
}, '')
await app.vault.modify(state.file, newContent)
const file = app.vault.getFileByPath(state.file)
if (!file) {
throw new Error('File not found')
}
await app.vault.modify(file, newContent)
if (state.onClose) {
state.onClose(true)
}

View File

@ -401,7 +401,7 @@ const Chat = forwardRef<ChatRef, ChatProps>((props, ref) => {
type: APPLY_VIEW_TYPE,
active: true,
state: {
file: opFile,
file: opFile.path,
oldContent: '',
newContent: toolArgs.content,
onClose: (applied: boolean) => {
@ -452,7 +452,7 @@ const Chat = forwardRef<ChatRef, ChatProps>((props, ref) => {
type: APPLY_VIEW_TYPE,
active: true,
state: {
file: opFile,
file: opFile.path,
oldContent: fileContent,
newContent: appliedFileContent,
onClose: (applied: boolean) => {
@ -494,7 +494,7 @@ const Chat = forwardRef<ChatRef, ChatProps>((props, ref) => {
type: APPLY_VIEW_TYPE,
active: true,
state: {
file: opFile,
file: opFile.path,
oldContent: fileContent,
newContent: appliedFileContent,
onClose: (applied: boolean) => {
@ -536,7 +536,7 @@ const Chat = forwardRef<ChatRef, ChatProps>((props, ref) => {
type: APPLY_VIEW_TYPE,
active: true,
state: {
file: opFile,
file: opFile.path,
oldContent: fileContent,
newContent: appliedResult.content,
onClose: (applied: boolean) => {

View File

@ -98,7 +98,7 @@ const CustomModeView = () => {
setCustomInstructions(customMode.customInstructions || '');
setSelectedTools(customMode.groups);
} else {
console.log("error, custom mode not found")
console.error("custom mode not found")
}
}
}, [selectedMode, customModeList]);

View File

@ -11,7 +11,7 @@ import { removeAITags } from '../../utils/content-filter';
import { PromptGenerator } from '../../utils/prompt-generator';
type InlineEditProps = {
source: string;
source?: string;
secStartLine: number;
secEndLine: number;
plugin: Plugin;
@ -173,20 +173,14 @@ export const InlineEdit: React.FC<InlineEditProps> = ({
};
const parseSmartComposeBlock = (content: string) => {
const match = /<infio_block[^>]*>([\s\S]*?)<\/infio_block>/.exec(content);
const match = /<response>([\s\S]*?)<\/response>/.exec(content);
if (!match) {
return null;
}
const blockContent = match[1].trim();
const attributes = /startLine="(\d+)"/.exec(match[0]);
const startLine = attributes ? parseInt(attributes[1]) : undefined;
const endLineMatch = /endLine="(\d+)"/.exec(match[0]);
const endLine = endLineMatch ? parseInt(endLineMatch[1]) : undefined;
return {
startLine,
endLine,
content: blockContent,
};
};
@ -196,6 +190,7 @@ export const InlineEdit: React.FC<InlineEditProps> = ({
try {
const { activeFile, editor, selection } = await getActiveContext();
if (!activeFile || !editor || !selection) {
console.error("No active file, editor, or selection");
setIsSubmitting(false);
return;
}
@ -237,14 +232,26 @@ export const InlineEdit: React.FC<InlineEditProps> = ({
response.choices[0].message.content
);
const finalContent = parsedBlock?.content || response.choices[0].message.content;
const startLine = parsedBlock?.startLine || defaultStartLine;
const endLine = parsedBlock?.endLine || defaultEndLine;
if (!activeFile || !(activeFile.path && typeof activeFile.path === 'string')) {
setIsSubmitting(false);
throw new Error("Invalid active file");
}
let fileContent: string;
try {
fileContent = await plugin.app.vault.cachedRead(activeFile);
} catch (error) {
console.error("Failed to read file:", error);
setIsSubmitting(false);
return;
}
const updatedContent = await ApplyEditToFile(
await plugin.app.vault.cachedRead(activeFile),
fileContent,
finalContent,
startLine,
endLine
defaultStartLine,
defaultEndLine
);
if (!updatedContent) {
@ -258,7 +265,7 @@ export const InlineEdit: React.FC<InlineEditProps> = ({
type: APPLY_VIEW_TYPE,
active: true,
state: {
file: activeFile,
file: activeFile.path,
oldContent: removeAITags(oldContent),
newContent: removeAITags(updatedContent),
},
@ -277,8 +284,8 @@ export const InlineEdit: React.FC<InlineEditProps> = ({
<InputArea value={instruction} onChange={setInstruction} handleSubmit={handleSubmit} handleClose={handleClose} />
<button className="infio-ai-block-close-button" onClick={handleClose}>
<svg
width="14"
height="14"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"

View File

@ -491,18 +491,29 @@ export class PromptGenerator {
}
private getSystemMessage(shouldUseRAG: boolean, type?: string): RequestMessage {
const systemPromptEdit = `You are an intelligent assistant to help edit text content based on user instructions. You will be given the current text content and the user's instruction for how to modify it.
const systemPromptEdit = `You are an expert text editor assistant. Your task is to modify the selected content precisely according to the user's instruction, while preserving the original formatting and ensuring consistency with the surrounding context.
1. Your response should contain the modified text content wrapped in <infio_block> tags with appropriate attributes:
<infio_block filename="path/to/file.md" language="markdown" startLine="10" endLine="20" type="edit">
[modified content here]
</infio_block>
You will receive:
- <task>: The specific editing instruction
- <selected_content>: The text to be modified
- <surrounding_context>: The surrounding file context (may be truncated)
2. Preserve the original formatting, indentation and line breaks unless specifically instructed otherwise.
When performing the edit:
- Make only the minimal changes necessary to fulfill the instruction
- Preserve original formatting (indentation, line breaks, spacing) unless the instruction explicitly requires changing it
- Use the context to ensure the edit maintains consistency with the surrounding content
- Match the style, terminology, and conventions of the original document
- Handle special content types appropriately:
- Code: Maintain syntax correctness and follow existing code style
- Lists: Preserve formatting and hierarchy
- Tables: Keep alignment and structure
- Markdown/formatting: Respect existing markup
3. Make minimal changes necessary to fulfill the user's instruction. Do not modify parts of the text that don't need to change.
4. If the instruction is unclear or cannot be fulfilled, respond with "ERROR: " followed by a brief explanation.`
Your edit response must be wrapped in <response> tags:
<response>
[modified content here]
</response>
`
const systemPrompt = `You are an intelligent assistant to help answer any questions that the user has, particularly about editing and organizing markdown files in Obsidian.
@ -604,6 +615,30 @@ ${fileContent}
}
}
private async getContextForEdit(
currentFile: TFile,
startLine: number,
endLine: number
): Promise<string | null> {
// 如果选中内容超过500行则不提供上下文
if (endLine - startLine + 1 > 500) {
return null;
}
const fileContent = await readTFileContent(currentFile, this.app.vault);
const lines = fileContent.split('\n');
// 计算上下文范围,并处理边界情况
const contextStartLine = Math.max(1, startLine - 20);
const contextEndLine = Math.min(lines.length, endLine + 20);
// 提取上下文行
const contextLines = lines.slice(contextStartLine - 1, contextEndLine);
// 返回带行号的上下文内容
return addLineNumbers(contextLines.join('\n'), contextStartLine);
}
public async generateEditMessages({
currentFile,
selectedContent,
@ -617,14 +652,27 @@ ${fileContent}
startLine: number
endLine: number
}): Promise<RequestMessage[]> {
const systemMessage = this.getSystemMessage(false, 'edit')
const currentFileMessage = await this.getCurrentFileMessage(currentFile)
const userMessage: RequestMessage = {
role: 'user',
content: `Selected text (lines ${startLine}-${endLine}):\n${selectedContent}\n\nInstruction:\n${instruction}`,
const systemMessage = this.getSystemMessage(false, 'edit');
// 获取适当大小的上下文
const context = await this.getContextForEdit(currentFile, startLine, endLine);
let userPrompt = `<task>\n${instruction}\n</task>\n\n
<selected_content location="${currentFile.path}#L${startLine}-${endLine}">\n${selectedContent}\n</selected_content>`;
// 只有当上下文不为null时才添加
if (context !== null) {
userPrompt += `\n\n<surrounding_context location="${currentFile.path}">\n${context}\n</surrounding_context>`;
} else {
userPrompt += `\n\n<surrounding_context location="${currentFile.path}">\n(No relevant context found)\n</surrounding_context>`;
}
return [systemMessage, currentFileMessage, userMessage]
const userMessage: RequestMessage = {
role: 'user',
content: userPrompt,
};
return [systemMessage, userMessage];
}
private getRagInstructionMessage(): RequestMessage {