Skip to content

Commit 7129a52

Browse files
CopilotMte90
andcommitted
Fix plugin to only communicate with PicoCode backend and add project_id support to /code endpoint
Co-authored-by: Mte90 <403283+Mte90@users.noreply.github.com>
1 parent c34eb80 commit 7129a52

File tree

2 files changed

+54
-72
lines changed

2 files changed

+54
-72
lines changed

main.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,31 @@ def code_endpoint(request: Request):
251251
prompt = payload["prompt"]
252252
explicit_context = payload.get("context", "") or ""
253253
use_rag = bool(payload.get("use_rag", True))
254+
255+
# Support both analysis_id (old) and project_id (new for plugin)
254256
analysis_id = payload.get("analysis_id")
257+
project_id = payload.get("project_id")
258+
259+
# If project_id is provided, get the database path and find the first analysis
260+
database_path = DATABASE # default to main database
261+
if project_id and not analysis_id:
262+
try:
263+
project = get_project_by_id(project_id)
264+
if not project:
265+
return JSONResponse({"error": "Project not found"}, status_code=404)
266+
267+
database_path = project["database_path"]
268+
269+
# Get the first analysis from this project
270+
analyses = list_analyses(database_path)
271+
if not analyses:
272+
return JSONResponse({"error": "Project not indexed yet"}, status_code=400)
273+
274+
analysis_id = analyses[0]["id"]
275+
except Exception as e:
276+
logger.exception(f"Error getting project analysis: {e}")
277+
return JSONResponse({"error": "Failed to get project analysis"}, status_code=500)
278+
255279
try:
256280
top_k = int(payload.get("top_k", 5))
257281
except Exception:
@@ -263,7 +287,7 @@ def code_endpoint(request: Request):
263287
# If RAG requested and an analysis_id provided, perform semantic search and build context
264288
if use_rag and analysis_id:
265289
try:
266-
retrieved = search_semantic(prompt, DATABASE, analysis_id=int(analysis_id), top_k=top_k)
290+
retrieved = search_semantic(prompt, database_path, analysis_id=int(analysis_id), top_k=top_k)
267291
# Build context WITHOUT including snippets: only include file references and scores
268292
context_parts = []
269293
total_len = len(combined_context)

plugin/src/main/kotlin/com/picocode/PicoCodeToolWindowContent.kt

Lines changed: 29 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,15 @@ import com.google.gson.JsonObject
2626

2727
/**
2828
* Main tool window content for PicoCode RAG Assistant
29-
* Handles server lifecycle, API key management, and streaming responses
29+
* Communicates with PicoCode backend only (no direct OpenAI calls)
3030
*/
3131
class PicoCodeToolWindowContent(private val project: Project) {
32-
private val serverPort = 8000
33-
private val serverHost = "localhost"
32+
// PicoCode server configuration
33+
private val serverHostField = JBTextField("localhost")
34+
private val serverPortField = JBTextField("8000")
3435
private var serverProcess: Process? = null
35-
private var wsClient: WebSocketClient? = null
3636

3737
// UI Components
38-
private val apiKeyField = JPasswordField(20)
39-
private val apiBaseField = JBTextField("https://api.openai.com/v1")
40-
private val embeddingModelField = JBTextField("text-embedding-3-small")
41-
private val codingModelField = JBTextField("gpt-4")
4238
private val queryField = JBTextArea(3, 40)
4339
private val responseArea = JBTextArea(20, 40)
4440
private val statusLabel = JLabel("Server: Not running")
@@ -53,20 +49,18 @@ class PicoCodeToolWindowContent(private val project: Project) {
5349
retrievedFilesPanel.layout = BoxLayout(retrievedFilesPanel, BoxLayout.Y_AXIS)
5450
progressBar.isIndeterminate = false
5551
progressBar.isVisible = false
56-
57-
// Load saved API key from IDE password safe
58-
loadApiKey()
5952
}
6053

54+
private fun getServerHost(): String = serverHostField.text.trim()
55+
private fun getServerPort(): Int = serverPortField.text.trim().toIntOrNull() ?: 8000
56+
6157
fun getContent(): JComponent {
6258
val panel = JPanel(BorderLayout())
6359

64-
// Top panel with configuration
60+
// Top panel with PicoCode server configuration
6561
val configPanel = FormBuilder.createFormBuilder()
66-
.addLabeledComponent("API Base URL:", apiBaseField)
67-
.addLabeledComponent("API Key:", apiKeyField)
68-
.addLabeledComponent("Embedding Model:", embeddingModelField)
69-
.addLabeledComponent("Coding Model:", codingModelField)
62+
.addLabeledComponent("PicoCode Host:", serverHostField)
63+
.addLabeledComponent("PicoCode Port:", serverPortField)
7064
.panel
7165

7266
// Control buttons
@@ -75,7 +69,6 @@ class PicoCodeToolWindowContent(private val project: Project) {
7569
val stopServerBtn = JButton("Stop Server")
7670
val indexProjectBtn = JButton("Index Project")
7771
val queryBtn = JButton("Query")
78-
val saveApiKeyBtn = JButton("Save API Key")
7972

8073
stopServerBtn.isEnabled = false
8174
indexProjectBtn.isEnabled = false
@@ -97,11 +90,6 @@ class PicoCodeToolWindowContent(private val project: Project) {
9790
queryBtn.isEnabled = false
9891
}
9992

100-
saveApiKeyBtn.addActionListener {
101-
saveApiKey()
102-
JOptionPane.showMessageDialog(panel, "API Key saved securely")
103-
}
104-
10593
indexProjectBtn.addActionListener {
10694
indexProject()
10795
}
@@ -114,7 +102,6 @@ class PicoCodeToolWindowContent(private val project: Project) {
114102
buttonPanel.add(stopServerBtn)
115103
buttonPanel.add(indexProjectBtn)
116104
buttonPanel.add(queryBtn)
117-
buttonPanel.add(saveApiKeyBtn)
118105

119106
// Query panel
120107
val queryPanel = JPanel(BorderLayout())
@@ -158,6 +145,8 @@ class PicoCodeToolWindowContent(private val project: Project) {
158145
*/
159146
private fun startServer() {
160147
val projectPath = project.basePath ?: return
148+
val host = getServerHost()
149+
val port = getServerPort()
161150

162151
statusLabel.text = "Server: Starting..."
163152

@@ -192,7 +181,7 @@ class PicoCodeToolWindowContent(private val project: Project) {
192181
Thread.sleep(3000)
193182

194183
SwingUtilities.invokeLater {
195-
statusLabel.text = "Server: Running on http://$serverHost:$serverPort"
184+
statusLabel.text = "Server: Running on http://$host:$port"
196185
}
197186
} catch (e: Exception) {
198187
SwingUtilities.invokeLater {
@@ -209,25 +198,25 @@ class PicoCodeToolWindowContent(private val project: Project) {
209198
private fun stopServer() {
210199
serverProcess?.destroy()
211200
serverProcess = null
212-
wsClient?.close()
213-
wsClient = null
214201
statusLabel.text = "Server: Stopped"
215202
}
216203

217204
/**
218-
* Index the current project
205+
* Index the current project via PicoCode backend
219206
*/
220207
private fun indexProject() {
221208
val projectPath = project.basePath ?: return
222-
val storeDir = File(projectPath, ".local_rag").absolutePath
209+
val host = getServerHost()
210+
val port = getServerPort()
223211

224212
progressBar.isVisible = true
225213
progressBar.isIndeterminate = true
226214
statusLabel.text = "Indexing project..."
227215

228216
ApplicationManager.getApplication().executeOnPooledThread {
229217
try {
230-
val url = URL("http://$serverHost:$serverPort/api/projects")
218+
// Create/get project
219+
val url = URL("http://$host:$port/api/projects")
231220
val connection = url.openConnection() as HttpURLConnection
232221
connection.requestMethod = "POST"
233222
connection.setRequestProperty("Content-Type", "application/json")
@@ -248,7 +237,7 @@ class PicoCodeToolWindowContent(private val project: Project) {
248237
val projectId = jsonResponse.get("id").asString
249238

250239
// Start indexing
251-
val indexUrl = URL("http://$serverHost:$serverPort/api/projects/index")
240+
val indexUrl = URL("http://$host:$port/api/projects/index")
252241
val indexConnection = indexUrl.openConnection() as HttpURLConnection
253242
indexConnection.requestMethod = "POST"
254243
indexConnection.setRequestProperty("Content-Type", "application/json")
@@ -262,7 +251,7 @@ class PicoCodeToolWindowContent(private val project: Project) {
262251
SwingUtilities.invokeLater {
263252
progressBar.isVisible = false
264253
statusLabel.text = "Project indexed successfully"
265-
JOptionPane.showMessageDialog(null, "Project indexed. Store: $storeDir")
254+
JOptionPane.showMessageDialog(null, "Project indexed successfully")
266255
}
267256
} else {
268257
throw Exception("Server returned error: $responseCode - $response")
@@ -278,7 +267,7 @@ class PicoCodeToolWindowContent(private val project: Project) {
278267
}
279268

280269
/**
281-
* Execute a query with WebSocket streaming
270+
* Execute a query via PicoCode backend /code endpoint
282271
*/
283272
private fun executeQuery() {
284273
val query = queryField.text.trim()
@@ -288,25 +277,27 @@ class PicoCodeToolWindowContent(private val project: Project) {
288277
}
289278

290279
val projectPath = project.basePath ?: return
280+
val host = getServerHost()
281+
val port = getServerPort()
291282

292283
responseArea.text = ""
293284
retrievedFilesPanel.removeAll()
294285
statusLabel.text = "Querying..."
295286

296-
// Get project ID first
297287
ApplicationManager.getApplication().executeOnPooledThread {
298288
try {
299-
// Get projects list to find our project
300-
val projectsUrl = URL("http://$serverHost:$serverPort/api/projects")
289+
// Get project ID first
290+
val projectsUrl = URL("http://$host:$port/api/projects")
301291
val connection = projectsUrl.openConnection() as HttpURLConnection
302292
val projectsResponse = connection.inputStream.bufferedReader().readText()
303293
val projects = gson.fromJson(projectsResponse, Array<JsonObject>::class.java)
304294

305295
val currentProject = projects.find { it.get("path").asString == projectPath }
306-
val projectId = currentProject?.get("id")?.asString ?: throw Exception("Project not found")
296+
val projectId = currentProject?.get("id")?.asString
297+
?: throw Exception("Project not indexed. Please index first.")
307298

308-
// Use synchronous query endpoint (WebSocket would require additional dependencies)
309-
val queryUrl = URL("http://$serverHost:$serverPort/api/code")
299+
// Use /code endpoint with project_id (backend will handle finding the analysis)
300+
val queryUrl = URL("http://$host:$port/code")
310301
val queryConnection = queryUrl.openConnection() as HttpURLConnection
311302
queryConnection.requestMethod = "POST"
312303
queryConnection.setRequestProperty("Content-Type", "application/json")
@@ -372,37 +363,4 @@ class PicoCodeToolWindowContent(private val project: Project) {
372363
}
373364
}
374365
}
375-
376-
/**
377-
* Load API key from IDE password safe
378-
*/
379-
private fun loadApiKey() {
380-
try {
381-
val credentials = PasswordSafe.instance.get(
382-
com.intellij.credentialStore.CredentialAttributes(
383-
"PicoCodeAPIKey",
384-
"api_key"
385-
)
386-
)
387-
credentials?.getPasswordAsString()?.let {
388-
apiKeyField.text = it
389-
}
390-
} catch (e: Exception) {
391-
// API key not found or error, use empty
392-
}
393-
}
394-
395-
/**
396-
* Save API key to IDE password safe
397-
*/
398-
private fun saveApiKey() {
399-
val apiKey = String(apiKeyField.password)
400-
PasswordSafe.instance.setPassword(
401-
com.intellij.credentialStore.CredentialAttributes(
402-
"PicoCodeAPIKey",
403-
"api_key"
404-
),
405-
apiKey
406-
)
407-
}
408366
}

0 commit comments

Comments
 (0)