Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { INotebookDocumentService } from '../../../../../services/notebook/commo
import { ExplorerFolderContext } from '../../../../files/common/files.js';
import { IWorkspaceSymbol } from '../../../../search/common/search.js';
import { IChatContentInlineReference } from '../../../common/chatService/chatService.js';
import { IPromptsService } from '../../../common/promptSyntax/service/promptsService.js';
import { IChatWidgetService } from '../../chat.js';
import { chatAttachmentResourceContextKey, hookUpSymbolAttachmentDragAndContextMenu } from '../../attachments/chatAttachmentWidgets.js';
import { IChatMarkdownAnchorService } from './chatMarkdownAnchorService.js';
Expand Down Expand Up @@ -90,6 +91,7 @@ export class InlineAnchorWidget extends Disposable {
@ILanguageService languageService: ILanguageService,
@IMenuService menuService: IMenuService,
@IModelService modelService: IModelService,
@IPromptsService promptsService: IPromptsService,
@ITelemetryService telemetryService: ITelemetryService,
@IThemeService themeService: IThemeService,
@INotebookDocumentService private readonly notebookDocumentService: INotebookDocumentService,
Expand Down Expand Up @@ -126,7 +128,9 @@ export class InlineAnchorWidget extends Disposable {
} else {
location = this.data;

const filePathLabel = labelService.getUriBasenameLabel(location.uri);
// For skills, we should use the skill name as the label
const skillInfo = promptsService.getSkillByUri(location.uri);
const filePathLabel = skillInfo ? skillInfo.name : labelService.getUriBasenameLabel(location.uri);
if (location.range && this.data.kind !== 'symbol') {
const suffix = location.range.startLineNumber === location.range.endLineNumber
? `:${location.range.startLineNumber}`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,4 +331,11 @@ export interface IPromptsService extends IDisposable {
* Gets list of agent skills files.
*/
findAgentSkills(token: CancellationToken): Promise<IAgentSkill[] | undefined>;

/**
* Gets skill info by URI from the cached skills list.
* Returns undefined if the URI is not a known skill or skills haven't been loaded yet.
* This is a synchronous lookup against already-loaded skills.
*/
getSkillByUri(uri: URI): IAgentSkill | undefined;
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ export class PromptsService extends Disposable implements IPromptsService {
[PromptsType.agent]: new ResourceMap<Promise<IExtensionPromptPath>>(),
};

/**
* Cached skills keyed by URI for synchronous lookup.
* Updated whenever findAgentSkills is called.
*/
private readonly cachedSkillsByUri = new ResourceMap<IAgentSkill>();

constructor(
@ILogService public readonly logger: ILogService,
@ILabelService private readonly labelService: ILabelService,
Expand Down Expand Up @@ -705,10 +711,20 @@ export class PromptsService extends Disposable implements IPromptsService {
skippedParseFailed
});

// Update the cached skills map for synchronous lookup
this.cachedSkillsByUri.clear();
for (const skill of result) {
this.cachedSkillsByUri.set(skill.uri, skill);
}
Comment on lines +714 to +718
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cache is only populated when findAgentSkills is called, but there's no mechanism to invalidate or refresh the cache when skill files change. If a skill file is added, removed, or modified after findAgentSkills is initially called, getSkillByUri will continue returning stale data. Consider adding file watchers to invalidate the cache when skill files change, or implementing a cache refresh mechanism similar to how cachedCustomAgents.refresh() works for custom agents.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: I think we should support skills as a promptType and leverage the existing watcher mechanisms there?


return result;
}
return undefined;
}

public getSkillByUri(uri: URI): IAgentSkill | undefined {
return this.cachedSkillsByUri.get(uri);
}
Comment on lines +725 to +727
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new getSkillByUri method lacks test coverage. Since there are comprehensive tests for findAgentSkills in promptsService.test.ts, tests should be added to verify that getSkillByUri correctly returns cached skills after findAgentSkills is called, and returns undefined when the cache is empty or the URI is not found.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above. We should wait until things are more unified before testing here.

}

// helpers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,6 @@ export class MockPromptsService implements IPromptsService {
setDisabledPromptFiles(type: PromptsType, uris: ResourceSet): void { throw new Error('Method not implemented.'); }
registerCustomAgentsProvider(extension: IExtensionDescription, provider: { provideCustomAgents: (options: ICustomAgentQueryOptions, token: CancellationToken) => Promise<IExternalCustomAgent[] | undefined> }): IDisposable { throw new Error('Method not implemented.'); }
findAgentSkills(token: CancellationToken): Promise<IAgentSkill[] | undefined> { throw new Error('Method not implemented.'); }
getSkillByUri(uri: URI): IAgentSkill | undefined { return undefined; }
dispose(): void { }
}
Loading