-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Upstream model generated file and line linkification #1803
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
|
||
| export class FileLinkificationInstructions extends PromptElement<{}> { | ||
| render() { | ||
| return <Tag name='file_linkification'> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a gut feeling but this seems pretty verbose and I'm not sure how well models will follow the good/bad method written this way
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
| For casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.<br /> | ||
| <br /> | ||
| When referring to a filename or symbol in the user's workspace, wrap it in backticks.<br /> | ||
| <FileLinkificationInstructions /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this should break up the example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
| - Don'ts: no nested bullets/hierarchies; no ANSI codes; don't cram unrelated keywords; keep keyword lists short—wrap/reformat if long; avoid naming formatting styles in answers.<br /> | ||
| - Adaptation: code explanations → precise, structured with code refs; simple tasks → lead with outcome; big changes → logical walkthrough + rationale + next actions; casual one-offs → plain sentences, no headers/bullets.<br /> | ||
| - File References: When referencing files in your response, always follow the below rules:<br /> | ||
| * Use inline code to make file paths clickable.<br /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should revisit these instructions too as they duplicate the linkfication stuff. I'd expect to have some base set of linkfication rules and then a (hopefully) small set of additional customizations for each model
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
| // Example: [src/file.ts](src/file.ts#L10-12) or [src/file.ts](src/file.ts) | ||
| const modelLinkRe = /\[(?<text>[^\]\n]+)\]\((?<target>[^\s)]+)\)/gu; | ||
|
|
||
| export class ModelFilePathLinkifier implements IContributedLinkifier { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's break up the existing FilePathLinkifier into the real links functionality and the inline code functionality. Maybe just delete the real links stuff from FilePathLinkifier and keep this class. I'd like to avoid the duplication though and make it so we just have one place that handles the markdown file links
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
… into vijayu/autoGen-links-3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR moves file path linkification upstream to AI models by instructing them to emit canonical Markdown links with line number anchors ([path](path#L10-12)). A new ModelFilePathLinkifier processes these structured links first, with the existing FilePathLinkifier serving as fallback for other patterns.
Key changes:
- New
FileLinkificationInstructionscomponent with detailed prompting rules for models ModelFilePathLinkifierclass to parse model-generated links with#Lline anchors- Integration across all model-specific prompts (OpenAI, Anthropic, Gemini, xAI, VSC)
- Removal of markdown link handling from legacy
FilePathLinkifier - Enhanced
LinkifyLocationAnchorwithtitleparameter for display paths
Reviewed Changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/extension/prompts/node/agent/fileLinkificationInstructions.tsx | New shared prompt component with linkification instructions for models |
| src/extension/prompts/node/agent/openAIPrompts.tsx | Integrated FileLinkificationInstructions, updated GPT-5 examples, removed old inline instructions |
| src/extension/prompts/node/agent/anthropicPrompts.tsx | Added FileLinkificationInstructions to Claude prompts |
| src/extension/prompts/node/agent/geminiPrompts.tsx | Added FileLinkificationInstructions to Gemini prompts |
| src/extension/prompts/node/agent/xAIPrompts.tsx | Added FileLinkificationInstructions to Grok prompts |
| src/extension/prompts/node/agent/vscModelPrompts.tsx | Added FileLinkificationInstructions to VSC model prompts |
| src/extension/linkify/common/modelFilePathLinkifier.ts | New linkifier for parsing model-generated markdown links with line anchors |
| src/extension/linkify/common/filePathLinkifier.ts | Removed markdown link handling, improved directory slash handling |
| src/extension/linkify/common/linkifyService.ts | Registered ModelFilePathLinkifier before FilePathLinkifier for priority processing |
| src/extension/linkify/test/node/modelFilePathLinkifier.spec.ts | Test suite for new model linkifier functionality |
| src/extension/linkify/test/node/util.ts | Enhanced mock services to support directory detection and workspace methods |
| src/extension/prompt/node/chatParticipantRequestHandler.ts | Updated anchor-to-markdown conversion to use title field and include line numbers in labels |
Comments suppressed due to low confidence (4)
src/extension/prompts/node/agent/xAIPrompts.tsx:115
- [nitpick] The examples only show file references with backticks but don't demonstrate the line number linkification format introduced by
<FileLinkificationInstructions />. For consistency with the GPT-5 prompt (which includes an example like[src/network/httpClient.ts](src/network/httpClient.ts#L42)), consider adding a similar example to help the model understand when and how to use the line number format:
<Tag name='example'>
The class `Person` is in `src/models/person.ts`.<br />
The function `calculateTotal` is defined in [lib/utils/math.ts](lib/utils/math.ts#L42).<br />
You can find the configuration in `config/app.config.json`.
</Tag> <Tag name='example'>
The class `Person` is in `src/models/person.ts`.<br />
The function `calculateTotal` is defined in `lib/utils/math.ts`.<br />
You can find the configuration in `config/app.config.json`.
</Tag>
src/extension/prompts/node/agent/geminiPrompts.tsx:110
- [nitpick] The examples only show file references with backticks but don't demonstrate the line number linkification format introduced by
<FileLinkificationInstructions />. For consistency with the GPT-5 prompt (which includes an example like[src/network/httpClient.ts](src/network/httpClient.ts#L42)), consider adding a similar example to help the model understand when and how to use the line number format:
<Tag name='example'>
The class `Person` is in `src/models/person.ts`.<br />
The function `calculateTotal` is defined in [lib/utils/math.ts](lib/utils/math.ts#L42).<br />
You can find the configuration in `config/app.config.json`.
</Tag> <Tag name='example'>
The class `Person` is in `src/models/person.ts`.<br />
The function `calculateTotal` is defined in `lib/utils/math.ts`.<br />
You can find the configuration in `config/app.config.json`.
src/extension/prompts/node/agent/openAIPrompts.tsx:110
- [nitpick] The examples only show file references with backticks but don't demonstrate the line number linkification format introduced by
<FileLinkificationInstructions />. For consistency with the GPT-5 prompt (which includes an example like[src/network/httpClient.ts](src/network/httpClient.ts#L42)), consider adding a similar example to help the model understand when and how to use the line number format:
<Tag name='example'>
The class `Person` is in `src/models/person.ts`.<br />
The function `calculateTotal` is defined in [lib/utils/math.ts](lib/utils/math.ts#L42).<br />
You can find the configuration in `config/app.config.json`.
</Tag> <Tag name='example'>
The class `Person` is in `src/models/person.ts`.<br />
The function `calculateTotal` is defined in `lib/utils/math.ts`.<br />
You can find the configuration in `config/app.config.json`.
</Tag>
src/extension/prompt/node/chatParticipantRequestHandler.ts:463
- The markdown link format on line 463 appears incorrect. When generating markdown links for Location anchors with line numbers, the line number should be part of the URL fragment (e.g.,
path#L10), not as a separate title attribute in the markdown link syntax.
Currently: [text](path "title") where text includes #L10 but path doesn't
Expected: [text](path#L10) where the line number is part of the URL
Consider updating to:
if (isLocation(anchor.value)) {
const lineFragment = `#L${anchor.value.range.start.line + 1}${anchor.value.range.start.line === anchor.value.range.end.line ? '' : `-${anchor.value.range.end.line + 1}`}`;
path = `${getWorkspaceFileDisplayPath(workspaceService, anchor.value.uri)}${lineFragment}`;
const label = anchor.title ?? path;
text = `\`${label}\``;
}This ensures the URL includes the line fragment so it's linkifiable by the ModelFilePathLinkifier.
} else if (isLocation(anchor.value)) {
path = getWorkspaceFileDisplayPath(workspaceService, anchor.value.uri);
const label = anchor.title ?? `${path}#L${anchor.value.range.start.line + 1}${anchor.value.range.start.line === anchor.value.range.end.line ? '' : `-${anchor.value.range.end.line + 1}`}`;
text = `\`${label}\``;
} else if (isSymbolInformation(anchor.value)) {
path = getWorkspaceFileDisplayPath(workspaceService, anchor.value.location.uri);
text = `\`${anchor.value.name}\``;
} else {
// Unknown anchor type
return '';
}
return `[${text}](${path} ${anchor.title ? `"${anchor.title}"` : ''})`;
src/extension/prompts/node/agent/fileLinkificationInstructions.tsx
Outdated
Show resolved
Hide resolved
src/extension/prompts/node/agent/fileLinkificationInstructions.tsx
Outdated
Show resolved
Hide resolved
| * foo.ts | ||
| * ``` | ||
| */ | ||
| export class FilePathLinkifier implements IContributedLinkifier { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still need this class at all? Maybe just delete it and call new ModelFilePathLinkifier FilePathLinkifier instead
It seems like the new linkifier should handle everything that the current one does. If there are any gaps we can fix those instead of keeping the fallback around
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now ModelFilePathLinkifier handles structured markdown links with anchors texttext, while FilePathLinkifier handles inline code and plain text paths.
They're registered with clear separation of concerns, where FilePathLinkifier acts as a fallback for informal references.
That said, I'm happy to explore merging them if you think that would be better! Let me know your preference and I can make it work either way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My hope is that the model will handle creating proper links now. The inline code and plain text path logic was added because previous models were no good at generating links consistently
Worth testing removing the old linkifier to and seeing if the model still generates paths in plaintext / inline code. If it does, maybe we need to tweak the instructions a bit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still interested to see if we can avoid having two linkifier paths and just prefer using the model
|
|
||
| // Matches markdown links where the text is a path and optional #L anchor is present | ||
| // Example: [src/file.ts](src/file.ts#L10-12) or [src/file.ts](src/file.ts) | ||
| const modelLinkRe = /\[(?<text>[^\]\n]+)\]\((?<target>[^\s)]+)\)/gu; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sure this can support the case where the path text is code too as this is fairly common and models have likely been trained on a lot of it:
[`file.ts`](file.ts)
Especially true if we get rid of the old linkifier
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, works. Added unit test to validate this.
| continue; | ||
| } | ||
|
|
||
| const resolved = await this.resolveTarget(parsed.targetPath, workspaceFolders, parsed.preserveDirectorySlash); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's try to run these type of calls in parallel instead of awaiting each iteration
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Valid point. Updated
| - `See [path/to/file.ts](path/to/file.ts#L10-12) for the range.`<br /> | ||
| - `Configuration is defined in [path/to/file.ts](path/to/file.ts).` (whole file)<br /> | ||
| When you need a bullet list of references, write a short description before the link, for example:<br /> | ||
| - Await chat view: [path/to/chatQuick.ts](path/to/chatQuick.ts#L142)<br /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the syntax we want or should we support:
[Await chat view](path/to/chatQuick.ts#L142)
That feels more natural if we can get the model to generate these links properly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, updated
| - Show widget: [path/to/chatQuick.ts](path/to/chatQuick.ts#L321)<br /> | ||
| Examples:<br /> | ||
| ❌ `The function is in exampleScript.ts at line 25.`<br /> | ||
| ✓ `The function is in [exampleScript.ts](exampleScript.ts#L25).`<br /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the ❌ how we provided counter examples to the model? Seems like it's mostly used in our docs, not in the actual prompts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
| return <Tag name='file_linkification'> | ||
| ALWAYS convert file paths to markdown links with 1-based line numbers whenever you cite specific code locations. Use links inside normal sentences, not as the entire answer.<br /> | ||
| Format examples:<br /> | ||
| - `The handler lives in [path/to/file.ts](path/to/file.ts#L10).` (single line)<br /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the advantage of this over a path in backticks? We're asking the model to repeat the path twice, it could be long.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In every other path scenario, we ask it to use absolute paths. How do you handle relative paths within multiroot workspaces?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And right now I think we support linkifying many different patterns, does this mean we would no longer support those patterns? (I strongly support simplifying the patterns we handle)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For multi root workspace, currently the first match is selected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So that means that it's not possible for the model to precisely refer to a certain file like package.json which would exist at the same place in both repos? I also worry that it might try to dedupe by including the name of the workspace, which is something I've seen it try to do with search tools, even though you don't ask for that.
| - `The handler lives in [path/to/file.ts](path/to/file.ts#L10).` (single line)<br /> | ||
| - `See [path/to/file.ts](path/to/file.ts#L10-12) for the range.`<br /> | ||
| - `Configuration is defined in [path/to/file.ts](path/to/file.ts).` (whole file)<br /> | ||
| When you need a bullet list of references, write a short description before the link, for example:<br /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
model was generating responses like below, without any description on what those lines represent.
chatListRenderer.ts#857-857
chatListRenderer.ts#1001-1001
chatListRenderer.ts#1477-1477
chatListRenderer.ts#1486-1486
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's interesting. I wonder if all the rules about links caused it to hyper-focus on links specifically and forget what is was actually trying to communicate 😅
|
|
||
| export class FileLinkificationInstructions extends PromptElement<{}> { | ||
| render() { | ||
| return <Tag name='file_linkification'> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a lot, I just don't think all these rules and examples are necessary for a modern model. What you're asking for is extremely simple, I would expect that a decent model can pick it up with just a couple sentences.
We could do it in a scientific way and write some evals to test all models and how far we can trim the rules while still getting good results.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Valid point, I started with simple few sentence prompts, but I got inconsistent results across models. Within the model also it was inconsistent between different files. I will try pruning it offline separately (with evals) and simplify without loosing the intent.
| } | ||
|
|
||
| private toVsUri(folder: Uri): Uri { | ||
| return Uri.parse(folder.toString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Uri -> string -> Uri flow seems strange. Why is it needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
|
|
||
| if (this.isAbsolutePath(targetPath)) { | ||
| const absoluteUri = this.tryCreateFileUri(targetPath); | ||
| if (!absoluteUri) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should look at the workspace folders to decide what type of path to create instead of always trying to create file: uris. Especially in remote cases, file may not be right
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
| return Uri.parse(folder.toString()); | ||
| } | ||
|
|
||
| private isEqualOrParentFs(target: Uri, folder: Uri): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should have a helper for this: isEqualOrParent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
|
|
||
| private normalizeFsPath(resource: Uri): string { | ||
| // Convert Windows backslashes to forward slashes and remove duplicate separators for stable comparisons. | ||
| return resource.fsPath.replace(/\\/g, '/').replace(/\/+/g, '/').toLowerCase(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doing this manually also seems fishy. If you want paths with just /, you a use .path instead of .fsPath. Also you can use normalizePath to normalize uris
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
|
|
||
| // Capture the start (and optional end) line numbers from the anchor. | ||
| // Support both L123-456 and L123-L456 formats | ||
| const match = /^L(\d+)(?:-L?(\d+))?$/.exec(anchor); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd skip the .test above since it duplicates the regex and just try parsing directly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
| return Boolean(workspaceFolders.length) && (textMatchesBase || textIsFilename || descriptiveWithAnchor); | ||
| } | ||
|
|
||
| private async resolveTarget(targetPath: string, workspaceFolders: readonly Uri[], preserveDirectorySlash: boolean): Promise<Uri | undefined> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth passing along the cancellation token in this case too and checking it in the calls to tryState
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
| The function `calculateTotal` is defined in `lib/utils/math.ts`.<br /> | ||
| You can find the configuration in `config/app.config.json`. | ||
| Identifiers in backticks: `Person`, `calculateTotal`, `AppConfig`.<br /> | ||
| File path and line anchor formatting rules are defined in `FileLinkificationInstructions` below. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove this line and just inlcude the examples inside the FileLinkificationInstructions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
| <NotebookInstructions {...this.props} /> | ||
| <Tag name='outputFormatting'> | ||
| Use proper Markdown formatting in your answers. When referring to a filename or symbol in the user's workspace, wrap it in backticks.<br /> | ||
| Use proper Markdown formatting. Backtick code identifiers (classes, methods, variables). For file paths and code locations, follow `FileLinkificationInstructions` (markdown links with line anchors; never backticks).<br /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The previous phrasing, “wrap in backticks,” was more proper than using “backtick” as a verb here and might be less confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also do we have anyway to test this besides manual testing? Might be good to update our benchmarks if not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
| - [Await chat view](path/to/chatQuick.ts#L142)<br /> | ||
| - [Show widget](path/to/chatQuick.ts#L321)<br /> | ||
| NEVER cite file paths as plain text when referring to specific locations. For example, instead of saying `The function is in exampleScript.ts at line 25.`, say `The function is in [exampleScript.ts](exampleScript.ts#L25).`<br /> | ||
| Critical rules:<br /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this makes much of an impact with most models if they are not included as reminders closer to the user message
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my testing, I have found this prompt to make a difference. Without this, line # always appear separate from the file path reference, for e.g. line 25 in file.ts or file.ts at line 25.
| - Bullets: use - ; merge related points; keep to one line when possible; 4-6 per list ordered by importance; keep phrasing consistent.<br /> | ||
| - Monospace: backticks for commands/paths/env vars/code ids and inline examples; use for literal keyword bullets; never combine with **.<br /> | ||
| - Monospace: backticks for commands, env vars, and code identifiers; never combine with **.<br /> | ||
| - File path + line anchor link rules are defined in `FileLinkificationInstructions` below.<br /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the model actually see the name FileLinkificationInstructions? Should we just include the instructions here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated it with the 'fileLinkification' tag, which it is able to find.
| File path and line anchor formatting rules are defined in `FileLinkificationInstructions` below. | ||
| </example> | ||
| <file_linkification> | ||
| ALWAYS convert file paths to markdown links with 1-based line numbers whenever you cite specific code locations. Use links inside normal sentences, not as the entire answer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if it would help models or not but may be worth seeing if we should clarify that this is meant for workspace files, not just any arbitrary file path (such as files in examples)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also worth calling out the paths should be relative to the workspace
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
| - [Show widget](path/to/chatQuick.ts#L321) | ||
| NEVER cite file paths as plain text when referring to specific locations. For example, instead of saying `The function is in exampleScript.ts at line 25.`, say `The function is in [exampleScript.ts](exampleScript.ts#L25).` | ||
| Critical rules: | ||
| - Link text must be the exact file path (no backticks, no `#L` in the visible text, no extra wording). Keep the `#L` anchor in the **link target**, e.g. `[src/file.ts](src/file.ts#L25)`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This instructions seems to go against the example above: [Await chat view](path/to/chatQuick.ts#L142)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simplified text
| NEVER cite file paths as plain text when referring to specific locations. For example, instead of saying `The function is in exampleScript.ts at line 25.`, say `The function is in [exampleScript.ts](exampleScript.ts#L25).` | ||
| Critical rules: | ||
| - Link text must be the exact file path (no backticks, no `#L` in the visible text, no extra wording). Keep the `#L` anchor in the **link target**, e.g. `[src/file.ts](src/file.ts#L25)`. | ||
| - Always include both brackets **and** parentheses. `[src/file.ts](src/file.ts#L25)` is valid; `[src/file.ts#L25]` is not. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth seeing if this is needed. If it is, maybe say something like "make sure it's a valid markdown link" instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is needed. I simplified text a little.
Common mistakes I've seen models make:
[src/file.ts#L25] - Missing parentheses (not a link at all, just literal text)
[src/file.ts] - Missing target completely
[src/file.ts] - Double brackets
src/file.ts#L25 - Anchor outside the parentheses
Also, models misplace the line anchor, without explicit instruction, models often do:
src/file.ts#L25 - Line number in display text
src/file.ts#L25 - Anchor after closing paren
src/file.ts L25 - Extra text in display
| - Path format: Strip drive letters and workspace parent folders - use only path after workspace root | ||
| - Transform `c:/Repos/workspace/src/file.ts` → `[src/file.ts](src/file.ts)` | ||
| - Always use forward slashes `/`, never backslashes `/` | ||
| - Do not use URIs like file://, vscode://, or https://. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The https part makes me worried it won't generate web links when it should
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed https
| - `The handler lives in [path/to/file.ts](path/to/file.ts#L10).` (single line) | ||
| - `See [path/to/file.ts](path/to/file.ts#L10-L12) for the range.` | ||
| - `Configuration is defined in [path/to/file.ts](path/to/file.ts).` (whole file) | ||
| - `The widget renderer attaches anchors ([src/renderer.ts](src/renderer.ts#L42-L48)).` (in parentheses) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the parens case special?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not needed, removed.
mjbvz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just minor feedback from me but worth getting a quick re-check on the FileLinkificationInstructions from Rob/Bhavya since they know about writing good prompts
| <Tag name='outputFormatting'> | ||
| Use proper Markdown formatting in your answers. When referring to a filename or symbol in the user's workspace, wrap it in backticks.<br /> | ||
| Use proper Markdown formatting. Backtick code identifiers (classes, functions, variables, commands). For file paths or specific code locations, do NOT use backticks—convert them to markdown links with line anchors; file path and line anchor link rules are defined in `FileLinkificationInstructions` below. Avoid duplicating those examples here.<br /> | ||
| <Tag name='example'> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the FileLinkificationInstructions be included in the output formatting section similar to MathIntegrationRules? Wondering we can avoid the File path link examples live in fileLinkification section below. section
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
| * Accepted: absolute, workspace-relative, a/ or b/ diff prefixes, or bare filename/suffix.<br /> | ||
| * Do not use URIs like file://, vscode://, or https://.<br /> | ||
| * Examples: src/app.ts, C:\repo\project\main.rs<br /> | ||
| - File path and line anchor link rules are defined in fileLinkification section below.<br /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need this sentence if we include the rules right after?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are added for additional re-enforcement as I see without this, models are not consistent in honoring the rules.
roblourens
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| return <Tag name='fileLinkification'> | ||
| ALWAYS convert file paths to markdown links with 1-based line numbers whenever you cite specific code locations in the workspace. Paths should be relative to workspace root.<br /> | ||
| <br /> | ||
| **Inline references:** Use the file path as link text within sentences:<br /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I tested this with 5.1-codex, I got a markdown link in backticks:
`[src/vs/workbench/contrib/chat/common/chatService.ts](src/vs/workbench/contrib/chat/common/chatService.ts)` is the central TypeScript definition file for the chat feature’s shared contracts
I think you aren't looking for the markdown link to be wrapped in backticks, but it's not clear from the examples because they are wrapped in backticks, so I would suggest removing those.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And then I pulled with the other commit you added, and I got a path that wasn't formatted as a link at all
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made few changes and made prompts consistent across models. In my local testing, the above scenario worked.
| return <Tag name='file_linkification'> | ||
| ALWAYS convert file paths to markdown links with 1-based line numbers whenever you cite specific code locations. Use links inside normal sentences, not as the entire answer.<br /> | ||
| Format examples:<br /> | ||
| - `The handler lives in [path/to/file.ts](path/to/file.ts#L10).` (single line)<br /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So that means that it's not possible for the model to precisely refer to a certain file like package.json which would exist at the same place in both repos? I also worry that it might try to dedupe by including the name of the workspace, which is something I've seen it try to do with search tools, even though you don't ask for that.
|
I have made the changes so now multi workspace paths show up correctly. Both app1/package.json and app2/package.json are adding the dependency for react version ^18.2.0. |

Fixes microsoft/vscode#276767
Motivation
Move file path linkification upstream to the model so it emits canonical, machine‑parsable Markdown links (path), reducing reliance on heuristic fallback and enabling precise line anchors. Linkification falls back to current component if model does not handle it.
Also ensure consistent behavior across all model families (OpenAI/GPT‑5, Anthropic/Claude, etc.) while eliminating duplicated prompt text.
This is example response with line number linkification: