feat: 批量上传支持及prompt优化

- 支持多文件批量上传,一次最多10个
- 新增json/toml/yaml格式支持
- 优化inline补全prompt结构,增加边界决策指南
- size计算包含doc_block内容长度
- 超限时显示警告tooltip
This commit is contained in:
2026-04-05 11:40:56 +08:00
parent 7ed199aaf1
commit 9904b9bd78
5 changed files with 542 additions and 197 deletions
+189 -131
View File
@@ -331,124 +331,111 @@ def build_inline_system_prompt(language_id: str = "markdown") -> str:
Return only the insertion text that should be placed between PREFIX and SUFFIX.
Hard constraints you must follow:
1) Output-only contract:
- Output insertion text only.
- No explanations, no meta labels, no wrapper quotes around the whole answer.
CORE PRINCIPLE: Output insertion text only. No explanations, no meta labels, no wrapper quotes.
2) Strict math formatting (KaTeX):
- If you output any math expression, it must be strict KaTeX-compatible math.
- Every formula must be wrapped with either $...$ (inline) or $$...$$ (block).
- Never output bare formulas without $ or $$ wrappers.
- Exception: If CURSOR_IN_FENCED_CODE_BLOCK=true and CURSOR_FENCE_LANGUAGE is latex/tex/katex,
output raw LaTeX without $ or $$ wrappers.
PRIORITY 1: CONTEXT AWARENESS (Read these flags from user prompt)
- CURSOR_IN_FENCED_CODE_BLOCK: Are you inside a code fence?
- CURSOR_FENCE_LANGUAGE: What language is the current fence?
- PREFIX_ENDS_WITH_NEWLINE: Does prefix end with newline?
- SUFFIX_STARTS_WITH_NEWLINE: Does suffix start with newline?
- MERMAID_CONTEXT: Is this a Mermaid diagram context?
3) Strict code formatting:
- Read CURSOR_IN_FENCED_CODE_BLOCK from the user prompt.
- If CURSOR_IN_FENCED_CODE_BLOCK=true:
- You are already inside a fenced code block.
- Never output triple backticks.
- Output code lines only.
- If CURSOR_IN_FENCED_CODE_BLOCK=false:
- Any code output must be in a fenced code block with a language tag:
PRIORITY 2: SPECIALIZED CONTENT RULES
2.1 Code Block Handling:
If CURSOR_IN_FENCED_CODE_BLOCK=true:
- You are inside a code fence
- Output code lines ONLY (no triple backticks)
- Use single \\n for code line separation
If CURSOR_IN_FENCED_CODE_BLOCK=false and code needed:
- Wrap code in fenced block with language tag:
```{{language}}
...
code here
```
- Do not output code snippets as inline backticks.
- Choose the language tag from context (no default fallback tag instruction).
- Never use inline backticks for code snippets
4) Mermaid-specific completion rules:
- Read CURSOR_FENCE_LANGUAGE and MERMAID_CONTEXT from the user prompt.
- If CURSOR_FENCE_LANGUAGE=mermaid:
- Output Mermaid statements only.
- Never output triple backticks.
- Never output prose explanations.
- If CURSOR_IN_FENCED_CODE_BLOCK=false and MERMAID_CONTEXT=true:
- Output a complete Mermaid fenced block:
2.2 Math Formatting (KaTeX):
- Inline math: wrap with $...$
- Block math: wrap with $$...$$
- Never output bare formulas
- Exception: inside latex/tex/katex fence, output raw LaTeX
2.3 Mermaid Diagrams:
If CURSOR_FENCE_LANGUAGE=mermaid:
- Output Mermaid syntax ONLY
- No backticks, no explanations
If MERMAID_CONTEXT=true and outside fence:
- Output complete fenced block:
```mermaid
...
diagram syntax
```
- Keep Mermaid syntax valid and concise.
- Never mix Mermaid code and explanatory narration in one output.
5) Boundary newline repair:
- Read PREFIX_ENDS_WITH_NEWLINE and SUFFIX_STARTS_WITH_NEWLINE from the user prompt.
- Carefully reason about whether OUTPUT should start or end with a newline.
- If PREFIX lacks a required boundary newline, add it at OUTPUT start.
- If SUFFIX lacks a required boundary newline, add it at OUTPUT end.
- Ensure PREFIX + OUTPUT + SUFFIX is structurally natural.
PRIORITY 3: MARKDOWN STRUCTURE
6) Context stitching:
- Do not repeat text that already appears at the start of SUFFIX.
- Preserve nearby language, tone, punctuation, indentation, and markdown structure.
- Continue existing structures naturally (lists, tables, block quotes, headings).
3.1 Newline Semantics:
- Single \\n: soft break (same paragraph, renders as space or <br>)
- Double \\n\\n: hard break (new paragraph/block)
- Use \\n\\n for: new paragraphs, before headings, starting lists/tables
- Use \\n for: continuation within blocks (list items, table cells)
- Exception: inside code blocks, use \\n freely for code lines
7) OCR safety:
- PREFIX may include hidden OCR metadata tags like <OCR:...>.
- Never output any OCR tag.
- Never output OCR tag fragments such as <OCR:...>."""
3.2 Boundary Management:
Check PREFIX_ENDS_WITH_NEWLINE and SUFFIX_STARTS_WITH_NEWLINE:
- If PREFIX lacks needed newline: start OUTPUT with \\n
- If SUFFIX lacks needed newline: end OUTPUT with \\n
- Common cases requiring leading \\n:
* Starting a list after "Steps:"
* Creating new paragraph after text
* Adding heading after paragraph
- Common cases requiring trailing \\n:
* Before new heading
* End of section
3.3 Context Stitching:
- Never repeat text from SUFFIX beginning
- Match PREFIX tone, style, indentation
- Continue structures: lists, tables, quotes, headings
PRIORITY 4: HIDDEN CONTEXT
- OCR metadata like <OCR:...> is hidden context
- Never copy OCR tags to output
- Use OCR content as semantic hint only
"""
if language_guidance:
system_prompt = f"{system_prompt.rstrip()}\n{language_guidance.strip()}"
system_prompt = f"{system_prompt.rstrip()}\\n{language_guidance.strip()}"
return system_prompt.strip()
INLINE_EXAMPLES = """[EX01] Prose continuation
INLINE_EXAMPLES = """=== CATEGORY A: PROSE CONTINUATION ===
[EX01] Simple prose continuation
<PREFIX>The quick brown fox </PREFIX>
<SUFFIX>jumps over the lazy dog.</SUFFIX>
Expected OUTPUT:
moved quietly and then
moved quietly and then
[EX02] Avoid repeating suffix beginning
[EX02] Avoid repeating suffix
<PREFIX>Our launch plan starts with </PREFIX>
<SUFFIX>phase one, followed by phase two.</SUFFIX>
Expected OUTPUT:
careful internal testing before
careful internal testing before
WRONG: phase one starts with (repeats suffix)
[EX03] Continue markdown checklist
=== CATEGORY B: MARKDOWN STRUCTURES ===
[EX03] Continue checklist
<PREFIX>## TODO
- [ ] Buy milk
- [ ] </PREFIX>
<SUFFIX></SUFFIX>
Expected OUTPUT:
Write release notes and share draft with team
Write release notes and share draft with team
[EX04] Cursor outside code block, code must use fenced block
CURSOR_IN_FENCED_CODE_BLOCK=false
<PREFIX>Parse this JSON payload in Python:</PREFIX>
<SUFFIX></SUFFIX>
Expected OUTPUT:
```python
import json
data = json.loads(payload)
```
[EX05] Cursor inside fenced code block, do not output fences
CURSOR_IN_FENCED_CODE_BLOCK=true
<PREFIX>```python
def add(a, b):
return </PREFIX>
<SUFFIX>
```</SUFFIX>
Expected OUTPUT:
a + b
[EX06] Inline math must use $...$
<PREFIX>The derivative of x^2 is </PREFIX>
<SUFFIX>.</SUFFIX>
Expected OUTPUT:
$2x$
[EX07] Block math must use $$...$$
<PREFIX>We can write the Gaussian integral as:</PREFIX>
<SUFFIX></SUFFIX>
Expected OUTPUT:
$$
\\int_{-\\infty}^{\\infty} e^{-x^2}\\,dx = \\sqrt{\\pi}
$$
[EX08] Prefix misses boundary newline; add newline at output start
[EX04] Start list after header (PREFIX lacks newline)
PREFIX_ENDS_WITH_NEWLINE=false
<PREFIX>Deployment steps:</PREFIX>
<SUFFIX></SUFFIX>
@@ -457,21 +444,7 @@ Expected OUTPUT:
- Build artifact
- Deploy service
[EX09] Suffix misses boundary newline; add newline at output end
SUFFIX_STARTS_WITH_NEWLINE=false
<PREFIX>Summary paragraph complete.</PREFIX>
<SUFFIX>## Next Section</SUFFIX>
Expected OUTPUT:
[EX10] OCR metadata exists but must never be emitted
<PREFIX>![whiteboard](img.png) <OCR:equation y = mx + b>
The relationship is </PREFIX>
<SUFFIX>.</SUFFIX>
Expected OUTPUT:
$y = mx + b$
[EX11] Continue markdown table with correct row shape
[EX05] Continue table row
<PREFIX>| Name | Score |
| --- | --- |
| Alice | 92 |
@@ -480,30 +453,91 @@ $y = mx + b$
Expected OUTPUT:
88 |
[EX12] Mixed text + math + code in one insertion
CURSOR_IN_FENCED_CODE_BLOCK=false
<PREFIX>Use the area formula and provide a tiny JS helper.</PREFIX>
[EX06] Start new paragraph
<PREFIX>First paragraph ends.</PREFIX>
<SUFFIX></SUFFIX>
Expected OUTPUT:
The area is $A = \\pi r^2$.
```javascript
const area = (r) => Math.PI * r * r;
Second paragraph starts.
WRONG: Second paragraph starts. (missing leading \\n\\n)
[EX07] Add newline before heading
PREFIX_ENDS_WITH_NEWLINE=false
<PREFIX>End of previous section.</PREFIX>
<SUFFIX>## Next Heading</SUFFIX>
Expected OUTPUT:
WRONG: (would join with heading without separation)
=== CATEGORY C: CODE BLOCKS ===
[EX08] Outside fence: wrap code in fence
CURSOR_IN_FENCED_CODE_BLOCK=false
<PREFIX>Parse this JSON payload in Python:</PREFIX>
<SUFFIX></SUFFIX>
Expected OUTPUT:
```python
import json
data = json.loads(payload)
```
WRONG: import json\\ndata = json.loads(payload) (no fence)
[EX13] Cursor inside mermaid fence: no backticks, mermaid lines only
[EX09] Inside fence: output code only
CURSOR_IN_FENCED_CODE_BLOCK=true
<PREFIX>```python
def add(a, b):
return </PREFIX>
<SUFFIX>
```</SUFFIX>
Expected OUTPUT:
a + b
WRONG: ```python\\nreturn a + b\\n``` (duplicate fences)
[EX10] Code inside fence uses single newline
CURSOR_IN_FENCED_CODE_BLOCK=true
<PREFIX>```python
def hello():</PREFIX>
<SUFFIX>
```</SUFFIX>
Expected OUTPUT:
print("Hello")
return True
(Note: single \\n between code lines, no markdown rules)
=== CATEGORY D: MATH ===
[EX11] Inline math
<PREFIX>The derivative of x^2 is </PREFIX>
<SUFFIX>.</SUFFIX>
Expected OUTPUT:
$2x$
WRONG: 2x (bare formula)
[EX12] Block math
<PREFIX>We can write the Gaussian integral as:</PREFIX>
<SUFFIX></SUFFIX>
Expected OUTPUT:
$$
\\int_{-\\infty}^{\\infty} e^{-x^2}\\,dx = \\sqrt{\\pi}
$$
WRONG: \\int... (bare formula without $$)
=== CATEGORY E: MERMAID ===
[EX13] Inside mermaid fence
CURSOR_FENCE_LANGUAGE=mermaid
CURSOR_IN_FENCED_CODE_BLOCK=true
<PREFIX>```mermaid
flowchart TD
A[Start] --> </PREFIX>
A[Start] --> </PREFIX>
<SUFFIX>
```</SUFFIX>
Expected OUTPUT:
B{Valid?}
B -->|Yes| C[Done]
WRONG: ```mermaid\\nB{Valid?}... (duplicate fence)
[EX14] Mermaid context outside fence: return full mermaid block
[EX14] Outside fence with mermaid context
CURSOR_IN_FENCED_CODE_BLOCK=false
MERMAID_CONTEXT=true
<PREFIX>Please provide a simple release pipeline diagram.</PREFIX>
@@ -511,8 +545,18 @@ MERMAID_CONTEXT=true
Expected OUTPUT:
```mermaid
flowchart LR
Build --> Test --> Deploy
```"""
Build --> Test --> Deploy
```
=== CATEGORY F: OCR METADATA ===
[EX15] Use OCR as context, never output
<PREFIX>![whiteboard](img.png) <OCR:equation y = mx + b>
The relationship is </PREFIX>
<SUFFIX>.</SUFFIX>
Expected OUTPUT:
$y = mx + b$
WRONG: <OCR:equation y = mx + b> (OCR tag in output)"""
def build_completion_prompts(
@@ -552,35 +596,49 @@ def build_completion_prompts(
preferences_instruction = f"\nUser Preferences:\n{preferences_instruction}"
user_prompt = f"""Current time: {current_time}{location_info}{preferences_instruction}
Reasoning hint: {thinking_level}
Editor language id: {safe_language_id}
Reasoning level: {thinking_level}
Editor language: {safe_language_id}
Completion state flags:
=== STATE FLAGS ===
- CURSOR_IN_FENCED_CODE_BLOCK: {"true" if cursor_in_fenced_code_block else "false"}
- CURSOR_FENCE_LANGUAGE: {cursor_fence_language}
- MERMAID_CONTEXT: {"true" if mermaid_context else "false"}
- PREFIX_ENDS_WITH_NEWLINE: {"true" if prefix_ends_with_newline else "false"}
- SUFFIX_STARTS_WITH_NEWLINE: {"true" if suffix_starts_with_newline else "false"}
Task:
- Produce the best insertion text at the cursor between PREFIX and SUFFIX.
- Keep insertion meaningful and non-empty.
- Keep insertion concise unless structure requires more content.
=== TASK ===
Produce the best insertion text between PREFIX and SUFFIX.
Requirements:
- Non-empty and meaningful
- Concise unless structure needs more
- Follows markdown rules in system prompt
Context notes:
- PREFIX may include OCR metadata after image markdown, e.g. ![alt](url) <OCR:description>.
- OCR metadata is hidden context and must never be copied into output.
- Preserve local style and formatting.
=== BOUNDARY DECISION GUIDE ===
Decision policy:
- Prioritize seamless join: PREFIX + OUTPUT + SUFFIX must read naturally.
- Do not repeat SUFFIX-leading text.
- If uncertain, prefer a complete short phrase/sentence with clear meaning.
Step 1: Check PREFIX_ENDS_WITH_NEWLINE
If false, ask: "Does output need to start on a new line?"
- YES if PREFIX ends with: ":", "steps:", "items:", heading text, or complete sentence before heading
- If YES: start output with \\n
Comprehensive examples:
Step 2: Check SUFFIX_STARTS_WITH_NEWLINE
If false, ask: "Does output need to end with a newline?"
- YES if SUFFIX starts with: heading (##), new paragraph, or list marker
- If YES: end output with \\n
Step 3: Choose newline type
- Use \\n\\n for: new paragraphs, before headings, starting lists
- Use \\n for: continuing within blocks, list items, table cells
- Exception: inside code fences, use \\n freely
=== CONTEXT NOTES ===
- OCR metadata (e.g., <OCR:description>) is hidden context, never copy to output
- Match PREFIX tone, style, and indentation
- Do not repeat text from SUFFIX beginning
=== EXAMPLES BY CATEGORY ===
{INLINE_EXAMPLES}
Now produce the insertion.
=== NOW COMPLETE THE TASK ===
<PREFIX>
{recent_prefix}