Skip to content
Draft
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
282 changes: 1 addition & 281 deletions src/extension/context/node/resolvers/promptWorkspaceLabels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
*--------------------------------------------------------------------------------------------*/


import { ConfigKey, IConfigurationService } from '../../../../platform/configuration/common/configurationService';
import { IFileSystemService } from '../../../../platform/filesystem/common/fileSystemService';
import { IIgnoreService } from '../../../../platform/ignore/common/ignoreService';
import { IExperimentationService } from '../../../../platform/telemetry/common/nullExperimentationService';
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry';
import { IWorkspaceService } from '../../../../platform/workspace/common/workspaceService';
import { createServiceIdentifier } from '../../../../util/common/services';
Expand All @@ -24,30 +22,20 @@ export interface IPromptWorkspaceLabels {
collectContext(): Promise<void>;
}

const enum PromptWorkspaceLabelsStrategy {
Basic,
Expanded
}

export class PromptWorkspaceLabels implements IPromptWorkspaceLabels {
declare _serviceBrand: undefined;

private readonly basicWorkspaceLabels: IPromptWorkspaceLabelsStrategy;
private readonly expandedWorkspaceLabels: IPromptWorkspaceLabelsStrategy;
private strategy = PromptWorkspaceLabelsStrategy.Basic;

private get workspaceLabels(): IPromptWorkspaceLabelsStrategy {
return this.strategy === PromptWorkspaceLabelsStrategy.Basic ? this.basicWorkspaceLabels : this.expandedWorkspaceLabels;
return this.basicWorkspaceLabels;
}

constructor(
@IExperimentationService private readonly _experimentationService: IExperimentationService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
) {
this.basicWorkspaceLabels = this._instantiationService.createInstance(BasicPromptWorkspaceLabels);
this.expandedWorkspaceLabels = this._instantiationService.createInstance(ExpandedPromptWorkspaceLabels);
}

public get labels(): string[] {
Expand All @@ -56,8 +44,6 @@ export class PromptWorkspaceLabels implements IPromptWorkspaceLabels {
}

public async collectContext(): Promise<void> {
const expandedLabels = this._configurationService.getExperimentBasedConfig(ConfigKey.Advanced.ProjectLabelsExpanded, this._experimentationService);
this.strategy = expandedLabels ? PromptWorkspaceLabelsStrategy.Expanded : PromptWorkspaceLabelsStrategy.Basic;
await this.workspaceLabels.collectContext();

const uniqueLabels = [...new Set(this.labels)].sort();
Expand Down Expand Up @@ -245,269 +231,3 @@ class BasicPromptWorkspaceLabels implements IPromptWorkspaceLabelsStrategy {
return tags;
}
}

class ExpandedPromptWorkspaceLabels extends BasicPromptWorkspaceLabels {

constructor(
@IWorkspaceService workspaceService: IWorkspaceService,
@IFileSystemService fileSystemService: IFileSystemService,
@IIgnoreService ignoreService: IIgnoreService,
) {
super(workspaceService, fileSystemService, ignoreService);
this.addContentIndicator('package.json', this.collectPackageJsonIndicatorsExpanded);
this.addContentIndicator('requirements.txt', this.collectPythonRequirementsIndicators);
this.addContentIndicator('pyproject.toml', this.collectPythonTomlIndicators);
}

protected collectPackageJsonIndicatorsExpanded(contents: string): string[] {
const tags: string[] = [];

const extractMajorMinorVersion = (version: string): string => {
const [major, minor] = version.split('.');
return `${major.replace(/[^0-9]/g, '')}.${minor.replace(/[^0-9]/g, '')}`;
};

const checkDependencies = (dependencies: Record<string, string> | undefined, list: { dependency: string; prefix?: string }[]) => {
if (!dependencies) { return; }
list.forEach(({ dependency, prefix }) => {
if (dependencies[dependency]) {
const version = extractMajorMinorVersion(dependencies[dependency]);
tags.push(`${prefix || dependency}@${version}`);
}
});
};

let json: any;
try {
json = JSON.parse(contents);
} catch {
return tags;
}

const allDependenciesFields = [
json.dependencies,
json.devDependencies,
json.peerDependencies,
json.optionalDependencies
];

const dependenciesList = [
// Frontend Frameworks
{ dependency: 'react' },
{ dependency: 'vue' },
{ dependency: '@angular/core' },
{ dependency: 'svelte' },
{ dependency: 'solid-js' },
{ dependency: 'alpinejs' },

// State Management Libraries
{ dependency: 'redux' },
{ dependency: 'mobx' },
{ dependency: 'vuex' },
{ dependency: 'ngrx' },

// UI Libraries
{ dependency: 'antd' },
{ dependency: 'bootstrap' },
{ dependency: 'bulma' },
{ dependency: '@mui/material' },
{ dependency: 'semantic-ui-react' },

// Rendering Frameworks
{ dependency: 'next' },
{ dependency: 'gatsby' },
{ dependency: 'remix' },
{ dependency: 'astro' },
{ dependency: 'sveltekit' },
{ dependency: 'nuxt' },

// Testing Tools
{ dependency: 'jest' },
{ dependency: 'mocha' },
{ dependency: 'cypress' },
{ dependency: '@testing-library/react' },
{ dependency: '@playwright/test' },
{ dependency: 'vitest' },
{ dependency: '@storybook/react' },

// CSS Tools
{ dependency: 'tailwindcss' },
{ dependency: 'sass' },
{ dependency: 'styled-components' },
{ dependency: 'css-modules' },
{ dependency: 'postcss' },
{ dependency: '@emotion/react' },

// Build Tools
{ dependency: 'vite' },
{ dependency: 'webpack' },
{ dependency: 'parcel' },
{ dependency: 'rollup' },
{ dependency: 'snowpack' },
{ dependency: 'esbuild' },
{ dependency: '@swc/core' },

// Real-time Communication
{ dependency: 'socket.io' },

// API and Data Handling
{ dependency: 'd3' },
{ dependency: 'graphql' },

// Utility Libraries
{ dependency: 'lodash' },
{ dependency: 'moment' },
{ dependency: 'rxjs' },
{ dependency: 'underscore' },

// Task Runners
{ dependency: 'gulp' },

// Older Libraries
{ dependency: 'backbone' },
{ dependency: 'ember-source' },
{ dependency: 'handlebars' },
{ dependency: 'jquery' },
{ dependency: 'knockout' },

// Cloud SDKs
{ dependency: 'aws-sdk' },
{ dependency: 'cloudinary' },
{ dependency: 'firebase' },
{ dependency: '@azure/storage-blob' },
{ dependency: '@google-cloud/storage' },

// Cloud Functions
{ dependency: '@aws-lambda' },
{ dependency: '@azure/functions' },
{ dependency: '@google-cloud/functions' },
{ dependency: 'firebase-functions' },

// Cloud Databases
{ dependency: '@azure/cosmos' },
{ dependency: '@google-cloud/firestore' },
{ dependency: 'mongoose' },

// Containerization and Orchestration
{ dependency: 'dockerode' },
{ dependency: 'kubernetes-client' },

// Monitoring and Logging
{ dependency: '@elastic/elasticsearch' },
{ dependency: '@sentry/node' },
{ dependency: 'log4js' },
{ dependency: 'winston' },

// Security
{ dependency: 'bcrypt' },
{ dependency: 'helmet' },
{ dependency: 'jsonwebtoken' },
{ dependency: 'passport' },

// Azure Libraries
{ dependency: '@azure/identity' },
{ dependency: '@azure/keyvault-certificates' },
{ dependency: '@azure/keyvault-keys' },
{ dependency: '@azure/keyvault-secrets' },
{ dependency: '@azure/service-bus' },
{ dependency: '@azure/event-hubs' },
{ dependency: '@azure/data-tables' },
{ dependency: '@azure/monitor-query' },
{ dependency: '@azure/app-configuration' },

// Development Tools
{ dependency: 'babel' },
{ dependency: 'eslint' },
{ dependency: 'parcel' },
{ dependency: 'prettier' },
{ dependency: 'rollup' },
{ dependency: 'typescript' },
{ dependency: 'webpack' },
{ dependency: 'vite' },
];

const enginesList = [
// Engines
{ dependency: 'node' },
{ dependency: 'vscode', prefix: 'vscode extension' }
];

allDependenciesFields.forEach((deps) => checkDependencies(deps, dependenciesList));
checkDependencies(json.engines, enginesList);

return tags;
}


private popularPackages: string[] = [
// Data Science and Machine Learning
'numpy', 'pandas', 'scipy', 'scikit-learn', 'matplotlib', 'tensorflow', 'keras',
'torch', 'seaborn', 'plotly', 'dash', 'jupyter', 'notebook', 'ipython', 'openai', 'pyspark',
'airflow', 'nltk', 'sympy', 'spacy', 'langchain',

// Web Development
'Flask', 'Django', 'fastapi', 'pydantic', 'requests', 'beautifulsoup4',
'gunicorn', 'uvicorn', 'httpx', 'Jinja2', 'aiohttp',

// Testing
'pytest', 'tox', 'nox', 'selenium', 'playwright', 'coverage', 'hypothesis',

// Documentation
'Sphinx',

// Task Queue
'celery', 'asyncio',

// Cloud and DevOps
'boto3', 'google-cloud-storage', 'azure-storage-blob', 'docker', 'kubernetes', 'azure', 'google', 'ansible',

// Security
'cryptography', 'paramiko', 'PyJWT',

// Enterprise, Legacy & data storage
'xlrd', 'xlrd-2024', 'openpyxl', 'pywin32', 'pywin', 'psycopg2', 'mysqlclient', 'SQLite4', 'Werkzeug', 'pymongo', 'redis', 'PyMySQL',

// Utilities
'Pillow', 'SQLAlchemy', 'lxml', 'html5lib', 'Markdown', 'pytz', 'Click',
'attrs', 'PyYAML', 'configparser', 'loguru', 'structlog', 'pygame', 'discord'
];


private collectPythonRequirementsIndicators(contents: string): string[] {
const tags: string[] = [];

const lines = contents.split('\n');
lines.forEach(line => {
const [pkg, version] = line.split('==');
if (this.popularPackages.includes(pkg)) {
tags.push(`${pkg}-${version || 'latest'}`);
}
});

return tags;
}

private collectPythonTomlIndicators(contents: string): string[] {
const tags: string[] = [];

const lines = contents.split('\n');
let inDependenciesSection = false;

// TODO@digitarald: Should use npm `toml` package, but this is avoiding a dependency for now
lines.forEach(line => {
line = line.trim();
if (line === '[tool.poetry.dependencies]') {
inDependenciesSection = true;
} else if (line.startsWith('[') && line.endsWith(']')) {
inDependenciesSection = false;
} else if (inDependenciesSection && line) {
const [pkg, version] = line.split('=').map(s => s.trim().replace(/"|'/g, ''));
if (this.popularPackages.includes(pkg)) {
tags.push(`${pkg}-${version || 'latest'}`);
}
}
});

return tags;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
*--------------------------------------------------------------------------------------------*/

import { PromptElement, PromptSizing, SystemMessage, UserMessage } from '@vscode/prompt-tsx';
import { ConfigKey, IConfigurationService } from '../../../../platform/configuration/common/configurationService';
import { IIgnoreService } from '../../../../platform/ignore/common/ignoreService';
import { KnownSources } from '../../../../platform/languageServer/common/languageContextService';
import { IParserService } from '../../../../platform/parser/node/parserService';
import { IExperimentationService } from '../../../../platform/telemetry/common/nullExperimentationService';
import { isNotebookCellOrNotebookChatInput } from '../../../../util/common/notebooks';
import { illegalArgument } from '../../../../util/vs/base/common/errors';
import { OffsetRange } from '../../../../util/vs/editor/common/core/ranges/offsetRange';
Expand Down Expand Up @@ -46,8 +44,6 @@ export class InlineChatEditCodePrompt extends PromptElement<InlineChatEditCodePr
props: InlineChatEditCodePromptProps,
@IIgnoreService private readonly _ignoreService: IIgnoreService,
@IParserService private readonly _parserService: IParserService,
@IExperimentationService private readonly _experimentationService: IExperimentationService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
) {
super(props);
}
Expand All @@ -71,8 +67,6 @@ export class InlineChatEditCodePrompt extends PromptElement<InlineChatEditCodePr
}
const { query, history, chatVariables, } = this.props.promptContext;

const useProjectLabels = this._configurationService.getExperimentBasedConfig(ConfigKey.Advanced.ProjectLabelsInline, this._experimentationService);

const data = await SummarizedDocumentData.create(this._parserService, document, context.fileIndentInfo, context.wholeRange, SelectionSplitKind.Adjusted);

const replyInterpreterFactory = (splitDoc: SummarizedDocumentSplit) => splitDoc.createReplyInterpreter(
Expand All @@ -98,7 +92,7 @@ export class InlineChatEditCodePrompt extends PromptElement<InlineChatEditCodePr
{data.hasCodeWithoutSelection && <>The user includes existing code and marks with {data.placeholderText} where the selected code should go.<br /></>}
</InstructionMessage>
</HistoryWithInstructions>
{useProjectLabels && <ProjectLabels priority={600} embeddedInsideUserMessage={false} />}
<ProjectLabels priority={600} embeddedInsideUserMessage={false} />
<UserMessage>
{!this.props.ignoreCustomInstructions && <CustomInstructions priority={725} chatVariables={chatVariables} languageId={languageId} />}
<LanguageServerContextPrompt priority={700} document={document} position={context.selection.start} requestId={this.props.promptContext.requestId} source={KnownSources.chat} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
*--------------------------------------------------------------------------------------------*/

import { PromptElement, PromptSizing, SystemMessage, UserMessage } from '@vscode/prompt-tsx';
import { ConfigKey, IConfigurationService } from '../../../../platform/configuration/common/configurationService';
import { IIgnoreService } from '../../../../platform/ignore/common/ignoreService';
import { KnownSources } from '../../../../platform/languageServer/common/languageContextService';
import { IParserService } from '../../../../platform/parser/node/parserService';
import { IExperimentationService } from '../../../../platform/telemetry/common/nullExperimentationService';
import { isNotebookCellOrNotebookChatInput } from '../../../../util/common/notebooks';
import { illegalArgument } from '../../../../util/vs/base/common/errors';
import { GenericInlinePromptProps } from '../../../context/node/resolvers/genericInlineIntentInvocation';
Expand All @@ -34,8 +32,6 @@ export class InlineChatGenerateCodePrompt extends PromptElement<InlineChatGenera
props: InlineChatGenerateCodePromptProps,
@IIgnoreService private readonly _ignoreService: IIgnoreService,
@IParserService private readonly _parserService: IParserService,
@IExperimentationService private readonly _experimentationService: IExperimentationService,
@IConfigurationService private readonly _configurationService: IConfigurationService
) {
super(props);
}
Expand All @@ -60,8 +56,6 @@ export class InlineChatGenerateCodePrompt extends PromptElement<InlineChatGenera

const { query, history, chatVariables, } = this.props.promptContext;

const useProjectLabels = this._configurationService.getExperimentBasedConfig(ConfigKey.Advanced.ProjectLabelsInline, this._experimentationService);

const data = await SummarizedDocumentData.create(this._parserService, document, context.fileIndentInfo, context.wholeRange, SelectionSplitKind.OriginalEnd);

const replyInterpreterFn = (splitDoc: SummarizedDocumentSplit) => splitDoc.createReplyInterpreter(
Expand Down Expand Up @@ -90,7 +84,7 @@ export class InlineChatGenerateCodePrompt extends PromptElement<InlineChatGenera
{!data.hasContent && <>Your must generate a code block surrounded with ``` that will be used in a new file<br /></>}
</InstructionMessage>
</HistoryWithInstructions>
{useProjectLabels && <ProjectLabels priority={600} embeddedInsideUserMessage={false} />}
<ProjectLabels priority={600} embeddedInsideUserMessage={false} />
<UserMessage priority={725}>
<CustomInstructions languageId={languageId} chatVariables={chatVariables} />
<LanguageServerContextPrompt priority={700} document={document} position={context.selection.start} requestId={this.props.promptContext.requestId} source={KnownSources.chat} />
Expand Down
Loading
Loading