mcp-prompt-optimizer 3.0.2 ā 3.0.4
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/README.md +251 -403
- package/index.js +316 -24
- package/lib/api-key-manager.js +1 -1
- package/lib/optimization-templates.json +466 -0
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Production-grade with Bayesian optimization, AG-UI real-time features, enhanced network resilience,
|
|
6
6
|
* development mode, and complete backend alignment
|
|
7
7
|
*
|
|
8
|
-
* Version:
|
|
8
|
+
* Version: 3.0.2 - Aligned with FastAPI Backend production-v2.2.0-stable
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
|
@@ -14,6 +14,7 @@ const { CallToolRequestSchema, ListToolsRequestSchema } = require('@modelcontext
|
|
|
14
14
|
const https = require('https');
|
|
15
15
|
const CloudApiKeyManager = require('./lib/api-key-manager');
|
|
16
16
|
const packageJson = require('./package.json');
|
|
17
|
+
const OPTIMIZATION_TEMPLATES = require('./lib/optimization-templates.json');
|
|
17
18
|
|
|
18
19
|
const API_KEYS_PREFIX = '/api/v1/api-keys';
|
|
19
20
|
const MCP_PREFIX = '/api/v1/mcp';
|
|
@@ -35,9 +36,6 @@ const ENDPOINTS = {
|
|
|
35
36
|
|
|
36
37
|
/** Update (PATCH) */
|
|
37
38
|
UPDATE: (id) => `${MCP_PREFIX}/templates/${id}`,
|
|
38
|
-
|
|
39
|
-
/** Delete (DELETE) */
|
|
40
|
-
DELETE: (id) => `${MCP_PREFIX}/templates/${id}`,
|
|
41
39
|
},
|
|
42
40
|
|
|
43
41
|
/** Search templates (GET) ā MCP endpoint, API-key auth */
|
|
@@ -77,9 +75,9 @@ class MCPPromptOptimizer {
|
|
|
77
75
|
this.developmentMode = false;
|
|
78
76
|
this.requestTimeout = parseInt(process.env.OPTIMIZER_REQUEST_TIMEOUT) || 30000;
|
|
79
77
|
|
|
80
|
-
//
|
|
81
|
-
this.bayesianOptimizationEnabled = process.env.ENABLE_BAYESIAN_OPTIMIZATION
|
|
82
|
-
this.aguiFeatures = process.env.ENABLE_AGUI_FEATURES
|
|
78
|
+
// Feature flags: enabled by default, set to 'false' to disable
|
|
79
|
+
this.bayesianOptimizationEnabled = process.env.ENABLE_BAYESIAN_OPTIMIZATION !== 'false';
|
|
80
|
+
this.aguiFeatures = process.env.ENABLE_AGUI_FEATURES !== 'false';
|
|
83
81
|
|
|
84
82
|
this.setupMCPHandlers();
|
|
85
83
|
}
|
|
@@ -208,11 +206,16 @@ class MCPPromptOptimizer {
|
|
|
208
206
|
type: "string",
|
|
209
207
|
description: "Filter by optimization strategy used"
|
|
210
208
|
},
|
|
211
|
-
limit: {
|
|
212
|
-
type: "number",
|
|
209
|
+
limit: {
|
|
210
|
+
type: "number",
|
|
213
211
|
default: 5,
|
|
214
212
|
description: "Number of templates to return (1-20)"
|
|
215
213
|
},
|
|
214
|
+
page: {
|
|
215
|
+
type: "number",
|
|
216
|
+
default: 1,
|
|
217
|
+
description: "Page number for pagination (use with limit to access results beyond the first page)"
|
|
218
|
+
},
|
|
216
219
|
sort_by: {
|
|
217
220
|
type: "string",
|
|
218
221
|
enum: ["created_at", "confidence_score", "usage_count", "title"],
|
|
@@ -228,6 +231,20 @@ class MCPPromptOptimizer {
|
|
|
228
231
|
}
|
|
229
232
|
}
|
|
230
233
|
},
|
|
234
|
+
{
|
|
235
|
+
name: "list_recent_templates",
|
|
236
|
+
description: "š List your most recently saved optimization templates, sorted by creation date.",
|
|
237
|
+
inputSchema: {
|
|
238
|
+
type: "object",
|
|
239
|
+
properties: {
|
|
240
|
+
limit: {
|
|
241
|
+
type: "number",
|
|
242
|
+
default: 10,
|
|
243
|
+
description: "Number of recent templates to return (1-20)"
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
},
|
|
231
248
|
{
|
|
232
249
|
name: "detect_ai_context",
|
|
233
250
|
description: "š§ Detects the AI context for a given prompt using advanced backend analysis.",
|
|
@@ -287,6 +304,7 @@ class MCPPromptOptimizer {
|
|
|
287
304
|
case "optimize_prompt": return await this.handleOptimizePrompt(args);
|
|
288
305
|
case "get_quota_status": return await this.handleGetQuotaStatus();
|
|
289
306
|
case "search_templates": return await this.handleSearchTemplates(args);
|
|
307
|
+
case "list_recent_templates": return await this.handleListRecentTemplates(args);
|
|
290
308
|
case "detect_ai_context": return await this.handleDetectAIContext(args);
|
|
291
309
|
case "create_template": return await this.handleCreateTemplate(args);
|
|
292
310
|
case "get_template": return await this.handleGetTemplate(args);
|
|
@@ -301,11 +319,185 @@ class MCPPromptOptimizer {
|
|
|
301
319
|
});
|
|
302
320
|
}
|
|
303
321
|
|
|
322
|
+
// āāā Rules-Based Optimization (offline / fallback tier) āāāāāāāāāāāāāāāāāāāāā
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Select the best-matching template for a prompt using pattern scoring.
|
|
326
|
+
* Mirrors the backend's pattern-based fallback (no LLM required).
|
|
327
|
+
*/
|
|
328
|
+
_matchTemplate(prompt, backendContext) {
|
|
329
|
+
const lc = prompt.toLowerCase();
|
|
330
|
+
let bestTemplate = null;
|
|
331
|
+
let bestScore = 0;
|
|
332
|
+
let fallbackName = null;
|
|
333
|
+
|
|
334
|
+
for (const [name, template] of Object.entries(OPTIMIZATION_TEMPLATES)) {
|
|
335
|
+
if (template.context !== backendContext) continue;
|
|
336
|
+
if (name.startsWith('fallback_')) { fallbackName = name; continue; }
|
|
337
|
+
|
|
338
|
+
let hits = 0;
|
|
339
|
+
for (const pattern of template.patterns) {
|
|
340
|
+
if (pattern === '.*') continue;
|
|
341
|
+
if (lc.includes(pattern.toLowerCase())) hits++;
|
|
342
|
+
}
|
|
343
|
+
if (hits === 0) continue;
|
|
344
|
+
|
|
345
|
+
// Confidence: 1 hit ā 0.6, 2 hits ā 0.75, 3+ hits ā 0.9 (mirrors backend)
|
|
346
|
+
const patternConf = hits === 1 ? 0.6 : hits === 2 ? 0.75 : 0.9;
|
|
347
|
+
const score = patternConf + (template.priority || 1) / 100;
|
|
348
|
+
|
|
349
|
+
if (score > bestScore) { bestScore = score; bestTemplate = name; }
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (!bestTemplate) {
|
|
353
|
+
return { templateName: fallbackName || `fallback_${backendContext.toLowerCase()}`, matchConfidence: 0.3 };
|
|
354
|
+
}
|
|
355
|
+
return { templateName: bestTemplate, matchConfidence: bestScore };
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** Extract a user-defined role from the start of a prompt (e.g. "As a doctor, ā¦"). */
|
|
359
|
+
_extractUserRole(request) {
|
|
360
|
+
const rolePatterns = [
|
|
361
|
+
/^['"]?(?:As a|You are a|My role is)\s+([a-zA-Z0-9\s\-/()]+?)(?:,|(?=\s*\.))/i,
|
|
362
|
+
/^['"]?(?:I am a|I'm a)\s+([a-zA-Z0-9\s\-/()]+?)(?:,|(?=\s*\.))/i,
|
|
363
|
+
];
|
|
364
|
+
for (const re of rolePatterns) {
|
|
365
|
+
const m = request.match(re);
|
|
366
|
+
if (m) return m[1].trim();
|
|
367
|
+
}
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Compile a template playbook into a user-facing prose prompt.
|
|
373
|
+
* Produces readable output instead of XML scaffolding, matching the
|
|
374
|
+
* result a backend LLM pass would generate from the same playbook.
|
|
375
|
+
*/
|
|
376
|
+
_compilePlaybook(playbook, originalRequest) {
|
|
377
|
+
const parts = [];
|
|
378
|
+
|
|
379
|
+
parts.push(originalRequest.trim());
|
|
380
|
+
parts.push('');
|
|
381
|
+
|
|
382
|
+
const userFacingPrinciples = (playbook.principles || []).filter(p => {
|
|
383
|
+
const lc = p.toLowerCase();
|
|
384
|
+
return !lc.includes('scratchpad') &&
|
|
385
|
+
!lc.startsWith('first, think') &&
|
|
386
|
+
!/<[a-z]/i.test(p);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
if (userFacingPrinciples.length > 0) {
|
|
390
|
+
parts.push('To address this effectively:');
|
|
391
|
+
for (const p of userFacingPrinciples) parts.push(`- ${p}`);
|
|
392
|
+
parts.push('');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (playbook.output_format) {
|
|
396
|
+
parts.push(`*Response format: ${playbook.output_format}*`);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return parts.join('\n');
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Enhance an image generation prompt by appending style-appropriate
|
|
404
|
+
* quality/composition boosters (mirrors backend _compile_image_prompt_fallback).
|
|
405
|
+
*/
|
|
406
|
+
_compileImagePrompt(originalRequest) {
|
|
407
|
+
const text = originalRequest.trim();
|
|
408
|
+
const lc = text.toLowerCase();
|
|
409
|
+
|
|
410
|
+
const styles = {
|
|
411
|
+
photorealistic: ['photorealistic','realistic','photo','photograph','photography'],
|
|
412
|
+
'3d_render': ['3d','render','octane','unreal engine','blender','cinema 4d','ray tracing'],
|
|
413
|
+
cinematic: ['cinematic','movie','film','dramatic','epic'],
|
|
414
|
+
digital_art: ['digital art','concept art','digital illustration','cg','cgi'],
|
|
415
|
+
artistic: ['artistic','painting','watercolor','oil painting','impressionist'],
|
|
416
|
+
anime: ['anime','manga'],
|
|
417
|
+
vintage: ['vintage','retro','nostalgic'],
|
|
418
|
+
minimalist: ['minimalist','minimal','simple','clean'],
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
let detectedStyle = null;
|
|
422
|
+
for (const [style, kws] of Object.entries(styles)) {
|
|
423
|
+
if (kws.some(kw => lc.includes(kw))) { detectedStyle = style; break; }
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const enhancements = [];
|
|
427
|
+
const hasQuality = ['high quality','8k','4k','hd','highly detailed','detailed'].some(t => lc.includes(t));
|
|
428
|
+
const hasLighting = ['lighting','light','shadow','illuminated','lit'].some(t => lc.includes(t));
|
|
429
|
+
const hasComposition = ['composition','rule of thirds','centered','framed'].some(t => lc.includes(t));
|
|
430
|
+
|
|
431
|
+
if (detectedStyle === 'photorealistic' && !hasQuality) {
|
|
432
|
+
enhancements.push('ultra realistic, sharp focus, professional photography');
|
|
433
|
+
} else if (detectedStyle === '3d_render' && !['octane','render'].some(t => lc.includes(t))) {
|
|
434
|
+
enhancements.push('high quality 3D render, volumetric lighting, ray traced shadows');
|
|
435
|
+
} else if (detectedStyle === 'cinematic' && !hasLighting) {
|
|
436
|
+
enhancements.push('cinematic lighting, dramatic atmosphere, film grain');
|
|
437
|
+
} else if (detectedStyle === 'digital_art' && !hasQuality) {
|
|
438
|
+
enhancements.push('highly detailed digital art, professional illustration');
|
|
439
|
+
} else if (detectedStyle === 'artistic' && !lc.includes('masterpiece')) {
|
|
440
|
+
enhancements.push('masterful technique, rich colors, artistic composition');
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (!hasLighting && detectedStyle !== 'minimalist') enhancements.push('dynamic lighting');
|
|
444
|
+
if (!hasComposition) enhancements.push('balanced composition');
|
|
445
|
+
if (!hasQuality) enhancements.push('high quality, 4K');
|
|
446
|
+
|
|
447
|
+
return enhancements.length > 0 ? `${text}, ${enhancements.join(', ')}` : text;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Core rules-based optimizer ā no network, no LLM.
|
|
452
|
+
* Selects the best template by pattern matching, then compiles
|
|
453
|
+
* the playbook into a structured prompt. Confidence range: 0.35ā0.55.
|
|
454
|
+
*/
|
|
455
|
+
rulesBasedOptimize(prompt, aiContext, goals = []) {
|
|
456
|
+
const contextMap = {
|
|
457
|
+
code_generation: 'CODE_GENERATION',
|
|
458
|
+
llm_interaction: 'LLM_INTERACTION',
|
|
459
|
+
image_generation: 'IMAGE_GENERATION',
|
|
460
|
+
human_communication: 'HUMAN_COMMUNICATION',
|
|
461
|
+
api_automation: 'API_AUTOMATION',
|
|
462
|
+
technical_automation: 'TECHNICAL_AUTOMATION',
|
|
463
|
+
structured_output: 'STRUCTURED_OUTPUT',
|
|
464
|
+
creative_enhancement: 'CREATIVE_ENHANCEMENT',
|
|
465
|
+
creative_writing: 'CREATIVE_ENHANCEMENT',
|
|
466
|
+
general_assistant: 'LLM_INTERACTION',
|
|
467
|
+
};
|
|
468
|
+
const backendContext = contextMap[aiContext] || 'LLM_INTERACTION';
|
|
469
|
+
|
|
470
|
+
const { templateName, matchConfidence } = this._matchTemplate(prompt, backendContext);
|
|
471
|
+
const template = OPTIMIZATION_TEMPLATES[templateName];
|
|
472
|
+
|
|
473
|
+
const optimizedPrompt = backendContext === 'IMAGE_GENERATION'
|
|
474
|
+
? this._compileImagePrompt(prompt)
|
|
475
|
+
: this._compilePlaybook(template.playbook, prompt);
|
|
476
|
+
|
|
477
|
+
// Honest confidence: rules-based tops out around 0.55
|
|
478
|
+
const confidence = parseFloat(Math.min(0.35 + matchConfidence * 0.2, 0.55).toFixed(2));
|
|
479
|
+
|
|
480
|
+
return {
|
|
481
|
+
optimized_prompt: optimizedPrompt,
|
|
482
|
+
confidence_score: confidence,
|
|
483
|
+
tier: 'rules',
|
|
484
|
+
template_used: templateName,
|
|
485
|
+
rules_based: true,
|
|
486
|
+
template_saved: false,
|
|
487
|
+
templates_found: [],
|
|
488
|
+
optimization_insights: null,
|
|
489
|
+
bayesian_insights: null,
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// āāā End Rules-Based Optimization āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
494
|
+
|
|
304
495
|
generateMockOptimization(prompt, goals, aiContext, enableBayesian = false) {
|
|
305
|
-
|
|
496
|
+
// Use real rules-based optimization instead of fake placeholder output
|
|
497
|
+
const rulesResult = this.rulesBasedOptimize(prompt, aiContext, goals);
|
|
306
498
|
const baseResult = {
|
|
307
|
-
|
|
308
|
-
|
|
499
|
+
...rulesResult,
|
|
500
|
+
rules_based: false, // Show as normal optimized output in mock mode
|
|
309
501
|
tier: 'explorer',
|
|
310
502
|
mock_mode: true,
|
|
311
503
|
template_saved: true,
|
|
@@ -381,7 +573,7 @@ class MCPPromptOptimizer {
|
|
|
381
573
|
secondary_contexts: ['llm_interaction'],
|
|
382
574
|
detected_parameters: [],
|
|
383
575
|
mock_mode: true,
|
|
384
|
-
reason: '
|
|
576
|
+
reason: 'Backend unavailable ā using local pattern matching as fallback.'
|
|
385
577
|
};
|
|
386
578
|
}
|
|
387
579
|
|
|
@@ -432,7 +624,7 @@ class MCPPromptOptimizer {
|
|
|
432
624
|
if (error.message.includes('Network') || error.message.includes('DNS') || error.message.includes('timeout') || error.message.includes('Connection')) {
|
|
433
625
|
const fallbackContext = args.ai_context || 'human_communication';
|
|
434
626
|
const fallbackEnableBayesian = args.enable_bayesian !== false && this.bayesianOptimizationEnabled;
|
|
435
|
-
const fallbackResult = this.
|
|
627
|
+
const fallbackResult = this.rulesBasedOptimize(args.prompt, fallbackContext, args.goals || ['clarity']);
|
|
436
628
|
fallbackResult.fallback_mode = true;
|
|
437
629
|
fallbackResult.error_reason = error.message;
|
|
438
630
|
const formatted = this.formatOptimizationResult(fallbackResult, { detectedContext: fallbackContext, enableBayesian: fallbackEnableBayesian });
|
|
@@ -451,7 +643,7 @@ class MCPPromptOptimizer {
|
|
|
451
643
|
async handleSearchTemplates(args) {
|
|
452
644
|
try {
|
|
453
645
|
const params = new URLSearchParams({
|
|
454
|
-
page:
|
|
646
|
+
page: (args.page || 1).toString(),
|
|
455
647
|
per_page: Math.min(args.limit || 5, 20).toString(),
|
|
456
648
|
sort_by: args.sort_by || 'confidence_score',
|
|
457
649
|
sort_order: args.sort_order || 'desc'
|
|
@@ -492,6 +684,49 @@ class MCPPromptOptimizer {
|
|
|
492
684
|
}
|
|
493
685
|
}
|
|
494
686
|
|
|
687
|
+
async handleListRecentTemplates(args) {
|
|
688
|
+
try {
|
|
689
|
+
const limit = Math.min(Math.max(args.limit || 10, 1), 20);
|
|
690
|
+
const params = new URLSearchParams({
|
|
691
|
+
page: '1',
|
|
692
|
+
per_page: limit.toString(),
|
|
693
|
+
sort_by: 'created_at',
|
|
694
|
+
sort_order: 'desc'
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
const endpoint = `${ENDPOINTS.SEARCH_TEMPLATES}?${params.toString()}`;
|
|
698
|
+
const result = await this.callBackendAPI(endpoint, null, 'GET');
|
|
699
|
+
|
|
700
|
+
const templates = result.templates || [];
|
|
701
|
+
let output = `# š Recent Templates\n\n`;
|
|
702
|
+
output += `Showing **${templates.length}** most recently saved template(s).\n\n`;
|
|
703
|
+
|
|
704
|
+
if (templates.length === 0) {
|
|
705
|
+
output += `š No templates found yet.\nRun \`optimize_prompt\` to start building your template library.\n`;
|
|
706
|
+
} else {
|
|
707
|
+
output += `## š **Template Results**\n`;
|
|
708
|
+
templates.forEach((t, index) => {
|
|
709
|
+
const confidence = t.confidence_score ? `${(t.confidence_score * 100).toFixed(1)}%` : 'N/A';
|
|
710
|
+
const preview = t.optimized_prompt ? t.optimized_prompt.substring(0, 60) + '...' : 'Preview unavailable';
|
|
711
|
+
output += `### ${index + 1}. ${t.title}\n`;
|
|
712
|
+
output += `- **Confidence:** ${confidence}\n`;
|
|
713
|
+
output += `- **ID:** \`${t.id}\`\n`;
|
|
714
|
+
output += `- **Preview:** ${preview}\n`;
|
|
715
|
+
if (t.ai_context) output += `- **Context:** ${t.ai_context}\n`;
|
|
716
|
+
if (t.optimization_goals && t.optimization_goals.length) {
|
|
717
|
+
output += `- **Goals:** ${t.optimization_goals.join(', ')}\n`;
|
|
718
|
+
}
|
|
719
|
+
output += `\n`;
|
|
720
|
+
});
|
|
721
|
+
output += `š” Use \`get_template\` with an ID above to view the full optimized prompt.\n`;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
return { content: [{ type: "text", text: output }] };
|
|
725
|
+
} catch (error) {
|
|
726
|
+
return { content: [{ type: "text", text: `ā Could not retrieve recent templates: ${error.message}` }] };
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
495
730
|
async handleGetOptimizationInsights(args) {
|
|
496
731
|
if (!this.bayesianOptimizationEnabled) {
|
|
497
732
|
return { content: [{ type: "text", text: "š§ Bayesian optimization features are not enabled. Set ENABLE_BAYESIAN_OPTIMIZATION=true to access advanced insights." }] };
|
|
@@ -607,6 +842,18 @@ class MCPPromptOptimizer {
|
|
|
607
842
|
}
|
|
608
843
|
|
|
609
844
|
async handleCreateTemplate(args) {
|
|
845
|
+
// Client-side validation before network call
|
|
846
|
+
const requiredStrings = ['title', 'original_prompt', 'optimized_prompt'];
|
|
847
|
+
for (const field of requiredStrings) {
|
|
848
|
+
if (!args[field] || typeof args[field] !== 'string' || args[field].trim() === '') {
|
|
849
|
+
return { content: [{ type: "text", text: `ā Missing required field: '${field}'. Required fields: title, original_prompt, optimized_prompt, confidence_score (0.0ā1.0)` }] };
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
if (args.confidence_score === undefined || args.confidence_score === null ||
|
|
853
|
+
typeof args.confidence_score !== 'number' || args.confidence_score < 0 || args.confidence_score > 1) {
|
|
854
|
+
return { content: [{ type: "text", text: `ā Missing required field: 'confidence_score'. Required fields: title, original_prompt, optimized_prompt, confidence_score (0.0ā1.0)` }] };
|
|
855
|
+
}
|
|
856
|
+
|
|
610
857
|
try {
|
|
611
858
|
const result = await this.callBackendAPI(ENDPOINTS.TEMPLATE.CREATE, args);
|
|
612
859
|
let output = `# ā
Template Created Successfully!\n\n`;
|
|
@@ -638,6 +885,10 @@ class MCPPromptOptimizer {
|
|
|
638
885
|
output += `**Optimized Prompt:**\n\`\`\`\n${result.optimized_prompt}\n\`\`\`\n`;
|
|
639
886
|
return { content: [{ type: "text", text: output }] };
|
|
640
887
|
} catch (error) {
|
|
888
|
+
const msg = error.message || '';
|
|
889
|
+
if (msg.includes('404') || msg.toLowerCase().includes('not found')) {
|
|
890
|
+
throw new Error(`Template \`${args.template_id}\` not found. It may have been deleted or the ID is incorrect. Use \`search_templates\` to find available templates.`);
|
|
891
|
+
}
|
|
641
892
|
throw new Error(`Failed to retrieve template: ${error.message}`);
|
|
642
893
|
}
|
|
643
894
|
}
|
|
@@ -736,8 +987,37 @@ class MCPPromptOptimizer {
|
|
|
736
987
|
}
|
|
737
988
|
|
|
738
989
|
formatOptimizationResult(result, context) {
|
|
739
|
-
let output
|
|
740
|
-
|
|
990
|
+
let output;
|
|
991
|
+
if (result.rules_based) {
|
|
992
|
+
if (result.fallback_mode) {
|
|
993
|
+
output = `# š§ Rules-Based Optimization Applied\n\n`;
|
|
994
|
+
output += `ā ļø *Backend unreachable ā your prompt has been structured using local rule templates (no LLM). `;
|
|
995
|
+
output += `Re-run when the backend is available for full LLM optimization.*\n\n`;
|
|
996
|
+
} else {
|
|
997
|
+
output = `# š§ Rules-Based Optimization Applied\n\n`;
|
|
998
|
+
output += `*API key not validated ā optimized using local rule templates. `;
|
|
999
|
+
output += `Set \`MCP_API_KEY\` for full LLM optimization.*\n\n`;
|
|
1000
|
+
}
|
|
1001
|
+
output += `**Template:** \`${result.template_used || 'general'}\`\n\n`;
|
|
1002
|
+
output += `**Optimized Prompt:**\n\`\`\`\n${result.optimized_prompt}\n\`\`\`\n\n`;
|
|
1003
|
+
} else if (result.fallback_mode) {
|
|
1004
|
+
// Legacy path ā should no longer be reached
|
|
1005
|
+
output = `# ā ļø Backend Unavailable ā Prompt Not Optimized\n\n`;
|
|
1006
|
+
output += `**Issue:** ${result.error_reason}\n`;
|
|
1007
|
+
output += `The backend could not be reached. Your original prompt is returned below unmodified.\n\n`;
|
|
1008
|
+
output += `**Original Prompt:**\n\`\`\`\n${result.optimized_prompt}\n\`\`\`\n\n`;
|
|
1009
|
+
} else {
|
|
1010
|
+
output = `# šÆ Optimized Prompt\n\n${result.optimized_prompt}\n\n`;
|
|
1011
|
+
if (result.confidence_score < 0.25) {
|
|
1012
|
+
output += `> ā¹ļø *Low confidence indicates the backend applied rules-based optimization (no LLM). `;
|
|
1013
|
+
output += `Ensure \`OPENROUTER_API_KEY\` is configured in the backend for full LLM enhancement.*\n\n`;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
if (result.rules_based) {
|
|
1017
|
+
output += `**Confidence:** ${(result.confidence_score * 100).toFixed(1)}% *(rules-based ā LLM optimization typically 70ā95%)*\n`;
|
|
1018
|
+
} else {
|
|
1019
|
+
output += `**Confidence:** ${(result.confidence_score * 100).toFixed(1)}%\n`;
|
|
1020
|
+
}
|
|
741
1021
|
output += `**AI Context:** ${context.detectedContext}\n`;
|
|
742
1022
|
|
|
743
1023
|
if (result.template_saved) {
|
|
@@ -747,8 +1027,9 @@ class MCPPromptOptimizer {
|
|
|
747
1027
|
if (result.templates_found?.length) {
|
|
748
1028
|
output += `\nš **Similar Templates Found**\nFound **${result.templates_found.length}** similar template(s):\n`;
|
|
749
1029
|
result.templates_found.slice(0, 3).forEach(t => {
|
|
750
|
-
output += `- ${t.title} (${(t.confidence_score * 100).toFixed(1)}% match)
|
|
1030
|
+
output += `- ${t.title} (${(t.confidence_score * 100).toFixed(1)}% match) ā ID: \`${t.id}\`\n`;
|
|
751
1031
|
});
|
|
1032
|
+
output += `\nš” Use \`get_template\` with any ID above to view the full optimized prompt.\n`;
|
|
752
1033
|
}
|
|
753
1034
|
|
|
754
1035
|
if (result.optimization_insights) {
|
|
@@ -796,12 +1077,10 @@ class MCPPromptOptimizer {
|
|
|
796
1077
|
}
|
|
797
1078
|
}
|
|
798
1079
|
|
|
799
|
-
if (result.fallback_mode) {
|
|
800
|
-
output += `\n
|
|
1080
|
+
if (!result.fallback_mode) {
|
|
1081
|
+
output += `\nš **Quick Actions**\n- Dashboard: https://promptoptimizer-blog.vercel.app/dashboard\n- Analytics: https://promptoptimizer-blog.vercel.app/analytics\n`;
|
|
801
1082
|
}
|
|
802
1083
|
|
|
803
|
-
output += `\nš **Quick Actions**\n- Dashboard: https://promptoptimizer-blog.vercel.app/dashboard\n- Analytics: https://promptoptimizer-blog.vercel.app/analytics\n`;
|
|
804
|
-
|
|
805
1084
|
return output;
|
|
806
1085
|
}
|
|
807
1086
|
|
|
@@ -821,6 +1100,17 @@ class MCPPromptOptimizer {
|
|
|
821
1100
|
else if (percentage >= 75) statusIcon = 'š”';
|
|
822
1101
|
|
|
823
1102
|
output += `**Usage:** ${statusIcon} ${used}/${limit} (${percentage}%)\n`;
|
|
1103
|
+
|
|
1104
|
+
const remaining = limit - used;
|
|
1105
|
+
if (remaining <= 0) {
|
|
1106
|
+
output += `\nā **Quota Exhausted** ā You have no optimizations remaining this month.\n`;
|
|
1107
|
+
output += `Upgrade at https://promptoptimizer-blog.vercel.app/pricing\n`;
|
|
1108
|
+
output += `*(Quota resets at the start of your next billing cycle)*\n`;
|
|
1109
|
+
} else if (percentage >= 90) {
|
|
1110
|
+
output += `\nā ļø **Critical** ā ${remaining} optimization${remaining === 1 ? '' : 's'} remaining. Upgrade at https://promptoptimizer-blog.vercel.app/pricing\n`;
|
|
1111
|
+
} else if (percentage >= 75) {
|
|
1112
|
+
output += `\nā ļø **Warning** ā Approaching your monthly limit.\n`;
|
|
1113
|
+
}
|
|
824
1114
|
}
|
|
825
1115
|
|
|
826
1116
|
output += `\n## ⨠**Available Features**\n`;
|
|
@@ -865,10 +1155,12 @@ class MCPPromptOptimizer {
|
|
|
865
1155
|
|
|
866
1156
|
if (!result.templates || result.templates.length === 0) {
|
|
867
1157
|
output += `š **No Templates Found**\n`;
|
|
868
|
-
|
|
869
|
-
|
|
1158
|
+
const hasActiveFilters = originalArgs.query || originalArgs.ai_context || originalArgs.sophistication_level || originalArgs.complexity_level;
|
|
1159
|
+
if (hasActiveFilters) {
|
|
1160
|
+
output += `No templates matched your filters. Try removing \`ai_context\` or \`query\` filters.\n`;
|
|
870
1161
|
} else {
|
|
871
1162
|
output += `You don't have any saved templates yet. Templates are automatically saved when optimization confidence is >70%.\n`;
|
|
1163
|
+
output += `Run \`optimize_prompt\` to start building your template library.\n`;
|
|
872
1164
|
}
|
|
873
1165
|
} else {
|
|
874
1166
|
output += `## š **Template Results**\n`;
|
package/lib/api-key-manager.js
CHANGED
|
@@ -488,7 +488,7 @@ class CloudApiKeyManager {
|
|
|
488
488
|
|
|
489
489
|
try {
|
|
490
490
|
// Step 1: Validate API key
|
|
491
|
-
|
|
491
|
+
let validation = await this.validateApiKey();
|
|
492
492
|
|
|
493
493
|
// Step 2: Get comprehensive quota status
|
|
494
494
|
const info = await this.getApiKeyInfo();
|