Skip to content

Commit 72fa4c3

Browse files
committed
Merge branch 'main' of https://github.com/microsoft/vscode-copilot-chat into remove-experimentation-service
2 parents 0f5e375 + 17a4969 commit 72fa4c3

960 files changed

Lines changed: 103888 additions & 24823 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.esbuild.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const baseNodeBuildOptions = {
4545
mainFields: ["module", "main"], // needed for jsonc-parser,
4646
define: {
4747
'process.env.APPLICATIONINSIGHTS_CONFIGURATION_CONTENT': '"{}"'
48-
}
48+
},
4949
} satisfies esbuild.BuildOptions;
5050

5151
const nodeExtHostTestGlobs = [
@@ -65,7 +65,7 @@ const testBundlePlugin: esbuild.Plugin = {
6565
return { path: path.resolve(args.path) };
6666
});
6767
build.onLoad({ filter: /[\/\\]test-extension\.ts$/ }, async args => {
68-
let files = await glob(nodeExtHostTestGlobs, { cwd: REPO_ROOT, posix: true });
68+
let files = await glob(nodeExtHostTestGlobs, { cwd: REPO_ROOT, posix: true, ignore: ['src/extension/completions-core/**/*'] });
6969
files = files.map(f => path.posix.relative('src', f));
7070
if (files.length === 0) {
7171
throw new Error('No extension tests found');
@@ -95,7 +95,7 @@ const sanityTestBundlePlugin: esbuild.Plugin = {
9595
return { path: path.resolve(args.path) };
9696
});
9797
build.onLoad({ filter: /[\/\\]sanity-test-extension\.ts$/ }, async args => {
98-
let files = await glob(nodeExtHostSanityTestGlobs, { cwd: REPO_ROOT, posix: true });
98+
let files = await glob(nodeExtHostSanityTestGlobs, { cwd: REPO_ROOT, posix: true, ignore: ['src/extension/completions-core/**/*'] });
9999
files = files.map(f => path.posix.relative('src', f));
100100
if (files.length === 0) {
101101
throw new Error('No extension tests found');
@@ -111,6 +111,23 @@ const sanityTestBundlePlugin: esbuild.Plugin = {
111111
}
112112
};
113113

114+
const importMetaPlugin: esbuild.Plugin = {
115+
name: 'claudeCodeImportMetaPlugin',
116+
setup(build) {
117+
// Handle import.meta.url in @anthropic-ai/claude-code package
118+
build.onLoad({ filter: /node_modules[\/\\]@anthropic-ai[\/\\]claude-code[\/\\].*\.mjs$/ }, async (args) => {
119+
const contents = await fs.promises.readFile(args.path, 'utf8');
120+
return {
121+
contents: contents.replace(
122+
/import\.meta\.url/g,
123+
'require("url").pathToFileURL(__filename).href'
124+
),
125+
loader: 'js'
126+
};
127+
});
128+
}
129+
};
130+
114131
const shimVsCodeTypesPlugin: esbuild.Plugin = {
115132
name: 'shimVsCodeTypesPlugin',
116133
setup(build) {
@@ -157,7 +174,7 @@ const nodeExtHostBuildOptions = {
157174
{ in: './src/sanity-test-extension.ts', out: 'sanity-test-extension' },
158175
],
159176
loader: { '.ps1': 'text' },
160-
plugins: [testBundlePlugin, sanityTestBundlePlugin],
177+
plugins: [testBundlePlugin, sanityTestBundlePlugin, importMetaPlugin],
161178
external: [
162179
...baseNodeBuildOptions.external,
163180
'vscode'
@@ -173,6 +190,7 @@ const webExtHostBuildOptions = {
173190
format: 'cjs', // Necessary to export activate function from bundle for extension
174191
external: [
175192
'vscode',
193+
'http',
176194
]
177195
} satisfies esbuild.BuildOptions;
178196

@@ -217,7 +235,7 @@ const nodeSimulationWorkbenchUIBuildOptions = {
217235
'child_process',
218236
'http',
219237
'assert',
220-
]
238+
],
221239
} satisfies esbuild.BuildOptions;
222240

223241
async function typeScriptServerPluginPackageJsonInstall(): Promise<void> {
@@ -322,6 +340,7 @@ async function main() {
322340
`**/*.w.json`,
323341
'**/*.sqlite',
324342
'**/*.sqlite-journal',
343+
'test/aml/out/**'
325344
]
326345
});
327346
rebuild();

.eslint-ignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ test/simulation/fixtures/**
1010
test/scenarios/**
1111
.simulation/**
1212
.eslintplugin/**
13+
chat-lib/**
14+
test/aml/out/**
15+
.vscode-test/**
1316

1417
# ignore vs
1518
src/util/vs/**
@@ -26,3 +29,6 @@ src/extension/typescriptContext/serverPlugin/dist/**
2629

2730
# Ignore Built test-extension
2831
.vscode/extensions/test-extension/dist/**
32+
33+
# Ignore completions-core
34+
src/extension/completions-core/**
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as eslint from 'eslint';
7+
8+
export = new class NoBadGDPRComment implements eslint.Rule.RuleModule {
9+
readonly meta: eslint.Rule.RuleMetaData = {
10+
type: 'problem',
11+
docs: {
12+
description: 'Ensure "Generate with Copilot" string in GitHubPullRequestProviders is never changed',
13+
category: 'Best Practices'
14+
},
15+
schema: [
16+
{
17+
type: 'object',
18+
properties: {
19+
className: { type: 'string' },
20+
string: { type: 'string' }
21+
},
22+
additionalProperties: false
23+
}
24+
]
25+
}
26+
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
27+
const options = context.options[0] || {};
28+
const className = options.className || 'GitHubPullRequestProviders';
29+
const requiredString = options.string || 'Copilot';
30+
31+
let inTargetClass = false;
32+
33+
return {
34+
ClassDeclaration(node) {
35+
if (node.id && node.id.name === className) {
36+
inTargetClass = true;
37+
}
38+
},
39+
'ClassDeclaration:exit'(node) {
40+
if (node.id && node.id.name === className) {
41+
inTargetClass = false;
42+
}
43+
},
44+
Literal(node) {
45+
if (inTargetClass && typeof node.value === 'string' && node.value.includes('Generate')) {
46+
if (!node.value.includes(requiredString)) {
47+
context.report({
48+
node,
49+
message: `String literal in ${className} must include the word "Copilot" as the string is referenced in the GitHub Pull Request extension. Talk to alexr00 if you need to change it.`
50+
});
51+
}
52+
}
53+
}
54+
};
55+
}
56+
};

.github/copilot-instructions.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,19 @@ This is the **GitHub Copilot Chat** extension for Visual Studio Code - a VS Code
2323
- **Vitest**: Unit testing framework
2424
- **Python**: For notebooks integration and ML evaluation scripts
2525

26+
## Validating changes
27+
28+
You MUST check compilation output before running ANY script or declaring work complete!
29+
30+
1. **ALWAYS** check the `start-watch-tasks` watch task output for compilation errors
31+
2. **NEVER** use the `compile` task as a way to check if everything is working properly
32+
3. **FIX** all compilation errors before moving forward
33+
34+
### TypeScript compilation steps
35+
- Monitor the `start-watch-tasks` task outputs for real-time compilation errors as you make changes
36+
- This task runs `npm: watch:tsc-extension`,`npm: watch:tsc-extension-web`, `npm: watch:tsc-simulation-workbench`, and `npm: watch:esbuild` to incrementally compile the project
37+
- Start the task if it's not already running in the background
38+
2639
## Project Architecture
2740

2841
### Top-Level Directory Structure
@@ -225,6 +238,7 @@ x => x + x // ✓ Correct
225238
### Code Structure
226239
- Always surround loop and conditional bodies with curly braces
227240
- Open curly braces always go on the same line as whatever necessitates them
241+
- An open curly brace MUST be followed by a newline, with the body indented on the next line
228242
- Parenthesized constructs should have no surrounding whitespace
229243
- Single space follows commas, colons, and semicolons
230244

@@ -241,6 +255,8 @@ function f(x: number, y: string): void { }
241255
### Type Management
242256
- Do not export `types` or `functions` unless you need to share it across multiple components
243257
- Do not introduce new `types` or `values` to the global namespace
258+
- Use proper types. Do not use `any` unless absolutely necessary.
259+
- Use `readonly` whenever possible.
244260

245261
## Key APIs and Integrations
246262

@@ -319,3 +335,7 @@ The extension uses numerous proposed VS Code APIs for advanced functionality:
319335
- **Configuration**: Modify `package.json` contributions for VS Code integration
320336

321337
This extension is a complex, multi-layered system that provides comprehensive AI assistance within VS Code. Understanding the service architecture, contribution system, and separation between platform and extension layers is crucial for making effective changes.
338+
339+
## Best Practices
340+
- Use services and dependency injection whenever possible instead of using node or vscode APIs directly. For example, use `IFileService` instead of node's `fs`.
341+
- Always use the URI type instead of using string file paths. There are many helpers available for working with URIs.
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
---
2+
applyTo: '**/*.tsx'
3+
description: Prompt-TSX coding guidelines
4+
---
5+
6+
Guidelines for TSX files using [prompt-tsx](https://github.com/microsoft/vscode-prompt-tsx) focusing on specific patterns and token budget management for AI prompt engineering.
7+
8+
## Component Structure
9+
10+
### Base Pattern
11+
- Extend `PromptElement<Props>` or `PromptElement<Props, State>` for all prompt components
12+
- Props interfaces must extend `BasePromptElementProps`
13+
14+
```tsx
15+
interface MyPromptProps extends BasePromptElementProps {
16+
readonly userQuery: string;
17+
}
18+
19+
class MyPrompt extends PromptElement<MyPromptProps> {
20+
render() {
21+
return (
22+
<>
23+
<SystemMessage priority={1000}>...</SystemMessage>
24+
<UserMessage priority={900}>{this.props.userQuery}</UserMessage>
25+
</>
26+
);
27+
}
28+
}
29+
```
30+
31+
### Async Components
32+
- The `render` method can be async for components that need to perform async operations
33+
- All async work should be done directly in the `render` method
34+
35+
```tsx
36+
class FileContextPrompt extends PromptElement<FileContextProps> {
37+
async render() {
38+
const fileContent = await readFileAsync(this.props.filePath);
39+
return (
40+
<>
41+
<SystemMessage priority={1000}>File content:</SystemMessage>
42+
<UserMessage priority={900}>{fileContent}</UserMessage>
43+
</>
44+
);
45+
}
46+
}
47+
```
48+
49+
## Prompt-Specific JSX
50+
51+
### Line Breaks
52+
- **CRITICAL**: Use `<br />` for line breaks - newlines are NOT preserved in JSX
53+
- Never rely on whitespace or string literal newlines
54+
55+
```tsx
56+
// ✅ Correct
57+
<SystemMessage>
58+
You are an AI assistant.<br />
59+
Follow these guidelines.<br />
60+
</SystemMessage>
61+
62+
// ❌ Wrong - newlines will be collapsed
63+
<SystemMessage>
64+
You are an AI assistant.
65+
Follow these guidelines.
66+
</SystemMessage>
67+
```
68+
69+
## Priority System
70+
71+
### Priority Values
72+
- Higher numbers = higher priority (like z-index)
73+
- Use consistent ranges:
74+
- System messages: 1000
75+
- User queries: 900
76+
- Recent history: 700-800
77+
- Context/attachments: 600-700
78+
- Background info: 0-500
79+
80+
```tsx
81+
<SystemMessage priority={1000}>...</SystemMessage>
82+
<UserMessage priority={900}>{query}</UserMessage>
83+
<HistoryMessages priority={700} />
84+
<ContextualData priority={500} />
85+
```
86+
87+
### Flex Properties for Token Budget
88+
- `flexGrow={1}` - expand to fill remaining token space
89+
- `flexReserve` - reserve tokens before rendering
90+
- `passPriority` - pass-through containers that don't affect child priorities
91+
92+
```tsx
93+
<FileContext priority={70} flexGrow={1} files={this.props.files} />
94+
<History passPriority older={0} newer={80} flexGrow={2} flexReserve="/5" />
95+
```
96+
97+
## Content Handling
98+
99+
### TextChunk for Truncation
100+
- Use `TextChunk` for content that may exceed token budget
101+
- Set `breakOn` patterns for intelligent truncation
102+
103+
```tsx
104+
<TextChunk breakOnWhitespace priority={100}>
105+
{longUserQuery}
106+
</TextChunk>
107+
108+
<TextChunk breakOn=" " priority={80}>
109+
{documentContent}
110+
</TextChunk>
111+
```
112+
113+
### Tag Component for Structured Content
114+
- Use `Tag` for XML-like structured content with attributes
115+
- Validates tag names and properly formats attributes
116+
117+
```tsx
118+
<Tag name="attachments" attrs={{ id: variableName, type: "file" }}>
119+
{content}
120+
</Tag>
121+
```
122+
123+
## References and Metadata
124+
125+
### Prompt References
126+
- Use `<references>` for tracking variable usage
127+
- Use `<meta>` for metadata that survives pruning
128+
129+
```tsx
130+
<references value={[new PromptReference({ variableName })]} />
131+
<meta value={new ToolResultMetadata(id, result)} />
132+
```
133+
134+
### Keep-With Pattern
135+
- Use `useKeepWith()` for content that should be pruned together
136+
137+
```tsx
138+
const KeepWith = useKeepWith();
139+
return (
140+
<>
141+
<KeepWith priority={2}>
142+
<ToolCallRequest>...</ToolCallRequest>
143+
</KeepWith>
144+
<KeepWith priority={1}>
145+
<ToolCallResponse>...</ToolCallResponse>
146+
</KeepWith>
147+
</>
148+
);
149+
```
150+
151+
## Token Budget Management
152+
153+
### Sizing-Aware Rendering
154+
- Use `PromptSizing` parameter for budget-aware content generation
155+
- Implement cooperative token usage
156+
157+
```tsx
158+
async render(sizing: PromptSizing): Promise<PromptPiece> {
159+
const content = await this.generateContent(sizing.tokenBudget);
160+
return <>{content}</>;
161+
}
162+
```
163+
164+
### Performance
165+
- Avoid expensive work in `render` methods when possible
166+
- Cache computations when appropriate
167+
- Use async `render` for all async operations

0 commit comments

Comments
 (0)