Skip to content

Commit da83a3b

Browse files
committed
feat: Update model options and enhance AI response handling in webview
1 parent 895eb7e commit da83a3b

4 files changed

Lines changed: 77 additions & 32 deletions

File tree

server/server.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
MODELS = {
1111
"gemma3-4b": "gemma3:4b",
12-
"gemma3-8b": "gemma3:8b",
12+
"gemma3-12b": "gemma3:12b",
1313
"deepseek-r1-8b": "deepseek-r1:8b"
1414
}
1515

@@ -51,10 +51,21 @@ def completion():
5151
prompt = data.get("prompt", "")
5252
context = data.get("context", "")
5353
task_type = data.get("task_type", "chat") # 'chat', 'code', 'edit'
54-
55-
if model not in MODELS:
56-
return jsonify({"error": f"Model {model} not available"}), 400
57-
54+
55+
# Accept both "gemma3:4b" and "gemma3-4b" formats
56+
model_key = model.replace(":", "-")
57+
if model_key not in MODELS and model not in MODELS.values():
58+
print(f"Model not found: {model}")
59+
return jsonify({"error": f"Model {model} not available. Valid models: {list(MODELS.keys()) + list(MODELS.values())}"}), 400
60+
61+
# Use Ollama model name
62+
ollama_model = MODELS.get(model_key, model)
63+
64+
# Validate prompt
65+
if not prompt:
66+
print("Missing prompt in request.")
67+
return jsonify({"error": "Missing prompt in request."}), 400
68+
5869
# Build the prompt based on task type
5970
if task_type == "code":
6071
system_prompt = "You are a coding assistant. Provide only code without explanations unless asked. Format code properly."
@@ -69,7 +80,7 @@ def completion():
6980
response = requests.post(
7081
OLLAMA_API_URL,
7182
json={
72-
"model": MODELS[model],
83+
"model": ollama_model,
7384
"prompt": full_prompt,
7485
"stream": False
7586
},
@@ -80,11 +91,19 @@ def completion():
8091
return jsonify({"error": f"Ollama API error: {response.text}"}), 500
8192

8293
result = response.json()
94+
print("Ollama API response:", result)
8395
completion_text = result.get("response", "").strip()
84-
96+
97+
if not completion_text:
98+
print("Ollama returned an empty response.")
99+
return jsonify({
100+
"error": "Ollama returned an empty response. Check if the model is running and prompt is valid.",
101+
"ollama_response": result
102+
}), 500
103+
85104
# Determine if this is code or chat
86105
is_code = detect_code_blocks(completion_text) or task_type in ["code", "edit"]
87-
106+
88107
# Extract code if it's in markdown format
89108
if is_code and '```' in completion_text:
90109
code_content = extract_code_from_markdown(completion_text)
@@ -93,7 +112,7 @@ def completion():
93112
"raw_completion": completion_text,
94113
"completion_type": "code"
95114
})
96-
115+
97116
return jsonify({
98117
"completion": completion_text,
99118
"completion_type": "code" if is_code else "chat"

vscode-extension/src/extension.ts

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ function openChatPanel(context: vscode.ExtensionContext) {
156156

157157
async function handleChatMessage(message: any) {
158158
const editor = vscode.window.activeTextEditor;
159-
159+
160160
// Show loading state
161161
currentPanel?.webview.postMessage({
162162
type: 'aiResponse',
@@ -169,28 +169,31 @@ async function handleChatMessage(message: any) {
169169
let context = '';
170170
let taskType = 'chat';
171171

172-
// Get context from active editor if available
172+
// Smart context gathering
173173
if (editor) {
174174
const selection = editor.selection;
175175
const selectedText = editor.document.getText(selection);
176-
176+
const document = editor.document;
177+
const cursorPosition = editor.selection.active;
178+
// Get up to 40 lines before and after cursor for context
179+
const startLine = Math.max(0, cursorPosition.line - 40);
180+
const endLine = Math.min(document.lineCount - 1, cursorPosition.line + 40);
181+
const range = new vscode.Range(startLine, 0, endLine, document.lineAt(endLine).text.length);
182+
const surroundingContext = document.getText(range);
183+
177184
if (selectedText) {
178-
context = selectedText;
185+
context = selectedText + '\n\n--- Surrounding Context ---\n' + surroundingContext;
179186
taskType = 'code';
180187
} else {
181-
// Get surrounding context
182-
const document = editor.document;
183-
const cursorPosition = editor.selection.active;
184-
const startLine = Math.max(0, cursorPosition.line - 10);
185-
const endLine = Math.min(document.lineCount - 1, cursorPosition.line + 10);
186-
const range = new vscode.Range(startLine, 0, endLine, document.lineAt(endLine).text.length);
187-
context = document.getText(range);
188+
context = surroundingContext;
188189
}
189190
}
190191

191192
const response = await callAI(message.prompt, taskType, context, message.model);
193+
console.log('AI response from server:', response);
192194

193195
if (response.error) {
196+
console.error('AI error response:', response.error);
194197
currentPanel?.webview.postMessage({
195198
type: 'error',
196199
content: response.error
@@ -200,16 +203,26 @@ async function handleChatMessage(message: any) {
200203
}
201204

202205
const isCode = response.completion_type === 'code';
206+
console.log('Sending message to webview:', isCode ? 'codeResponse' : 'chatResponse', response.completion);
203207

204-
currentPanel?.webview.postMessage({
205-
type: 'aiResponse',
206-
content: response.completion,
207-
rawContent: response.raw_completion,
208-
isCode: isCode,
209-
loading: false
210-
});
208+
if (isCode) {
209+
currentPanel?.webview.postMessage({
210+
type: 'codeResponse',
211+
code: response.completion,
212+
rawContent: response.raw_completion,
213+
explanation: 'Preview and insert, replace, or diff with selection.',
214+
loading: false
215+
});
216+
} else {
217+
currentPanel?.webview.postMessage({
218+
type: 'chatResponse',
219+
content: response.completion,
220+
loading: false
221+
});
222+
}
211223

212224
} catch (err: any) {
225+
console.error('Exception in handleChatMessage:', err);
213226
currentPanel?.webview.postMessage({
214227
type: 'error',
215228
content: `Error: ${err.message}`
@@ -249,8 +262,14 @@ function insertCodeInEditor(code: string) {
249262
return;
250263
}
251264

265+
// Smart insertion: insert code at cursor, auto-indent
252266
editor.edit((editBuilder) => {
253-
editBuilder.insert(editor.selection.active, code);
267+
const position = editor.selection.active;
268+
// Indent code to match current line
269+
const currentLine = editor.document.lineAt(position.line);
270+
const indent = currentLine.text.match(/^\s*/)?.[0] || '';
271+
const indentedCode = code.split('\n').map((line, i) => i === 0 ? line : indent + line).join('\n');
272+
editBuilder.insert(position, indentedCode);
254273
});
255274
}
256275

@@ -263,7 +282,7 @@ async function applyCodeEdit(code: string) {
263282

264283
const selection = editor.selection;
265284

266-
// Show diff first
285+
// Show diff preview before applying edit
267286
const originalDocument = editor.document;
268287
const originalText = originalDocument.getText(selection);
269288

@@ -278,7 +297,8 @@ async function applyCodeEdit(code: string) {
278297
'vscode.diff',
279298
originalDocument.uri,
280299
newDoc.uri,
281-
'Original ← → AI Suggestion'
300+
'Original ← → AI Suggestion',
301+
{ preview: true }
282302
);
283303

284304
// Ask user to apply

vscode-extension/src/webview.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@
174174
<label for="modelSelect">Model:</label>
175175
<select id="modelSelect">
176176
<option value="gemma3:4b">Gemma3 4B (Fast)</option>
177-
<option value="gemma3:8b">Gemma3 8B (Balanced)</option>
177+
<option value="gemma3:12b">Gemma3 12B (Large)</option>
178178
<option value="deepseek-r1:8b">DeepSeek-R1 8B (Reasoning)</option>
179179
</select>
180180
</div>

vscode-extension/src/webview.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
alert('Webview loaded!');
12
(function() {
23
const vscode = acquireVsCodeApi();
34

@@ -133,7 +134,8 @@
133134
// Listen for messages from the extension
134135
window.addEventListener('message', event => {
135136
const message = event.data;
136-
137+
console.log('Received message from extension:', message);
138+
137139
removeLoadingMessage();
138140
isProcessing = false;
139141
sendButton.disabled = false;
@@ -150,6 +152,10 @@
150152
}
151153
break;
152154

155+
case 'aiResponse':
156+
addMessage(message.content, 'ai', message.isCode);
157+
break;
158+
153159
case 'error':
154160
addMessage(`Error: ${message.content}`, 'system');
155161
break;

0 commit comments

Comments
 (0)