Skip to content
Open
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
10 changes: 5 additions & 5 deletions src/extension/byok/vscode-node/ollamaProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class OllamaModelRegistry extends BaseOpenAICompatibleBYOKRegistry {
try {
// Check Ollama server version before proceeding with model operations
await this._checkOllamaVersion();

const response = await this._fetcherService.fetch(`${this._ollamaBaseUrl}/api/tags`, { method: 'GET' });
const models = (await response.json()).models;
return models.map((model: { model: string; name: string }) => ({ id: model.model, name: model.name }));
Expand Down Expand Up @@ -97,7 +97,7 @@ export class OllamaModelRegistry extends BaseOpenAICompatibleBYOKRegistry {
try {
const response = await this._fetcherService.fetch(`${this._ollamaBaseUrl}/api/version`, { method: 'GET' });
const versionInfo = await response.json() as OllamaVersionResponse;

if (!this._isVersionSupported(versionInfo.version)) {
throw new Error(
`Ollama server version ${versionInfo.version} is not supported. ` +
Expand Down Expand Up @@ -127,19 +127,19 @@ export class OllamaModelRegistry extends BaseOpenAICompatibleBYOKRegistry {
// Simple version comparison: split by dots and compare numerically
const currentParts = currentVersion.split('.').map(n => parseInt(n, 10));
const minimumParts = MINIMUM_OLLAMA_VERSION.split('.').map(n => parseInt(n, 10));

for (let i = 0; i < Math.max(currentParts.length, minimumParts.length); i++) {
const current = currentParts[i] || 0;
const minimum = minimumParts[i] || 0;

if (current > minimum) {
return true;
}
if (current < minimum) {
return false;
}
}

return true; // versions are equal
}
}
19 changes: 11 additions & 8 deletions src/extension/conversation/vscode-node/remoteAgents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { RemoteAgentChatEndpoint } from '../../../platform/endpoint/node/chatEnd
import { IVSCodeExtensionContext } from '../../../platform/extContext/common/extensionContext';
import { IGitService, getGitHubRepoInfoFromContext, toGithubNwo } from '../../../platform/git/common/gitService';
import { IGithubRepositoryService } from '../../../platform/github/common/githubService';
import { HAS_IGNORED_FILES_MESSAGE, IIgnoreService } from '../../../platform/ignore/common/ignoreService';
import { HAS_IGNORED_FILES_MESSAGE, IIgnoreService, IgnoreReason } from '../../../platform/ignore/common/ignoreService';
import { ILogService } from '../../../platform/log/common/logService';
import { ICopilotKnowledgeBaseReference, ICopilotReference } from '../../../platform/networking/common/fetch';
import { IFetcherService, Response } from '../../../platform/networking/common/fetcherService';
Expand Down Expand Up @@ -374,10 +374,10 @@ export class RemoteAgentContribution implements IDisposable {
copilotReferences.push(...copilotSkillReferences);
}

let hasIgnoredFiles = false;
let hasContentExcluded = false;
try {
const result = await this.prepareClientPlatformReferences([...request.references], slug);
hasIgnoredFiles = result.hasIgnoredFiles;
hasContentExcluded = result.hasContentExcluded;

if (result.clientReferences) {
copilotReferences.push(...result.clientReferences);
Expand Down Expand Up @@ -549,7 +549,7 @@ export class RemoteAgentContribution implements IDisposable {
);

metadata['copilot_references'] = [...new Set(reportedReferences.values()).values(), ...agentReferences];
if (response.type === ChatFetchResponseType.Success && hasIgnoredFiles) {
if (response.type === ChatFetchResponseType.Success && hasContentExcluded) {
responseStream.markdown(HAS_IGNORED_FILES_MESSAGE);
}

Expand Down Expand Up @@ -648,15 +648,18 @@ export class RemoteAgentContribution implements IDisposable {
variableName: string;
value?: Uri | Location | undefined;
} | Location | Uri)[] = [];
let hasIgnoredFiles = false;
let hasContentExcluded = false;
let hasSentImplicitSelectionReference = false;

const redactFileContents = async (document: TextDocument, range?: Range) => {
const filename = path.basename(document.uri.toString());
let content = document.getText(range);
if (await this.ignoreService.isCopilotIgnored(document.uri)) {
hasIgnoredFiles = true;
const ignored = await this.ignoreService.isCopilotIgnored(document.uri);
if (ignored === IgnoreReason.ContentExclusion) {
hasContentExcluded = true;
content = 'content-exclusion';
} else if (ignored === IgnoreReason.BehavioralExclusion) {
content = 'excluded';
} else if (filename.startsWith('.')) {
content = 'hidden-file'; // e.g. .env
} else if (Buffer.byteLength(content, 'utf8') > 1024 ** 3) {
Expand Down Expand Up @@ -774,7 +777,7 @@ export class RemoteAgentContribution implements IDisposable {
}
}

return { clientReferences, vscodeReferences, hasIgnoredFiles };
return { clientReferences, vscodeReferences, hasContentExcluded };
}

private async listEnabledSkills(authToken: string) {
Expand Down
2 changes: 1 addition & 1 deletion src/extension/ignore/vscode-node/ignoreProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class IgnoredFileProvider implements vscode.LanguageModelIgnoredFileProvider {
) { }

provideFileIgnored(uri: vscode.Uri, token: vscode.CancellationToken): vscode.ProviderResult<boolean> {
return this._ignoreService.isCopilotIgnored(uri);
return !!this._ignoreService.isCopilotIgnored(uri);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { ServicesAccessor } from '../../../../util/vs/platform/instantiation/com
import { getStructure } from '../../../context/node/resolvers/selectionContextHelpers';
import { EarlyStopping, LeadingMarkdownStreaming, ReplyInterpreter, ReplyInterpreterMetaData } from '../../../prompt/node/intents';
import { TextPieceClassifiers } from '../../../prompt/node/streamingEdits';
import { IgnoredFiles } from '../../../prompts/node/base/ignoredFiles';
import { Tag } from '../../../prompts/node/base/tag';
import { getAdjustedSelection } from '../../../prompts/node/inline/adjustSelection';
import { MarkdownBlock } from '../../../prompts/node/inline/inlineChatGenerateMarkdownPrompt';
Expand Down Expand Up @@ -156,7 +157,7 @@ export class SummarizedDocumentWithSelection extends PromptElement<SummarizedDoc
const isIgnored = await this.ignoreService.isCopilotIgnored(documentData.document.uri);

if (isIgnored) {
return <ignoredFiles value={[documentData.document.uri]} />;
return <IgnoredFiles uris={documentData.document.uri} reason={isIgnored} />;
}

let { tokenBudget } = this.props;
Expand Down
8 changes: 5 additions & 3 deletions src/extension/intents/node/toolCallingLoop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { IAuthenticationChatUpgradeService } from '../../../platform/authenticat
import { FetchStreamSource, IResponsePart } from '../../../platform/chat/common/chatMLFetcher';
import { CanceledResult, ChatFetchResponseType, ChatResponse } from '../../../platform/chat/common/commonTypes';
import { IEndpointProvider } from '../../../platform/endpoint/common/endpointProvider';
import { IgnoredMetadata, IgnoreReason } from '../../../platform/ignore/common/ignoreService';
import { ILogService } from '../../../platform/log/common/logService';
import { FinishedCallback, OpenAiFunctionDef, OptionalChatRequestParams } from '../../../platform/networking/common/fetch';
import { IRequestLogger } from '../../../platform/requestLogger/node/requestLogger';
Expand Down Expand Up @@ -449,6 +450,7 @@ export abstract class ToolCallingLoop<TOptions extends IToolCallingLoopOptions =

this.turn.setMetadata(interactionOutcomeComputer.interactionOutcome);
const toolInputRetry = isToolInputFailure ? (this.toolCallRounds.at(-1)?.toolInputRetry || 0) + 1 : 0;
const hadIgnoredFiles = buildPromptResult.metadata.get(IgnoredMetadata)?.reason ?? (buildPromptResult.hasIgnoredFiles ? IgnoreReason.ContentExclusion : IgnoreReason.NotIgnored);
if (fetchResult.type === ChatFetchResponseType.Success) {
return {
response: fetchResult,
Expand All @@ -459,15 +461,15 @@ export abstract class ToolCallingLoop<TOptions extends IToolCallingLoopOptions =
undefined
),
chatResult,
hadIgnoredFiles: buildPromptResult.hasIgnoredFiles,
hadIgnoredFiles,
lastRequestMessages: buildPromptResult.messages,
availableToolCount: availableTools.length
};
}

return {
response: fetchResult,
hadIgnoredFiles: buildPromptResult.hasIgnoredFiles,
hadIgnoredFiles,
lastRequestMessages: buildPromptResult.messages,
availableToolCount: availableTools.length,
round: new ToolCallRound('', toolCalls, toolInputRetry, undefined)
Expand Down Expand Up @@ -636,7 +638,7 @@ export interface IToolCallSingleResult {
response: ChatResponse;
round: IToolCallRound;
chatResult?: ChatResult; // TODO should just be metadata
hadIgnoredFiles: boolean;
hadIgnoredFiles: IgnoreReason;
lastRequestMessages: Raw.ChatMessage[];
availableToolCount: number;
}
Expand Down
6 changes: 3 additions & 3 deletions src/extension/prompt/node/defaultIntentRequestHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { CanceledResult, ChatFetchResponseType, ChatLocation, ChatResponse, getE
import { IConversationOptions } from '../../../platform/chat/common/conversationOptions';
import { IEditSurvivalTrackerService, IEditSurvivalTrackingSession, NullEditSurvivalTrackingSession } from '../../../platform/editSurvivalTracking/common/editSurvivalTrackerService';
import { IEndpointProvider } from '../../../platform/endpoint/common/endpointProvider';
import { HAS_IGNORED_FILES_MESSAGE } from '../../../platform/ignore/common/ignoreService';
import { HAS_IGNORED_FILES_MESSAGE, IgnoreReason } from '../../../platform/ignore/common/ignoreService';
import { ILogService } from '../../../platform/log/common/logService';
import { FinishedCallback, OptionalChatRequestParams } from '../../../platform/networking/common/fetch';
import { IRequestLogger } from '../../../platform/requestLogger/node/requestLogger';
Expand Down Expand Up @@ -132,7 +132,7 @@ export class DefaultIntentRequestHandler {
chatResult.errorDetails = intentInvocation.modifyErrorDetails(chatResult.errorDetails, resultDetails.response);
}

if (resultDetails.hadIgnoredFiles) {
if (resultDetails.hadIgnoredFiles === IgnoreReason.ContentExclusion) {
this.stream.markdown(HAS_IGNORED_FILES_MESSAGE);
}

Expand Down Expand Up @@ -468,7 +468,7 @@ interface IInternalRequestResult {
response: ChatResponse;
round: IToolCallRound;
chatResult?: ChatResult; // TODO should just be metadata
hadIgnoredFiles: boolean;
hadIgnoredFiles: IgnoreReason;
lastRequestMessages: Raw.ChatMessage[];
lastRequestTelemetry: ChatTelemetry;
availableToolCount: number;
Expand Down
11 changes: 7 additions & 4 deletions src/extension/prompt/node/definitionAroundCursor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@

import { PromptElement, PromptElementProps, PromptPiece, PromptSizing, UserMessage } from '@vscode/prompt-tsx';
import type * as vscode from 'vscode';
import { IIgnoreService } from '../../../platform/ignore/common/ignoreService';
import { IgnoreReason, IIgnoreService } from '../../../platform/ignore/common/ignoreService';
import { IChatEndpoint } from '../../../platform/networking/common/networking';
import { TreeSitterOffsetRange } from '../../../platform/parser/node/nodes';
import { NodeToDocumentContext } from '../../../platform/parser/node/parserImpl';
import { IParserService, treeSitterOffsetRangeToVSCodeRange as toRange, vscodeToTreeSitterOffsetRange as toTSOffsetRange } from '../../../platform/parser/node/parserService';
import { ITelemetryService } from '../../../platform/telemetry/common/telemetry';
import { CodeContextRegion, CodeContextTracker } from '../../inlineChat/node/codeContextRegion';
import { IgnoredFiles } from '../../prompts/node/base/ignoredFiles';
import { IDocumentContext } from './documentContext';

export type Props = PromptElementProps<{
Expand All @@ -29,6 +30,7 @@ export type State =
}
| {
k: 'ignored';
reason: IgnoreReason;
}
;

Expand All @@ -44,8 +46,9 @@ export class DefinitionAroundCursor extends PromptElement<Props, State> {
}

override async prepare(sizing: PromptSizing, progress?: vscode.Progress<vscode.ChatResponseProgressPart | vscode.ChatResponseReferencePart> | undefined, token?: vscode.CancellationToken | undefined): Promise<State> {
if (await this._ignoreService.isCopilotIgnored(this.props.documentContext.document.uri)) {
return { k: 'ignored' };
const ignored = await this._ignoreService.isCopilotIgnored(this.props.documentContext.document.uri);
if (ignored) {
return { k: 'ignored', reason: ignored };
}
const nodeToDocument = this.props.nodeToDocument ?? await determineNodeToDocument(this._parserService, this._telemetryService, this.props.documentContext);
const contextInfo = generateDocContext(this.props.endpointInfo, this.props.documentContext, nodeToDocument.range);
Expand All @@ -58,7 +61,7 @@ export class DefinitionAroundCursor extends PromptElement<Props, State> {

override render(state: State, sizing: PromptSizing): PromptPiece<any, any> | undefined {
if (state.k === 'ignored') {
return <ignoredFiles value={[this.props.documentContext.document.uri]} />;
return <IgnoredFiles uris={this.props.documentContext.document.uri} reason={state.reason} />;
}
const codeExcerpt = state.codeExcerptToDocument.generatePrompt().join('\n');
return (
Expand Down
6 changes: 4 additions & 2 deletions src/extension/prompts/node/agent/agentPrompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ConfigKey, IConfigurationService } from '../../../../platform/configura
import { CacheType } from '../../../../platform/endpoint/common/endpointTypes';
import { IEnvService, OperatingSystem } from '../../../../platform/env/common/envService';
import { getGitHubRepoInfoFromContext, IGitService } from '../../../../platform/git/common/gitService';
import { IIgnoreService } from '../../../../platform/ignore/common/ignoreService';
import { ILogService } from '../../../../platform/log/common/logService';
import { IChatEndpoint } from '../../../../platform/networking/common/networking';
import { IAlternativeNotebookContentService } from '../../../../platform/notebook/common/alternativeContent';
Expand Down Expand Up @@ -410,6 +411,7 @@ class CurrentEditorContext extends PromptElement<CurrentEditorContextProps> {
@IPromptPathRepresentationService private readonly promptPathRepresentationService: IPromptPathRepresentationService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IAlternativeNotebookContentService private readonly alternativeNotebookContent: IAlternativeNotebookContentService,
@IIgnoreService private readonly ignoreService: IIgnoreService,
) {
super(props);
}
Expand All @@ -421,12 +423,12 @@ class CurrentEditorContext extends PromptElement<CurrentEditorContextProps> {

let context: PromptElement | undefined;
const activeEditor = this.tabsAndEditorsService.activeTextEditor;
if (activeEditor) {
if (activeEditor && !(await this.ignoreService.isCopilotIgnored(this.tabsAndEditorsService.activeTextEditor.document.uri))) {
context = this.renderActiveTextEditor(activeEditor);
}

const activeNotebookEditor = this.tabsAndEditorsService.activeNotebookEditor;
if (activeNotebookEditor) {
if (activeNotebookEditor && !(await this.ignoreService.isCopilotIgnored(activeNotebookEditor.notebook.uri))) {
context = this.renderActiveNotebookEditor(activeNotebookEditor);
}

Expand Down
22 changes: 22 additions & 0 deletions src/extension/prompts/node/base/ignoredFiles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { BasePromptElementProps, PromptElement } from '@vscode/prompt-tsx';
import { URI } from '@vscode/prompt-tsx/dist/base/util/vs/common/uri';
import { IgnoredMetadata, IgnoreReason } from '../../../../platform/ignore/common/ignoreService';

export class IgnoredFiles extends PromptElement<BasePromptElementProps & { uris: URI | URI[]; reason: IgnoreReason }> {
override render() {
const uris = Array.isArray(this.props.uris) ? this.props.uris : [this.props.uris];
if (this.props.reason === IgnoreReason.NotIgnored || !uris.length) {
return;
}

return <>
<ignoredFiles value={Array.isArray(this.props.uris) ? this.props.uris : [this.props.uris]} />
<meta value={new IgnoredMetadata(this.props.reason, uris)} />
</>;
}
}
5 changes: 3 additions & 2 deletions src/extension/prompts/node/codeMapper/codeMapperPrompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { IInstantiationService } from '../../../../util/vs/platform/instantiatio
import { Uri } from '../../../../vscodeTypes';
import { getStructure } from '../../../context/node/resolvers/selectionContextHelpers';
import { CompositeElement } from '../base/common';
import { IgnoredFiles } from '../base/ignoredFiles';
import { ResponseTranslationRules } from '../base/responseTranslationRules';
import { LegacySafetyRules } from '../base/safetyRules';
import { Tag } from '../base/tag';
Expand Down Expand Up @@ -54,7 +55,7 @@ export class CodeMapperPatchRewritePrompt extends PromptElement<CodeMapperPrompt

const isIgnored = await this.ignoreService.isCopilotIgnored(document.uri);
if (isIgnored) {
return <ignoredFiles value={[document.uri]} />;
return <IgnoredFiles uris={document.uri} reason={isIgnored} />;
}

const inputDocCharLimit = (sizing.endpoint.modelMaxPromptTokens / 3) * 4; // consume one 3rd of the model window, estimating roughly 4 chars per token;
Expand Down Expand Up @@ -234,7 +235,7 @@ export class CodeMapperFullRewritePrompt extends PromptElement<CodeMapperPromptP
const document = this.props.request.existingDocument;
const isIgnored = await this.ignoreService.isCopilotIgnored(document.uri);
if (isIgnored) {
return <ignoredFiles value={[document.uri]} />;
return <IgnoredFiles uris={document.uri} reason={isIgnored} />;
}

const summarized = document instanceof NotebookDocumentSnapshot ?
Expand Down
9 changes: 5 additions & 4 deletions src/extension/prompts/node/inline/diagnosticsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
*--------------------------------------------------------------------------------------------*/
import { BasePromptElementProps, PromptElement, PromptReference, PromptSizing } from '@vscode/prompt-tsx';
import { TextDocumentSnapshot } from '../../../../platform/editing/common/textDocumentSnapshot';
import { IIgnoreService } from '../../../../platform/ignore/common/ignoreService';
import { IgnoreReason, IIgnoreService } from '../../../../platform/ignore/common/ignoreService';
import { ILogService } from '../../../../platform/log/common/logService';
import { IParserService, treeSitterOffsetRangeToVSCodeRange, treeSitterToVSCodeRange, vscodeToTreeSitterOffsetRange, vscodeToTreeSitterRange } from '../../../../platform/parser/node/parserService';
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry';
import { IWorkspaceService } from '../../../../platform/workspace/common/workspaceService';
import { Diagnostic, Location, Range, Uri } from '../../../../vscodeTypes';
import { asyncComputeWithTimeBudget } from '../../../context/node/resolvers/selectionContextHelpers';
import { IDocumentContext } from '../../../prompt/node/documentContext';
import { IgnoredFiles } from '../base/ignoredFiles';
import { Tag } from '../base/tag';
import { ReferencesAtPosition } from '../panel/referencesAtPosition';
import { CodeBlock } from '../panel/safeElements';
Expand Down Expand Up @@ -44,7 +45,7 @@ export class Diagnostics extends PromptElement<DiagnosticsProps> {
const { diagnostics, documentContext } = this.props;
const isIgnored = await this.ignoreService.isCopilotIgnored(documentContext.document.uri);
if (isIgnored) {
return <ignoredFiles value={[documentContext.document.uri]} />;
return <IgnoredFiles uris={documentContext.document.uri} reason={isIgnored} />;
}

return (
Expand Down Expand Up @@ -141,7 +142,7 @@ export class DiagnosticRelatedInfo extends PromptElement<DiagnosticRelatedInfoPr
async render(_state: void, sizing: PromptSizing) {
const { infos, ignoredFiles, definitionRanges } = await this.getRelatedInfos();
if (!infos.length && !definitionRanges.length) {
return <ignoredFiles value={ignoredFiles} />;
return <IgnoredFiles uris={ignoredFiles} reason={IgnoreReason.ContentExclusion} />;
}
return <>
This diagnostic has some related code:<br />
Expand All @@ -151,7 +152,7 @@ export class DiagnosticRelatedInfo extends PromptElement<DiagnosticRelatedInfoPr
{
definitionRanges.map(range => <ReferencesAtPosition document={this.props.document} position={range.start} />)
}
<ignoredFiles value={ignoredFiles} />
<IgnoredFiles uris={ignoredFiles} reason={IgnoreReason.ContentExclusion} />
</>;
}

Expand Down
Loading
Loading