Skip to content

Commit 1b60ce1

Browse files
author
feifei
committed
feat: merge main into feature-branch and resolve merge conflicts
2 parents f0bd734 + 38f1092 commit 1b60ce1

39 files changed

+1606
-368
lines changed

src/api/providers/__tests__/openai-native.test.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,20 @@ describe("OpenAiNativeHandler", () => {
130130
})
131131

132132
mockCreate.mockResolvedValueOnce({
133-
choices: [{ message: { content: null } }],
134-
usage: {
135-
prompt_tokens: 0,
136-
completion_tokens: 0,
137-
total_tokens: 0,
133+
[Symbol.asyncIterator]: async function* () {
134+
yield {
135+
choices: [
136+
{
137+
delta: { content: null },
138+
index: 0,
139+
},
140+
],
141+
usage: {
142+
prompt_tokens: 0,
143+
completion_tokens: 0,
144+
total_tokens: 0,
145+
},
146+
}
138147
},
139148
})
140149

@@ -144,10 +153,7 @@ describe("OpenAiNativeHandler", () => {
144153
results.push(result)
145154
}
146155

147-
expect(results).toEqual([
148-
{ type: "text", text: "" },
149-
{ type: "usage", inputTokens: 0, outputTokens: 0 },
150-
])
156+
expect(results).toEqual([{ type: "usage", inputTokens: 0, outputTokens: 0 }])
151157

152158
// Verify developer role is used for system prompt with o1 model
153159
expect(mockCreate).toHaveBeenCalledWith({
@@ -156,6 +162,8 @@ describe("OpenAiNativeHandler", () => {
156162
{ role: "developer", content: "Formatting re-enabled\n" + systemPrompt },
157163
{ role: "user", content: "Hello!" },
158164
],
165+
stream: true,
166+
stream_options: { include_usage: true },
159167
})
160168
})
161169

src/api/providers/mistral.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export class MistralHandler implements ApiHandler {
3535
}
3636

3737
private getBaseUrl(): string {
38-
const modelId = this.options.apiModelId
38+
const modelId = this.options.apiModelId ?? mistralDefaultModelId
3939
if (modelId?.startsWith("codestral-")) {
4040
return this.options.mistralCodestralUrl || "https://codestral.mistral.ai"
4141
}
@@ -86,4 +86,25 @@ export class MistralHandler implements ApiHandler {
8686
info: mistralModels[mistralDefaultModelId],
8787
}
8888
}
89+
90+
async completePrompt(prompt: string): Promise<string> {
91+
try {
92+
const response = await this.client.chat.complete({
93+
model: this.options.apiModelId || mistralDefaultModelId,
94+
messages: [{ role: "user", content: prompt }],
95+
temperature: this.options.modelTemperature ?? MISTRAL_DEFAULT_TEMPERATURE,
96+
})
97+
98+
const content = response.choices?.[0]?.message.content
99+
if (Array.isArray(content)) {
100+
return content.map((c) => (c.type === "text" ? c.text : "")).join("")
101+
}
102+
return content || ""
103+
} catch (error) {
104+
if (error instanceof Error) {
105+
throw new Error(`Mistral completion error: ${error.message}`)
106+
}
107+
throw error
108+
}
109+
}
89110
}

src/api/providers/openai-native.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,11 @@ export class OpenAiNativeHandler implements ApiHandler, SingleCompletionHandler
5656
},
5757
...convertToOpenAiMessages(messages),
5858
],
59+
stream: true,
60+
stream_options: { include_usage: true },
5961
})
6062

61-
yield* this.yieldResponseData(response)
63+
yield* this.handleStreamResponse(response)
6264
}
6365

6466
private async *handleO3FamilyMessage(

src/core/mentions/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { extractTextFromFile } from "../../integrations/misc/extract-text"
88
import { isBinaryFile } from "isbinaryfile"
99
import { diagnosticsToProblemsString } from "../../integrations/diagnostics"
1010
import { getCommitInfo, getWorkingState } from "../../utils/git"
11+
import { getLatestTerminalOutput } from "../../integrations/terminal/get-latest-output"
1112

1213
export async function openMention(mention?: string): Promise<void> {
1314
if (!mention) {
@@ -29,6 +30,8 @@ export async function openMention(mention?: string): Promise<void> {
2930
}
3031
} else if (mention === "problems") {
3132
vscode.commands.executeCommand("workbench.actions.view.problems")
33+
} else if (mention === "terminal") {
34+
vscode.commands.executeCommand("workbench.action.terminal.focus")
3235
} else if (mention.startsWith("http")) {
3336
vscode.env.openExternal(vscode.Uri.parse(mention))
3437
}
@@ -51,6 +54,8 @@ export async function parseMentions(text: string, cwd: string, urlContentFetcher
5154
return `Working directory changes (see below for details)`
5255
} else if (/^[a-f0-9]{7,40}$/.test(mention)) {
5356
return `Git commit '${mention}' (see below for commit info)`
57+
} else if (mention === "terminal") {
58+
return `Terminal Output (see below for output)`
5459
}
5560
return match
5661
})
@@ -118,6 +123,13 @@ export async function parseMentions(text: string, cwd: string, urlContentFetcher
118123
} catch (error) {
119124
parsedText += `\n\n<git_commit hash="${mention}">\nError fetching commit info: ${error.message}\n</git_commit>`
120125
}
126+
} else if (mention === "terminal") {
127+
try {
128+
const terminalOutput = await getLatestTerminalOutput()
129+
parsedText += `\n\n<terminal_output>\n${terminalOutput}\n</terminal_output>`
130+
} catch (error) {
131+
parsedText += `\n\n<terminal_output>\nError fetching terminal output: ${error.message}\n</terminal_output>`
132+
}
121133
}
122134
}
123135

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import * as vscode from "vscode"
2+
3+
/**
4+
* Gets the contents of the active terminal
5+
* @returns The terminal contents as a string
6+
*/
7+
export async function getLatestTerminalOutput(): Promise<string> {
8+
// Store original clipboard content to restore later
9+
const originalClipboard = await vscode.env.clipboard.readText()
10+
11+
try {
12+
// Select terminal content
13+
await vscode.commands.executeCommand("workbench.action.terminal.selectAll")
14+
15+
// Copy selection to clipboard
16+
await vscode.commands.executeCommand("workbench.action.terminal.copySelection")
17+
18+
// Clear the selection
19+
await vscode.commands.executeCommand("workbench.action.terminal.clearSelection")
20+
21+
// Get terminal contents from clipboard
22+
let terminalContents = (await vscode.env.clipboard.readText()).trim()
23+
24+
// Check if there's actually a terminal open
25+
if (terminalContents === originalClipboard) {
26+
return ""
27+
}
28+
29+
// Clean up command separation
30+
const lines = terminalContents.split("\n")
31+
const lastLine = lines.pop()?.trim()
32+
if (lastLine) {
33+
let i = lines.length - 1
34+
while (i >= 0 && !lines[i].trim().startsWith(lastLine)) {
35+
i--
36+
}
37+
terminalContents = lines.slice(Math.max(i, 0)).join("\n")
38+
}
39+
40+
return terminalContents
41+
} finally {
42+
// Restore original clipboard content
43+
await vscode.env.clipboard.writeText(originalClipboard)
44+
}
45+
}

src/shared/context-mentions.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ Mention regex:
2626
- **Exact Word ('problems')**: Matches the exact word 'problems'.
2727
- **Word Boundary (`\b`)**: Ensures that 'problems' is matched as a whole word and not as part of another word (e.g., 'problematic').
2828
- `|`: Logical OR.
29-
- `problems\b`:
30-
- **Exact Word ('git-changes')**: Matches the exact word 'git-changes'.
31-
- **Word Boundary (`\b`)**: Ensures that 'git-changes' is matched as a whole word and not as part of another word.
32-
29+
- `terminal\b`:
30+
- **Exact Word ('terminal')**: Matches the exact word 'terminal'.
31+
- **Word Boundary (`\b`)**: Ensures that 'terminal' is matched as a whole word and not as part of another word (e.g., 'terminals').
3332
- `(?=[.,;:!?]?(?=[\s\r\n]|$))`:
3433
- **Positive Lookahead (`(?=...)`)**: Ensures that the match is followed by specific patterns without including them in the match.
3534
- `[.,;:!?]?`:
@@ -43,14 +42,15 @@ Mention regex:
4342
- URLs that start with a protocol (like 'http://') followed by any non-whitespace characters (including query parameters).
4443
- The exact word 'problems'.
4544
- The exact word 'git-changes'.
45+
- The exact word 'terminal'.
4646
- It ensures that any trailing punctuation marks (such as ',', '.', '!', etc.) are not included in the matched mention, allowing the punctuation to follow the mention naturally in the text.
4747
4848
- **Global Regex**:
4949
- `mentionRegexGlobal`: Creates a global version of the `mentionRegex` to find all matches within a given string.
5050
5151
*/
5252
export const mentionRegex =
53-
/@((?:\/|\w+:\/\/)[^\s]+?|[a-f0-9]{7,40}\b|problems\b|git-changes\b)(?=[.,;:!?]?(?=[\s\r\n]|$))/
53+
/@((?:\/|\w+:\/\/)[^\s]+?|[a-f0-9]{7,40}\b|problems\b|git-changes\b|terminal\b)(?=[.,;:!?]?(?=[\s\r\n]|$))/
5454
export const mentionRegexGlobal = new RegExp(mentionRegex.source, "g")
5555

5656
export interface MentionSuggestion {

webview-ui/.storybook/main.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import type { StorybookConfig } from "@storybook/react-vite"
22

33
const config: StorybookConfig = {
44
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
5-
addons: ["@storybook/addon-essentials", "@storybook/addon-interactions"],
5+
addons: ["@storybook/addon-essentials", "storybook-dark-mode"],
66
framework: {
77
name: "@storybook/react-vite",
88
options: {},
99
},
1010
}
11-
export default config
11+
export default config

webview-ui/.storybook/preview.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Preview } from "@storybook/react"
22

3-
import "../src/index.css"
43
import "./vscode.css"
4+
import "../src/index.css"
55

66
const preview: Preview = {
77
parameters: {
@@ -14,4 +14,4 @@ const preview: Preview = {
1414
},
1515
}
1616

17-
export default preview
17+
export default preview

webview-ui/.storybook/vscode.css

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,51 @@
66
*/
77

88
:root {
9-
--vscode-editor-background: #1f1f1f; /* "editor.background" */
10-
--vscode-editor-foreground: #cccccc; /* "editor.foreground" */
11-
--vscode-menu-background: #1f1f1f; /* "menu.background" */
12-
--vscode-menu-foreground: #cccccc; /* "menu.foreground" */
13-
--vscode-button-background: #0078d4; /* "button.background" */
14-
--vscode-button-foreground: #ffffff; /* "button.foreground" */
15-
--vscode-button-secondaryBackground: #313131; /* "button.secondaryBackground" */
16-
--vscode-button-secondaryForeground: #cccccc; /* "button.secondaryForeground" */
17-
--vscode-disabledForeground: #313131; /* "disabledForeground" */
18-
--vscode-descriptionForeground: #9d9d9d; /* "descriptionForeground" */
19-
--vscode-focusBorder: #0078d4; /* "focusBorder" */
20-
--vscode-errorForeground: #f85149; /* "errorForeground" */
21-
--vscode-widget-border: #313131; /* "widget.border" */
22-
--vscode-input-background: #313131; /* "input.background" */
23-
--vscode-input-foreground: #cccccc; /* "input.foreground" */
24-
--vscode-input-border: #3c3c3c; /* "input.border" */
25-
26-
/* I can't find these in the output of `Developer: Generate Color Theme From Current Settings` */
27-
--vscode-charts-red: red;
28-
--vscode-charts-blue: blue;
29-
--vscode-charts-yellow: yellow;
30-
--vscode-charts-orange: orange;
31-
--vscode-charts-green: green;
9+
/**
10+
* The styles below have been defined for Tailwind.
11+
*/
12+
13+
--vscode-foreground: #d1d5da; /* "foreground" */
14+
15+
--vscode-editor-foreground: #e1e4e8; /* "editor.foreground" */
16+
--vscode-editor-background: #24292e; /* "editor.background" */
17+
18+
--vscode-button-foreground: #dcffe4; /* "button.foreground" */
19+
--vscode-button-background: #176f2c; /* "button.background" */
20+
--vscode-button-secondaryForeground: #ffffff; /* "button.secondaryForeground" */
21+
--vscode-button-secondaryBackground: #444d56; /* "button.secondaryBackground" */
22+
23+
--vscode-dropdown-foreground: #e1e4e8; /* "dropdown.foreground" */
24+
--vscode-dropdown-background: #2f363d; /* "dropdown.background" */
25+
--vscode-dropdown-border: #1b1f23; /* "dropdown.border" */
26+
27+
--vscode-input-foreground: #e1e4e8; /* "input.foreground" */
28+
--vscode-input-background: #2f363d; /* "input.background" */
29+
--vscode-input-border: #1b1f23; /* "input.border" */
30+
31+
--vscode-focusBorder: #005cc5; /* "focusBorder" */
32+
33+
--vscode-badge-foreground: #c8e1ff; /* "badge.foreground" */
34+
--vscode-badge-background: #044289; /* "badge.background" */
35+
36+
--vscode-notifications-foreground: #e1e4e8; /* "notifications.foreground" */
37+
--vscode-notifications-background: #2f363d; /* "notifications.background" */
38+
--vscode-notifications-border: #1b1f23; /* "notifications.border" */
39+
40+
--vscode-descriptionForeground: #959da5; /* "descriptionForeground" */
41+
--vscode-errorForeground: #f97583; /* "errorForeground" */
42+
43+
--vscode-list-hoverForeground: #e1e4e8; /* "list.hoverForeground" */
44+
--vscode-list-hoverBackground: #282e34; /* "list.hoverBackground" */
45+
--vscode-list-focusBackground: #044289; /* "list.focusBackground" */
46+
47+
/**
48+
* The styles below are used in the @shadcn/ui + Tailwind theme but are
49+
* not exposed as `--color-vscode-*` variables.
50+
*/
51+
52+
--vscode-menu-background: #2f363d; /* "menu.background" [MISSING] */
53+
--vscode-menu-foreground: #e1e4e8; /* "menu.foreground" [MISSING] */
54+
55+
--vscode-disabledForeground: #cccccc; /* "disabledForeground" [MISSING] */
3256
}

0 commit comments

Comments
 (0)