vite-plugin-opencode-assistant 1.0.44 → 1.0.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/client/App.vue.js +27 -4
- package/es/client/components/ChromeWarmupError-sfc.css +1 -1
- package/es/client/components/ChromeWarmupError.vue.d.ts +10 -2
- package/es/client/components/ChromeWarmupError.vue.js +197 -56
- package/es/client/styles.css +1 -1
- package/es/core/api.d.ts +8 -10
- package/es/core/api.js +70 -230
- package/es/core/service.d.ts +6 -1
- package/es/core/service.js +11 -2
- package/es/endpoints/types.d.ts +6 -2
- package/es/endpoints/warmup.js +58 -11
- package/es/index.js +2 -1
- package/lib/client/App.vue.js +27 -4
- package/lib/client/components/ChromeWarmupError-sfc.css +1 -1
- package/lib/client/components/ChromeWarmupError.vue.d.ts +10 -2
- package/lib/client/components/ChromeWarmupError.vue.js +216 -75
- package/lib/client/styles.css +1 -1
- package/lib/client.js +3552 -3394
- package/lib/core/api.d.ts +8 -10
- package/lib/core/api.js +70 -230
- package/lib/core/service.d.ts +6 -1
- package/lib/core/service.js +11 -2
- package/lib/endpoints/types.d.ts +6 -2
- package/lib/endpoints/warmup.js +58 -11
- package/lib/index.js +2 -1
- package/lib/style.css +1 -1
- package/package.json +4 -4
package/es/core/api.js
CHANGED
|
@@ -59,21 +59,6 @@ class OpenCodeAPI {
|
|
|
59
59
|
__publicField(this, "getPort", getPort);
|
|
60
60
|
__publicField(this, "getProxyPort", getProxyPort);
|
|
61
61
|
__publicField(this, "warmupChromeMcpConfig", warmupChromeMcpConfig);
|
|
62
|
-
__publicField(this, "failedFreeModels", /* @__PURE__ */ new Set());
|
|
63
|
-
}
|
|
64
|
-
markModelAsFailed(providerID, modelID) {
|
|
65
|
-
const key = `${providerID}:${modelID}`;
|
|
66
|
-
this.failedFreeModels.add(key);
|
|
67
|
-
log.debug("Marked model as failed", {
|
|
68
|
-
providerID,
|
|
69
|
-
modelID,
|
|
70
|
-
key,
|
|
71
|
-
failedCount: this.failedFreeModels.size
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
clearFailedModels() {
|
|
75
|
-
this.failedFreeModels.clear();
|
|
76
|
-
log.debug("Cleared failed models cache");
|
|
77
62
|
}
|
|
78
63
|
createHttpRequest(options, body, timeout) {
|
|
79
64
|
const timer = new PerformanceTimer("HTTP Request", {
|
|
@@ -187,7 +172,7 @@ class OpenCodeAPI {
|
|
|
187
172
|
throw lastError;
|
|
188
173
|
});
|
|
189
174
|
}
|
|
190
|
-
|
|
175
|
+
getAvailableModels() {
|
|
191
176
|
return __async(this, null, function* () {
|
|
192
177
|
var _a, _b;
|
|
193
178
|
try {
|
|
@@ -200,7 +185,6 @@ class OpenCodeAPI {
|
|
|
200
185
|
const connectedProviders = new Set(response.connected);
|
|
201
186
|
const allModels = [];
|
|
202
187
|
for (const provider of response.all) {
|
|
203
|
-
if (provider.id === "opencode") continue;
|
|
204
188
|
if (!connectedProviders.has(provider.id)) {
|
|
205
189
|
log.debug("Skipping not connected provider", { providerID: provider.id });
|
|
206
190
|
continue;
|
|
@@ -216,34 +200,14 @@ class OpenCodeAPI {
|
|
|
216
200
|
}
|
|
217
201
|
}
|
|
218
202
|
allModels.sort((a, b) => a.inputCost - b.inputCost);
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
);
|
|
222
|
-
if (!availableModel) {
|
|
223
|
-
log.debug("All models have failed", {
|
|
224
|
-
totalModels: allModels.length,
|
|
225
|
-
failedModels: this.failedFreeModels.size,
|
|
226
|
-
connectedProviders: response.connected
|
|
227
|
-
});
|
|
228
|
-
return null;
|
|
229
|
-
}
|
|
230
|
-
log.debug("Found cheapest available model for warmup", {
|
|
231
|
-
providerID: availableModel.providerID,
|
|
232
|
-
modelID: availableModel.modelID,
|
|
233
|
-
name: availableModel.name,
|
|
234
|
-
inputCost: availableModel.inputCost,
|
|
235
|
-
releaseDate: availableModel.releaseDate,
|
|
236
|
-
totalModels: allModels.length,
|
|
237
|
-
failedModels: this.failedFreeModels.size,
|
|
203
|
+
log.debug("Found available models for warmup", {
|
|
204
|
+
count: allModels.length,
|
|
238
205
|
connectedProviders: response.connected
|
|
239
206
|
});
|
|
240
|
-
return
|
|
241
|
-
providerID: availableModel.providerID,
|
|
242
|
-
modelID: availableModel.modelID
|
|
243
|
-
};
|
|
207
|
+
return allModels;
|
|
244
208
|
} catch (error) {
|
|
245
|
-
log.warn("Failed to get
|
|
246
|
-
return
|
|
209
|
+
log.warn("Failed to get available models", { error });
|
|
210
|
+
return [];
|
|
247
211
|
}
|
|
248
212
|
});
|
|
249
213
|
}
|
|
@@ -317,12 +281,10 @@ class OpenCodeAPI {
|
|
|
317
281
|
throw lastError;
|
|
318
282
|
});
|
|
319
283
|
}
|
|
320
|
-
|
|
284
|
+
executeWarmupChromeMcp(projectDir, operation, viteOrigin, selectedModel) {
|
|
321
285
|
return __async(this, null, function* () {
|
|
322
|
-
|
|
323
|
-
const timer = log.timer("warmupChromeMcp", { viteOrigin });
|
|
286
|
+
const timer = log.timer(`${operation}WarmupChromeMcp`, { viteOrigin, operation });
|
|
324
287
|
let warmupSessionId = null;
|
|
325
|
-
let freeModel = null;
|
|
326
288
|
const chromeAvailable = yield checkChromeDevToolsAvailable();
|
|
327
289
|
if (!chromeAvailable) {
|
|
328
290
|
const error = new ChromeMcpWarmupError(
|
|
@@ -330,14 +292,14 @@ class OpenCodeAPI {
|
|
|
330
292
|
"Chrome DevTools Protocol is not available",
|
|
331
293
|
"Chrome remote debugging is not enabled or not running on port 9222. Please enable Chrome remote debugging first."
|
|
332
294
|
);
|
|
333
|
-
log.warn(
|
|
295
|
+
log.warn(`Chrome DevTools not available for ${operation}`, {
|
|
334
296
|
port: CHROME_DEVTOOLS_PORT,
|
|
335
297
|
hint: "Enable Chrome remote debugging at chrome://inspect/#remote-debugging"
|
|
336
298
|
});
|
|
337
|
-
timer.end(
|
|
338
|
-
|
|
299
|
+
timer.end(`Chrome DevTools not available for ${operation}`);
|
|
300
|
+
return { success: false, error };
|
|
339
301
|
}
|
|
340
|
-
log.debug(
|
|
302
|
+
log.debug(`Chrome DevTools is available, proceeding with ${operation} warmup`);
|
|
341
303
|
try {
|
|
342
304
|
const warmupSession = yield this.createSession(
|
|
343
305
|
projectDir,
|
|
@@ -345,14 +307,26 @@ class OpenCodeAPI {
|
|
|
345
307
|
"__chrome_mcp_warmup__"
|
|
346
308
|
);
|
|
347
309
|
warmupSessionId = warmupSession.id;
|
|
348
|
-
|
|
349
|
-
if (
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
310
|
+
let modelToUse = selectedModel;
|
|
311
|
+
if (!modelToUse) {
|
|
312
|
+
const models = yield this.getAvailableModels();
|
|
313
|
+
if (models.length > 0) {
|
|
314
|
+
modelToUse = {
|
|
315
|
+
providerID: models[0].providerID,
|
|
316
|
+
modelID: models[0].modelID
|
|
317
|
+
};
|
|
318
|
+
log.debug(`Using cheapest model for ${operation} warmup`, {
|
|
319
|
+
providerID: modelToUse.providerID,
|
|
320
|
+
modelID: modelToUse.modelID
|
|
321
|
+
});
|
|
322
|
+
} else {
|
|
323
|
+
log.debug(`No model available for ${operation}, using default model`);
|
|
324
|
+
}
|
|
354
325
|
} else {
|
|
355
|
-
log.debug(
|
|
326
|
+
log.debug(`Using selected model for ${operation} warmup`, {
|
|
327
|
+
providerID: modelToUse.providerID,
|
|
328
|
+
modelID: modelToUse.modelID
|
|
329
|
+
});
|
|
356
330
|
}
|
|
357
331
|
const WARMUP_TIMEOUT = 6e4;
|
|
358
332
|
const data = yield this.createHttpRequest(
|
|
@@ -370,10 +344,10 @@ class OpenCodeAPI {
|
|
|
370
344
|
text: "Test if the chrome-devtools_list_pages tool is available. If available, reply with: ready. If not available, explain why."
|
|
371
345
|
}
|
|
372
346
|
]
|
|
373
|
-
},
|
|
347
|
+
}, modelToUse && {
|
|
374
348
|
model: {
|
|
375
|
-
providerID:
|
|
376
|
-
modelID:
|
|
349
|
+
providerID: modelToUse.providerID,
|
|
350
|
+
modelID: modelToUse.modelID
|
|
377
351
|
}
|
|
378
352
|
})),
|
|
379
353
|
WARMUP_TIMEOUT
|
|
@@ -394,56 +368,43 @@ class OpenCodeAPI {
|
|
|
394
368
|
`AI responded with: ${responseText.substring(0, 200)}`
|
|
395
369
|
);
|
|
396
370
|
}
|
|
397
|
-
timer.end(
|
|
371
|
+
timer.end(`Chrome MCP ${operation} warmed up successfully`);
|
|
372
|
+
return { success: true };
|
|
398
373
|
} catch (e) {
|
|
399
374
|
if (e instanceof ChromeMcpWarmupError) {
|
|
400
375
|
if (e.type === ChromeMcpWarmupErrorType.SESSION_ERROR) {
|
|
401
376
|
timer.end("Session creation failed");
|
|
402
377
|
}
|
|
403
|
-
log.warn(`Chrome MCP warmup failed: ${e.type}`,
|
|
378
|
+
log.warn(`Chrome MCP ${operation} warmup failed: ${e.type}`, {
|
|
404
379
|
message: e.message,
|
|
405
380
|
details: e.details
|
|
406
|
-
}, freeModel && {
|
|
407
|
-
model: `${freeModel.providerID}/${freeModel.modelID}`
|
|
408
|
-
}));
|
|
409
|
-
timer.end(`Chrome MCP warmup failed: ${e.type}`);
|
|
410
|
-
throw e;
|
|
411
|
-
}
|
|
412
|
-
if (freeModel) {
|
|
413
|
-
this.markModelAsFailed(freeModel.providerID, freeModel.modelID);
|
|
414
|
-
log.debug("Marked model as failed due to warmup error", {
|
|
415
|
-
providerID: freeModel.providerID,
|
|
416
|
-
modelID: freeModel.modelID,
|
|
417
|
-
error: e instanceof Error ? e.message : String(e)
|
|
418
381
|
});
|
|
382
|
+
timer.end(`Chrome MCP ${operation} warmup failed: ${e.type}`);
|
|
383
|
+
return { success: false, error: e };
|
|
419
384
|
}
|
|
420
385
|
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
421
386
|
if (errorMessage.includes("timeout") || errorMessage.includes("Timeout")) {
|
|
422
387
|
const error2 = new ChromeMcpWarmupError(
|
|
423
388
|
ChromeMcpWarmupErrorType.AI_TIMEOUT,
|
|
424
389
|
"AI response timeout",
|
|
425
|
-
"AI did not respond within
|
|
390
|
+
"AI did not respond within 60 seconds. Please check if the OpenCode AI model is properly configured and available."
|
|
426
391
|
);
|
|
427
|
-
log.warn(
|
|
392
|
+
log.warn(`Chrome MCP ${operation} warmup timeout`, {
|
|
428
393
|
error: errorMessage
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
}
|
|
432
|
-
timer.end("Chrome MCP warmup timeout");
|
|
433
|
-
throw error2;
|
|
394
|
+
});
|
|
395
|
+
timer.end(`Chrome MCP ${operation} warmup timeout`);
|
|
396
|
+
return { success: false, error: error2 };
|
|
434
397
|
}
|
|
435
398
|
const error = new ChromeMcpWarmupError(
|
|
436
399
|
ChromeMcpWarmupErrorType.UNKNOWN,
|
|
437
|
-
|
|
400
|
+
`Unknown error during Chrome MCP ${operation} warmup`,
|
|
438
401
|
errorMessage
|
|
439
402
|
);
|
|
440
|
-
log.warn(
|
|
403
|
+
log.warn(`Chrome MCP ${operation} warmup failed with unknown error`, {
|
|
441
404
|
error: errorMessage
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
}
|
|
445
|
-
timer.end("Chrome MCP warmup failed");
|
|
446
|
-
throw error;
|
|
405
|
+
});
|
|
406
|
+
timer.end(`Chrome MCP ${operation} warmup failed`);
|
|
407
|
+
return { success: false, error };
|
|
447
408
|
} finally {
|
|
448
409
|
if (warmupSessionId) {
|
|
449
410
|
try {
|
|
@@ -458,6 +419,27 @@ class OpenCodeAPI {
|
|
|
458
419
|
}
|
|
459
420
|
});
|
|
460
421
|
}
|
|
422
|
+
warmupChromeMcp(projectDir, viteOrigin) {
|
|
423
|
+
return __async(this, null, function* () {
|
|
424
|
+
if (!this.warmupChromeMcpConfig) return;
|
|
425
|
+
const models = yield this.getAvailableModels();
|
|
426
|
+
const cheapestModel = models[0];
|
|
427
|
+
const result = yield this.executeWarmupChromeMcp(
|
|
428
|
+
projectDir,
|
|
429
|
+
"warmup",
|
|
430
|
+
viteOrigin,
|
|
431
|
+
cheapestModel ? { providerID: cheapestModel.providerID, modelID: cheapestModel.modelID } : void 0
|
|
432
|
+
);
|
|
433
|
+
if (!result.success) {
|
|
434
|
+
throw result.error;
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
retryWarmupChromeMcp(projectDir, viteOrigin, selectedModel) {
|
|
439
|
+
return __async(this, null, function* () {
|
|
440
|
+
return this.executeWarmupChromeMcp(projectDir, "retry", viteOrigin, selectedModel);
|
|
441
|
+
});
|
|
442
|
+
}
|
|
461
443
|
getOrCreateSession(projectDir) {
|
|
462
444
|
return __async(this, null, function* () {
|
|
463
445
|
const timer = log.timer("getOrCreateSession", { projectDir });
|
|
@@ -479,148 +461,6 @@ class OpenCodeAPI {
|
|
|
479
461
|
return url;
|
|
480
462
|
});
|
|
481
463
|
}
|
|
482
|
-
retryWarmupChromeMcp(projectDir, viteOrigin) {
|
|
483
|
-
return __async(this, null, function* () {
|
|
484
|
-
const timer = log.timer("retryWarmupChromeMcp", { viteOrigin });
|
|
485
|
-
let warmupSessionId = null;
|
|
486
|
-
let freeModel = null;
|
|
487
|
-
const chromeAvailable = yield checkChromeDevToolsAvailable();
|
|
488
|
-
if (!chromeAvailable) {
|
|
489
|
-
const error = new ChromeMcpWarmupError(
|
|
490
|
-
ChromeMcpWarmupErrorType.CHROME_NOT_CONNECTED,
|
|
491
|
-
"Chrome DevTools Protocol is not available",
|
|
492
|
-
"Chrome remote debugging is not enabled or not running on port 9222. Please enable Chrome remote debugging first."
|
|
493
|
-
);
|
|
494
|
-
log.warn("Chrome DevTools not available for retry", {
|
|
495
|
-
port: CHROME_DEVTOOLS_PORT,
|
|
496
|
-
hint: "Enable Chrome remote debugging at chrome://inspect/#remote-debugging"
|
|
497
|
-
});
|
|
498
|
-
timer.end("Chrome DevTools not available for retry");
|
|
499
|
-
return { success: false, error };
|
|
500
|
-
}
|
|
501
|
-
log.debug("Chrome DevTools is available, proceeding with retry warmup");
|
|
502
|
-
try {
|
|
503
|
-
const warmupSession = yield this.createSession(
|
|
504
|
-
projectDir,
|
|
505
|
-
DEFAULT_RETRIES,
|
|
506
|
-
"__chrome_mcp_warmup__"
|
|
507
|
-
);
|
|
508
|
-
warmupSessionId = warmupSession.id;
|
|
509
|
-
freeModel = yield this.getCheapestModel();
|
|
510
|
-
if (freeModel) {
|
|
511
|
-
log.debug("Using cheapest model for retry warmup", {
|
|
512
|
-
providerID: freeModel.providerID,
|
|
513
|
-
modelID: freeModel.modelID
|
|
514
|
-
});
|
|
515
|
-
} else {
|
|
516
|
-
log.debug("No model available for retry, using default model");
|
|
517
|
-
}
|
|
518
|
-
const WARMUP_TIMEOUT = 6e4;
|
|
519
|
-
const data = yield this.createHttpRequest(
|
|
520
|
-
{
|
|
521
|
-
hostname: this.hostname,
|
|
522
|
-
port: this.getPort(),
|
|
523
|
-
path: `/session/${warmupSessionId}/message`,
|
|
524
|
-
method: "POST",
|
|
525
|
-
headers: { "Content-Type": "application/json" }
|
|
526
|
-
},
|
|
527
|
-
JSON.stringify(__spreadValues({
|
|
528
|
-
parts: [
|
|
529
|
-
{
|
|
530
|
-
type: "text",
|
|
531
|
-
text: "Test if the chrome-devtools_list_pages tool is available. If available, reply with: ready. If not available, explain why."
|
|
532
|
-
}
|
|
533
|
-
]
|
|
534
|
-
}, freeModel && {
|
|
535
|
-
model: {
|
|
536
|
-
providerID: freeModel.providerID,
|
|
537
|
-
modelID: freeModel.modelID
|
|
538
|
-
}
|
|
539
|
-
})),
|
|
540
|
-
WARMUP_TIMEOUT
|
|
541
|
-
);
|
|
542
|
-
log.debug("Chrome MCP warmup response:", { data });
|
|
543
|
-
const responseText = extractTextFromResponse(data);
|
|
544
|
-
if (!responseText) {
|
|
545
|
-
throw new ChromeMcpWarmupError(
|
|
546
|
-
ChromeMcpWarmupErrorType.AI_RESPONSE_ERROR,
|
|
547
|
-
"AI did not respond to the warmup request",
|
|
548
|
-
"Empty response from AI"
|
|
549
|
-
);
|
|
550
|
-
}
|
|
551
|
-
const lowerResponse = responseText.toLowerCase();
|
|
552
|
-
if (!lowerResponse.includes("ready")) {
|
|
553
|
-
throw new ChromeMcpWarmupError(
|
|
554
|
-
ChromeMcpWarmupErrorType.AI_RESPONSE_ERROR,
|
|
555
|
-
"AI response does not indicate success",
|
|
556
|
-
`AI responded with: ${responseText.substring(0, 200)}`
|
|
557
|
-
);
|
|
558
|
-
}
|
|
559
|
-
timer.end("Chrome MCP warmed up successfully");
|
|
560
|
-
return { success: true };
|
|
561
|
-
} catch (e) {
|
|
562
|
-
if (e instanceof ChromeMcpWarmupError) {
|
|
563
|
-
if (e.type === ChromeMcpWarmupErrorType.SESSION_ERROR) {
|
|
564
|
-
timer.end("Session creation failed");
|
|
565
|
-
}
|
|
566
|
-
log.warn(`Chrome MCP warmup retry failed: ${e.type}`, __spreadValues({
|
|
567
|
-
message: e.message,
|
|
568
|
-
details: e.details
|
|
569
|
-
}, freeModel && {
|
|
570
|
-
model: `${freeModel.providerID}/${freeModel.modelID}`
|
|
571
|
-
}));
|
|
572
|
-
timer.end(`Chrome MCP warmup retry failed: ${e.type}`);
|
|
573
|
-
return { success: false, error: e };
|
|
574
|
-
}
|
|
575
|
-
if (freeModel) {
|
|
576
|
-
this.markModelAsFailed(freeModel.providerID, freeModel.modelID);
|
|
577
|
-
log.debug("Marked model as failed due to retry warmup error", {
|
|
578
|
-
providerID: freeModel.providerID,
|
|
579
|
-
modelID: freeModel.modelID,
|
|
580
|
-
error: e instanceof Error ? e.message : String(e)
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
584
|
-
if (errorMessage.includes("timeout") || errorMessage.includes("Timeout")) {
|
|
585
|
-
const error2 = new ChromeMcpWarmupError(
|
|
586
|
-
ChromeMcpWarmupErrorType.AI_TIMEOUT,
|
|
587
|
-
"AI response timeout",
|
|
588
|
-
"AI did not respond within 60 seconds. Please check if the OpenCode AI model is properly configured and available."
|
|
589
|
-
);
|
|
590
|
-
log.warn("Chrome MCP warmup retry timeout", __spreadValues({
|
|
591
|
-
error: errorMessage
|
|
592
|
-
}, freeModel && {
|
|
593
|
-
model: `${freeModel.providerID}/${freeModel.modelID}`
|
|
594
|
-
}));
|
|
595
|
-
timer.end("Chrome MCP warmup retry timeout");
|
|
596
|
-
return { success: false, error: error2 };
|
|
597
|
-
}
|
|
598
|
-
const error = new ChromeMcpWarmupError(
|
|
599
|
-
ChromeMcpWarmupErrorType.UNKNOWN,
|
|
600
|
-
"Unknown error during Chrome MCP warmup retry",
|
|
601
|
-
errorMessage
|
|
602
|
-
);
|
|
603
|
-
log.warn("Chrome MCP warmup retry failed with unknown error", __spreadValues({
|
|
604
|
-
error: errorMessage
|
|
605
|
-
}, freeModel && {
|
|
606
|
-
model: `${freeModel.providerID}/${freeModel.modelID}`
|
|
607
|
-
}));
|
|
608
|
-
timer.end("Chrome MCP warmup retry failed");
|
|
609
|
-
return { success: false, error };
|
|
610
|
-
} finally {
|
|
611
|
-
if (warmupSessionId) {
|
|
612
|
-
try {
|
|
613
|
-
yield this.deleteSession(warmupSessionId, 5);
|
|
614
|
-
} catch (e) {
|
|
615
|
-
log.warn("Failed to delete warmup session after retries", {
|
|
616
|
-
error: e,
|
|
617
|
-
warmupSessionId
|
|
618
|
-
});
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
});
|
|
623
|
-
}
|
|
624
464
|
}
|
|
625
465
|
export {
|
|
626
466
|
OpenCodeAPI
|
package/es/core/service.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ResultPromise } from "execa";
|
|
2
2
|
import type http from "http";
|
|
3
|
+
import type { ModelInfo } from "@vite-plugin-opencode-assistant/shared";
|
|
3
4
|
import type { OpenCodeOptions, ServiceStartupTask } from "@vite-plugin-opencode-assistant/shared";
|
|
4
5
|
import { ChromeMcpWarmupErrorType } from "@vite-plugin-opencode-assistant/shared";
|
|
5
6
|
import type { OpenCodeAPI } from "./api.js";
|
|
@@ -26,7 +27,11 @@ export declare class OpenCodeService {
|
|
|
26
27
|
constructor(config: Required<OpenCodeOptions>, api: OpenCodeAPI, sseClients: Set<http.ServerResponse>, onPortAllocated: (port: number) => void, onProxyPortAllocated: (port: number) => void);
|
|
27
28
|
private sendTaskUpdate;
|
|
28
29
|
start(corsOrigins?: string[], contextApiUrl?: string, logsApiUrl?: string, viteOrigin?: string): Promise<void>;
|
|
29
|
-
|
|
30
|
+
getAvailableModels(): Promise<ModelInfo[]>;
|
|
31
|
+
retryWarmupChromeMcp(viteOrigin?: string, selectedModel?: {
|
|
32
|
+
providerID: string;
|
|
33
|
+
modelID: string;
|
|
34
|
+
}): Promise<{
|
|
30
35
|
success: boolean;
|
|
31
36
|
errorType?: string;
|
|
32
37
|
errorMessage?: string;
|
package/es/core/service.js
CHANGED
|
@@ -262,9 +262,18 @@ Please install OpenCode first:
|
|
|
262
262
|
return this.startPromise;
|
|
263
263
|
});
|
|
264
264
|
}
|
|
265
|
-
|
|
265
|
+
getAvailableModels() {
|
|
266
266
|
return __async(this, null, function* () {
|
|
267
|
-
|
|
267
|
+
return this.api.getAvailableModels();
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
retryWarmupChromeMcp(viteOrigin, selectedModel) {
|
|
271
|
+
return __async(this, null, function* () {
|
|
272
|
+
const result = yield this.api.retryWarmupChromeMcp(
|
|
273
|
+
this.workspaceRoot,
|
|
274
|
+
viteOrigin,
|
|
275
|
+
selectedModel
|
|
276
|
+
);
|
|
268
277
|
if (result.success) {
|
|
269
278
|
this.chromeMcpWarmupFailed = false;
|
|
270
279
|
this.sendTaskUpdate("ready");
|
package/es/endpoints/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PageContext, SessionInfo, ServiceStartupTask } from "@vite-plugin-opencode-assistant/shared";
|
|
1
|
+
import type { PageContext, SessionInfo, ServiceStartupTask, ModelInfo } from "@vite-plugin-opencode-assistant/shared";
|
|
2
2
|
import type http from "http";
|
|
3
3
|
export interface EndpointContext {
|
|
4
4
|
get webUrl(): string | null;
|
|
@@ -15,7 +15,11 @@ export interface EndpointContext {
|
|
|
15
15
|
deleteSession: (id: string) => Promise<void>;
|
|
16
16
|
resolveWidgetPath: () => string;
|
|
17
17
|
resolveWidgetStylePath: () => string;
|
|
18
|
-
|
|
18
|
+
getAvailableModels: () => Promise<ModelInfo[]>;
|
|
19
|
+
retryWarmupChromeMcp: (selectedModel?: {
|
|
20
|
+
providerID: string;
|
|
21
|
+
modelID: string;
|
|
22
|
+
}) => Promise<{
|
|
19
23
|
success: boolean;
|
|
20
24
|
errorType?: string;
|
|
21
25
|
errorMessage?: string;
|
package/es/endpoints/warmup.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
|
|
1
2
|
var __async = (__this, __arguments, generator) => {
|
|
2
3
|
return new Promise((resolve, reject) => {
|
|
3
4
|
var fulfilled = (value) => {
|
|
@@ -18,37 +19,83 @@ var __async = (__this, __arguments, generator) => {
|
|
|
18
19
|
step((generator = generator.apply(__this, __arguments)).next());
|
|
19
20
|
});
|
|
20
21
|
};
|
|
22
|
+
var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it);
|
|
21
23
|
import { createLogger } from "@vite-plugin-opencode-assistant/shared";
|
|
22
24
|
const log = createLogger("Endpoints:Warmup");
|
|
23
25
|
function setupWarmupEndpoint(server, ctx) {
|
|
24
26
|
server.middlewares.use("/__opencode_warmup__", (req, res) => __async(null, null, function* () {
|
|
27
|
+
if (req.method === "GET") {
|
|
28
|
+
try {
|
|
29
|
+
const models = yield ctx.getAvailableModels();
|
|
30
|
+
res.setHeader("Content-Type", "application/json");
|
|
31
|
+
res.writeHead(200);
|
|
32
|
+
res.end(JSON.stringify({ success: true, models }));
|
|
33
|
+
} catch (e) {
|
|
34
|
+
log.error("Failed to get available models", { error: e });
|
|
35
|
+
res.setHeader("Content-Type", "application/json");
|
|
36
|
+
res.writeHead(500);
|
|
37
|
+
res.end(JSON.stringify({ success: false, models: [] }));
|
|
38
|
+
}
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
25
41
|
if (req.method !== "POST") {
|
|
26
42
|
res.writeHead(405);
|
|
27
43
|
res.end("Method not allowed");
|
|
28
44
|
return;
|
|
29
45
|
}
|
|
30
46
|
try {
|
|
31
|
-
|
|
47
|
+
let body = "";
|
|
48
|
+
try {
|
|
49
|
+
for (var iter = __forAwait(req), more, temp, error; more = !(temp = yield iter.next()).done; more = false) {
|
|
50
|
+
const chunk = temp.value;
|
|
51
|
+
body += chunk;
|
|
52
|
+
}
|
|
53
|
+
} catch (temp) {
|
|
54
|
+
error = [temp];
|
|
55
|
+
} finally {
|
|
56
|
+
try {
|
|
57
|
+
more && (temp = iter.return) && (yield temp.call(iter));
|
|
58
|
+
} finally {
|
|
59
|
+
if (error)
|
|
60
|
+
throw error[0];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
let selectedModel;
|
|
64
|
+
if (body) {
|
|
65
|
+
try {
|
|
66
|
+
const parsed = JSON.parse(body);
|
|
67
|
+
if (parsed.providerID && parsed.modelID) {
|
|
68
|
+
selectedModel = { providerID: parsed.providerID, modelID: parsed.modelID };
|
|
69
|
+
}
|
|
70
|
+
} catch (e) {
|
|
71
|
+
log.debug("Failed to parse request body, using default model");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const result = yield ctx.retryWarmupChromeMcp(selectedModel);
|
|
32
75
|
res.setHeader("Content-Type", "application/json");
|
|
33
76
|
res.writeHead(200);
|
|
34
77
|
if (result.success) {
|
|
35
78
|
res.end(JSON.stringify({ success: true }));
|
|
36
79
|
} else {
|
|
37
|
-
res.end(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
80
|
+
res.end(
|
|
81
|
+
JSON.stringify({
|
|
82
|
+
success: false,
|
|
83
|
+
errorType: result.errorType,
|
|
84
|
+
error: result.errorMessage
|
|
85
|
+
})
|
|
86
|
+
);
|
|
42
87
|
}
|
|
43
88
|
} catch (e) {
|
|
44
89
|
log.error("Failed to retry warmup", { error: e });
|
|
45
90
|
res.setHeader("Content-Type", "application/json");
|
|
46
91
|
res.writeHead(500);
|
|
47
|
-
res.end(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
92
|
+
res.end(
|
|
93
|
+
JSON.stringify({
|
|
94
|
+
success: false,
|
|
95
|
+
errorType: "UNKNOWN",
|
|
96
|
+
error: String(e)
|
|
97
|
+
})
|
|
98
|
+
);
|
|
52
99
|
}
|
|
53
100
|
}));
|
|
54
101
|
}
|
package/es/index.js
CHANGED
|
@@ -123,7 +123,8 @@ function createOpenCodePlugin(options = {}) {
|
|
|
123
123
|
deleteSession: (id) => api.deleteSession(id),
|
|
124
124
|
resolveWidgetPath,
|
|
125
125
|
resolveWidgetStylePath,
|
|
126
|
-
|
|
126
|
+
getAvailableModels: () => service.getAvailableModels(),
|
|
127
|
+
retryWarmupChromeMcp: (selectedModel) => service.retryWarmupChromeMcp(getViteOrigin(), selectedModel)
|
|
127
128
|
});
|
|
128
129
|
(_a2 = server.httpServer) == null ? void 0 : _a2.on("listening", () => __async(null, null, function* () {
|
|
129
130
|
var _a3;
|
package/lib/client/App.vue.js
CHANGED
|
@@ -96,6 +96,7 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
|
|
|
96
96
|
const loading = (0, import_vue2.ref)(false);
|
|
97
97
|
const widgetRef = (0, import_vue2.ref)(null);
|
|
98
98
|
const retryingWarmup = (0, import_vue2.ref)(false);
|
|
99
|
+
const availableModels = (0, import_vue2.ref)([]);
|
|
99
100
|
const {
|
|
100
101
|
theme: initialTheme = "auto",
|
|
101
102
|
open: autoOpen = false,
|
|
@@ -175,10 +176,14 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
|
|
|
175
176
|
}
|
|
176
177
|
return "\u52A0\u8F7D\u4F1A\u8BDD...";
|
|
177
178
|
});
|
|
178
|
-
const retryWarmup = () => __async(null, null, function* () {
|
|
179
|
+
const retryWarmup = (selectedModel) => __async(null, null, function* () {
|
|
179
180
|
retryingWarmup.value = true;
|
|
180
181
|
try {
|
|
181
|
-
const res = yield fetch("/__opencode_warmup__", {
|
|
182
|
+
const res = yield fetch("/__opencode_warmup__", {
|
|
183
|
+
method: "POST",
|
|
184
|
+
headers: { "Content-Type": "application/json" },
|
|
185
|
+
body: selectedModel ? JSON.stringify(selectedModel) : ""
|
|
186
|
+
});
|
|
182
187
|
const data = yield res.json();
|
|
183
188
|
if (data.success) {
|
|
184
189
|
chromeMcpFailed.value = false;
|
|
@@ -206,6 +211,18 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
|
|
|
206
211
|
retryingWarmup.value = false;
|
|
207
212
|
}
|
|
208
213
|
});
|
|
214
|
+
const fetchAvailableModels = () => __async(null, null, function* () {
|
|
215
|
+
try {
|
|
216
|
+
const res = yield fetch("/__opencode_warmup__", { method: "GET" });
|
|
217
|
+
const data = yield res.json();
|
|
218
|
+
if (data.success && data.models) {
|
|
219
|
+
availableModels.value = data.models;
|
|
220
|
+
}
|
|
221
|
+
} catch (e) {
|
|
222
|
+
console.error("[OpenCode] Failed to fetch available models:", e);
|
|
223
|
+
availableModels.value = [];
|
|
224
|
+
}
|
|
225
|
+
});
|
|
209
226
|
const ensureServicesStarted = () => __async(null, null, function* () {
|
|
210
227
|
if (serviceStatus.value !== "idle") return true;
|
|
211
228
|
try {
|
|
@@ -245,6 +262,11 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
|
|
|
245
262
|
loadSessions();
|
|
246
263
|
}
|
|
247
264
|
});
|
|
265
|
+
(0, import_vue2.watch)(chromeMcpFailed, (failed) => {
|
|
266
|
+
if (failed) {
|
|
267
|
+
fetchAvailableModels();
|
|
268
|
+
}
|
|
269
|
+
});
|
|
248
270
|
(0, import_vue2.onMounted)(() => {
|
|
249
271
|
if (serviceStatus.value === "ready") {
|
|
250
272
|
loadSessions();
|
|
@@ -332,7 +354,7 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
|
|
|
332
354
|
const handleFrameLoaded = () => {
|
|
333
355
|
iframeLoading.value = false;
|
|
334
356
|
};
|
|
335
|
-
const __returned__ = { props, open, selectMode, sessionListCollapsed, loading, widgetRef, retryingWarmup, initialTheme, autoOpen, hotkey, proxyPort, proxyHost, displayMode, splitMode, widgetTheme, splitPanelWidth, proxyBaseUrl, showNotification, serviceStatus, chromeMcpFailed, chromeMcpErrorType, chromeMcpErrorMessage, loadingText, updateStatusFromTask, setStarting, selectedElements, removeElement, clearElements, theme, sendThemeToIframe, sessions, loadingSessionList, currentSessionId, iframeSrc, iframeLoading, loadSessions, createSession, deleteSession, selectSession, updateSessionInfo, updateContext, serverSSE, opencodeSSE, thinking, sessionStates, showSessionListSkeleton, computedLoading, displayLoadingText, retryWarmup, ensureServicesStarted, toggleSelectMode, handleToggle, handleSelectNode, handleClearSelected, handleSelectModeChange, handleSessionListCollapsedChange, handleThemeChange, handleSplitPanelWidthChange, handleRemoveSelectedNode, handleFrameLoaded, get OpenCodeWidget() {
|
|
357
|
+
const __returned__ = { props, open, selectMode, sessionListCollapsed, loading, widgetRef, retryingWarmup, availableModels, initialTheme, autoOpen, hotkey, proxyPort, proxyHost, displayMode, splitMode, widgetTheme, splitPanelWidth, proxyBaseUrl, showNotification, serviceStatus, chromeMcpFailed, chromeMcpErrorType, chromeMcpErrorMessage, loadingText, updateStatusFromTask, setStarting, selectedElements, removeElement, clearElements, theme, sendThemeToIframe, sessions, loadingSessionList, currentSessionId, iframeSrc, iframeLoading, loadSessions, createSession, deleteSession, selectSession, updateSessionInfo, updateContext, serverSSE, opencodeSSE, thinking, sessionStates, showSessionListSkeleton, computedLoading, displayLoadingText, retryWarmup, fetchAvailableModels, ensureServicesStarted, toggleSelectMode, handleToggle, handleSelectNode, handleClearSelected, handleSelectModeChange, handleSessionListCollapsedChange, handleThemeChange, handleSplitPanelWidthChange, handleRemoveSelectedNode, handleFrameLoaded, get OpenCodeWidget() {
|
|
336
358
|
return import_components.OpenCodeWidget;
|
|
337
359
|
}, LoadingContent: import_LoadingContent_vue.default, ChromeWarmupError: import_ChromeWarmupError_vue.default };
|
|
338
360
|
Object.defineProperty(__returned__, "__isScriptSetup", { enumerable: false, value: true });
|
|
@@ -384,8 +406,9 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
384
406
|
retrying: $setup.retryingWarmup,
|
|
385
407
|
"error-type": $setup.chromeMcpErrorType,
|
|
386
408
|
"error-message": $setup.chromeMcpErrorMessage,
|
|
409
|
+
models: $setup.availableModels,
|
|
387
410
|
onRetry: $setup.retryWarmup
|
|
388
|
-
}, null, 8, ["retrying", "error-type", "error-message"])) : (0, import_vue3.createCommentVNode)("v-if", true)
|
|
411
|
+
}, null, 8, ["retrying", "error-type", "error-message", "models"])) : (0, import_vue3.createCommentVNode)("v-if", true)
|
|
389
412
|
]),
|
|
390
413
|
_: 1
|
|
391
414
|
/* STABLE */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.opencode-chrome-warmup-error-details[data-v-
|
|
1
|
+
.opencode-chrome-warmup-error-details[data-v-06c8b833]{margin-top:8px;padding:12px;background:var(--oc-bg-tertiary);border-radius:6px;font-family:Monaco,Menlo,Ubuntu Mono,monospace;font-size:12px;color:var(--oc-text-secondary);max-height:120px;overflow-y:auto;word-break:break-word}.opencode-model-selector[data-v-06c8b833]{display:flex;flex-direction:column;gap:12px;max-width:400px}.select-wrapper[data-v-06c8b833]{position:relative;width:100%}.native-select[data-v-06c8b833]{width:100%;padding:10px 36px 10px 12px;border-radius:8px;border:1px solid var(--oc-border-primary);background:var(--oc-bg-primary);color:var(--oc-text-primary);font-size:14px;cursor:pointer;outline:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;transition:border-color .15s ease,background-color .15s ease,box-shadow .15s ease}.native-select[data-v-06c8b833]:hover:not(:disabled){border-color:var(--oc-border-hover);background:var(--oc-bg-secondary)}.native-select[data-v-06c8b833]:focus{border-color:var(--oc-primary);box-shadow:0 0 0 2px rgba(var(--oc-primary-rgb, 59, 130, 246),.2)}.native-select[data-v-06c8b833]:disabled{opacity:.6;cursor:not-allowed}.native-select option[data-v-06c8b833]{background:var(--oc-bg-primary);color:var(--oc-text-primary);padding:8px}.native-select optgroup[data-v-06c8b833]{color:var(--oc-text-secondary);font-weight:600;font-size:12px}.select-arrow[data-v-06c8b833]{position:absolute;right:12px;top:50%;transform:translateY(-50%);pointer-events:none;color:var(--oc-text-secondary);display:flex;align-items:center}.native-select:disabled+.select-arrow[data-v-06c8b833]{opacity:.6}.retry-btn[data-v-06c8b833]{width:100%;padding:10px 20px;border-radius:8px;border:none;background:var(--oc-primary);color:#fff;font-size:14px;cursor:pointer;transition:background-color .15s ease}.retry-btn[data-v-06c8b833]:hover:not(:disabled){background:var(--oc-primary-hover)}.retry-btn[data-v-06c8b833]:disabled{opacity:.6;cursor:not-allowed}.opencode-chrome-warmup-failed-actions[data-v-06c8b833]{margin-top:16px;display:flex;justify-content:center}.opencode-chrome-warmup-failed-btn[data-v-06c8b833]{padding:10px 20px;border-radius:8px;border:none;font-size:14px;cursor:pointer;transition:background-color .15s ease}.opencode-chrome-warmup-failed-btn.primary[data-v-06c8b833]{background:var(--oc-primary);color:#fff}.opencode-chrome-warmup-failed-btn.primary[data-v-06c8b833]:hover:not(:disabled){background:var(--oc-primary-hover)}.opencode-chrome-warmup-failed-btn[data-v-06c8b833]:disabled{opacity:.6;cursor:not-allowed}
|