mcp-prompt-optimizer 3.7.0 → 3.7.2
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/CHANGELOG.md +9 -0
- package/README.md +6 -1
- package/index.js +1994 -1988
- package/lib/api-key-manager.js +730 -729
- package/package.json +271 -263
package/index.js
CHANGED
|
@@ -1,1989 +1,1995 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* MCP Prompt Optimizer - Professional Cloud-Based MCP Server
|
|
5
|
-
* Production-grade with Bayesian optimization, AG-UI real-time features, enhanced network resilience,
|
|
6
|
-
* development mode, and complete backend alignment
|
|
7
|
-
*
|
|
8
|
-
* Version: 3.2.0 - add delete_template tool (15 tools total)
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
|
12
|
-
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
13
|
-
const { CallToolRequestSchema, ListToolsRequestSchema } = require('@modelcontextprotocol/sdk/types.js');
|
|
14
|
-
const https = require('https');
|
|
15
|
-
const CloudApiKeyManager = require('./lib/api-key-manager');
|
|
16
|
-
const packageJson = require('./package.json');
|
|
17
|
-
const OPTIMIZATION_TEMPLATES = require('./lib/optimization-templates.json');
|
|
18
|
-
|
|
19
|
-
const API_KEYS_PREFIX = '/api/v1/api-keys';
|
|
20
|
-
const MCP_PREFIX = '/api/v1/mcp';
|
|
21
|
-
|
|
22
|
-
const ENDPOINTS = {
|
|
23
|
-
/** Detect AI context (POST) — MCP endpoint, API-key auth */
|
|
24
|
-
DETECT_CONTEXT: `${MCP_PREFIX}/detect-context`,
|
|
25
|
-
|
|
26
|
-
/** Prompt optimization (POST) — MCP endpoint, API-key auth */
|
|
27
|
-
OPTIMIZE: `${MCP_PREFIX}/optimize`,
|
|
28
|
-
|
|
29
|
-
/** CRUD on templates — MCP endpoints, API-key auth */
|
|
30
|
-
TEMPLATE: {
|
|
31
|
-
/** Create (POST) */
|
|
32
|
-
CREATE: `${MCP_PREFIX}/templates`,
|
|
33
|
-
|
|
34
|
-
/** Read (GET) */
|
|
35
|
-
GET: (id) => `${MCP_PREFIX}/templates/${id}`,
|
|
36
|
-
|
|
37
|
-
/** Update (PATCH) */
|
|
38
|
-
UPDATE: (id) => `${MCP_PREFIX}/templates/${id}`,
|
|
39
|
-
|
|
40
|
-
/** Delete (DELETE) */
|
|
41
|
-
DELETE: (id) => `${MCP_PREFIX}/templates/${id}`,
|
|
42
|
-
},
|
|
43
|
-
|
|
44
|
-
/** Search templates (GET) — MCP endpoint, API-key auth */
|
|
45
|
-
SEARCH_TEMPLATES: `${MCP_PREFIX}/templates`,
|
|
46
|
-
|
|
47
|
-
/** Quota status (GET) — MCP endpoint, API-key auth */
|
|
48
|
-
QUOTA_STATUS: `${MCP_PREFIX}/quota-status`,
|
|
49
|
-
|
|
50
|
-
/** Validate API key (POST) — standard api-keys router */
|
|
51
|
-
VALIDATE_KEY: `${API_KEYS_PREFIX}/validate`,
|
|
52
|
-
|
|
53
|
-
/** Bayesian insights (GET) */
|
|
54
|
-
ANALYTICS_BAYESIAN_INSIGHTS:
|
|
55
|
-
'/api/v1/analytics/bayesian-insights',
|
|
56
|
-
|
|
57
|
-
/** AG‑UI status (GET) */
|
|
58
|
-
AGUI_STATUS: '/api/status',
|
|
59
|
-
|
|
60
|
-
/** Context Engineer (CE) endpoints */
|
|
61
|
-
CE: {
|
|
62
|
-
SOP: '/api/v1/context-engineer/sop',
|
|
63
|
-
GENERATE_SKILL_PACKAGE: '/api/v1/context-engineer/generate-skill-package',
|
|
64
|
-
SESSION: (id) => `/api/v1/context-engineer/sessions/${id}`,
|
|
65
|
-
TRANSFORM: '/api/v1/context-engineer/transform',
|
|
66
|
-
QUOTA: '/api/v1/context-engineer/quota',
|
|
67
|
-
HARNESS_BUNDLE: '/api/v1/context-engineer/harness-bundle',
|
|
68
|
-
SOP_EXPLORE: '/api/v1/context-engineer/sop-explore',
|
|
69
|
-
SOP_BLEND: '/api/v1/context-engineer/sop-blend',
|
|
70
|
-
},
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const DEPLOY_TARGET_ENUM = [
|
|
74
|
-
"claude_code", "claude_desktop", "cursor", "copilot",
|
|
75
|
-
"windsurf", "cline", "zed", "replit", "openai_agents", "ollama",
|
|
76
|
-
"amazon_q", "aider", "continue_dev", "crewai"
|
|
77
|
-
];
|
|
78
|
-
|
|
79
|
-
class MCPPromptOptimizer {
|
|
80
|
-
constructor() {
|
|
81
|
-
this.server = new Server(
|
|
82
|
-
{
|
|
83
|
-
name: "mcp-prompt-optimizer",
|
|
84
|
-
version: packageJson.version,
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
capabilities: {
|
|
88
|
-
tools: {},
|
|
89
|
-
},
|
|
90
|
-
}
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
this.backendUrl = process.env.OPTIMIZER_BACKEND_URL || 'https://p01--project-optimizer--fvmrdk8m9k9j.code.run';
|
|
94
|
-
this.apiKey = process.env.OPTIMIZER_API_KEY;
|
|
95
|
-
// SECURITY: Development mode removed - all environments require backend validation
|
|
96
|
-
this.developmentMode = false;
|
|
97
|
-
this.requestTimeout = parseInt(process.env.OPTIMIZER_REQUEST_TIMEOUT) || 30000;
|
|
98
|
-
|
|
99
|
-
// Feature flags: enabled by default, set to 'false' to disable
|
|
100
|
-
this.bayesianOptimizationEnabled = process.env.ENABLE_BAYESIAN_OPTIMIZATION !== 'false';
|
|
101
|
-
this.aguiFeatures = process.env.ENABLE_AGUI_FEATURES !== 'false';
|
|
102
|
-
|
|
103
|
-
this.setupMCPHandlers();
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
setupMCPHandlers() {
|
|
107
|
-
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
108
|
-
const baseTools = [
|
|
109
|
-
{
|
|
110
|
-
name: "optimize_prompt",
|
|
111
|
-
description: "🎯 Professional AI-powered prompt optimization with intelligent context detection, Bayesian optimization, template auto-save, and comprehensive optimization insights",
|
|
112
|
-
inputSchema: {
|
|
113
|
-
type: "object",
|
|
114
|
-
properties: {
|
|
115
|
-
prompt: {
|
|
116
|
-
type: "string",
|
|
117
|
-
description: "The prompt text to optimize"
|
|
118
|
-
},
|
|
119
|
-
goals: {
|
|
120
|
-
type: "array",
|
|
121
|
-
items: { type: "string" },
|
|
122
|
-
description: "Optimization goals (e.g., 'clarity', 'conciseness', 'creativity', 'technical_accuracy', 'analytical_depth', 'creative_enhancement')",
|
|
123
|
-
default: ["clarity"]
|
|
124
|
-
},
|
|
125
|
-
ai_context: {
|
|
126
|
-
type: "string",
|
|
127
|
-
enum: [
|
|
128
|
-
"human_communication", "llm_interaction", "image_generation", "technical_automation",
|
|
129
|
-
"structured_output", "code_generation", "api_automation", "data_analysis",
|
|
130
|
-
"creative_writing", "business_strategy", "technical_strategy", "academic_research",
|
|
131
|
-
"legal_compliance", "medical_healthcare", "educational_content"
|
|
132
|
-
],
|
|
133
|
-
description: "The context for the AI's task (auto-detected if not specified with enhanced detection)"
|
|
134
|
-
},
|
|
135
|
-
enable_bayesian: {
|
|
136
|
-
type: "boolean",
|
|
137
|
-
description: "Enable Bayesian optimization features for parameter tuning (if available)",
|
|
138
|
-
default: true
|
|
139
|
-
},
|
|
140
|
-
value_hierarchy: {
|
|
141
|
-
type: "array",
|
|
142
|
-
description: "Ordered list of values/constraints the optimizer must respect. NON_NEGOTIABLE entries force LLM-tier routing and inject hard constraints into the system prompt. Example: [{label:'NON_NEGOTIABLE',description:'Never suggest removing error handling'},{label:'HIGH',description:'Preserve technical terminology'}]",
|
|
143
|
-
items: {
|
|
144
|
-
type: "object",
|
|
145
|
-
properties: {
|
|
146
|
-
label: {
|
|
147
|
-
type: "string",
|
|
148
|
-
enum: ["NON_NEGOTIABLE", "HIGH", "MEDIUM", "LOW"],
|
|
149
|
-
description: "Priority level for this constraint"
|
|
150
|
-
},
|
|
151
|
-
description: {
|
|
152
|
-
type: "string",
|
|
153
|
-
description: "The value or constraint to enforce during optimization"
|
|
154
|
-
}
|
|
155
|
-
},
|
|
156
|
-
required: ["label", "description"]
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
intent_frame: {
|
|
160
|
-
type: "object",
|
|
161
|
-
description: "Question Method intent framing — steers optimization toward a specific angle, excludes off-topic territory, and defines what success looks like. Any non-null field floors routing to HYBRID tier minimum.",
|
|
162
|
-
properties: {
|
|
163
|
-
perspective: {
|
|
164
|
-
type: "string",
|
|
165
|
-
description: "The angle or thesis to optimize from (e.g. 'growth is a retention problem, not an acquisition problem'). Gives the optimizer a north-star direction."
|
|
166
|
-
},
|
|
167
|
-
out_of_scope: {
|
|
168
|
-
type: "array",
|
|
169
|
-
items: { type: "string" },
|
|
170
|
-
description: "Topics, approaches, or angles to explicitly exclude from optimization (e.g. ['pricing strategy', 'acquisition channels'])."
|
|
171
|
-
},
|
|
172
|
-
success_definition: {
|
|
173
|
-
type: "string",
|
|
174
|
-
description: "Narrative description of what a successful optimized output achieves (e.g. 'reader understands why churn drives flat revenue even with user growth')."
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
},
|
|
179
|
-
required: ["prompt"]
|
|
180
|
-
}
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
name: "get_quota_status",
|
|
184
|
-
description: "📊 Check subscription status, quota usage, and account information with detailed insights and Bayesian optimization metrics",
|
|
185
|
-
inputSchema: { type: "object", properties: {}, additionalProperties: false }
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
name: "create_template",
|
|
189
|
-
description: "➕ Create a new optimization template.",
|
|
190
|
-
inputSchema: {
|
|
191
|
-
type: "object",
|
|
192
|
-
properties: {
|
|
193
|
-
title: { type: "string", description: "Title of the template" },
|
|
194
|
-
description: { type: "string", description: "Description of the template" },
|
|
195
|
-
original_prompt: { type: "string", description: "The original prompt text" },
|
|
196
|
-
optimized_prompt: { type: "string", description: "The optimized prompt text" },
|
|
197
|
-
optimization_goals: { type: "array", items: { type: "string" }, description: "Goals for this optimization (e.g., 'clarity', 'conciseness', 'creativity', 'technical_accuracy', 'analytical_depth', 'creative_enhancement')" },
|
|
198
|
-
confidence_score: { type: "number", description: "Confidence score of the optimization (0.0-1.0)" },
|
|
199
|
-
model_used: { type: "string", description: "Model used for optimization" },
|
|
200
|
-
optimization_tier: { type: "string", description: "Tier of optimization (e.g., rules, llm, hybrid)" },
|
|
201
|
-
ai_context_detected: { type: "string", description: "Detected AI context (e.g., code_generation, image_generation)" },
|
|
202
|
-
is_public: { type: "boolean", default: false, description: "Whether the template is public" },
|
|
203
|
-
tags: { type: "array", items: { type: "string" }, description: "Tags for the template" }
|
|
204
|
-
},
|
|
205
|
-
required: ["title", "original_prompt", "optimized_prompt", "confidence_score"]
|
|
206
|
-
}
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
name: "get_template",
|
|
210
|
-
description: "🔍 Retrieve a specific template by its ID.",
|
|
211
|
-
inputSchema: {
|
|
212
|
-
type: "object",
|
|
213
|
-
properties: {
|
|
214
|
-
template_id: { type: "string", description: "The ID of the template to retrieve" }
|
|
215
|
-
},
|
|
216
|
-
required: ["template_id"]
|
|
217
|
-
}
|
|
218
|
-
},
|
|
219
|
-
{
|
|
220
|
-
name: "update_template",
|
|
221
|
-
description: "✏️ Update an existing optimization template.",
|
|
222
|
-
inputSchema: {
|
|
223
|
-
type: "object",
|
|
224
|
-
properties: {
|
|
225
|
-
template_id: { type: "string", description: "The ID of the template to update" },
|
|
226
|
-
title: { type: "string", description: "New title for the template" },
|
|
227
|
-
description: { type: "string", description: "New description for the template" },
|
|
228
|
-
original_prompt: { type: "string", description: "New original prompt text" },
|
|
229
|
-
optimized_prompt: { type: "string", description: "New optimized prompt text" },
|
|
230
|
-
optimization_goals: { type: "array", items: { type: "string" }, description: "New optimization goals" },
|
|
231
|
-
confidence_score: { type: "number", description: "New confidence score (0.0-1.0)" },
|
|
232
|
-
model_used: { type: "string", description: "New model used for optimization" },
|
|
233
|
-
optimization_tier: { type: "string", description: "New tier of optimization" },
|
|
234
|
-
ai_context_detected: { type: "string", description: "New detected AI context" },
|
|
235
|
-
is_public: { type: "boolean", description: "Whether the template is public" },
|
|
236
|
-
tags: { type: "array", items: { type: "string" }, description: "New tags for the template" }
|
|
237
|
-
},
|
|
238
|
-
required: ["template_id"]
|
|
239
|
-
}
|
|
240
|
-
},
|
|
241
|
-
{
|
|
242
|
-
name: "delete_template",
|
|
243
|
-
description: "🗑️ Delete a saved optimization template by ID.",
|
|
244
|
-
inputSchema: {
|
|
245
|
-
type: "object",
|
|
246
|
-
properties: {
|
|
247
|
-
template_id: { type: "string", description: "The ID of the template to delete" }
|
|
248
|
-
},
|
|
249
|
-
required: ["template_id"]
|
|
250
|
-
}
|
|
251
|
-
},
|
|
252
|
-
{
|
|
253
|
-
name: "search_templates",
|
|
254
|
-
description: "🔍 Search your saved template library with AI-aware filtering, context-based search, and sophisticated template matching",
|
|
255
|
-
inputSchema: {
|
|
256
|
-
type: "object",
|
|
257
|
-
properties: {
|
|
258
|
-
query: {
|
|
259
|
-
type: "string",
|
|
260
|
-
description: "Search term to filter templates by content or title"
|
|
261
|
-
},
|
|
262
|
-
ai_context: {
|
|
263
|
-
type: "string",
|
|
264
|
-
enum: ["human_communication", "llm_interaction", "image_generation", "technical_automation", "structured_output", "code_generation", "api_automation"],
|
|
265
|
-
description: "Filter templates by AI context type"
|
|
266
|
-
},
|
|
267
|
-
sophistication_level: {
|
|
268
|
-
type: "string",
|
|
269
|
-
enum: ["basic", "intermediate", "advanced", "expert"],
|
|
270
|
-
description: "Filter by template sophistication level"
|
|
271
|
-
},
|
|
272
|
-
complexity_level: {
|
|
273
|
-
type: "string",
|
|
274
|
-
enum: ["simple", "moderate", "complex", "very_complex"],
|
|
275
|
-
description: "Filter by template complexity level"
|
|
276
|
-
},
|
|
277
|
-
optimization_strategy: {
|
|
278
|
-
type: "string",
|
|
279
|
-
description: "Filter by optimization strategy used"
|
|
280
|
-
},
|
|
281
|
-
limit: {
|
|
282
|
-
type: "number",
|
|
283
|
-
default: 5,
|
|
284
|
-
description: "Number of templates to return (1-20)"
|
|
285
|
-
},
|
|
286
|
-
page: {
|
|
287
|
-
type: "number",
|
|
288
|
-
default: 1,
|
|
289
|
-
description: "Page number for pagination (use with limit to access results beyond the first page)"
|
|
290
|
-
},
|
|
291
|
-
sort_by: {
|
|
292
|
-
type: "string",
|
|
293
|
-
enum: ["created_at", "confidence_score", "usage_count", "title"],
|
|
294
|
-
default: "confidence_score",
|
|
295
|
-
description: "Sort templates by field"
|
|
296
|
-
},
|
|
297
|
-
sort_order: {
|
|
298
|
-
type: "string",
|
|
299
|
-
enum: ["asc", "desc"],
|
|
300
|
-
default: "desc",
|
|
301
|
-
description: "Sort order"
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
},
|
|
306
|
-
{
|
|
307
|
-
name: "list_recent_templates",
|
|
308
|
-
description: "📋 List your most recently saved optimization templates, sorted by creation date.",
|
|
309
|
-
inputSchema: {
|
|
310
|
-
type: "object",
|
|
311
|
-
properties: {
|
|
312
|
-
limit: {
|
|
313
|
-
type: "number",
|
|
314
|
-
default: 10,
|
|
315
|
-
description: "Number of recent templates to return (1-20)"
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
},
|
|
320
|
-
{
|
|
321
|
-
name: "detect_ai_context",
|
|
322
|
-
description: "🧠 Detects the AI context for a given prompt using advanced backend analysis.",
|
|
323
|
-
inputSchema: {
|
|
324
|
-
type: "object",
|
|
325
|
-
properties: {
|
|
326
|
-
prompt: {
|
|
327
|
-
type: "string",
|
|
328
|
-
description: "The prompt text for which to detect the AI context"
|
|
329
|
-
}
|
|
330
|
-
},
|
|
331
|
-
required: ["prompt"]
|
|
332
|
-
}
|
|
333
|
-
},
|
|
334
|
-
{
|
|
335
|
-
name: "generate_agent_sop",
|
|
336
|
-
description: "Generate a structured SOP document for an AI agent from a goal description.",
|
|
337
|
-
inputSchema: {
|
|
338
|
-
type: "object",
|
|
339
|
-
properties: {
|
|
340
|
-
goal: { type: "string", description: "What the agent should accomplish" },
|
|
341
|
-
context: { type: "string", description: "Additional context (optional)" },
|
|
342
|
-
model_id: { type: "string", description: "Model to use (optional)" },
|
|
343
|
-
intent_frame: {
|
|
344
|
-
type: "object",
|
|
345
|
-
description: "Optional IntentFrame to sharpen SOP scope and success criteria.",
|
|
346
|
-
properties: {
|
|
347
|
-
perspective: { type: "string", description: "The agent role or viewpoint (e.g. DevOps engineer)." },
|
|
348
|
-
out_of_scope: { type: "string", description: "What is explicitly excluded from this workflow." },
|
|
349
|
-
success_definition: { type: "string", description: "Measurable criteria that define success." }
|
|
350
|
-
},
|
|
351
|
-
additionalProperties: false
|
|
352
|
-
}
|
|
353
|
-
},
|
|
354
|
-
required: ["goal"]
|
|
355
|
-
}
|
|
356
|
-
},
|
|
357
|
-
{
|
|
358
|
-
name: "generate_skill_package",
|
|
359
|
-
description: "Generate a complete skill package (SOP + SKILL.md + examples + helper.py) for an AI agent. Takes 30-120 seconds (async).",
|
|
360
|
-
inputSchema: {
|
|
361
|
-
type: "object",
|
|
362
|
-
properties: {
|
|
363
|
-
goal: { type: "string", description: "What the agent should accomplish" },
|
|
364
|
-
format: { type: "string", enum: ["knowledge_doc", "agent_spec"], description: "Output format" },
|
|
365
|
-
model_id: { type: "string", description: "Model to use (optional)" }
|
|
366
|
-
},
|
|
367
|
-
required: ["goal"]
|
|
368
|
-
}
|
|
369
|
-
},
|
|
370
|
-
{
|
|
371
|
-
name: "transform_for_framework",
|
|
372
|
-
description: "Transform a SOP into native code for LangChain, AutoGen, or Claude Code.",
|
|
373
|
-
inputSchema: {
|
|
374
|
-
type: "object",
|
|
375
|
-
properties: {
|
|
376
|
-
sop_content: { type: "string", description: "SOP content to transform" },
|
|
377
|
-
goal: { type: "string", description: "What the agent should accomplish" },
|
|
378
|
-
framework: { type: "string", enum: ["langchain_tool", "autogen_agent", "claude_skill"], description: "Target framework" }
|
|
379
|
-
},
|
|
380
|
-
required: ["sop_content", "goal", "framework"]
|
|
381
|
-
}
|
|
382
|
-
},
|
|
383
|
-
{
|
|
384
|
-
name: "get_ce_quota_status",
|
|
385
|
-
description: "Check your Context Engineer credit balance and available workflow types.",
|
|
386
|
-
inputSchema: { type: "object", properties: {}, additionalProperties: false }
|
|
387
|
-
},
|
|
388
|
-
{
|
|
389
|
-
name: "generate_harness_bundle",
|
|
390
|
-
description: (
|
|
391
|
-
"Generate a deployment-ready Agentic Harness ZIP bundle for a specific platform. "
|
|
392
|
-
+ "Returns a confirmation message when the bundle is queued. "
|
|
393
|
-
+ "Explorer+ required for non-default deploy targets."
|
|
394
|
-
),
|
|
395
|
-
inputSchema: {
|
|
396
|
-
type: "object",
|
|
397
|
-
properties: {
|
|
398
|
-
goal: {
|
|
399
|
-
type: "string",
|
|
400
|
-
description: "The workflow goal the harness is built for."
|
|
401
|
-
},
|
|
402
|
-
deploy_target: {
|
|
403
|
-
oneOf: [
|
|
404
|
-
{
|
|
405
|
-
type: "string",
|
|
406
|
-
enum: DEPLOY_TARGET_ENUM,
|
|
407
|
-
description: "Single deploy target."
|
|
408
|
-
},
|
|
409
|
-
{
|
|
410
|
-
type: "array",
|
|
411
|
-
minItems: 1,
|
|
412
|
-
items: {
|
|
413
|
-
type: "string",
|
|
414
|
-
enum: DEPLOY_TARGET_ENUM
|
|
415
|
-
},
|
|
416
|
-
description: "Multiple deploy targets simultaneously (Creator+ required)."
|
|
417
|
-
}
|
|
418
|
-
],
|
|
419
|
-
description: (
|
|
420
|
-
"Target deployment platform(s). Single string (Explorer+) or array (Creator+). "
|
|
421
|
-
+ "amazon_q, aider, continue_dev, crewai require Creator+. "
|
|
422
|
-
+ "Default: claude_code."
|
|
423
|
-
)
|
|
424
|
-
},
|
|
425
|
-
session_id: {
|
|
426
|
-
type: "string",
|
|
427
|
-
description: "Optional: session ID from a prior generate_skill_package call to reuse SOP."
|
|
428
|
-
},
|
|
429
|
-
sop_content: {
|
|
430
|
-
type: "string",
|
|
431
|
-
description: "The SOP content to base the harness on (required if no session_id)."
|
|
432
|
-
}
|
|
433
|
-
},
|
|
434
|
-
required: ["goal"]
|
|
435
|
-
}
|
|
436
|
-
},
|
|
437
|
-
{
|
|
438
|
-
name: "explore_sop_approaches",
|
|
439
|
-
description: (
|
|
440
|
-
"Generate 3 parallel SOP variants (process-oriented, decision-tree, role-based) for comparison before committing. " +
|
|
441
|
-
"Returns exploration_html (self-contained comparison grid), variants array, and a recommended variant. " +
|
|
442
|
-
"Innovator tier required. " +
|
|
443
|
-
"Optionally provide blend_description to skip comparison and receive a single blended SOP instead."
|
|
444
|
-
),
|
|
445
|
-
inputSchema: {
|
|
446
|
-
type: "object",
|
|
447
|
-
properties: {
|
|
448
|
-
goal: {
|
|
449
|
-
type: "string",
|
|
450
|
-
description: "The workflow goal to generate SOP variants for"
|
|
451
|
-
},
|
|
452
|
-
context: {
|
|
453
|
-
type: "string",
|
|
454
|
-
description: "Optional background context or documentation excerpt"
|
|
455
|
-
},
|
|
456
|
-
blend_description: {
|
|
457
|
-
type: "string",
|
|
458
|
-
description: "Optional: if provided, skips variant comparison and blends all 3 into one SOP using this description"
|
|
459
|
-
},
|
|
460
|
-
perspective: { type: "string", description: "Agent role or viewpoint (IntentFrame)" },
|
|
461
|
-
out_of_scope: { type: "string", description: "What is explicitly excluded (IntentFrame)" },
|
|
462
|
-
success_definition: { type: "string", description: "Measurable success criteria (IntentFrame)" },
|
|
463
|
-
},
|
|
464
|
-
required: ["goal"],
|
|
465
|
-
additionalProperties: false
|
|
466
|
-
}
|
|
467
|
-
},
|
|
468
|
-
];
|
|
469
|
-
|
|
470
|
-
// Add advanced tools if Bayesian optimization is enabled
|
|
471
|
-
if (this.bayesianOptimizationEnabled) {
|
|
472
|
-
baseTools.push({
|
|
473
|
-
name: "get_optimization_insights",
|
|
474
|
-
description: "🧠 Get advanced Bayesian optimization insights, performance analytics, and parameter tuning recommendations",
|
|
475
|
-
inputSchema: {
|
|
476
|
-
type: "object",
|
|
477
|
-
properties: {
|
|
478
|
-
analysis_depth: {
|
|
479
|
-
type: "string",
|
|
480
|
-
enum: ["basic", "detailed", "comprehensive"],
|
|
481
|
-
default: "detailed",
|
|
482
|
-
description: "Depth of analysis to provide"
|
|
483
|
-
},
|
|
484
|
-
include_recommendations: {
|
|
485
|
-
type: "boolean",
|
|
486
|
-
default: true,
|
|
487
|
-
description: "Include optimization recommendations"
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
// Add AG-UI tools if enabled
|
|
495
|
-
if (this.aguiFeatures) {
|
|
496
|
-
baseTools.push({
|
|
497
|
-
name: "get_real_time_status",
|
|
498
|
-
description: "⚡ Get real-time optimization status, AG-UI capabilities, and streaming optimization availability",
|
|
499
|
-
inputSchema: { type: "object", properties: {}, additionalProperties: false }
|
|
500
|
-
});
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
return { tools: baseTools };
|
|
504
|
-
});
|
|
505
|
-
|
|
506
|
-
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
507
|
-
const { name, arguments: args } = request.params;
|
|
508
|
-
try {
|
|
509
|
-
switch (name) {
|
|
510
|
-
case "optimize_prompt": return await this.handleOptimizePrompt(args);
|
|
511
|
-
case "get_quota_status": return await this.handleGetQuotaStatus();
|
|
512
|
-
case "search_templates": return await this.handleSearchTemplates(args);
|
|
513
|
-
case "list_recent_templates": return await this.handleListRecentTemplates(args);
|
|
514
|
-
case "detect_ai_context": return await this.handleDetectAIContext(args);
|
|
515
|
-
case "create_template": return await this.handleCreateTemplate(args);
|
|
516
|
-
case "get_template": return await this.handleGetTemplate(args);
|
|
517
|
-
case "update_template": return await this.handleUpdateTemplate(args);
|
|
518
|
-
case "delete_template": return await this.handleDeleteTemplate(args);
|
|
519
|
-
case "get_optimization_insights": return await this.handleGetOptimizationInsights(args);
|
|
520
|
-
case "get_real_time_status": return await this.handleGetRealTimeStatus();
|
|
521
|
-
case "generate_agent_sop": return await this.handleGenerateAgentSop(args);
|
|
522
|
-
case "generate_skill_package": return await this.handleGenerateSkillPackage(args);
|
|
523
|
-
case "transform_for_framework": return await this.handleTransformForFramework(args);
|
|
524
|
-
case "get_ce_quota_status": return await this.handleGetCEQuotaStatus();
|
|
525
|
-
case "generate_harness_bundle": return await this.handleGenerateHarnessBundle(args);
|
|
526
|
-
case "explore_sop_approaches": return await this.handleExploreSopApproaches(args);
|
|
527
|
-
default: throw new Error(`Unknown tool: ${name}`);
|
|
528
|
-
}
|
|
529
|
-
} catch (error) {
|
|
530
|
-
throw new Error(`Tool execution failed: ${error.message}`);
|
|
531
|
-
}
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
// ─── Rules-Based Optimization (offline / fallback tier) ─────────────────────
|
|
536
|
-
|
|
537
|
-
/**
|
|
538
|
-
* Select the best-matching template for a prompt using pattern scoring.
|
|
539
|
-
* Mirrors the backend's pattern-based fallback (no LLM required).
|
|
540
|
-
*/
|
|
541
|
-
_matchTemplate(prompt, backendContext) {
|
|
542
|
-
const lc = prompt.toLowerCase();
|
|
543
|
-
let bestTemplate = null;
|
|
544
|
-
let bestScore = 0;
|
|
545
|
-
let fallbackName = null;
|
|
546
|
-
|
|
547
|
-
for (const [name, template] of Object.entries(OPTIMIZATION_TEMPLATES)) {
|
|
548
|
-
if (template.context !== backendContext) continue;
|
|
549
|
-
if (name.startsWith('fallback_')) { fallbackName = name; continue; }
|
|
550
|
-
|
|
551
|
-
let hits = 0;
|
|
552
|
-
for (const pattern of template.patterns) {
|
|
553
|
-
if (pattern === '.*') continue;
|
|
554
|
-
if (lc.includes(pattern.toLowerCase())) hits++;
|
|
555
|
-
}
|
|
556
|
-
if (hits === 0) continue;
|
|
557
|
-
|
|
558
|
-
// Confidence: 1 hit → 0.6, 2 hits → 0.75, 3+ hits → 0.9 (mirrors backend)
|
|
559
|
-
const patternConf = hits === 1 ? 0.6 : hits === 2 ? 0.75 : 0.9;
|
|
560
|
-
const score = patternConf + (template.priority || 1) / 100;
|
|
561
|
-
|
|
562
|
-
if (score > bestScore) { bestScore = score; bestTemplate = name; }
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
if (!bestTemplate) {
|
|
566
|
-
return { templateName: fallbackName || `fallback_${backendContext.toLowerCase()}`, matchConfidence: 0.3 };
|
|
567
|
-
}
|
|
568
|
-
return { templateName: bestTemplate, matchConfidence: bestScore };
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
/** Extract a user-defined role from the start of a prompt (e.g. "As a doctor, …"). */
|
|
572
|
-
_extractUserRole(request) {
|
|
573
|
-
const rolePatterns = [
|
|
574
|
-
/^['"]?(?:As a|You are a|My role is)\s+([a-zA-Z0-9\s\-/()]+?)(?:,|(?=\s*\.))/i,
|
|
575
|
-
/^['"]?(?:I am a|I'm a)\s+([a-zA-Z0-9\s\-/()]+?)(?:,|(?=\s*\.))/i,
|
|
576
|
-
];
|
|
577
|
-
for (const re of rolePatterns) {
|
|
578
|
-
const m = request.match(re);
|
|
579
|
-
if (m) return m[1].trim();
|
|
580
|
-
}
|
|
581
|
-
return null;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
/**
|
|
585
|
-
* Compile a template playbook into a user-facing prose prompt.
|
|
586
|
-
* Produces readable output instead of XML scaffolding, matching the
|
|
587
|
-
* result a backend LLM pass would generate from the same playbook.
|
|
588
|
-
*/
|
|
589
|
-
_compilePlaybook(playbook, originalRequest) {
|
|
590
|
-
const parts = [];
|
|
591
|
-
|
|
592
|
-
parts.push(originalRequest.trim());
|
|
593
|
-
parts.push('');
|
|
594
|
-
|
|
595
|
-
const userFacingPrinciples = (playbook.principles || []).filter(p => {
|
|
596
|
-
const lc = p.toLowerCase();
|
|
597
|
-
return !lc.includes('scratchpad') &&
|
|
598
|
-
!lc.startsWith('first, think') &&
|
|
599
|
-
!/<[a-z]/i.test(p);
|
|
600
|
-
});
|
|
601
|
-
|
|
602
|
-
if (userFacingPrinciples.length > 0) {
|
|
603
|
-
parts.push('To address this effectively:');
|
|
604
|
-
for (const p of userFacingPrinciples) parts.push(`- ${p}`);
|
|
605
|
-
parts.push('');
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
if (playbook.output_format) {
|
|
609
|
-
parts.push(`*Response format: ${playbook.output_format}*`);
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
return parts.join('\n');
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
/**
|
|
616
|
-
* Enhance an image generation prompt by appending style-appropriate
|
|
617
|
-
* quality/composition boosters (mirrors backend _compile_image_prompt_fallback).
|
|
618
|
-
*/
|
|
619
|
-
_compileImagePrompt(originalRequest) {
|
|
620
|
-
const text = originalRequest.trim();
|
|
621
|
-
const lc = text.toLowerCase();
|
|
622
|
-
|
|
623
|
-
const styles = {
|
|
624
|
-
photorealistic: ['photorealistic','realistic','photo','photograph','photography'],
|
|
625
|
-
'3d_render': ['3d','render','octane','unreal engine','blender','cinema 4d','ray tracing'],
|
|
626
|
-
cinematic: ['cinematic','movie','film','dramatic','epic'],
|
|
627
|
-
digital_art: ['digital art','concept art','digital illustration','cg','cgi'],
|
|
628
|
-
artistic: ['artistic','painting','watercolor','oil painting','impressionist'],
|
|
629
|
-
anime: ['anime','manga'],
|
|
630
|
-
vintage: ['vintage','retro','nostalgic'],
|
|
631
|
-
minimalist: ['minimalist','minimal','simple','clean'],
|
|
632
|
-
};
|
|
633
|
-
|
|
634
|
-
let detectedStyle = null;
|
|
635
|
-
for (const [style, kws] of Object.entries(styles)) {
|
|
636
|
-
if (kws.some(kw => lc.includes(kw))) { detectedStyle = style; break; }
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
const enhancements = [];
|
|
640
|
-
const hasQuality = ['high quality','8k','4k','hd','highly detailed','detailed'].some(t => lc.includes(t));
|
|
641
|
-
const hasLighting = ['lighting','light','shadow','illuminated','lit'].some(t => lc.includes(t));
|
|
642
|
-
const hasComposition = ['composition','rule of thirds','centered','framed'].some(t => lc.includes(t));
|
|
643
|
-
|
|
644
|
-
if (detectedStyle === 'photorealistic' && !hasQuality) {
|
|
645
|
-
enhancements.push('ultra realistic, sharp focus, professional photography');
|
|
646
|
-
} else if (detectedStyle === '3d_render' && !['octane','render'].some(t => lc.includes(t))) {
|
|
647
|
-
enhancements.push('high quality 3D render, volumetric lighting, ray traced shadows');
|
|
648
|
-
} else if (detectedStyle === 'cinematic' && !hasLighting) {
|
|
649
|
-
enhancements.push('cinematic lighting, dramatic atmosphere, film grain');
|
|
650
|
-
} else if (detectedStyle === 'digital_art' && !hasQuality) {
|
|
651
|
-
enhancements.push('highly detailed digital art, professional illustration');
|
|
652
|
-
} else if (detectedStyle === 'artistic' && !lc.includes('masterpiece')) {
|
|
653
|
-
enhancements.push('masterful technique, rich colors, artistic composition');
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
if (!hasLighting && detectedStyle !== 'minimalist') enhancements.push('dynamic lighting');
|
|
657
|
-
if (!hasComposition) enhancements.push('balanced composition');
|
|
658
|
-
if (!hasQuality) enhancements.push('high quality, 4K');
|
|
659
|
-
|
|
660
|
-
return enhancements.length > 0 ? `${text}, ${enhancements.join(', ')}` : text;
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
/**
|
|
664
|
-
* Core rules-based optimizer — no network, no LLM.
|
|
665
|
-
* Selects the best template by pattern matching, then compiles
|
|
666
|
-
* the playbook into a structured prompt. Confidence range: 0.35–0.55.
|
|
667
|
-
*/
|
|
668
|
-
rulesBasedOptimize(prompt, aiContext, goals = []) {
|
|
669
|
-
const contextMap = {
|
|
670
|
-
code_generation: 'CODE_GENERATION',
|
|
671
|
-
llm_interaction: 'LLM_INTERACTION',
|
|
672
|
-
image_generation: 'IMAGE_GENERATION',
|
|
673
|
-
human_communication: 'HUMAN_COMMUNICATION',
|
|
674
|
-
api_automation: 'API_AUTOMATION',
|
|
675
|
-
technical_automation: 'TECHNICAL_AUTOMATION',
|
|
676
|
-
structured_output: 'STRUCTURED_OUTPUT',
|
|
677
|
-
creative_enhancement: 'CREATIVE_ENHANCEMENT',
|
|
678
|
-
creative_writing: 'CREATIVE_ENHANCEMENT',
|
|
679
|
-
general_assistant: 'LLM_INTERACTION',
|
|
680
|
-
};
|
|
681
|
-
const backendContext = contextMap[aiContext] || 'LLM_INTERACTION';
|
|
682
|
-
|
|
683
|
-
const { templateName, matchConfidence } = this._matchTemplate(prompt, backendContext);
|
|
684
|
-
const template = OPTIMIZATION_TEMPLATES[templateName];
|
|
685
|
-
|
|
686
|
-
const optimizedPrompt = backendContext === 'IMAGE_GENERATION'
|
|
687
|
-
? this._compileImagePrompt(prompt)
|
|
688
|
-
: this._compilePlaybook(template.playbook, prompt);
|
|
689
|
-
|
|
690
|
-
// Honest confidence: rules-based tops out around 0.55
|
|
691
|
-
const confidence = parseFloat(Math.min(0.35 + matchConfidence * 0.2, 0.55).toFixed(2));
|
|
692
|
-
|
|
693
|
-
return {
|
|
694
|
-
optimized_prompt: optimizedPrompt,
|
|
695
|
-
confidence_score: confidence,
|
|
696
|
-
tier: 'rules',
|
|
697
|
-
template_used: templateName,
|
|
698
|
-
rules_based: true,
|
|
699
|
-
template_saved: false,
|
|
700
|
-
templates_found: [],
|
|
701
|
-
optimization_insights: null,
|
|
702
|
-
bayesian_insights: null,
|
|
703
|
-
};
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
// ─── End Rules-Based Optimization ────────────────────────────────────────────
|
|
707
|
-
|
|
708
|
-
generateMockOptimization(prompt, goals, aiContext, enableBayesian = false) {
|
|
709
|
-
// Use real rules-based optimization instead of fake placeholder output
|
|
710
|
-
const rulesResult = this.rulesBasedOptimize(prompt, aiContext, goals);
|
|
711
|
-
const baseResult = {
|
|
712
|
-
...rulesResult,
|
|
713
|
-
rules_based: false, // Show as normal optimized output in mock mode
|
|
714
|
-
tier: 'free',
|
|
715
|
-
mock_mode: true,
|
|
716
|
-
template_saved: true,
|
|
717
|
-
template_id: 'test-template-123',
|
|
718
|
-
templates_found: [{ title: 'Similar Template 1', confidence_score: 0.85, id: 'tmpl-1' }],
|
|
719
|
-
optimization_insights: {
|
|
720
|
-
improvement_metrics: {
|
|
721
|
-
clarity_improvement: 0.25,
|
|
722
|
-
specificity_improvement: 0.20,
|
|
723
|
-
length_optimization: 0.15,
|
|
724
|
-
context_alignment: 0.30
|
|
725
|
-
},
|
|
726
|
-
user_patterns: {
|
|
727
|
-
optimization_confidence: '87.0%',
|
|
728
|
-
prompt_complexity: 'intermediate',
|
|
729
|
-
ai_context: aiContext
|
|
730
|
-
},
|
|
731
|
-
recommendations: [
|
|
732
|
-
`Context detected as ${aiContext}`,
|
|
733
|
-
'Enhanced goal optimization applied',
|
|
734
|
-
'Template auto-save threshold met'
|
|
735
|
-
]
|
|
736
|
-
}
|
|
737
|
-
};
|
|
738
|
-
|
|
739
|
-
// Add Bayesian optimization insights if enabled
|
|
740
|
-
if (enableBayesian && this.bayesianOptimizationEnabled) {
|
|
741
|
-
baseResult.bayesian_insights = {
|
|
742
|
-
parameter_optimization: {
|
|
743
|
-
temperature_adjustment: '+0.1',
|
|
744
|
-
context_weight: '+0.15',
|
|
745
|
-
goal_prioritization: 'clarity > specificity > engagement'
|
|
746
|
-
},
|
|
747
|
-
performance_prediction: {
|
|
748
|
-
expected_improvement: '12-18%',
|
|
749
|
-
confidence_interval: '85-95%',
|
|
750
|
-
optimization_strategy: 'gradient_boost_context'
|
|
751
|
-
},
|
|
752
|
-
next_optimization_recommendation: {
|
|
753
|
-
suggested_goals: ['analytical_depth', 'creative_enhancement'],
|
|
754
|
-
estimated_improvement: '8-12%'
|
|
755
|
-
}
|
|
756
|
-
};
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
return baseResult;
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
generateMockContextDetection(prompt) {
|
|
763
|
-
let primary_context = 'human_communication'; // Default context
|
|
764
|
-
const lc = prompt.toLowerCase(); // one‑off lower‑case copy
|
|
765
|
-
|
|
766
|
-
/* 1️⃣ Code / programming – now includes `def` / `return`. */
|
|
767
|
-
if (lc.match(/def\b|return\b|import\b|class\b|for\b|while\b|if\b|else\b|elif\b|function\b|code\b|python|javascript|java|c\+\+/i)) {
|
|
768
|
-
primary_context = 'code_generation';
|
|
769
|
-
|
|
770
|
-
/* 2️⃣ Image / art – unchanged. */
|
|
771
|
-
} else if (lc.match(/image|generate|dall-e|midjourney/i)) {
|
|
772
|
-
primary_context = 'image_generation';
|
|
773
|
-
|
|
774
|
-
/* 3️⃣ Automation – unchanged. */
|
|
775
|
-
} else if (lc.match(/automate|script|api/i)) {
|
|
776
|
-
primary_context = 'technical_automation';
|
|
777
|
-
|
|
778
|
-
/* 4️⃣ LLM / analysis – newly added keyword “analyze”. */
|
|
779
|
-
} else if (lc.match(/analyze|explain|evaluate|summary|research|paper|analysis|interpret|discussion|assessment|compare|contrast/i)) {
|
|
780
|
-
primary_context = 'llm_interaction';
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
return {
|
|
784
|
-
primary_context: primary_context,
|
|
785
|
-
confidence: 0.75,
|
|
786
|
-
secondary_contexts: ['llm_interaction'],
|
|
787
|
-
detected_parameters: [],
|
|
788
|
-
mock_mode: true,
|
|
789
|
-
reason: 'Backend unavailable — using local pattern matching as fallback.'
|
|
790
|
-
};
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
async handleOptimizePrompt(args) {
|
|
794
|
-
if (!args.prompt) throw new Error('Prompt is required');
|
|
795
|
-
|
|
796
|
-
const manager = new CloudApiKeyManager(this.apiKey);
|
|
797
|
-
|
|
798
|
-
try {
|
|
799
|
-
const validation = await manager.validateApiKey();
|
|
800
|
-
|
|
801
|
-
if (validation.mock_mode || this.developmentMode) {
|
|
802
|
-
// In mock/dev mode, we still need a context for mock generation
|
|
803
|
-
const mockContext = args.ai_context || 'human_communication';
|
|
804
|
-
const mockGoals = args.goals || ['clarity'];
|
|
805
|
-
const mockEnableBayesian = args.enable_bayesian !== false && this.bayesianOptimizationEnabled;
|
|
806
|
-
const mockResult = this.generateMockOptimization(args.prompt, mockGoals, mockContext, mockEnableBayesian);
|
|
807
|
-
const formatted = this.formatOptimizationResult(mockResult, { detectedContext: mockContext, enableBayesian: mockEnableBayesian });
|
|
808
|
-
return { content: [{ type: "text", text: formatted }] };
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
// 1. Detect AI Context from backend
|
|
812
|
-
let detectedContext = args.ai_context;
|
|
813
|
-
if (!detectedContext) {
|
|
814
|
-
try {
|
|
815
|
-
const contextDetectionResult = await this.callBackendAPI(ENDPOINTS.DETECT_CONTEXT, { prompt: args.prompt });
|
|
816
|
-
detectedContext = contextDetectionResult.primary_context;
|
|
817
|
-
console.error(`Detected AI Context from backend: ${detectedContext}`);
|
|
818
|
-
} catch (contextError) {
|
|
819
|
-
console.error(`Failed to detect AI context from backend, falling back to default: ${contextError.message}`);
|
|
820
|
-
detectedContext = 'human_communication'; // Fallback
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
// 2. Call the main optimization endpoint
|
|
825
|
-
const optimizationPayload = {
|
|
826
|
-
prompt: args.prompt,
|
|
827
|
-
goals: args.goals || ['clarity'],
|
|
828
|
-
ai_context: detectedContext,
|
|
829
|
-
};
|
|
830
|
-
|
|
831
|
-
if (args.value_hierarchy && args.value_hierarchy.length > 0) {
|
|
832
|
-
optimizationPayload.value_hierarchy = args.value_hierarchy;
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
if (args.intent_frame && typeof args.intent_frame === 'object') {
|
|
836
|
-
const { perspective, out_of_scope, success_definition } = args.intent_frame;
|
|
837
|
-
if (perspective || (out_of_scope && out_of_scope.length > 0) || success_definition) {
|
|
838
|
-
optimizationPayload.intent_frame = args.intent_frame;
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
const result = await this.callBackendAPI(ENDPOINTS.OPTIMIZE, optimizationPayload);
|
|
843
|
-
|
|
844
|
-
const enableBayesian = args.enable_bayesian !== false && this.bayesianOptimizationEnabled;
|
|
845
|
-
return { content: [{ type: "text", text: this.formatOptimizationResult(result, { detectedContext, enableBayesian }) }] };
|
|
846
|
-
|
|
847
|
-
} catch (error) {
|
|
848
|
-
if (error.message.includes('Network') || error.message.includes('DNS') || error.message.includes('timeout') || error.message.includes('Connection')) {
|
|
849
|
-
const fallbackContext = args.ai_context || 'human_communication';
|
|
850
|
-
const fallbackEnableBayesian = args.enable_bayesian !== false && this.bayesianOptimizationEnabled;
|
|
851
|
-
const fallbackResult = this.rulesBasedOptimize(args.prompt, fallbackContext, args.goals || ['clarity']);
|
|
852
|
-
fallbackResult.fallback_mode = true;
|
|
853
|
-
fallbackResult.error_reason = error.message;
|
|
854
|
-
const formatted = this.formatOptimizationResult(fallbackResult, { detectedContext: fallbackContext, enableBayesian: fallbackEnableBayesian });
|
|
855
|
-
return { content: [{ type: "text", text: formatted }] };
|
|
856
|
-
}
|
|
857
|
-
throw new Error(`Optimization failed: ${error.message}`);
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
async handleGetQuotaStatus() {
|
|
862
|
-
const manager = new CloudApiKeyManager(this.apiKey);
|
|
863
|
-
const info = await manager.getApiKeyInfo();
|
|
864
|
-
return { content: [{ type: "text", text: this.formatQuotaStatus(info) }] };
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
async handleSearchTemplates(args) {
|
|
868
|
-
try {
|
|
869
|
-
const params = new URLSearchParams({
|
|
870
|
-
page: (args.page || 1).toString(),
|
|
871
|
-
per_page: Math.min(args.limit || 5, 20).toString(),
|
|
872
|
-
sort_by: args.sort_by || 'confidence_score',
|
|
873
|
-
sort_order: args.sort_order || 'desc'
|
|
874
|
-
});
|
|
875
|
-
|
|
876
|
-
if (args.query) params.append('query', args.query);
|
|
877
|
-
if (args.ai_context) params.append('ai_context', args.ai_context);
|
|
878
|
-
if (args.sophistication_level) params.append('sophistication_level', args.sophistication_level);
|
|
879
|
-
if (args.complexity_level) params.append('complexity_level', args.complexity_level);
|
|
880
|
-
if (args.optimization_strategy) params.append('optimization_strategy', args.optimization_strategy);
|
|
881
|
-
|
|
882
|
-
const endpoint = `${ENDPOINTS.SEARCH_TEMPLATES}?${params.toString()}`;
|
|
883
|
-
const result = await this.callBackendAPI(endpoint, null, 'GET');
|
|
884
|
-
|
|
885
|
-
const searchResult = {
|
|
886
|
-
templates: result.templates || [],
|
|
887
|
-
total: result.total || 0,
|
|
888
|
-
query: args.query,
|
|
889
|
-
ai_context: args.ai_context,
|
|
890
|
-
sophistication_level: args.sophistication_level,
|
|
891
|
-
complexity_level: args.complexity_level
|
|
892
|
-
};
|
|
893
|
-
|
|
894
|
-
const formatted = this.formatTemplateSearchResults(searchResult, args);
|
|
895
|
-
return { content: [{ type: "text", text: formatted }] };
|
|
896
|
-
|
|
897
|
-
} catch (error) {
|
|
898
|
-
console.error(`Template search failed: ${error.message}`);
|
|
899
|
-
const fallbackResult = {
|
|
900
|
-
templates: [],
|
|
901
|
-
total: 0,
|
|
902
|
-
message: "Template search is temporarily unavailable.",
|
|
903
|
-
error: error.message,
|
|
904
|
-
fallback_mode: true
|
|
905
|
-
};
|
|
906
|
-
const formatted = this.formatTemplateSearchResults(fallbackResult, args);
|
|
907
|
-
return { content: [{ type: "text", text: formatted }] };
|
|
908
|
-
}
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
async handleListRecentTemplates(args) {
|
|
912
|
-
try {
|
|
913
|
-
const limit = Math.min(Math.max(args.limit || 10, 1), 20);
|
|
914
|
-
const params = new URLSearchParams({
|
|
915
|
-
page: '1',
|
|
916
|
-
per_page: limit.toString(),
|
|
917
|
-
sort_by: 'created_at',
|
|
918
|
-
sort_order: 'desc'
|
|
919
|
-
});
|
|
920
|
-
|
|
921
|
-
const endpoint = `${ENDPOINTS.SEARCH_TEMPLATES}?${params.toString()}`;
|
|
922
|
-
const result = await this.callBackendAPI(endpoint, null, 'GET');
|
|
923
|
-
|
|
924
|
-
const templates = result.templates || [];
|
|
925
|
-
let output = `# 📋 Recent Templates\n\n`;
|
|
926
|
-
output += `Showing **${templates.length}** most recently saved template(s).\n\n`;
|
|
927
|
-
|
|
928
|
-
if (templates.length === 0) {
|
|
929
|
-
output += `📭 No templates found yet.\nRun \`optimize_prompt\` to start building your template library.\n`;
|
|
930
|
-
} else {
|
|
931
|
-
output += `## 📋 **Template Results**\n`;
|
|
932
|
-
templates.forEach((t, index) => {
|
|
933
|
-
const confidence = t.confidence_score ? `${(t.confidence_score * 100).toFixed(1)}%` : 'N/A';
|
|
934
|
-
const preview = t.optimized_prompt ? t.optimized_prompt.substring(0, 60) + '...' : 'Preview unavailable';
|
|
935
|
-
output += `### ${index + 1}. ${t.title}\n`;
|
|
936
|
-
output += `- **Confidence:** ${confidence}\n`;
|
|
937
|
-
output += `- **ID:** \`${t.id}\`\n`;
|
|
938
|
-
output += `- **Preview:** ${preview}\n`;
|
|
939
|
-
if (t.ai_context) output += `- **Context:** ${t.ai_context}\n`;
|
|
940
|
-
if (t.optimization_goals && t.optimization_goals.length) {
|
|
941
|
-
output += `- **Goals:** ${t.optimization_goals.join(', ')}\n`;
|
|
942
|
-
}
|
|
943
|
-
output += `\n`;
|
|
944
|
-
});
|
|
945
|
-
output += `💡 Use \`get_template\` with an ID above to view the full optimized prompt.\n`;
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
return { content: [{ type: "text", text: output }] };
|
|
949
|
-
} catch (error) {
|
|
950
|
-
return { content: [{ type: "text", text: `❌ Could not retrieve recent templates: ${error.message}` }] };
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
async handleGetOptimizationInsights(args) {
|
|
955
|
-
if (!this.bayesianOptimizationEnabled) {
|
|
956
|
-
return { content: [{ type: "text", text: "🧠 Bayesian optimization features are not enabled. Set ENABLE_BAYESIAN_OPTIMIZATION=true to access advanced insights." }] };
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
try {
|
|
960
|
-
// Try to get insights from backend
|
|
961
|
-
const endpoint = `${ENDPOINTS.ANALYTICS_BAYESIAN_INSIGHTS}?depth=${args.analysis_depth || 'detailed'}&recommendations=${args.include_recommendations !== false}`;
|
|
962
|
-
const result = await this.callBackendAPI(endpoint, null, 'GET');
|
|
963
|
-
|
|
964
|
-
return { content: [{ type: "text", text: this.formatOptimizationInsights(result) }] };
|
|
965
|
-
|
|
966
|
-
} catch (error) {
|
|
967
|
-
// Fallback to mock insights
|
|
968
|
-
const mockInsights = {
|
|
969
|
-
bayesian_status: {
|
|
970
|
-
optimization_active: true,
|
|
971
|
-
total_optimizations: 47,
|
|
972
|
-
improvement_rate: '23.5%',
|
|
973
|
-
confidence_score: 0.89
|
|
974
|
-
},
|
|
975
|
-
parameter_insights: {
|
|
976
|
-
most_effective_goals: ['clarity', 'technical_accuracy', 'analytical_depth'],
|
|
977
|
-
context_performance: {
|
|
978
|
-
'code_generation': 0.92,
|
|
979
|
-
'llm_interaction': 0.87,
|
|
980
|
-
'technical_automation': 0.84
|
|
981
|
-
},
|
|
982
|
-
optimization_trends: 'Steady improvement in technical contexts'
|
|
983
|
-
},
|
|
984
|
-
recommendations: args.include_recommendations !== false ? [
|
|
985
|
-
'Focus on technical_accuracy for code generation prompts',
|
|
986
|
-
'Combine clarity with analytical_depth for best results',
|
|
987
|
-
'Consider using structured_output context for data tasks'
|
|
988
|
-
] : []
|
|
989
|
-
};
|
|
990
|
-
|
|
991
|
-
return { content: [{ type: "text", text: this.formatOptimizationInsights(mockInsights) }] };
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
async handleGetRealTimeStatus() {
|
|
996
|
-
if (!this.aguiFeatures) {
|
|
997
|
-
return { content: [{ type: "text", text: "⚡ AG-UI real-time features are not enabled. Set ENABLE_AGUI_FEATURES=true to access real-time optimization capabilities." }] };
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
try {
|
|
1001
|
-
const result = await this.callBackendAPI(ENDPOINTS.AGUI_STATUS, null, 'GET');
|
|
1002
|
-
|
|
1003
|
-
return { content: [{ type: "text", text: this.formatRealTimeStatus(result) }] };
|
|
1004
|
-
|
|
1005
|
-
} catch (error) {
|
|
1006
|
-
const mockStatus = {
|
|
1007
|
-
agui_status: 'available',
|
|
1008
|
-
streaming_optimization: true,
|
|
1009
|
-
websocket_support: true,
|
|
1010
|
-
real_time_analytics: true,
|
|
1011
|
-
active_optimizations: 3,
|
|
1012
|
-
average_response_time: '1.2s',
|
|
1013
|
-
features: {
|
|
1014
|
-
live_optimization: true,
|
|
1015
|
-
collaborative_editing: true,
|
|
1016
|
-
instant_feedback: true,
|
|
1017
|
-
performance_monitoring: true
|
|
1018
|
-
}
|
|
1019
|
-
};
|
|
1020
|
-
|
|
1021
|
-
return { content: [{ type: "text", text: this.formatRealTimeStatus(mockStatus) }] };
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
async handleDetectAIContext(args) {
|
|
1026
|
-
if (!args.prompt) throw new Error('Prompt is required');
|
|
1027
|
-
|
|
1028
|
-
const formatResult = (result) => {
|
|
1029
|
-
let output = `# 🧠 AI Context Detection Result\n\n`;
|
|
1030
|
-
output += `**Primary Context:** ${result.primary_context}\n`;
|
|
1031
|
-
output += `**Confidence:** ${(result.confidence * 100).toFixed(1)}%\n`;
|
|
1032
|
-
if (result.secondary_contexts && result.secondary_contexts.length > 0) {
|
|
1033
|
-
output += `**Secondary Contexts:** ${result.secondary_contexts.join(', ')}\n`;
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
const detections = result.detected_parameters ?? [];
|
|
1037
|
-
const safeDetections = detections.filter(d => d && d.name);
|
|
1038
|
-
|
|
1039
|
-
if (safeDetections.length > 0) {
|
|
1040
|
-
output += `**Detected Parameters:** ${safeDetections.map(d => d.name).join(', ')}\n`;
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
if (result.mock_mode) {
|
|
1044
|
-
output += `\n⚠️ **Fallback Mode Active:** Using mock data due to development mode or network issues.\n`;
|
|
1045
|
-
}
|
|
1046
|
-
return { content: [{ type: "text", text: output }] };
|
|
1047
|
-
};
|
|
1048
|
-
|
|
1049
|
-
try {
|
|
1050
|
-
const manager = new CloudApiKeyManager(this.apiKey);
|
|
1051
|
-
const validation = await manager.validateApiKey();
|
|
1052
|
-
|
|
1053
|
-
if (validation.mock_mode || this.developmentMode) {
|
|
1054
|
-
const mockResult = this.generateMockContextDetection(args.prompt);
|
|
1055
|
-
return formatResult(mockResult);
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
const result = await this.callBackendAPI(ENDPOINTS.DETECT_CONTEXT, { prompt: args.prompt });
|
|
1059
|
-
return formatResult(result);
|
|
1060
|
-
|
|
1061
|
-
} catch (error) {
|
|
1062
|
-
// Fallback for ANY error during the process (missing key, network, etc.)
|
|
1063
|
-
const fallbackResult = this.generateMockContextDetection(args.prompt);
|
|
1064
|
-
return formatResult(fallbackResult);
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
async handleCreateTemplate(args) {
|
|
1069
|
-
// Client-side validation before network call
|
|
1070
|
-
const requiredStrings = ['title', 'original_prompt', 'optimized_prompt'];
|
|
1071
|
-
for (const field of requiredStrings) {
|
|
1072
|
-
if (!args[field] || typeof args[field] !== 'string' || args[field].trim() === '') {
|
|
1073
|
-
return { content: [{ type: "text", text: `❌ Missing required field: '${field}'. Required fields: title, original_prompt, optimized_prompt, confidence_score (0.0–1.0)` }] };
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
if (args.confidence_score === undefined || args.confidence_score === null ||
|
|
1077
|
-
typeof args.confidence_score !== 'number' || args.confidence_score < 0 || args.confidence_score > 1) {
|
|
1078
|
-
return { content: [{ type: "text", text: `❌ Missing required field: 'confidence_score'. Required fields: title, original_prompt, optimized_prompt, confidence_score (0.0–1.0)` }] };
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
try {
|
|
1082
|
-
const result = await this.callBackendAPI(ENDPOINTS.TEMPLATE.CREATE, args);
|
|
1083
|
-
let output = `# ✅ Template Created Successfully!\n\n`;
|
|
1084
|
-
output += `**Title:** ${result.title}\n`;
|
|
1085
|
-
output += `**ID:** \`${result.id}\`\n`;
|
|
1086
|
-
output += `**Confidence Score:** ${(result.confidence_score * 100).toFixed(1)}%\n`;
|
|
1087
|
-
output += `**AI Context:** ${result.ai_context_detected || 'N/A'}\n`;
|
|
1088
|
-
output += `**Public:** ${result.is_public ? 'Yes' : 'No'}\n`;
|
|
1089
|
-
output += `\n**Optimized Prompt Preview:**\n\`\`\`\n${result.optimized_prompt.substring(0, 150)}...\n\`\`\`\n`;
|
|
1090
|
-
return { content: [{ type: "text", text: output }] };
|
|
1091
|
-
} catch (error) {
|
|
1092
|
-
throw new Error(`Failed to create template: ${error.message}`);
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
async handleGetTemplate(args) {
|
|
1097
|
-
if (!args.template_id) throw new Error('Template ID is required');
|
|
1098
|
-
try {
|
|
1099
|
-
const result = await this.callBackendAPI(ENDPOINTS.TEMPLATE.GET(args.template_id), null, 'GET');
|
|
1100
|
-
let output = `# 📄 Template Details\n\n`;
|
|
1101
|
-
output += `**Title:** ${result.title}\n`;
|
|
1102
|
-
output += `**ID:** \`${result.id}\`\n`;
|
|
1103
|
-
output += `**Description:** ${result.description || 'N/A'}\n`;
|
|
1104
|
-
output += `**AI Context:** ${result.ai_context_detected || 'N/A'}\n`;
|
|
1105
|
-
output += `**Confidence Score:** ${(result.confidence_score * 100).toFixed(1)}%\n`;
|
|
1106
|
-
output += `**Public:** ${result.is_public ? 'Yes' : 'No'}\n`;
|
|
1107
|
-
output += `**Tags:** ${result.tags ? result.tags.join(', ') : 'None'}\n\n`;
|
|
1108
|
-
output += `**Original Prompt:**\n\`\`\`\n${result.original_prompt}\n\`\`\`\n\n`;
|
|
1109
|
-
output += `**Optimized Prompt:**\n\`\`\`\n${result.optimized_prompt}\n\`\`\`\n`;
|
|
1110
|
-
return { content: [{ type: "text", text: output }] };
|
|
1111
|
-
} catch (error) {
|
|
1112
|
-
const msg = error.message || '';
|
|
1113
|
-
if (msg.includes('404') || msg.toLowerCase().includes('not found')) {
|
|
1114
|
-
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.`);
|
|
1115
|
-
}
|
|
1116
|
-
throw new Error(`Failed to retrieve template: ${error.message}`);
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
async handleUpdateTemplate(args) {
|
|
1121
|
-
if (!args.template_id) throw new Error('Template ID is required');
|
|
1122
|
-
try {
|
|
1123
|
-
const { template_id, ...updateData } = args;
|
|
1124
|
-
// Filter out undefined values so we only send fields that are being updated
|
|
1125
|
-
Object.keys(updateData).forEach(key => updateData[key] === undefined && delete updateData[key]);
|
|
1126
|
-
|
|
1127
|
-
const result = await this.callBackendAPI(ENDPOINTS.TEMPLATE.UPDATE(template_id), updateData, 'PATCH'); // PATCH is better for partial updates
|
|
1128
|
-
let output = `# ✅ Template Updated Successfully!\n\n`;
|
|
1129
|
-
output += `**ID:** \`${result.id}\`\n`;
|
|
1130
|
-
output += `**Title:** ${result.title}\n\n`;
|
|
1131
|
-
output += `Use 'get_template' with the ID to see the full updated template.`;
|
|
1132
|
-
return { content: [{ type: "text", text: output }] };
|
|
1133
|
-
} catch (error) {
|
|
1134
|
-
throw new Error(`Failed to update template: ${error.message}`);
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
|
-
async handleDeleteTemplate(args) {
|
|
1139
|
-
if (!args.template_id) throw new Error('Template ID is required');
|
|
1140
|
-
try {
|
|
1141
|
-
const result = await this.callBackendAPI(ENDPOINTS.TEMPLATE.DELETE(args.template_id), null, 'DELETE');
|
|
1142
|
-
const title = result.message || `Template ${args.template_id}`;
|
|
1143
|
-
return { content: [{ type: "text", text: `# 🗑️ Template Deleted\n\n${title}` }] };
|
|
1144
|
-
} catch (error) {
|
|
1145
|
-
throw new Error(`Failed to delete template: ${error.message}`);
|
|
1146
|
-
}
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
|
-
async handleGenerateAgentSop(args) {
|
|
1150
|
-
if (!args.goal) throw new Error('goal is required');
|
|
1151
|
-
const payload = { goal: args.goal };
|
|
1152
|
-
if (args.context) payload.context = args.context;
|
|
1153
|
-
if (args.model_id) payload.model_id = args.model_id;
|
|
1154
|
-
if (args.intent_frame) payload.intent_frame = args.intent_frame;
|
|
1155
|
-
try {
|
|
1156
|
-
const result = await this.callBackendAPI(ENDPOINTS.CE.SOP, payload);
|
|
1157
|
-
const sopContent = result.sop || result.content || result.result || JSON.stringify(result, null, 2);
|
|
1158
|
-
return { content: [{ type: "text", text: `# Agent SOP Generated\n\n${sopContent}\n\n---\n*Generated by MCP Prompt Optimizer CE*` }] };
|
|
1159
|
-
} catch (error) {
|
|
1160
|
-
throw new Error(`Failed to generate SOP: ${error.message}`);
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
async handleGenerateSkillPackage(args) {
|
|
1165
|
-
if (!args.goal) throw new Error('goal is required');
|
|
1166
|
-
const payload = { goal: args.goal, format: args.format || 'knowledge_doc' };
|
|
1167
|
-
if (args.model_id) payload.model_id = args.model_id;
|
|
1168
|
-
let workflowError = null;
|
|
1169
|
-
try {
|
|
1170
|
-
const startResult = await this.callBackendAPI(ENDPOINTS.CE.GENERATE_SKILL_PACKAGE, payload);
|
|
1171
|
-
const sessionId = startResult.session_id;
|
|
1172
|
-
if (!sessionId) {
|
|
1173
|
-
return { content: [{ type: "text", text: this._formatSkillPackage(startResult) }] };
|
|
1174
|
-
}
|
|
1175
|
-
for (let i = 0; i < 24; i++) {
|
|
1176
|
-
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
1177
|
-
const status = await this.callBackendAPI(ENDPOINTS.CE.SESSION(sessionId), null, 'GET');
|
|
1178
|
-
const state = status.workflow_state || status.current_state;
|
|
1179
|
-
if (state === 'complete') return { content: [{ type: "text", text: this._formatSkillPackage(status) }] };
|
|
1180
|
-
if (state === 'failed') {
|
|
1181
|
-
workflowError = new Error(`Generation failed: ${status.error || 'Unknown error'}`);
|
|
1182
|
-
throw workflowError;
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
workflowError = new Error(`Timed out after 120s. Session ID: ${sessionId}`);
|
|
1186
|
-
throw workflowError;
|
|
1187
|
-
} catch (error) {
|
|
1188
|
-
if (error === workflowError) throw error;
|
|
1189
|
-
throw new Error(`Failed to generate skill package: ${error.message}`);
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
async handleTransformForFramework(args) {
|
|
1194
|
-
if (!args.sop_content) throw new Error('sop_content is required');
|
|
1195
|
-
if (!args.goal) throw new Error('goal is required');
|
|
1196
|
-
if (!args.framework) throw new Error('framework is required');
|
|
1197
|
-
const valid = ['langchain_tool', 'autogen_agent', 'claude_skill'];
|
|
1198
|
-
if (!valid.includes(args.framework)) throw new Error(`framework must be one of: ${valid.join(', ')}`);
|
|
1199
|
-
try {
|
|
1200
|
-
const result = await this.callBackendAPI(ENDPOINTS.CE.TRANSFORM, {
|
|
1201
|
-
sop_content: args.sop_content, goal: args.goal, framework: args.framework
|
|
1202
|
-
});
|
|
1203
|
-
const code = result.code || result.content || result.result || JSON.stringify(result, null, 2);
|
|
1204
|
-
return { content: [{ type: "text", text: `# ${args.framework} Implementation\n\n\`\`\`python\n${code}\n\`\`\`\n\n---\n*Transformed by MCP Prompt Optimizer CE*` }] };
|
|
1205
|
-
} catch (error) {
|
|
1206
|
-
throw new Error(`Failed to transform: ${error.message}`);
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
async handleGetCEQuotaStatus() {
|
|
1211
|
-
try {
|
|
1212
|
-
const result = await this.callBackendAPI(ENDPOINTS.CE.QUOTA, null, 'GET');
|
|
1213
|
-
const lines = ['## CE Credit Balance', ''];
|
|
1214
|
-
if (result.is_unlimited) {
|
|
1215
|
-
lines.push(`Credits: **Unlimited** (${result.credits_used || 0} used this period)`);
|
|
1216
|
-
} else {
|
|
1217
|
-
lines.push(`Credits: **${result.credits_remaining ?? 'N/A'}** of ${result.credits_limit} remaining (${result.credits_used || 0} used)`);
|
|
1218
|
-
}
|
|
1219
|
-
lines.push('', '## Available Workflows');
|
|
1220
|
-
if (result.workflow_availability) {
|
|
1221
|
-
for (const [type, info] of Object.entries(result.workflow_availability)) {
|
|
1222
|
-
lines.push(`- ${info.available ? '✓' : '✗'} ${type}: ${info.cost_credits} credit(s)`);
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
if (result.message) lines.push('', result.message);
|
|
1226
|
-
return { content: [{ type: "text", text: lines.join('\n') }] };
|
|
1227
|
-
} catch (error) {
|
|
1228
|
-
throw new Error(`Failed to get CE quota: ${error.message}`);
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
async handleGenerateHarnessBundle(args) {
|
|
1233
|
-
if (!args.sop_content && !args.session_id) {
|
|
1234
|
-
return { content: [{ type: "text", text: "Error: provide either sop_content or session_id." }] };
|
|
1235
|
-
}
|
|
1236
|
-
// Normalize deploy_target: string → [string], array → array, undefined → ["claude_code"]
|
|
1237
|
-
let deployTargets;
|
|
1238
|
-
if (!args.deploy_target) {
|
|
1239
|
-
deployTargets = ["claude_code"];
|
|
1240
|
-
} else if (Array.isArray(args.deploy_target)) {
|
|
1241
|
-
deployTargets = args.deploy_target;
|
|
1242
|
-
} else {
|
|
1243
|
-
deployTargets = [args.deploy_target];
|
|
1244
|
-
}
|
|
1245
|
-
// Guard: empty array falls back to default
|
|
1246
|
-
if (deployTargets.length === 0) {
|
|
1247
|
-
deployTargets = ["claude_code"];
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
const payload = {
|
|
1251
|
-
goal: args.goal,
|
|
1252
|
-
deploy_target: deployTargets.length === 1 ? deployTargets[0] : deployTargets,
|
|
1253
|
-
platform: deployTargets[0],
|
|
1254
|
-
user_goal: args.goal,
|
|
1255
|
-
sop_content: args.sop_content || "",
|
|
1256
|
-
};
|
|
1257
|
-
|
|
1258
|
-
// If session_id provided, first fetch session artifacts for sop_content
|
|
1259
|
-
if (args.session_id) {
|
|
1260
|
-
try {
|
|
1261
|
-
const status = await this.callBackendAPI(ENDPOINTS.CE.SESSION(args.session_id), null, "GET");
|
|
1262
|
-
const sop = status.artifacts?.sop_content || status.sop_content || "";
|
|
1263
|
-
if (sop) payload.sop_content = sop;
|
|
1264
|
-
} catch (sessionErr) {
|
|
1265
|
-
console.error(`[handleGenerateHarnessBundle] Could not fetch session ${args.session_id}:`, sessionErr.message || sessionErr);
|
|
1266
|
-
// Proceed with empty sop_content; backend will handle gracefully
|
|
1267
|
-
}
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
try {
|
|
1271
|
-
await this.callBackendAPI(ENDPOINTS.CE.HARNESS_BUNDLE, payload);
|
|
1272
|
-
return {
|
|
1273
|
-
content: [{
|
|
1274
|
-
type: "text",
|
|
1275
|
-
text: `# Harness Bundle Requested\n\nDeploy target: **${deployTargets.join(", ")}**\nGoal: ${args.goal}\n\nDownload from the CE dashboard or via the /harness-bundle API endpoint.`
|
|
1276
|
-
}]
|
|
1277
|
-
};
|
|
1278
|
-
} catch (error) {
|
|
1279
|
-
const msg = error?.message || String(error);
|
|
1280
|
-
if (msg.includes("TIER_LIMIT_REACHED")) {
|
|
1281
|
-
return { content: [{ type: "text",
|
|
1282
|
-
text: `Upgrade required: this deploy target requires Pro tier or higher. Upgrade at /pricing.`
|
|
1283
|
-
}] };
|
|
1284
|
-
}
|
|
1285
|
-
throw error;
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
|
-
|
|
1289
|
-
async handleExploreSopApproaches(args) {
|
|
1290
|
-
if (!args.goal) {
|
|
1291
|
-
return { content: [{ type: "text", text: "Error: goal is required." }] };
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1294
|
-
// If blend_description provided, explore then blend in one call chain
|
|
1295
|
-
if (args.blend_description) {
|
|
1296
|
-
try {
|
|
1297
|
-
const explorePayload = {
|
|
1298
|
-
goal: args.goal,
|
|
1299
|
-
context: args.context || undefined,
|
|
1300
|
-
perspective: args.perspective || undefined,
|
|
1301
|
-
out_of_scope: args.out_of_scope || undefined,
|
|
1302
|
-
success_definition: args.success_definition || undefined,
|
|
1303
|
-
};
|
|
1304
|
-
const exploreResult = await this.callBackendAPI(ENDPOINTS.CE.SOP_EXPLORE, explorePayload);
|
|
1305
|
-
const blendPayload = {
|
|
1306
|
-
variants: exploreResult.variants,
|
|
1307
|
-
blend_description: args.blend_description,
|
|
1308
|
-
goal: args.goal,
|
|
1309
|
-
};
|
|
1310
|
-
const blendResult = await this.callBackendAPI(ENDPOINTS.CE.SOP_BLEND, blendPayload);
|
|
1311
|
-
return {
|
|
1312
|
-
content: [{
|
|
1313
|
-
type: "text",
|
|
1314
|
-
text: `# Blended SOP\n\n${blendResult.sop_content}`
|
|
1315
|
-
}]
|
|
1316
|
-
};
|
|
1317
|
-
} catch (error) {
|
|
1318
|
-
throw new Error(`Failed to blend SOP approaches: ${error.message}`);
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
|
-
// Standard exploration: return 3 variant summaries
|
|
1323
|
-
try {
|
|
1324
|
-
const payload = {
|
|
1325
|
-
goal: args.goal,
|
|
1326
|
-
context: args.context || undefined,
|
|
1327
|
-
perspective: args.perspective || undefined,
|
|
1328
|
-
out_of_scope: args.out_of_scope || undefined,
|
|
1329
|
-
success_definition: args.success_definition || undefined,
|
|
1330
|
-
};
|
|
1331
|
-
const result = await this.callBackendAPI(ENDPOINTS.CE.SOP_EXPLORE, payload);
|
|
1332
|
-
|
|
1333
|
-
const variantSummaries = result.variants.map(v => {
|
|
1334
|
-
const rec = v.id === result.recommended ? " *(Recommended)*" : "";
|
|
1335
|
-
return `## Variant ${v.id} — ${v.approach.replace('_', '-')}${rec}\n\n${v.content.slice(0, 600)}${v.content.length > 600 ? '\n\n...(truncated)' : ''}`;
|
|
1336
|
-
}).join('\n\n---\n\n');
|
|
1337
|
-
|
|
1338
|
-
return {
|
|
1339
|
-
content: [{
|
|
1340
|
-
type: "text",
|
|
1341
|
-
text: `# SOP Exploration Results\n\n**Goal:** ${args.goal}\n**Recommended:** Variant ${result.recommended}\n\n---\n\n${variantSummaries}\n\n---\n\n*To select a variant, call generate_skill_package with the full content of your chosen variant as sop_content. To blend variants, re-call explore_sop_approaches with blend_description.*`
|
|
1342
|
-
}]
|
|
1343
|
-
};
|
|
1344
|
-
} catch (error) {
|
|
1345
|
-
if (error.message && error.message.includes('403')) {
|
|
1346
|
-
return { content: [{ type: "text", text: "Error: SOP exploration requires Innovator tier. Upgrade at /pricing." }] };
|
|
1347
|
-
}
|
|
1348
|
-
throw new Error(`Failed to explore SOP approaches: ${error.message}`);
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
|
|
1352
|
-
_formatSkillPackage(result) {
|
|
1353
|
-
const sections = ['# Skill Package Generated'];
|
|
1354
|
-
const artifacts = result.artifacts || result.steps || {};
|
|
1355
|
-
if (typeof artifacts === 'object' && Object.keys(artifacts).length > 0) {
|
|
1356
|
-
for (const [key, value] of Object.entries(artifacts)) {
|
|
1357
|
-
if (value && typeof value === 'string') sections.push(`\n## ${key}\n\n${value}`);
|
|
1358
|
-
}
|
|
1359
|
-
} else {
|
|
1360
|
-
sections.push('\n```json\n' + JSON.stringify(result, null, 2) + '\n```');
|
|
1361
|
-
}
|
|
1362
|
-
sections.push('\n---\n*Generated by MCP Prompt Optimizer CE*');
|
|
1363
|
-
return sections.join('\n');
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
_buildUrl(path) {
|
|
1367
|
-
return `${this.backendUrl}${path}`;
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
|
-
async callBackendAPI(endpoint, data, method = 'POST') {
|
|
1371
|
-
return new Promise((resolve, reject) => {
|
|
1372
|
-
const url = this._buildUrl(endpoint);
|
|
1373
|
-
|
|
1374
|
-
const options = {
|
|
1375
|
-
method: method,
|
|
1376
|
-
headers: {
|
|
1377
|
-
'x-api-key': this.apiKey,
|
|
1378
|
-
'Content-Type': 'application/json',
|
|
1379
|
-
'User-Agent': `mcp-prompt-optimizer/${packageJson.version}`,
|
|
1380
|
-
'Accept': 'application/json',
|
|
1381
|
-
'Connection': 'close'
|
|
1382
|
-
},
|
|
1383
|
-
timeout: this.requestTimeout
|
|
1384
|
-
};
|
|
1385
|
-
|
|
1386
|
-
const client = this.backendUrl.startsWith('https://') ? https : require('http');
|
|
1387
|
-
const req = client.request(url, options, (res) => {
|
|
1388
|
-
let responseData = '';
|
|
1389
|
-
|
|
1390
|
-
res.on('data', (chunk) => {
|
|
1391
|
-
responseData += chunk;
|
|
1392
|
-
});
|
|
1393
|
-
|
|
1394
|
-
res.on('end', () => {
|
|
1395
|
-
try {
|
|
1396
|
-
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
1397
|
-
const contentType = res.headers['content-type'] || '';
|
|
1398
|
-
if (contentType.includes('application/json') || contentType === '') {
|
|
1399
|
-
try {
|
|
1400
|
-
const parsed = JSON.parse(responseData);
|
|
1401
|
-
resolve(parsed);
|
|
1402
|
-
} catch (e) {
|
|
1403
|
-
reject(new Error(`Invalid response format: ${e.message}`));
|
|
1404
|
-
}
|
|
1405
|
-
} else {
|
|
1406
|
-
// Binary or non-JSON response (e.g., application/zip) — return metadata
|
|
1407
|
-
resolve({ _binary: true, contentType, size: responseData.length });
|
|
1408
|
-
}
|
|
1409
|
-
} else {
|
|
1410
|
-
let errorMessage;
|
|
1411
|
-
try {
|
|
1412
|
-
const error = JSON.parse(responseData);
|
|
1413
|
-
errorMessage = (typeof error.detail === 'object' && error.detail !== null)
|
|
1414
|
-
? JSON.stringify(error.detail)
|
|
1415
|
-
: (error.detail || error.message || `HTTP ${res.statusCode}`);
|
|
1416
|
-
} catch {
|
|
1417
|
-
errorMessage = `HTTP ${res.statusCode}: ${responseData}`;
|
|
1418
|
-
}
|
|
1419
|
-
reject(new Error(errorMessage));
|
|
1420
|
-
}
|
|
1421
|
-
} catch (parseError) {
|
|
1422
|
-
reject(new Error(`Invalid response format: ${parseError.message}`));
|
|
1423
|
-
}
|
|
1424
|
-
});
|
|
1425
|
-
});
|
|
1426
|
-
|
|
1427
|
-
req.on('error', (error) => {
|
|
1428
|
-
if (error.code === 'ENOTFOUND') {
|
|
1429
|
-
reject(new Error(`DNS resolution failed: Cannot resolve ${this.backendUrl.replace(/^https?:\/\//, '')}`));
|
|
1430
|
-
} else if (error.code === 'ECONNREFUSED') {
|
|
1431
|
-
reject(new Error(`Connection refused: Backend server may be down`));
|
|
1432
|
-
} else if (error.code === 'ETIMEDOUT') {
|
|
1433
|
-
reject(new Error(`Connection timeout: Backend server is not responding`));
|
|
1434
|
-
} else if (error.code === 'ECONNRESET') {
|
|
1435
|
-
reject(new Error(`Connection reset: Network instability detected`));
|
|
1436
|
-
} else {
|
|
1437
|
-
reject(new Error(`Network error: ${error.message}`));
|
|
1438
|
-
}
|
|
1439
|
-
});
|
|
1440
|
-
|
|
1441
|
-
req.on('timeout', () => {
|
|
1442
|
-
req.destroy();
|
|
1443
|
-
reject(new Error('Request timeout - backend may be unavailable'));
|
|
1444
|
-
});
|
|
1445
|
-
|
|
1446
|
-
if (method !== 'GET' && data) {
|
|
1447
|
-
req.write(JSON.stringify(data));
|
|
1448
|
-
}
|
|
1449
|
-
req.end();
|
|
1450
|
-
});
|
|
1451
|
-
}
|
|
1452
|
-
|
|
1453
|
-
formatOptimizationResult(result, context) {
|
|
1454
|
-
let output;
|
|
1455
|
-
if (result.rules_based) {
|
|
1456
|
-
if (result.fallback_mode) {
|
|
1457
|
-
output = `# 🔧 Prompt Optimized (Local Rules)\n\n`;
|
|
1458
|
-
output += `*Optimized using local rule templates — LLM quality available once you connect your API key.*\n\n`;
|
|
1459
|
-
} else {
|
|
1460
|
-
output = `# 🔧 Rules-Based Optimization Applied\n\n`;
|
|
1461
|
-
output += `*API key not validated — optimized using local rule templates. `;
|
|
1462
|
-
output += `Set \`MCP_API_KEY\` for full LLM optimization.*\n\n`;
|
|
1463
|
-
}
|
|
1464
|
-
output += `**Template:** \`${result.template_used || 'general'}\`\n\n`;
|
|
1465
|
-
output += `**Optimized Prompt:**\n\`\`\`\n${result.optimized_prompt}\n\`\`\`\n\n`;
|
|
1466
|
-
} else if (result.fallback_mode) {
|
|
1467
|
-
output = `# 🔧 Optimized (local rules — backend slow)\n\n`;
|
|
1468
|
-
output += `*Backend unavailable this time — applied local rule templates. Try again for LLM optimization.*\n\n`;
|
|
1469
|
-
output += `**Optimized Prompt:**\n\`\`\`\n${result.optimized_prompt}\n\`\`\`\n\n`;
|
|
1470
|
-
} else {
|
|
1471
|
-
output = `# 🎯 Optimized Prompt\n\n${result.optimized_prompt}\n\n`;
|
|
1472
|
-
if (result.confidence_score < 0.25) {
|
|
1473
|
-
output += `> ℹ️ *Low confidence indicates the backend applied rules-based optimization (no LLM). `;
|
|
1474
|
-
output += `Ensure \`OPENROUTER_API_KEY\` is configured in the backend for full LLM enhancement.*\n\n`;
|
|
1475
|
-
}
|
|
1476
|
-
}
|
|
1477
|
-
if (result.rules_based) {
|
|
1478
|
-
output += `**Confidence:** ${(result.confidence_score * 100).toFixed(1)}% *(rules-based — LLM optimization typically 70–95%)*\n`;
|
|
1479
|
-
} else {
|
|
1480
|
-
output += `**Confidence:** ${(result.confidence_score * 100).toFixed(1)}%\n`;
|
|
1481
|
-
}
|
|
1482
|
-
output += `**AI Context:** ${result.metadata?.context_detection?.ai_context || context.detectedContext}\n`;
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
output +=
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
}
|
|
1533
|
-
|
|
1534
|
-
if (bayesian.
|
|
1535
|
-
output += `**
|
|
1536
|
-
output += `-
|
|
1537
|
-
output += `-
|
|
1538
|
-
}
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
output +=
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
output +=
|
|
1567
|
-
output +=
|
|
1568
|
-
output +=
|
|
1569
|
-
output += `
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
if (
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
output += `\n
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
output +=
|
|
1616
|
-
if (
|
|
1617
|
-
if (
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
output +=
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
}
|
|
1667
|
-
output +=
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
output +=
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
output +=
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
output +=
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
output
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
output
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
}
|
|
1751
|
-
|
|
1752
|
-
if (status.
|
|
1753
|
-
|
|
1754
|
-
output +=
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
}
|
|
1774
|
-
|
|
1775
|
-
async
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
console.error(
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
const
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
}
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
}
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
}
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
}
|
|
1921
|
-
|
|
1922
|
-
function
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
try {
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
console.log(
|
|
1953
|
-
|
|
1954
|
-
}
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MCP Prompt Optimizer - Professional Cloud-Based MCP Server
|
|
5
|
+
* Production-grade with Bayesian optimization, AG-UI real-time features, enhanced network resilience,
|
|
6
|
+
* development mode, and complete backend alignment
|
|
7
|
+
*
|
|
8
|
+
* Version: 3.2.0 - add delete_template tool (15 tools total)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
|
12
|
+
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
13
|
+
const { CallToolRequestSchema, ListToolsRequestSchema } = require('@modelcontextprotocol/sdk/types.js');
|
|
14
|
+
const https = require('https');
|
|
15
|
+
const CloudApiKeyManager = require('./lib/api-key-manager');
|
|
16
|
+
const packageJson = require('./package.json');
|
|
17
|
+
const OPTIMIZATION_TEMPLATES = require('./lib/optimization-templates.json');
|
|
18
|
+
|
|
19
|
+
const API_KEYS_PREFIX = '/api/v1/api-keys';
|
|
20
|
+
const MCP_PREFIX = '/api/v1/mcp';
|
|
21
|
+
|
|
22
|
+
const ENDPOINTS = {
|
|
23
|
+
/** Detect AI context (POST) — MCP endpoint, API-key auth */
|
|
24
|
+
DETECT_CONTEXT: `${MCP_PREFIX}/detect-context`,
|
|
25
|
+
|
|
26
|
+
/** Prompt optimization (POST) — MCP endpoint, API-key auth */
|
|
27
|
+
OPTIMIZE: `${MCP_PREFIX}/optimize`,
|
|
28
|
+
|
|
29
|
+
/** CRUD on templates — MCP endpoints, API-key auth */
|
|
30
|
+
TEMPLATE: {
|
|
31
|
+
/** Create (POST) */
|
|
32
|
+
CREATE: `${MCP_PREFIX}/templates`,
|
|
33
|
+
|
|
34
|
+
/** Read (GET) */
|
|
35
|
+
GET: (id) => `${MCP_PREFIX}/templates/${id}`,
|
|
36
|
+
|
|
37
|
+
/** Update (PATCH) */
|
|
38
|
+
UPDATE: (id) => `${MCP_PREFIX}/templates/${id}`,
|
|
39
|
+
|
|
40
|
+
/** Delete (DELETE) */
|
|
41
|
+
DELETE: (id) => `${MCP_PREFIX}/templates/${id}`,
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
/** Search templates (GET) — MCP endpoint, API-key auth */
|
|
45
|
+
SEARCH_TEMPLATES: `${MCP_PREFIX}/templates`,
|
|
46
|
+
|
|
47
|
+
/** Quota status (GET) — MCP endpoint, API-key auth */
|
|
48
|
+
QUOTA_STATUS: `${MCP_PREFIX}/quota-status`,
|
|
49
|
+
|
|
50
|
+
/** Validate API key (POST) — standard api-keys router */
|
|
51
|
+
VALIDATE_KEY: `${API_KEYS_PREFIX}/validate`,
|
|
52
|
+
|
|
53
|
+
/** Bayesian insights (GET) */
|
|
54
|
+
ANALYTICS_BAYESIAN_INSIGHTS:
|
|
55
|
+
'/api/v1/analytics/bayesian-insights',
|
|
56
|
+
|
|
57
|
+
/** AG‑UI status (GET) */
|
|
58
|
+
AGUI_STATUS: '/api/status',
|
|
59
|
+
|
|
60
|
+
/** Context Engineer (CE) endpoints */
|
|
61
|
+
CE: {
|
|
62
|
+
SOP: '/api/v1/context-engineer/sop',
|
|
63
|
+
GENERATE_SKILL_PACKAGE: '/api/v1/context-engineer/generate-skill-package',
|
|
64
|
+
SESSION: (id) => `/api/v1/context-engineer/sessions/${id}`,
|
|
65
|
+
TRANSFORM: '/api/v1/context-engineer/transform',
|
|
66
|
+
QUOTA: '/api/v1/context-engineer/quota',
|
|
67
|
+
HARNESS_BUNDLE: '/api/v1/context-engineer/harness-bundle',
|
|
68
|
+
SOP_EXPLORE: '/api/v1/context-engineer/sop-explore',
|
|
69
|
+
SOP_BLEND: '/api/v1/context-engineer/sop-blend',
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const DEPLOY_TARGET_ENUM = [
|
|
74
|
+
"claude_code", "claude_desktop", "cursor", "copilot",
|
|
75
|
+
"windsurf", "cline", "zed", "replit", "openai_agents", "ollama",
|
|
76
|
+
"amazon_q", "aider", "continue_dev", "crewai"
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
class MCPPromptOptimizer {
|
|
80
|
+
constructor() {
|
|
81
|
+
this.server = new Server(
|
|
82
|
+
{
|
|
83
|
+
name: "mcp-prompt-optimizer",
|
|
84
|
+
version: packageJson.version,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
capabilities: {
|
|
88
|
+
tools: {},
|
|
89
|
+
},
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
this.backendUrl = process.env.OPTIMIZER_BACKEND_URL || 'https://p01--project-optimizer--fvmrdk8m9k9j.code.run';
|
|
94
|
+
this.apiKey = process.env.OPTIMIZER_API_KEY;
|
|
95
|
+
// SECURITY: Development mode removed - all environments require backend validation
|
|
96
|
+
this.developmentMode = false;
|
|
97
|
+
this.requestTimeout = parseInt(process.env.OPTIMIZER_REQUEST_TIMEOUT) || 30000;
|
|
98
|
+
|
|
99
|
+
// Feature flags: enabled by default, set to 'false' to disable
|
|
100
|
+
this.bayesianOptimizationEnabled = process.env.ENABLE_BAYESIAN_OPTIMIZATION !== 'false';
|
|
101
|
+
this.aguiFeatures = process.env.ENABLE_AGUI_FEATURES !== 'false';
|
|
102
|
+
|
|
103
|
+
this.setupMCPHandlers();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
setupMCPHandlers() {
|
|
107
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
108
|
+
const baseTools = [
|
|
109
|
+
{
|
|
110
|
+
name: "optimize_prompt",
|
|
111
|
+
description: "🎯 Professional AI-powered prompt optimization with intelligent context detection, Bayesian optimization, template auto-save, and comprehensive optimization insights",
|
|
112
|
+
inputSchema: {
|
|
113
|
+
type: "object",
|
|
114
|
+
properties: {
|
|
115
|
+
prompt: {
|
|
116
|
+
type: "string",
|
|
117
|
+
description: "The prompt text to optimize"
|
|
118
|
+
},
|
|
119
|
+
goals: {
|
|
120
|
+
type: "array",
|
|
121
|
+
items: { type: "string" },
|
|
122
|
+
description: "Optimization goals (e.g., 'clarity', 'conciseness', 'creativity', 'technical_accuracy', 'analytical_depth', 'creative_enhancement')",
|
|
123
|
+
default: ["clarity"]
|
|
124
|
+
},
|
|
125
|
+
ai_context: {
|
|
126
|
+
type: "string",
|
|
127
|
+
enum: [
|
|
128
|
+
"human_communication", "llm_interaction", "image_generation", "technical_automation",
|
|
129
|
+
"structured_output", "code_generation", "api_automation", "data_analysis",
|
|
130
|
+
"creative_writing", "business_strategy", "technical_strategy", "academic_research",
|
|
131
|
+
"legal_compliance", "medical_healthcare", "educational_content"
|
|
132
|
+
],
|
|
133
|
+
description: "The context for the AI's task (auto-detected if not specified with enhanced detection)"
|
|
134
|
+
},
|
|
135
|
+
enable_bayesian: {
|
|
136
|
+
type: "boolean",
|
|
137
|
+
description: "Enable Bayesian optimization features for parameter tuning (if available)",
|
|
138
|
+
default: true
|
|
139
|
+
},
|
|
140
|
+
value_hierarchy: {
|
|
141
|
+
type: "array",
|
|
142
|
+
description: "Ordered list of values/constraints the optimizer must respect. NON_NEGOTIABLE entries force LLM-tier routing and inject hard constraints into the system prompt. Example: [{label:'NON_NEGOTIABLE',description:'Never suggest removing error handling'},{label:'HIGH',description:'Preserve technical terminology'}]",
|
|
143
|
+
items: {
|
|
144
|
+
type: "object",
|
|
145
|
+
properties: {
|
|
146
|
+
label: {
|
|
147
|
+
type: "string",
|
|
148
|
+
enum: ["NON_NEGOTIABLE", "HIGH", "MEDIUM", "LOW"],
|
|
149
|
+
description: "Priority level for this constraint"
|
|
150
|
+
},
|
|
151
|
+
description: {
|
|
152
|
+
type: "string",
|
|
153
|
+
description: "The value or constraint to enforce during optimization"
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
required: ["label", "description"]
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
intent_frame: {
|
|
160
|
+
type: "object",
|
|
161
|
+
description: "Question Method intent framing — steers optimization toward a specific angle, excludes off-topic territory, and defines what success looks like. Any non-null field floors routing to HYBRID tier minimum.",
|
|
162
|
+
properties: {
|
|
163
|
+
perspective: {
|
|
164
|
+
type: "string",
|
|
165
|
+
description: "The angle or thesis to optimize from (e.g. 'growth is a retention problem, not an acquisition problem'). Gives the optimizer a north-star direction."
|
|
166
|
+
},
|
|
167
|
+
out_of_scope: {
|
|
168
|
+
type: "array",
|
|
169
|
+
items: { type: "string" },
|
|
170
|
+
description: "Topics, approaches, or angles to explicitly exclude from optimization (e.g. ['pricing strategy', 'acquisition channels'])."
|
|
171
|
+
},
|
|
172
|
+
success_definition: {
|
|
173
|
+
type: "string",
|
|
174
|
+
description: "Narrative description of what a successful optimized output achieves (e.g. 'reader understands why churn drives flat revenue even with user growth')."
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
required: ["prompt"]
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: "get_quota_status",
|
|
184
|
+
description: "📊 Check subscription status, quota usage, and account information with detailed insights and Bayesian optimization metrics",
|
|
185
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false }
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: "create_template",
|
|
189
|
+
description: "➕ Create a new optimization template.",
|
|
190
|
+
inputSchema: {
|
|
191
|
+
type: "object",
|
|
192
|
+
properties: {
|
|
193
|
+
title: { type: "string", description: "Title of the template" },
|
|
194
|
+
description: { type: "string", description: "Description of the template" },
|
|
195
|
+
original_prompt: { type: "string", description: "The original prompt text" },
|
|
196
|
+
optimized_prompt: { type: "string", description: "The optimized prompt text" },
|
|
197
|
+
optimization_goals: { type: "array", items: { type: "string" }, description: "Goals for this optimization (e.g., 'clarity', 'conciseness', 'creativity', 'technical_accuracy', 'analytical_depth', 'creative_enhancement')" },
|
|
198
|
+
confidence_score: { type: "number", description: "Confidence score of the optimization (0.0-1.0)" },
|
|
199
|
+
model_used: { type: "string", description: "Model used for optimization" },
|
|
200
|
+
optimization_tier: { type: "string", description: "Tier of optimization (e.g., rules, llm, hybrid)" },
|
|
201
|
+
ai_context_detected: { type: "string", description: "Detected AI context (e.g., code_generation, image_generation)" },
|
|
202
|
+
is_public: { type: "boolean", default: false, description: "Whether the template is public" },
|
|
203
|
+
tags: { type: "array", items: { type: "string" }, description: "Tags for the template" }
|
|
204
|
+
},
|
|
205
|
+
required: ["title", "original_prompt", "optimized_prompt", "confidence_score"]
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: "get_template",
|
|
210
|
+
description: "🔍 Retrieve a specific template by its ID.",
|
|
211
|
+
inputSchema: {
|
|
212
|
+
type: "object",
|
|
213
|
+
properties: {
|
|
214
|
+
template_id: { type: "string", description: "The ID of the template to retrieve" }
|
|
215
|
+
},
|
|
216
|
+
required: ["template_id"]
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
name: "update_template",
|
|
221
|
+
description: "✏️ Update an existing optimization template.",
|
|
222
|
+
inputSchema: {
|
|
223
|
+
type: "object",
|
|
224
|
+
properties: {
|
|
225
|
+
template_id: { type: "string", description: "The ID of the template to update" },
|
|
226
|
+
title: { type: "string", description: "New title for the template" },
|
|
227
|
+
description: { type: "string", description: "New description for the template" },
|
|
228
|
+
original_prompt: { type: "string", description: "New original prompt text" },
|
|
229
|
+
optimized_prompt: { type: "string", description: "New optimized prompt text" },
|
|
230
|
+
optimization_goals: { type: "array", items: { type: "string" }, description: "New optimization goals" },
|
|
231
|
+
confidence_score: { type: "number", description: "New confidence score (0.0-1.0)" },
|
|
232
|
+
model_used: { type: "string", description: "New model used for optimization" },
|
|
233
|
+
optimization_tier: { type: "string", description: "New tier of optimization" },
|
|
234
|
+
ai_context_detected: { type: "string", description: "New detected AI context" },
|
|
235
|
+
is_public: { type: "boolean", description: "Whether the template is public" },
|
|
236
|
+
tags: { type: "array", items: { type: "string" }, description: "New tags for the template" }
|
|
237
|
+
},
|
|
238
|
+
required: ["template_id"]
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
name: "delete_template",
|
|
243
|
+
description: "🗑️ Delete a saved optimization template by ID.",
|
|
244
|
+
inputSchema: {
|
|
245
|
+
type: "object",
|
|
246
|
+
properties: {
|
|
247
|
+
template_id: { type: "string", description: "The ID of the template to delete" }
|
|
248
|
+
},
|
|
249
|
+
required: ["template_id"]
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
name: "search_templates",
|
|
254
|
+
description: "🔍 Search your saved template library with AI-aware filtering, context-based search, and sophisticated template matching",
|
|
255
|
+
inputSchema: {
|
|
256
|
+
type: "object",
|
|
257
|
+
properties: {
|
|
258
|
+
query: {
|
|
259
|
+
type: "string",
|
|
260
|
+
description: "Search term to filter templates by content or title"
|
|
261
|
+
},
|
|
262
|
+
ai_context: {
|
|
263
|
+
type: "string",
|
|
264
|
+
enum: ["human_communication", "llm_interaction", "image_generation", "technical_automation", "structured_output", "code_generation", "api_automation"],
|
|
265
|
+
description: "Filter templates by AI context type"
|
|
266
|
+
},
|
|
267
|
+
sophistication_level: {
|
|
268
|
+
type: "string",
|
|
269
|
+
enum: ["basic", "intermediate", "advanced", "expert"],
|
|
270
|
+
description: "Filter by template sophistication level"
|
|
271
|
+
},
|
|
272
|
+
complexity_level: {
|
|
273
|
+
type: "string",
|
|
274
|
+
enum: ["simple", "moderate", "complex", "very_complex"],
|
|
275
|
+
description: "Filter by template complexity level"
|
|
276
|
+
},
|
|
277
|
+
optimization_strategy: {
|
|
278
|
+
type: "string",
|
|
279
|
+
description: "Filter by optimization strategy used"
|
|
280
|
+
},
|
|
281
|
+
limit: {
|
|
282
|
+
type: "number",
|
|
283
|
+
default: 5,
|
|
284
|
+
description: "Number of templates to return (1-20)"
|
|
285
|
+
},
|
|
286
|
+
page: {
|
|
287
|
+
type: "number",
|
|
288
|
+
default: 1,
|
|
289
|
+
description: "Page number for pagination (use with limit to access results beyond the first page)"
|
|
290
|
+
},
|
|
291
|
+
sort_by: {
|
|
292
|
+
type: "string",
|
|
293
|
+
enum: ["created_at", "confidence_score", "usage_count", "title"],
|
|
294
|
+
default: "confidence_score",
|
|
295
|
+
description: "Sort templates by field"
|
|
296
|
+
},
|
|
297
|
+
sort_order: {
|
|
298
|
+
type: "string",
|
|
299
|
+
enum: ["asc", "desc"],
|
|
300
|
+
default: "desc",
|
|
301
|
+
description: "Sort order"
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
name: "list_recent_templates",
|
|
308
|
+
description: "📋 List your most recently saved optimization templates, sorted by creation date.",
|
|
309
|
+
inputSchema: {
|
|
310
|
+
type: "object",
|
|
311
|
+
properties: {
|
|
312
|
+
limit: {
|
|
313
|
+
type: "number",
|
|
314
|
+
default: 10,
|
|
315
|
+
description: "Number of recent templates to return (1-20)"
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
name: "detect_ai_context",
|
|
322
|
+
description: "🧠 Detects the AI context for a given prompt using advanced backend analysis.",
|
|
323
|
+
inputSchema: {
|
|
324
|
+
type: "object",
|
|
325
|
+
properties: {
|
|
326
|
+
prompt: {
|
|
327
|
+
type: "string",
|
|
328
|
+
description: "The prompt text for which to detect the AI context"
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
required: ["prompt"]
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
name: "generate_agent_sop",
|
|
336
|
+
description: "Generate a structured SOP document for an AI agent from a goal description.",
|
|
337
|
+
inputSchema: {
|
|
338
|
+
type: "object",
|
|
339
|
+
properties: {
|
|
340
|
+
goal: { type: "string", description: "What the agent should accomplish" },
|
|
341
|
+
context: { type: "string", description: "Additional context (optional)" },
|
|
342
|
+
model_id: { type: "string", description: "Model to use (optional)" },
|
|
343
|
+
intent_frame: {
|
|
344
|
+
type: "object",
|
|
345
|
+
description: "Optional IntentFrame to sharpen SOP scope and success criteria.",
|
|
346
|
+
properties: {
|
|
347
|
+
perspective: { type: "string", description: "The agent role or viewpoint (e.g. DevOps engineer)." },
|
|
348
|
+
out_of_scope: { type: "string", description: "What is explicitly excluded from this workflow." },
|
|
349
|
+
success_definition: { type: "string", description: "Measurable criteria that define success." }
|
|
350
|
+
},
|
|
351
|
+
additionalProperties: false
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
required: ["goal"]
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
name: "generate_skill_package",
|
|
359
|
+
description: "Generate a complete skill package (SOP + SKILL.md + examples + helper.py) for an AI agent. Takes 30-120 seconds (async).",
|
|
360
|
+
inputSchema: {
|
|
361
|
+
type: "object",
|
|
362
|
+
properties: {
|
|
363
|
+
goal: { type: "string", description: "What the agent should accomplish" },
|
|
364
|
+
format: { type: "string", enum: ["knowledge_doc", "agent_spec"], description: "Output format" },
|
|
365
|
+
model_id: { type: "string", description: "Model to use (optional)" }
|
|
366
|
+
},
|
|
367
|
+
required: ["goal"]
|
|
368
|
+
}
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
name: "transform_for_framework",
|
|
372
|
+
description: "Transform a SOP into native code for LangChain, AutoGen, or Claude Code.",
|
|
373
|
+
inputSchema: {
|
|
374
|
+
type: "object",
|
|
375
|
+
properties: {
|
|
376
|
+
sop_content: { type: "string", description: "SOP content to transform" },
|
|
377
|
+
goal: { type: "string", description: "What the agent should accomplish" },
|
|
378
|
+
framework: { type: "string", enum: ["langchain_tool", "autogen_agent", "claude_skill"], description: "Target framework" }
|
|
379
|
+
},
|
|
380
|
+
required: ["sop_content", "goal", "framework"]
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
name: "get_ce_quota_status",
|
|
385
|
+
description: "Check your Context Engineer credit balance and available workflow types.",
|
|
386
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false }
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
name: "generate_harness_bundle",
|
|
390
|
+
description: (
|
|
391
|
+
"Generate a deployment-ready Agentic Harness ZIP bundle for a specific platform. "
|
|
392
|
+
+ "Returns a confirmation message when the bundle is queued. "
|
|
393
|
+
+ "Explorer+ required for non-default deploy targets."
|
|
394
|
+
),
|
|
395
|
+
inputSchema: {
|
|
396
|
+
type: "object",
|
|
397
|
+
properties: {
|
|
398
|
+
goal: {
|
|
399
|
+
type: "string",
|
|
400
|
+
description: "The workflow goal the harness is built for."
|
|
401
|
+
},
|
|
402
|
+
deploy_target: {
|
|
403
|
+
oneOf: [
|
|
404
|
+
{
|
|
405
|
+
type: "string",
|
|
406
|
+
enum: DEPLOY_TARGET_ENUM,
|
|
407
|
+
description: "Single deploy target."
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
type: "array",
|
|
411
|
+
minItems: 1,
|
|
412
|
+
items: {
|
|
413
|
+
type: "string",
|
|
414
|
+
enum: DEPLOY_TARGET_ENUM
|
|
415
|
+
},
|
|
416
|
+
description: "Multiple deploy targets simultaneously (Creator+ required)."
|
|
417
|
+
}
|
|
418
|
+
],
|
|
419
|
+
description: (
|
|
420
|
+
"Target deployment platform(s). Single string (Explorer+) or array (Creator+). "
|
|
421
|
+
+ "amazon_q, aider, continue_dev, crewai require Creator+. "
|
|
422
|
+
+ "Default: claude_code."
|
|
423
|
+
)
|
|
424
|
+
},
|
|
425
|
+
session_id: {
|
|
426
|
+
type: "string",
|
|
427
|
+
description: "Optional: session ID from a prior generate_skill_package call to reuse SOP."
|
|
428
|
+
},
|
|
429
|
+
sop_content: {
|
|
430
|
+
type: "string",
|
|
431
|
+
description: "The SOP content to base the harness on (required if no session_id)."
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
required: ["goal"]
|
|
435
|
+
}
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
name: "explore_sop_approaches",
|
|
439
|
+
description: (
|
|
440
|
+
"Generate 3 parallel SOP variants (process-oriented, decision-tree, role-based) for comparison before committing. " +
|
|
441
|
+
"Returns exploration_html (self-contained comparison grid), variants array, and a recommended variant. " +
|
|
442
|
+
"Innovator tier required. " +
|
|
443
|
+
"Optionally provide blend_description to skip comparison and receive a single blended SOP instead."
|
|
444
|
+
),
|
|
445
|
+
inputSchema: {
|
|
446
|
+
type: "object",
|
|
447
|
+
properties: {
|
|
448
|
+
goal: {
|
|
449
|
+
type: "string",
|
|
450
|
+
description: "The workflow goal to generate SOP variants for"
|
|
451
|
+
},
|
|
452
|
+
context: {
|
|
453
|
+
type: "string",
|
|
454
|
+
description: "Optional background context or documentation excerpt"
|
|
455
|
+
},
|
|
456
|
+
blend_description: {
|
|
457
|
+
type: "string",
|
|
458
|
+
description: "Optional: if provided, skips variant comparison and blends all 3 into one SOP using this description"
|
|
459
|
+
},
|
|
460
|
+
perspective: { type: "string", description: "Agent role or viewpoint (IntentFrame)" },
|
|
461
|
+
out_of_scope: { type: "string", description: "What is explicitly excluded (IntentFrame)" },
|
|
462
|
+
success_definition: { type: "string", description: "Measurable success criteria (IntentFrame)" },
|
|
463
|
+
},
|
|
464
|
+
required: ["goal"],
|
|
465
|
+
additionalProperties: false
|
|
466
|
+
}
|
|
467
|
+
},
|
|
468
|
+
];
|
|
469
|
+
|
|
470
|
+
// Add advanced tools if Bayesian optimization is enabled
|
|
471
|
+
if (this.bayesianOptimizationEnabled) {
|
|
472
|
+
baseTools.push({
|
|
473
|
+
name: "get_optimization_insights",
|
|
474
|
+
description: "🧠 Get advanced Bayesian optimization insights, performance analytics, and parameter tuning recommendations",
|
|
475
|
+
inputSchema: {
|
|
476
|
+
type: "object",
|
|
477
|
+
properties: {
|
|
478
|
+
analysis_depth: {
|
|
479
|
+
type: "string",
|
|
480
|
+
enum: ["basic", "detailed", "comprehensive"],
|
|
481
|
+
default: "detailed",
|
|
482
|
+
description: "Depth of analysis to provide"
|
|
483
|
+
},
|
|
484
|
+
include_recommendations: {
|
|
485
|
+
type: "boolean",
|
|
486
|
+
default: true,
|
|
487
|
+
description: "Include optimization recommendations"
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Add AG-UI tools if enabled
|
|
495
|
+
if (this.aguiFeatures) {
|
|
496
|
+
baseTools.push({
|
|
497
|
+
name: "get_real_time_status",
|
|
498
|
+
description: "⚡ Get real-time optimization status, AG-UI capabilities, and streaming optimization availability",
|
|
499
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false }
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
return { tools: baseTools };
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
507
|
+
const { name, arguments: args } = request.params;
|
|
508
|
+
try {
|
|
509
|
+
switch (name) {
|
|
510
|
+
case "optimize_prompt": return await this.handleOptimizePrompt(args);
|
|
511
|
+
case "get_quota_status": return await this.handleGetQuotaStatus();
|
|
512
|
+
case "search_templates": return await this.handleSearchTemplates(args);
|
|
513
|
+
case "list_recent_templates": return await this.handleListRecentTemplates(args);
|
|
514
|
+
case "detect_ai_context": return await this.handleDetectAIContext(args);
|
|
515
|
+
case "create_template": return await this.handleCreateTemplate(args);
|
|
516
|
+
case "get_template": return await this.handleGetTemplate(args);
|
|
517
|
+
case "update_template": return await this.handleUpdateTemplate(args);
|
|
518
|
+
case "delete_template": return await this.handleDeleteTemplate(args);
|
|
519
|
+
case "get_optimization_insights": return await this.handleGetOptimizationInsights(args);
|
|
520
|
+
case "get_real_time_status": return await this.handleGetRealTimeStatus();
|
|
521
|
+
case "generate_agent_sop": return await this.handleGenerateAgentSop(args);
|
|
522
|
+
case "generate_skill_package": return await this.handleGenerateSkillPackage(args);
|
|
523
|
+
case "transform_for_framework": return await this.handleTransformForFramework(args);
|
|
524
|
+
case "get_ce_quota_status": return await this.handleGetCEQuotaStatus();
|
|
525
|
+
case "generate_harness_bundle": return await this.handleGenerateHarnessBundle(args);
|
|
526
|
+
case "explore_sop_approaches": return await this.handleExploreSopApproaches(args);
|
|
527
|
+
default: throw new Error(`Unknown tool: ${name}`);
|
|
528
|
+
}
|
|
529
|
+
} catch (error) {
|
|
530
|
+
throw new Error(`Tool execution failed: ${error.message}`);
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// ─── Rules-Based Optimization (offline / fallback tier) ─────────────────────
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Select the best-matching template for a prompt using pattern scoring.
|
|
539
|
+
* Mirrors the backend's pattern-based fallback (no LLM required).
|
|
540
|
+
*/
|
|
541
|
+
_matchTemplate(prompt, backendContext) {
|
|
542
|
+
const lc = prompt.toLowerCase();
|
|
543
|
+
let bestTemplate = null;
|
|
544
|
+
let bestScore = 0;
|
|
545
|
+
let fallbackName = null;
|
|
546
|
+
|
|
547
|
+
for (const [name, template] of Object.entries(OPTIMIZATION_TEMPLATES)) {
|
|
548
|
+
if (template.context !== backendContext) continue;
|
|
549
|
+
if (name.startsWith('fallback_')) { fallbackName = name; continue; }
|
|
550
|
+
|
|
551
|
+
let hits = 0;
|
|
552
|
+
for (const pattern of template.patterns) {
|
|
553
|
+
if (pattern === '.*') continue;
|
|
554
|
+
if (lc.includes(pattern.toLowerCase())) hits++;
|
|
555
|
+
}
|
|
556
|
+
if (hits === 0) continue;
|
|
557
|
+
|
|
558
|
+
// Confidence: 1 hit → 0.6, 2 hits → 0.75, 3+ hits → 0.9 (mirrors backend)
|
|
559
|
+
const patternConf = hits === 1 ? 0.6 : hits === 2 ? 0.75 : 0.9;
|
|
560
|
+
const score = patternConf + (template.priority || 1) / 100;
|
|
561
|
+
|
|
562
|
+
if (score > bestScore) { bestScore = score; bestTemplate = name; }
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (!bestTemplate) {
|
|
566
|
+
return { templateName: fallbackName || `fallback_${backendContext.toLowerCase()}`, matchConfidence: 0.3 };
|
|
567
|
+
}
|
|
568
|
+
return { templateName: bestTemplate, matchConfidence: bestScore };
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/** Extract a user-defined role from the start of a prompt (e.g. "As a doctor, …"). */
|
|
572
|
+
_extractUserRole(request) {
|
|
573
|
+
const rolePatterns = [
|
|
574
|
+
/^['"]?(?:As a|You are a|My role is)\s+([a-zA-Z0-9\s\-/()]+?)(?:,|(?=\s*\.))/i,
|
|
575
|
+
/^['"]?(?:I am a|I'm a)\s+([a-zA-Z0-9\s\-/()]+?)(?:,|(?=\s*\.))/i,
|
|
576
|
+
];
|
|
577
|
+
for (const re of rolePatterns) {
|
|
578
|
+
const m = request.match(re);
|
|
579
|
+
if (m) return m[1].trim();
|
|
580
|
+
}
|
|
581
|
+
return null;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Compile a template playbook into a user-facing prose prompt.
|
|
586
|
+
* Produces readable output instead of XML scaffolding, matching the
|
|
587
|
+
* result a backend LLM pass would generate from the same playbook.
|
|
588
|
+
*/
|
|
589
|
+
_compilePlaybook(playbook, originalRequest) {
|
|
590
|
+
const parts = [];
|
|
591
|
+
|
|
592
|
+
parts.push(originalRequest.trim());
|
|
593
|
+
parts.push('');
|
|
594
|
+
|
|
595
|
+
const userFacingPrinciples = (playbook.principles || []).filter(p => {
|
|
596
|
+
const lc = p.toLowerCase();
|
|
597
|
+
return !lc.includes('scratchpad') &&
|
|
598
|
+
!lc.startsWith('first, think') &&
|
|
599
|
+
!/<[a-z]/i.test(p);
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
if (userFacingPrinciples.length > 0) {
|
|
603
|
+
parts.push('To address this effectively:');
|
|
604
|
+
for (const p of userFacingPrinciples) parts.push(`- ${p}`);
|
|
605
|
+
parts.push('');
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
if (playbook.output_format) {
|
|
609
|
+
parts.push(`*Response format: ${playbook.output_format}*`);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
return parts.join('\n');
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Enhance an image generation prompt by appending style-appropriate
|
|
617
|
+
* quality/composition boosters (mirrors backend _compile_image_prompt_fallback).
|
|
618
|
+
*/
|
|
619
|
+
_compileImagePrompt(originalRequest) {
|
|
620
|
+
const text = originalRequest.trim();
|
|
621
|
+
const lc = text.toLowerCase();
|
|
622
|
+
|
|
623
|
+
const styles = {
|
|
624
|
+
photorealistic: ['photorealistic','realistic','photo','photograph','photography'],
|
|
625
|
+
'3d_render': ['3d','render','octane','unreal engine','blender','cinema 4d','ray tracing'],
|
|
626
|
+
cinematic: ['cinematic','movie','film','dramatic','epic'],
|
|
627
|
+
digital_art: ['digital art','concept art','digital illustration','cg','cgi'],
|
|
628
|
+
artistic: ['artistic','painting','watercolor','oil painting','impressionist'],
|
|
629
|
+
anime: ['anime','manga'],
|
|
630
|
+
vintage: ['vintage','retro','nostalgic'],
|
|
631
|
+
minimalist: ['minimalist','minimal','simple','clean'],
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
let detectedStyle = null;
|
|
635
|
+
for (const [style, kws] of Object.entries(styles)) {
|
|
636
|
+
if (kws.some(kw => lc.includes(kw))) { detectedStyle = style; break; }
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
const enhancements = [];
|
|
640
|
+
const hasQuality = ['high quality','8k','4k','hd','highly detailed','detailed'].some(t => lc.includes(t));
|
|
641
|
+
const hasLighting = ['lighting','light','shadow','illuminated','lit'].some(t => lc.includes(t));
|
|
642
|
+
const hasComposition = ['composition','rule of thirds','centered','framed'].some(t => lc.includes(t));
|
|
643
|
+
|
|
644
|
+
if (detectedStyle === 'photorealistic' && !hasQuality) {
|
|
645
|
+
enhancements.push('ultra realistic, sharp focus, professional photography');
|
|
646
|
+
} else if (detectedStyle === '3d_render' && !['octane','render'].some(t => lc.includes(t))) {
|
|
647
|
+
enhancements.push('high quality 3D render, volumetric lighting, ray traced shadows');
|
|
648
|
+
} else if (detectedStyle === 'cinematic' && !hasLighting) {
|
|
649
|
+
enhancements.push('cinematic lighting, dramatic atmosphere, film grain');
|
|
650
|
+
} else if (detectedStyle === 'digital_art' && !hasQuality) {
|
|
651
|
+
enhancements.push('highly detailed digital art, professional illustration');
|
|
652
|
+
} else if (detectedStyle === 'artistic' && !lc.includes('masterpiece')) {
|
|
653
|
+
enhancements.push('masterful technique, rich colors, artistic composition');
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
if (!hasLighting && detectedStyle !== 'minimalist') enhancements.push('dynamic lighting');
|
|
657
|
+
if (!hasComposition) enhancements.push('balanced composition');
|
|
658
|
+
if (!hasQuality) enhancements.push('high quality, 4K');
|
|
659
|
+
|
|
660
|
+
return enhancements.length > 0 ? `${text}, ${enhancements.join(', ')}` : text;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Core rules-based optimizer — no network, no LLM.
|
|
665
|
+
* Selects the best template by pattern matching, then compiles
|
|
666
|
+
* the playbook into a structured prompt. Confidence range: 0.35–0.55.
|
|
667
|
+
*/
|
|
668
|
+
rulesBasedOptimize(prompt, aiContext, goals = []) {
|
|
669
|
+
const contextMap = {
|
|
670
|
+
code_generation: 'CODE_GENERATION',
|
|
671
|
+
llm_interaction: 'LLM_INTERACTION',
|
|
672
|
+
image_generation: 'IMAGE_GENERATION',
|
|
673
|
+
human_communication: 'HUMAN_COMMUNICATION',
|
|
674
|
+
api_automation: 'API_AUTOMATION',
|
|
675
|
+
technical_automation: 'TECHNICAL_AUTOMATION',
|
|
676
|
+
structured_output: 'STRUCTURED_OUTPUT',
|
|
677
|
+
creative_enhancement: 'CREATIVE_ENHANCEMENT',
|
|
678
|
+
creative_writing: 'CREATIVE_ENHANCEMENT',
|
|
679
|
+
general_assistant: 'LLM_INTERACTION',
|
|
680
|
+
};
|
|
681
|
+
const backendContext = contextMap[aiContext] || 'LLM_INTERACTION';
|
|
682
|
+
|
|
683
|
+
const { templateName, matchConfidence } = this._matchTemplate(prompt, backendContext);
|
|
684
|
+
const template = OPTIMIZATION_TEMPLATES[templateName];
|
|
685
|
+
|
|
686
|
+
const optimizedPrompt = backendContext === 'IMAGE_GENERATION'
|
|
687
|
+
? this._compileImagePrompt(prompt)
|
|
688
|
+
: this._compilePlaybook(template.playbook, prompt);
|
|
689
|
+
|
|
690
|
+
// Honest confidence: rules-based tops out around 0.55
|
|
691
|
+
const confidence = parseFloat(Math.min(0.35 + matchConfidence * 0.2, 0.55).toFixed(2));
|
|
692
|
+
|
|
693
|
+
return {
|
|
694
|
+
optimized_prompt: optimizedPrompt,
|
|
695
|
+
confidence_score: confidence,
|
|
696
|
+
tier: 'rules',
|
|
697
|
+
template_used: templateName,
|
|
698
|
+
rules_based: true,
|
|
699
|
+
template_saved: false,
|
|
700
|
+
templates_found: [],
|
|
701
|
+
optimization_insights: null,
|
|
702
|
+
bayesian_insights: null,
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// ─── End Rules-Based Optimization ────────────────────────────────────────────
|
|
707
|
+
|
|
708
|
+
generateMockOptimization(prompt, goals, aiContext, enableBayesian = false) {
|
|
709
|
+
// Use real rules-based optimization instead of fake placeholder output
|
|
710
|
+
const rulesResult = this.rulesBasedOptimize(prompt, aiContext, goals);
|
|
711
|
+
const baseResult = {
|
|
712
|
+
...rulesResult,
|
|
713
|
+
rules_based: false, // Show as normal optimized output in mock mode
|
|
714
|
+
tier: 'free',
|
|
715
|
+
mock_mode: true,
|
|
716
|
+
template_saved: true,
|
|
717
|
+
template_id: 'test-template-123',
|
|
718
|
+
templates_found: [{ title: 'Similar Template 1', confidence_score: 0.85, id: 'tmpl-1' }],
|
|
719
|
+
optimization_insights: {
|
|
720
|
+
improvement_metrics: {
|
|
721
|
+
clarity_improvement: 0.25,
|
|
722
|
+
specificity_improvement: 0.20,
|
|
723
|
+
length_optimization: 0.15,
|
|
724
|
+
context_alignment: 0.30
|
|
725
|
+
},
|
|
726
|
+
user_patterns: {
|
|
727
|
+
optimization_confidence: '87.0%',
|
|
728
|
+
prompt_complexity: 'intermediate',
|
|
729
|
+
ai_context: aiContext
|
|
730
|
+
},
|
|
731
|
+
recommendations: [
|
|
732
|
+
`Context detected as ${aiContext}`,
|
|
733
|
+
'Enhanced goal optimization applied',
|
|
734
|
+
'Template auto-save threshold met'
|
|
735
|
+
]
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
|
|
739
|
+
// Add Bayesian optimization insights if enabled
|
|
740
|
+
if (enableBayesian && this.bayesianOptimizationEnabled) {
|
|
741
|
+
baseResult.bayesian_insights = {
|
|
742
|
+
parameter_optimization: {
|
|
743
|
+
temperature_adjustment: '+0.1',
|
|
744
|
+
context_weight: '+0.15',
|
|
745
|
+
goal_prioritization: 'clarity > specificity > engagement'
|
|
746
|
+
},
|
|
747
|
+
performance_prediction: {
|
|
748
|
+
expected_improvement: '12-18%',
|
|
749
|
+
confidence_interval: '85-95%',
|
|
750
|
+
optimization_strategy: 'gradient_boost_context'
|
|
751
|
+
},
|
|
752
|
+
next_optimization_recommendation: {
|
|
753
|
+
suggested_goals: ['analytical_depth', 'creative_enhancement'],
|
|
754
|
+
estimated_improvement: '8-12%'
|
|
755
|
+
}
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
return baseResult;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
generateMockContextDetection(prompt) {
|
|
763
|
+
let primary_context = 'human_communication'; // Default context
|
|
764
|
+
const lc = prompt.toLowerCase(); // one‑off lower‑case copy
|
|
765
|
+
|
|
766
|
+
/* 1️⃣ Code / programming – now includes `def` / `return`. */
|
|
767
|
+
if (lc.match(/def\b|return\b|import\b|class\b|for\b|while\b|if\b|else\b|elif\b|function\b|code\b|python|javascript|java|c\+\+/i)) {
|
|
768
|
+
primary_context = 'code_generation';
|
|
769
|
+
|
|
770
|
+
/* 2️⃣ Image / art – unchanged. */
|
|
771
|
+
} else if (lc.match(/image|generate|dall-e|midjourney/i)) {
|
|
772
|
+
primary_context = 'image_generation';
|
|
773
|
+
|
|
774
|
+
/* 3️⃣ Automation – unchanged. */
|
|
775
|
+
} else if (lc.match(/automate|script|api/i)) {
|
|
776
|
+
primary_context = 'technical_automation';
|
|
777
|
+
|
|
778
|
+
/* 4️⃣ LLM / analysis – newly added keyword “analyze”. */
|
|
779
|
+
} else if (lc.match(/analyze|explain|evaluate|summary|research|paper|analysis|interpret|discussion|assessment|compare|contrast/i)) {
|
|
780
|
+
primary_context = 'llm_interaction';
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
return {
|
|
784
|
+
primary_context: primary_context,
|
|
785
|
+
confidence: 0.75,
|
|
786
|
+
secondary_contexts: ['llm_interaction'],
|
|
787
|
+
detected_parameters: [],
|
|
788
|
+
mock_mode: true,
|
|
789
|
+
reason: 'Backend unavailable — using local pattern matching as fallback.'
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
async handleOptimizePrompt(args) {
|
|
794
|
+
if (!args.prompt) throw new Error('Prompt is required');
|
|
795
|
+
|
|
796
|
+
const manager = new CloudApiKeyManager(this.apiKey);
|
|
797
|
+
|
|
798
|
+
try {
|
|
799
|
+
const validation = await manager.validateApiKey();
|
|
800
|
+
|
|
801
|
+
if (validation.mock_mode || this.developmentMode) {
|
|
802
|
+
// In mock/dev mode, we still need a context for mock generation
|
|
803
|
+
const mockContext = args.ai_context || 'human_communication';
|
|
804
|
+
const mockGoals = args.goals || ['clarity'];
|
|
805
|
+
const mockEnableBayesian = args.enable_bayesian !== false && this.bayesianOptimizationEnabled;
|
|
806
|
+
const mockResult = this.generateMockOptimization(args.prompt, mockGoals, mockContext, mockEnableBayesian);
|
|
807
|
+
const formatted = this.formatOptimizationResult(mockResult, { detectedContext: mockContext, enableBayesian: mockEnableBayesian });
|
|
808
|
+
return { content: [{ type: "text", text: formatted }] };
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// 1. Detect AI Context from backend
|
|
812
|
+
let detectedContext = args.ai_context;
|
|
813
|
+
if (!detectedContext) {
|
|
814
|
+
try {
|
|
815
|
+
const contextDetectionResult = await this.callBackendAPI(ENDPOINTS.DETECT_CONTEXT, { prompt: args.prompt });
|
|
816
|
+
detectedContext = contextDetectionResult.primary_context;
|
|
817
|
+
console.error(`Detected AI Context from backend: ${detectedContext}`);
|
|
818
|
+
} catch (contextError) {
|
|
819
|
+
console.error(`Failed to detect AI context from backend, falling back to default: ${contextError.message}`);
|
|
820
|
+
detectedContext = 'human_communication'; // Fallback
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// 2. Call the main optimization endpoint
|
|
825
|
+
const optimizationPayload = {
|
|
826
|
+
prompt: args.prompt,
|
|
827
|
+
goals: args.goals || ['clarity'],
|
|
828
|
+
ai_context: detectedContext,
|
|
829
|
+
};
|
|
830
|
+
|
|
831
|
+
if (args.value_hierarchy && args.value_hierarchy.length > 0) {
|
|
832
|
+
optimizationPayload.value_hierarchy = args.value_hierarchy;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
if (args.intent_frame && typeof args.intent_frame === 'object') {
|
|
836
|
+
const { perspective, out_of_scope, success_definition } = args.intent_frame;
|
|
837
|
+
if (perspective || (out_of_scope && out_of_scope.length > 0) || success_definition) {
|
|
838
|
+
optimizationPayload.intent_frame = args.intent_frame;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
const result = await this.callBackendAPI(ENDPOINTS.OPTIMIZE, optimizationPayload);
|
|
843
|
+
|
|
844
|
+
const enableBayesian = args.enable_bayesian !== false && this.bayesianOptimizationEnabled;
|
|
845
|
+
return { content: [{ type: "text", text: this.formatOptimizationResult(result, { detectedContext, enableBayesian }) }] };
|
|
846
|
+
|
|
847
|
+
} catch (error) {
|
|
848
|
+
if (error.message.includes('Network') || error.message.includes('DNS') || error.message.includes('timeout') || error.message.includes('Connection')) {
|
|
849
|
+
const fallbackContext = args.ai_context || 'human_communication';
|
|
850
|
+
const fallbackEnableBayesian = args.enable_bayesian !== false && this.bayesianOptimizationEnabled;
|
|
851
|
+
const fallbackResult = this.rulesBasedOptimize(args.prompt, fallbackContext, args.goals || ['clarity']);
|
|
852
|
+
fallbackResult.fallback_mode = true;
|
|
853
|
+
fallbackResult.error_reason = error.message;
|
|
854
|
+
const formatted = this.formatOptimizationResult(fallbackResult, { detectedContext: fallbackContext, enableBayesian: fallbackEnableBayesian });
|
|
855
|
+
return { content: [{ type: "text", text: formatted }] };
|
|
856
|
+
}
|
|
857
|
+
throw new Error(`Optimization failed: ${error.message}`);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
async handleGetQuotaStatus() {
|
|
862
|
+
const manager = new CloudApiKeyManager(this.apiKey);
|
|
863
|
+
const info = await manager.getApiKeyInfo();
|
|
864
|
+
return { content: [{ type: "text", text: this.formatQuotaStatus(info) }] };
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
async handleSearchTemplates(args) {
|
|
868
|
+
try {
|
|
869
|
+
const params = new URLSearchParams({
|
|
870
|
+
page: (args.page || 1).toString(),
|
|
871
|
+
per_page: Math.min(args.limit || 5, 20).toString(),
|
|
872
|
+
sort_by: args.sort_by || 'confidence_score',
|
|
873
|
+
sort_order: args.sort_order || 'desc'
|
|
874
|
+
});
|
|
875
|
+
|
|
876
|
+
if (args.query) params.append('query', args.query);
|
|
877
|
+
if (args.ai_context) params.append('ai_context', args.ai_context);
|
|
878
|
+
if (args.sophistication_level) params.append('sophistication_level', args.sophistication_level);
|
|
879
|
+
if (args.complexity_level) params.append('complexity_level', args.complexity_level);
|
|
880
|
+
if (args.optimization_strategy) params.append('optimization_strategy', args.optimization_strategy);
|
|
881
|
+
|
|
882
|
+
const endpoint = `${ENDPOINTS.SEARCH_TEMPLATES}?${params.toString()}`;
|
|
883
|
+
const result = await this.callBackendAPI(endpoint, null, 'GET');
|
|
884
|
+
|
|
885
|
+
const searchResult = {
|
|
886
|
+
templates: result.templates || [],
|
|
887
|
+
total: result.total || 0,
|
|
888
|
+
query: args.query,
|
|
889
|
+
ai_context: args.ai_context,
|
|
890
|
+
sophistication_level: args.sophistication_level,
|
|
891
|
+
complexity_level: args.complexity_level
|
|
892
|
+
};
|
|
893
|
+
|
|
894
|
+
const formatted = this.formatTemplateSearchResults(searchResult, args);
|
|
895
|
+
return { content: [{ type: "text", text: formatted }] };
|
|
896
|
+
|
|
897
|
+
} catch (error) {
|
|
898
|
+
console.error(`Template search failed: ${error.message}`);
|
|
899
|
+
const fallbackResult = {
|
|
900
|
+
templates: [],
|
|
901
|
+
total: 0,
|
|
902
|
+
message: "Template search is temporarily unavailable.",
|
|
903
|
+
error: error.message,
|
|
904
|
+
fallback_mode: true
|
|
905
|
+
};
|
|
906
|
+
const formatted = this.formatTemplateSearchResults(fallbackResult, args);
|
|
907
|
+
return { content: [{ type: "text", text: formatted }] };
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
async handleListRecentTemplates(args) {
|
|
912
|
+
try {
|
|
913
|
+
const limit = Math.min(Math.max(args.limit || 10, 1), 20);
|
|
914
|
+
const params = new URLSearchParams({
|
|
915
|
+
page: '1',
|
|
916
|
+
per_page: limit.toString(),
|
|
917
|
+
sort_by: 'created_at',
|
|
918
|
+
sort_order: 'desc'
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
const endpoint = `${ENDPOINTS.SEARCH_TEMPLATES}?${params.toString()}`;
|
|
922
|
+
const result = await this.callBackendAPI(endpoint, null, 'GET');
|
|
923
|
+
|
|
924
|
+
const templates = result.templates || [];
|
|
925
|
+
let output = `# 📋 Recent Templates\n\n`;
|
|
926
|
+
output += `Showing **${templates.length}** most recently saved template(s).\n\n`;
|
|
927
|
+
|
|
928
|
+
if (templates.length === 0) {
|
|
929
|
+
output += `📭 No templates found yet.\nRun \`optimize_prompt\` to start building your template library.\n`;
|
|
930
|
+
} else {
|
|
931
|
+
output += `## 📋 **Template Results**\n`;
|
|
932
|
+
templates.forEach((t, index) => {
|
|
933
|
+
const confidence = t.confidence_score ? `${(t.confidence_score * 100).toFixed(1)}%` : 'N/A';
|
|
934
|
+
const preview = t.optimized_prompt ? t.optimized_prompt.substring(0, 60) + '...' : 'Preview unavailable';
|
|
935
|
+
output += `### ${index + 1}. ${t.title}\n`;
|
|
936
|
+
output += `- **Confidence:** ${confidence}\n`;
|
|
937
|
+
output += `- **ID:** \`${t.id}\`\n`;
|
|
938
|
+
output += `- **Preview:** ${preview}\n`;
|
|
939
|
+
if (t.ai_context) output += `- **Context:** ${t.ai_context}\n`;
|
|
940
|
+
if (t.optimization_goals && t.optimization_goals.length) {
|
|
941
|
+
output += `- **Goals:** ${t.optimization_goals.join(', ')}\n`;
|
|
942
|
+
}
|
|
943
|
+
output += `\n`;
|
|
944
|
+
});
|
|
945
|
+
output += `💡 Use \`get_template\` with an ID above to view the full optimized prompt.\n`;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
return { content: [{ type: "text", text: output }] };
|
|
949
|
+
} catch (error) {
|
|
950
|
+
return { content: [{ type: "text", text: `❌ Could not retrieve recent templates: ${error.message}` }] };
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
async handleGetOptimizationInsights(args) {
|
|
955
|
+
if (!this.bayesianOptimizationEnabled) {
|
|
956
|
+
return { content: [{ type: "text", text: "🧠 Bayesian optimization features are not enabled. Set ENABLE_BAYESIAN_OPTIMIZATION=true to access advanced insights." }] };
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
try {
|
|
960
|
+
// Try to get insights from backend
|
|
961
|
+
const endpoint = `${ENDPOINTS.ANALYTICS_BAYESIAN_INSIGHTS}?depth=${args.analysis_depth || 'detailed'}&recommendations=${args.include_recommendations !== false}`;
|
|
962
|
+
const result = await this.callBackendAPI(endpoint, null, 'GET');
|
|
963
|
+
|
|
964
|
+
return { content: [{ type: "text", text: this.formatOptimizationInsights(result) }] };
|
|
965
|
+
|
|
966
|
+
} catch (error) {
|
|
967
|
+
// Fallback to mock insights
|
|
968
|
+
const mockInsights = {
|
|
969
|
+
bayesian_status: {
|
|
970
|
+
optimization_active: true,
|
|
971
|
+
total_optimizations: 47,
|
|
972
|
+
improvement_rate: '23.5%',
|
|
973
|
+
confidence_score: 0.89
|
|
974
|
+
},
|
|
975
|
+
parameter_insights: {
|
|
976
|
+
most_effective_goals: ['clarity', 'technical_accuracy', 'analytical_depth'],
|
|
977
|
+
context_performance: {
|
|
978
|
+
'code_generation': 0.92,
|
|
979
|
+
'llm_interaction': 0.87,
|
|
980
|
+
'technical_automation': 0.84
|
|
981
|
+
},
|
|
982
|
+
optimization_trends: 'Steady improvement in technical contexts'
|
|
983
|
+
},
|
|
984
|
+
recommendations: args.include_recommendations !== false ? [
|
|
985
|
+
'Focus on technical_accuracy for code generation prompts',
|
|
986
|
+
'Combine clarity with analytical_depth for best results',
|
|
987
|
+
'Consider using structured_output context for data tasks'
|
|
988
|
+
] : []
|
|
989
|
+
};
|
|
990
|
+
|
|
991
|
+
return { content: [{ type: "text", text: this.formatOptimizationInsights(mockInsights) }] };
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
async handleGetRealTimeStatus() {
|
|
996
|
+
if (!this.aguiFeatures) {
|
|
997
|
+
return { content: [{ type: "text", text: "⚡ AG-UI real-time features are not enabled. Set ENABLE_AGUI_FEATURES=true to access real-time optimization capabilities." }] };
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
try {
|
|
1001
|
+
const result = await this.callBackendAPI(ENDPOINTS.AGUI_STATUS, null, 'GET');
|
|
1002
|
+
|
|
1003
|
+
return { content: [{ type: "text", text: this.formatRealTimeStatus(result) }] };
|
|
1004
|
+
|
|
1005
|
+
} catch (error) {
|
|
1006
|
+
const mockStatus = {
|
|
1007
|
+
agui_status: 'available',
|
|
1008
|
+
streaming_optimization: true,
|
|
1009
|
+
websocket_support: true,
|
|
1010
|
+
real_time_analytics: true,
|
|
1011
|
+
active_optimizations: 3,
|
|
1012
|
+
average_response_time: '1.2s',
|
|
1013
|
+
features: {
|
|
1014
|
+
live_optimization: true,
|
|
1015
|
+
collaborative_editing: true,
|
|
1016
|
+
instant_feedback: true,
|
|
1017
|
+
performance_monitoring: true
|
|
1018
|
+
}
|
|
1019
|
+
};
|
|
1020
|
+
|
|
1021
|
+
return { content: [{ type: "text", text: this.formatRealTimeStatus(mockStatus) }] };
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
async handleDetectAIContext(args) {
|
|
1026
|
+
if (!args.prompt) throw new Error('Prompt is required');
|
|
1027
|
+
|
|
1028
|
+
const formatResult = (result) => {
|
|
1029
|
+
let output = `# 🧠 AI Context Detection Result\n\n`;
|
|
1030
|
+
output += `**Primary Context:** ${result.primary_context}\n`;
|
|
1031
|
+
output += `**Confidence:** ${(result.confidence * 100).toFixed(1)}%\n`;
|
|
1032
|
+
if (result.secondary_contexts && result.secondary_contexts.length > 0) {
|
|
1033
|
+
output += `**Secondary Contexts:** ${result.secondary_contexts.join(', ')}\n`;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
const detections = result.detected_parameters ?? [];
|
|
1037
|
+
const safeDetections = detections.filter(d => d && d.name);
|
|
1038
|
+
|
|
1039
|
+
if (safeDetections.length > 0) {
|
|
1040
|
+
output += `**Detected Parameters:** ${safeDetections.map(d => d.name).join(', ')}\n`;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
if (result.mock_mode) {
|
|
1044
|
+
output += `\n⚠️ **Fallback Mode Active:** Using mock data due to development mode or network issues.\n`;
|
|
1045
|
+
}
|
|
1046
|
+
return { content: [{ type: "text", text: output }] };
|
|
1047
|
+
};
|
|
1048
|
+
|
|
1049
|
+
try {
|
|
1050
|
+
const manager = new CloudApiKeyManager(this.apiKey);
|
|
1051
|
+
const validation = await manager.validateApiKey();
|
|
1052
|
+
|
|
1053
|
+
if (validation.mock_mode || this.developmentMode) {
|
|
1054
|
+
const mockResult = this.generateMockContextDetection(args.prompt);
|
|
1055
|
+
return formatResult(mockResult);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
const result = await this.callBackendAPI(ENDPOINTS.DETECT_CONTEXT, { prompt: args.prompt });
|
|
1059
|
+
return formatResult(result);
|
|
1060
|
+
|
|
1061
|
+
} catch (error) {
|
|
1062
|
+
// Fallback for ANY error during the process (missing key, network, etc.)
|
|
1063
|
+
const fallbackResult = this.generateMockContextDetection(args.prompt);
|
|
1064
|
+
return formatResult(fallbackResult);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
async handleCreateTemplate(args) {
|
|
1069
|
+
// Client-side validation before network call
|
|
1070
|
+
const requiredStrings = ['title', 'original_prompt', 'optimized_prompt'];
|
|
1071
|
+
for (const field of requiredStrings) {
|
|
1072
|
+
if (!args[field] || typeof args[field] !== 'string' || args[field].trim() === '') {
|
|
1073
|
+
return { content: [{ type: "text", text: `❌ Missing required field: '${field}'. Required fields: title, original_prompt, optimized_prompt, confidence_score (0.0–1.0)` }] };
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
if (args.confidence_score === undefined || args.confidence_score === null ||
|
|
1077
|
+
typeof args.confidence_score !== 'number' || args.confidence_score < 0 || args.confidence_score > 1) {
|
|
1078
|
+
return { content: [{ type: "text", text: `❌ Missing required field: 'confidence_score'. Required fields: title, original_prompt, optimized_prompt, confidence_score (0.0–1.0)` }] };
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
try {
|
|
1082
|
+
const result = await this.callBackendAPI(ENDPOINTS.TEMPLATE.CREATE, args);
|
|
1083
|
+
let output = `# ✅ Template Created Successfully!\n\n`;
|
|
1084
|
+
output += `**Title:** ${result.title}\n`;
|
|
1085
|
+
output += `**ID:** \`${result.id}\`\n`;
|
|
1086
|
+
output += `**Confidence Score:** ${(result.confidence_score * 100).toFixed(1)}%\n`;
|
|
1087
|
+
output += `**AI Context:** ${result.ai_context_detected || 'N/A'}\n`;
|
|
1088
|
+
output += `**Public:** ${result.is_public ? 'Yes' : 'No'}\n`;
|
|
1089
|
+
output += `\n**Optimized Prompt Preview:**\n\`\`\`\n${result.optimized_prompt.substring(0, 150)}...\n\`\`\`\n`;
|
|
1090
|
+
return { content: [{ type: "text", text: output }] };
|
|
1091
|
+
} catch (error) {
|
|
1092
|
+
throw new Error(`Failed to create template: ${error.message}`);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
async handleGetTemplate(args) {
|
|
1097
|
+
if (!args.template_id) throw new Error('Template ID is required');
|
|
1098
|
+
try {
|
|
1099
|
+
const result = await this.callBackendAPI(ENDPOINTS.TEMPLATE.GET(args.template_id), null, 'GET');
|
|
1100
|
+
let output = `# 📄 Template Details\n\n`;
|
|
1101
|
+
output += `**Title:** ${result.title}\n`;
|
|
1102
|
+
output += `**ID:** \`${result.id}\`\n`;
|
|
1103
|
+
output += `**Description:** ${result.description || 'N/A'}\n`;
|
|
1104
|
+
output += `**AI Context:** ${result.ai_context_detected || 'N/A'}\n`;
|
|
1105
|
+
output += `**Confidence Score:** ${(result.confidence_score * 100).toFixed(1)}%\n`;
|
|
1106
|
+
output += `**Public:** ${result.is_public ? 'Yes' : 'No'}\n`;
|
|
1107
|
+
output += `**Tags:** ${result.tags ? result.tags.join(', ') : 'None'}\n\n`;
|
|
1108
|
+
output += `**Original Prompt:**\n\`\`\`\n${result.original_prompt}\n\`\`\`\n\n`;
|
|
1109
|
+
output += `**Optimized Prompt:**\n\`\`\`\n${result.optimized_prompt}\n\`\`\`\n`;
|
|
1110
|
+
return { content: [{ type: "text", text: output }] };
|
|
1111
|
+
} catch (error) {
|
|
1112
|
+
const msg = error.message || '';
|
|
1113
|
+
if (msg.includes('404') || msg.toLowerCase().includes('not found')) {
|
|
1114
|
+
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.`);
|
|
1115
|
+
}
|
|
1116
|
+
throw new Error(`Failed to retrieve template: ${error.message}`);
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
async handleUpdateTemplate(args) {
|
|
1121
|
+
if (!args.template_id) throw new Error('Template ID is required');
|
|
1122
|
+
try {
|
|
1123
|
+
const { template_id, ...updateData } = args;
|
|
1124
|
+
// Filter out undefined values so we only send fields that are being updated
|
|
1125
|
+
Object.keys(updateData).forEach(key => updateData[key] === undefined && delete updateData[key]);
|
|
1126
|
+
|
|
1127
|
+
const result = await this.callBackendAPI(ENDPOINTS.TEMPLATE.UPDATE(template_id), updateData, 'PATCH'); // PATCH is better for partial updates
|
|
1128
|
+
let output = `# ✅ Template Updated Successfully!\n\n`;
|
|
1129
|
+
output += `**ID:** \`${result.id}\`\n`;
|
|
1130
|
+
output += `**Title:** ${result.title}\n\n`;
|
|
1131
|
+
output += `Use 'get_template' with the ID to see the full updated template.`;
|
|
1132
|
+
return { content: [{ type: "text", text: output }] };
|
|
1133
|
+
} catch (error) {
|
|
1134
|
+
throw new Error(`Failed to update template: ${error.message}`);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
async handleDeleteTemplate(args) {
|
|
1139
|
+
if (!args.template_id) throw new Error('Template ID is required');
|
|
1140
|
+
try {
|
|
1141
|
+
const result = await this.callBackendAPI(ENDPOINTS.TEMPLATE.DELETE(args.template_id), null, 'DELETE');
|
|
1142
|
+
const title = result.message || `Template ${args.template_id}`;
|
|
1143
|
+
return { content: [{ type: "text", text: `# 🗑️ Template Deleted\n\n${title}` }] };
|
|
1144
|
+
} catch (error) {
|
|
1145
|
+
throw new Error(`Failed to delete template: ${error.message}`);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
async handleGenerateAgentSop(args) {
|
|
1150
|
+
if (!args.goal) throw new Error('goal is required');
|
|
1151
|
+
const payload = { goal: args.goal };
|
|
1152
|
+
if (args.context) payload.context = args.context;
|
|
1153
|
+
if (args.model_id) payload.model_id = args.model_id;
|
|
1154
|
+
if (args.intent_frame) payload.intent_frame = args.intent_frame;
|
|
1155
|
+
try {
|
|
1156
|
+
const result = await this.callBackendAPI(ENDPOINTS.CE.SOP, payload);
|
|
1157
|
+
const sopContent = result.sop || result.content || result.result || JSON.stringify(result, null, 2);
|
|
1158
|
+
return { content: [{ type: "text", text: `# Agent SOP Generated\n\n${sopContent}\n\n---\n*Generated by MCP Prompt Optimizer CE*` }] };
|
|
1159
|
+
} catch (error) {
|
|
1160
|
+
throw new Error(`Failed to generate SOP: ${error.message}`);
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
async handleGenerateSkillPackage(args) {
|
|
1165
|
+
if (!args.goal) throw new Error('goal is required');
|
|
1166
|
+
const payload = { goal: args.goal, format: args.format || 'knowledge_doc' };
|
|
1167
|
+
if (args.model_id) payload.model_id = args.model_id;
|
|
1168
|
+
let workflowError = null;
|
|
1169
|
+
try {
|
|
1170
|
+
const startResult = await this.callBackendAPI(ENDPOINTS.CE.GENERATE_SKILL_PACKAGE, payload);
|
|
1171
|
+
const sessionId = startResult.session_id;
|
|
1172
|
+
if (!sessionId) {
|
|
1173
|
+
return { content: [{ type: "text", text: this._formatSkillPackage(startResult) }] };
|
|
1174
|
+
}
|
|
1175
|
+
for (let i = 0; i < 24; i++) {
|
|
1176
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
1177
|
+
const status = await this.callBackendAPI(ENDPOINTS.CE.SESSION(sessionId), null, 'GET');
|
|
1178
|
+
const state = status.workflow_state || status.current_state;
|
|
1179
|
+
if (state === 'complete') return { content: [{ type: "text", text: this._formatSkillPackage(status) }] };
|
|
1180
|
+
if (state === 'failed') {
|
|
1181
|
+
workflowError = new Error(`Generation failed: ${status.error || 'Unknown error'}`);
|
|
1182
|
+
throw workflowError;
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
workflowError = new Error(`Timed out after 120s. Session ID: ${sessionId}`);
|
|
1186
|
+
throw workflowError;
|
|
1187
|
+
} catch (error) {
|
|
1188
|
+
if (error === workflowError) throw error;
|
|
1189
|
+
throw new Error(`Failed to generate skill package: ${error.message}`);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
async handleTransformForFramework(args) {
|
|
1194
|
+
if (!args.sop_content) throw new Error('sop_content is required');
|
|
1195
|
+
if (!args.goal) throw new Error('goal is required');
|
|
1196
|
+
if (!args.framework) throw new Error('framework is required');
|
|
1197
|
+
const valid = ['langchain_tool', 'autogen_agent', 'claude_skill'];
|
|
1198
|
+
if (!valid.includes(args.framework)) throw new Error(`framework must be one of: ${valid.join(', ')}`);
|
|
1199
|
+
try {
|
|
1200
|
+
const result = await this.callBackendAPI(ENDPOINTS.CE.TRANSFORM, {
|
|
1201
|
+
sop_content: args.sop_content, goal: args.goal, framework: args.framework
|
|
1202
|
+
});
|
|
1203
|
+
const code = result.code || result.content || result.result || JSON.stringify(result, null, 2);
|
|
1204
|
+
return { content: [{ type: "text", text: `# ${args.framework} Implementation\n\n\`\`\`python\n${code}\n\`\`\`\n\n---\n*Transformed by MCP Prompt Optimizer CE*` }] };
|
|
1205
|
+
} catch (error) {
|
|
1206
|
+
throw new Error(`Failed to transform: ${error.message}`);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
async handleGetCEQuotaStatus() {
|
|
1211
|
+
try {
|
|
1212
|
+
const result = await this.callBackendAPI(ENDPOINTS.CE.QUOTA, null, 'GET');
|
|
1213
|
+
const lines = ['## CE Credit Balance', ''];
|
|
1214
|
+
if (result.is_unlimited) {
|
|
1215
|
+
lines.push(`Credits: **Unlimited** (${result.credits_used || 0} used this period)`);
|
|
1216
|
+
} else {
|
|
1217
|
+
lines.push(`Credits: **${result.credits_remaining ?? 'N/A'}** of ${result.credits_limit} remaining (${result.credits_used || 0} used)`);
|
|
1218
|
+
}
|
|
1219
|
+
lines.push('', '## Available Workflows');
|
|
1220
|
+
if (result.workflow_availability) {
|
|
1221
|
+
for (const [type, info] of Object.entries(result.workflow_availability)) {
|
|
1222
|
+
lines.push(`- ${info.available ? '✓' : '✗'} ${type}: ${info.cost_credits} credit(s)`);
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
if (result.message) lines.push('', result.message);
|
|
1226
|
+
return { content: [{ type: "text", text: lines.join('\n') }] };
|
|
1227
|
+
} catch (error) {
|
|
1228
|
+
throw new Error(`Failed to get CE quota: ${error.message}`);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
async handleGenerateHarnessBundle(args) {
|
|
1233
|
+
if (!args.sop_content && !args.session_id) {
|
|
1234
|
+
return { content: [{ type: "text", text: "Error: provide either sop_content or session_id." }] };
|
|
1235
|
+
}
|
|
1236
|
+
// Normalize deploy_target: string → [string], array → array, undefined → ["claude_code"]
|
|
1237
|
+
let deployTargets;
|
|
1238
|
+
if (!args.deploy_target) {
|
|
1239
|
+
deployTargets = ["claude_code"];
|
|
1240
|
+
} else if (Array.isArray(args.deploy_target)) {
|
|
1241
|
+
deployTargets = args.deploy_target;
|
|
1242
|
+
} else {
|
|
1243
|
+
deployTargets = [args.deploy_target];
|
|
1244
|
+
}
|
|
1245
|
+
// Guard: empty array falls back to default
|
|
1246
|
+
if (deployTargets.length === 0) {
|
|
1247
|
+
deployTargets = ["claude_code"];
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
const payload = {
|
|
1251
|
+
goal: args.goal,
|
|
1252
|
+
deploy_target: deployTargets.length === 1 ? deployTargets[0] : deployTargets,
|
|
1253
|
+
platform: deployTargets[0],
|
|
1254
|
+
user_goal: args.goal,
|
|
1255
|
+
sop_content: args.sop_content || "",
|
|
1256
|
+
};
|
|
1257
|
+
|
|
1258
|
+
// If session_id provided, first fetch session artifacts for sop_content
|
|
1259
|
+
if (args.session_id) {
|
|
1260
|
+
try {
|
|
1261
|
+
const status = await this.callBackendAPI(ENDPOINTS.CE.SESSION(args.session_id), null, "GET");
|
|
1262
|
+
const sop = status.artifacts?.sop_content || status.sop_content || "";
|
|
1263
|
+
if (sop) payload.sop_content = sop;
|
|
1264
|
+
} catch (sessionErr) {
|
|
1265
|
+
console.error(`[handleGenerateHarnessBundle] Could not fetch session ${args.session_id}:`, sessionErr.message || sessionErr);
|
|
1266
|
+
// Proceed with empty sop_content; backend will handle gracefully
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
try {
|
|
1271
|
+
await this.callBackendAPI(ENDPOINTS.CE.HARNESS_BUNDLE, payload);
|
|
1272
|
+
return {
|
|
1273
|
+
content: [{
|
|
1274
|
+
type: "text",
|
|
1275
|
+
text: `# Harness Bundle Requested\n\nDeploy target: **${deployTargets.join(", ")}**\nGoal: ${args.goal}\n\nDownload from the CE dashboard or via the /harness-bundle API endpoint.`
|
|
1276
|
+
}]
|
|
1277
|
+
};
|
|
1278
|
+
} catch (error) {
|
|
1279
|
+
const msg = error?.message || String(error);
|
|
1280
|
+
if (msg.includes("TIER_LIMIT_REACHED")) {
|
|
1281
|
+
return { content: [{ type: "text",
|
|
1282
|
+
text: `Upgrade required: this deploy target requires Pro tier or higher. Upgrade at /pricing.`
|
|
1283
|
+
}] };
|
|
1284
|
+
}
|
|
1285
|
+
throw error;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
async handleExploreSopApproaches(args) {
|
|
1290
|
+
if (!args.goal) {
|
|
1291
|
+
return { content: [{ type: "text", text: "Error: goal is required." }] };
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
// If blend_description provided, explore then blend in one call chain
|
|
1295
|
+
if (args.blend_description) {
|
|
1296
|
+
try {
|
|
1297
|
+
const explorePayload = {
|
|
1298
|
+
goal: args.goal,
|
|
1299
|
+
context: args.context || undefined,
|
|
1300
|
+
perspective: args.perspective || undefined,
|
|
1301
|
+
out_of_scope: args.out_of_scope || undefined,
|
|
1302
|
+
success_definition: args.success_definition || undefined,
|
|
1303
|
+
};
|
|
1304
|
+
const exploreResult = await this.callBackendAPI(ENDPOINTS.CE.SOP_EXPLORE, explorePayload);
|
|
1305
|
+
const blendPayload = {
|
|
1306
|
+
variants: exploreResult.variants,
|
|
1307
|
+
blend_description: args.blend_description,
|
|
1308
|
+
goal: args.goal,
|
|
1309
|
+
};
|
|
1310
|
+
const blendResult = await this.callBackendAPI(ENDPOINTS.CE.SOP_BLEND, blendPayload);
|
|
1311
|
+
return {
|
|
1312
|
+
content: [{
|
|
1313
|
+
type: "text",
|
|
1314
|
+
text: `# Blended SOP\n\n${blendResult.sop_content}`
|
|
1315
|
+
}]
|
|
1316
|
+
};
|
|
1317
|
+
} catch (error) {
|
|
1318
|
+
throw new Error(`Failed to blend SOP approaches: ${error.message}`);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
// Standard exploration: return 3 variant summaries
|
|
1323
|
+
try {
|
|
1324
|
+
const payload = {
|
|
1325
|
+
goal: args.goal,
|
|
1326
|
+
context: args.context || undefined,
|
|
1327
|
+
perspective: args.perspective || undefined,
|
|
1328
|
+
out_of_scope: args.out_of_scope || undefined,
|
|
1329
|
+
success_definition: args.success_definition || undefined,
|
|
1330
|
+
};
|
|
1331
|
+
const result = await this.callBackendAPI(ENDPOINTS.CE.SOP_EXPLORE, payload);
|
|
1332
|
+
|
|
1333
|
+
const variantSummaries = result.variants.map(v => {
|
|
1334
|
+
const rec = v.id === result.recommended ? " *(Recommended)*" : "";
|
|
1335
|
+
return `## Variant ${v.id} — ${v.approach.replace('_', '-')}${rec}\n\n${v.content.slice(0, 600)}${v.content.length > 600 ? '\n\n...(truncated)' : ''}`;
|
|
1336
|
+
}).join('\n\n---\n\n');
|
|
1337
|
+
|
|
1338
|
+
return {
|
|
1339
|
+
content: [{
|
|
1340
|
+
type: "text",
|
|
1341
|
+
text: `# SOP Exploration Results\n\n**Goal:** ${args.goal}\n**Recommended:** Variant ${result.recommended}\n\n---\n\n${variantSummaries}\n\n---\n\n*To select a variant, call generate_skill_package with the full content of your chosen variant as sop_content. To blend variants, re-call explore_sop_approaches with blend_description.*`
|
|
1342
|
+
}]
|
|
1343
|
+
};
|
|
1344
|
+
} catch (error) {
|
|
1345
|
+
if (error.message && error.message.includes('403')) {
|
|
1346
|
+
return { content: [{ type: "text", text: "Error: SOP exploration requires Innovator tier. Upgrade at /pricing." }] };
|
|
1347
|
+
}
|
|
1348
|
+
throw new Error(`Failed to explore SOP approaches: ${error.message}`);
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
_formatSkillPackage(result) {
|
|
1353
|
+
const sections = ['# Skill Package Generated'];
|
|
1354
|
+
const artifacts = result.artifacts || result.steps || {};
|
|
1355
|
+
if (typeof artifacts === 'object' && Object.keys(artifacts).length > 0) {
|
|
1356
|
+
for (const [key, value] of Object.entries(artifacts)) {
|
|
1357
|
+
if (value && typeof value === 'string') sections.push(`\n## ${key}\n\n${value}`);
|
|
1358
|
+
}
|
|
1359
|
+
} else {
|
|
1360
|
+
sections.push('\n```json\n' + JSON.stringify(result, null, 2) + '\n```');
|
|
1361
|
+
}
|
|
1362
|
+
sections.push('\n---\n*Generated by MCP Prompt Optimizer CE*');
|
|
1363
|
+
return sections.join('\n');
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
_buildUrl(path) {
|
|
1367
|
+
return `${this.backendUrl}${path}`;
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
async callBackendAPI(endpoint, data, method = 'POST') {
|
|
1371
|
+
return new Promise((resolve, reject) => {
|
|
1372
|
+
const url = this._buildUrl(endpoint);
|
|
1373
|
+
|
|
1374
|
+
const options = {
|
|
1375
|
+
method: method,
|
|
1376
|
+
headers: {
|
|
1377
|
+
'x-api-key': this.apiKey,
|
|
1378
|
+
'Content-Type': 'application/json',
|
|
1379
|
+
'User-Agent': `mcp-prompt-optimizer/${packageJson.version}`,
|
|
1380
|
+
'Accept': 'application/json',
|
|
1381
|
+
'Connection': 'close'
|
|
1382
|
+
},
|
|
1383
|
+
timeout: this.requestTimeout
|
|
1384
|
+
};
|
|
1385
|
+
|
|
1386
|
+
const client = this.backendUrl.startsWith('https://') ? https : require('http');
|
|
1387
|
+
const req = client.request(url, options, (res) => {
|
|
1388
|
+
let responseData = '';
|
|
1389
|
+
|
|
1390
|
+
res.on('data', (chunk) => {
|
|
1391
|
+
responseData += chunk;
|
|
1392
|
+
});
|
|
1393
|
+
|
|
1394
|
+
res.on('end', () => {
|
|
1395
|
+
try {
|
|
1396
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
1397
|
+
const contentType = res.headers['content-type'] || '';
|
|
1398
|
+
if (contentType.includes('application/json') || contentType === '') {
|
|
1399
|
+
try {
|
|
1400
|
+
const parsed = JSON.parse(responseData);
|
|
1401
|
+
resolve(parsed);
|
|
1402
|
+
} catch (e) {
|
|
1403
|
+
reject(new Error(`Invalid response format: ${e.message}`));
|
|
1404
|
+
}
|
|
1405
|
+
} else {
|
|
1406
|
+
// Binary or non-JSON response (e.g., application/zip) — return metadata
|
|
1407
|
+
resolve({ _binary: true, contentType, size: responseData.length });
|
|
1408
|
+
}
|
|
1409
|
+
} else {
|
|
1410
|
+
let errorMessage;
|
|
1411
|
+
try {
|
|
1412
|
+
const error = JSON.parse(responseData);
|
|
1413
|
+
errorMessage = (typeof error.detail === 'object' && error.detail !== null)
|
|
1414
|
+
? JSON.stringify(error.detail)
|
|
1415
|
+
: (error.detail || error.message || `HTTP ${res.statusCode}`);
|
|
1416
|
+
} catch {
|
|
1417
|
+
errorMessage = `HTTP ${res.statusCode}: ${responseData}`;
|
|
1418
|
+
}
|
|
1419
|
+
reject(new Error(errorMessage));
|
|
1420
|
+
}
|
|
1421
|
+
} catch (parseError) {
|
|
1422
|
+
reject(new Error(`Invalid response format: ${parseError.message}`));
|
|
1423
|
+
}
|
|
1424
|
+
});
|
|
1425
|
+
});
|
|
1426
|
+
|
|
1427
|
+
req.on('error', (error) => {
|
|
1428
|
+
if (error.code === 'ENOTFOUND') {
|
|
1429
|
+
reject(new Error(`DNS resolution failed: Cannot resolve ${this.backendUrl.replace(/^https?:\/\//, '')}`));
|
|
1430
|
+
} else if (error.code === 'ECONNREFUSED') {
|
|
1431
|
+
reject(new Error(`Connection refused: Backend server may be down`));
|
|
1432
|
+
} else if (error.code === 'ETIMEDOUT') {
|
|
1433
|
+
reject(new Error(`Connection timeout: Backend server is not responding`));
|
|
1434
|
+
} else if (error.code === 'ECONNRESET') {
|
|
1435
|
+
reject(new Error(`Connection reset: Network instability detected`));
|
|
1436
|
+
} else {
|
|
1437
|
+
reject(new Error(`Network error: ${error.message}`));
|
|
1438
|
+
}
|
|
1439
|
+
});
|
|
1440
|
+
|
|
1441
|
+
req.on('timeout', () => {
|
|
1442
|
+
req.destroy();
|
|
1443
|
+
reject(new Error('Request timeout - backend may be unavailable'));
|
|
1444
|
+
});
|
|
1445
|
+
|
|
1446
|
+
if (method !== 'GET' && data) {
|
|
1447
|
+
req.write(JSON.stringify(data));
|
|
1448
|
+
}
|
|
1449
|
+
req.end();
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
formatOptimizationResult(result, context) {
|
|
1454
|
+
let output;
|
|
1455
|
+
if (result.rules_based) {
|
|
1456
|
+
if (result.fallback_mode) {
|
|
1457
|
+
output = `# 🔧 Prompt Optimized (Local Rules)\n\n`;
|
|
1458
|
+
output += `*Optimized using local rule templates — LLM quality available once you connect your API key.*\n\n`;
|
|
1459
|
+
} else {
|
|
1460
|
+
output = `# 🔧 Rules-Based Optimization Applied\n\n`;
|
|
1461
|
+
output += `*API key not validated — optimized using local rule templates. `;
|
|
1462
|
+
output += `Set \`MCP_API_KEY\` for full LLM optimization.*\n\n`;
|
|
1463
|
+
}
|
|
1464
|
+
output += `**Template:** \`${result.template_used || 'general'}\`\n\n`;
|
|
1465
|
+
output += `**Optimized Prompt:**\n\`\`\`\n${result.optimized_prompt}\n\`\`\`\n\n`;
|
|
1466
|
+
} else if (result.fallback_mode) {
|
|
1467
|
+
output = `# 🔧 Optimized (local rules — backend slow)\n\n`;
|
|
1468
|
+
output += `*Backend unavailable this time — applied local rule templates. Try again for LLM optimization.*\n\n`;
|
|
1469
|
+
output += `**Optimized Prompt:**\n\`\`\`\n${result.optimized_prompt}\n\`\`\`\n\n`;
|
|
1470
|
+
} else {
|
|
1471
|
+
output = `# 🎯 Optimized Prompt\n\n${result.optimized_prompt}\n\n`;
|
|
1472
|
+
if (result.confidence_score < 0.25) {
|
|
1473
|
+
output += `> ℹ️ *Low confidence indicates the backend applied rules-based optimization (no LLM). `;
|
|
1474
|
+
output += `Ensure \`OPENROUTER_API_KEY\` is configured in the backend for full LLM enhancement.*\n\n`;
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
if (result.rules_based) {
|
|
1478
|
+
output += `**Confidence:** ${(result.confidence_score * 100).toFixed(1)}% *(rules-based — LLM optimization typically 70–95%)*\n`;
|
|
1479
|
+
} else {
|
|
1480
|
+
output += `**Confidence:** ${(result.confidence_score * 100).toFixed(1)}%\n`;
|
|
1481
|
+
}
|
|
1482
|
+
output += `**AI Context:** ${result.metadata?.context_detection?.ai_context || result.metadata?.ai_context || context.detectedContext}\n`;
|
|
1483
|
+
if (result.metadata?.routing_score != null) {
|
|
1484
|
+
output += `**Routing Score:** ${result.metadata.routing_score.toFixed(3)} (${result.metadata?.routing_tier || 'unknown'})\n`;
|
|
1485
|
+
}
|
|
1486
|
+
if (!result.rules_based && !result.fallback_mode && result.metadata?.model_used) {
|
|
1487
|
+
output += `**Model:** ${result.metadata.model_used}\n`;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
if (result.template_saved) {
|
|
1491
|
+
output += `\n📁 **Template Auto-Save**\n✅ Automatically saved as template (ID: \`${result.template_id}\`)\n*Confidence threshold: >70% required for auto-save*\n`;
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
if (result.templates_found?.length) {
|
|
1495
|
+
output += `\n📋 **Similar Templates Found**\nFound **${result.templates_found.length}** similar template(s):\n`;
|
|
1496
|
+
result.templates_found.slice(0, 3).forEach(t => {
|
|
1497
|
+
output += `- ${t.title} (${(t.confidence_score * 100).toFixed(1)}% match) — ID: \`${t.id}\`\n`;
|
|
1498
|
+
});
|
|
1499
|
+
output += `\n💡 Use \`get_template\` with any ID above to view the full optimized prompt.\n`;
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
if (result.optimization_insights) {
|
|
1503
|
+
const metrics = result.optimization_insights.improvement_metrics;
|
|
1504
|
+
if (metrics) {
|
|
1505
|
+
output += `\n📊 **Optimization Insights**\n`;
|
|
1506
|
+
if (metrics.clarity_improvement) output += `- Clarity: +${(metrics.clarity_improvement * 100).toFixed(1)}%\n`;
|
|
1507
|
+
if (metrics.specificity_improvement) output += `- Specificity: +${(metrics.specificity_improvement * 100).toFixed(1)}%\n`;
|
|
1508
|
+
if (metrics.context_alignment) output += `- Context Alignment: +${(metrics.context_alignment * 100).toFixed(1)}%\n`;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
if (result.optimization_insights.recommendations?.length) {
|
|
1512
|
+
output += `\n💡 **Recommendations:**\n`;
|
|
1513
|
+
result.optimization_insights.recommendations.forEach(rec => {
|
|
1514
|
+
output += `- ${rec}\n`;
|
|
1515
|
+
});
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
// Add Bayesian insights if available
|
|
1520
|
+
if (result.bayesian_insights && context.enableBayesian) {
|
|
1521
|
+
output += `\n🧠 **Bayesian Optimization Insights**\n`;
|
|
1522
|
+
const bayesian = result.bayesian_insights;
|
|
1523
|
+
|
|
1524
|
+
if (bayesian.parameter_optimization) {
|
|
1525
|
+
output += `**Parameter Tuning:**\n`;
|
|
1526
|
+
if (bayesian.parameter_optimization.temperature_adjustment) {
|
|
1527
|
+
output += `- Temperature: ${bayesian.parameter_optimization.temperature_adjustment}\n`;
|
|
1528
|
+
}
|
|
1529
|
+
if (bayesian.parameter_optimization.goal_prioritization) {
|
|
1530
|
+
output += `- Goal Priority: ${bayesian.parameter_optimization.goal_prioritization}\n`;
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
if (bayesian.performance_prediction) {
|
|
1535
|
+
output += `**Performance Prediction:**\n`;
|
|
1536
|
+
output += `- Expected Improvement: ${bayesian.performance_prediction.expected_improvement}\n`;
|
|
1537
|
+
output += `- Confidence Interval: ${bayesian.performance_prediction.confidence_interval}\n`;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
if (bayesian.next_optimization_recommendation) {
|
|
1541
|
+
output += `**Next Optimization:**\n`;
|
|
1542
|
+
output += `- Suggested Goals: ${bayesian.next_optimization_recommendation.suggested_goals.join(', ')}\n`;
|
|
1543
|
+
output += `- Estimated Improvement: ${bayesian.next_optimization_recommendation.estimated_improvement}\n`;
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
if (!result.fallback_mode) {
|
|
1548
|
+
if (result.quota_used != null) {
|
|
1549
|
+
if (result.quota_limit == null) {
|
|
1550
|
+
// Unlimited plan — show status only, no upsell
|
|
1551
|
+
output += `\n📊 **Usage:** ${result.quota_used} optimizations — ✓ Unlimited plan\n`;
|
|
1552
|
+
} else {
|
|
1553
|
+
const remaining = result.quota_limit - result.quota_used;
|
|
1554
|
+
if (result.quota_used >= result.quota_limit) {
|
|
1555
|
+
output += `\n📊 **Usage:** ${result.quota_used}/${result.quota_limit} — quota reached. **[Upgrade for more →](https://promptoptimizer.xyz/pricing)**\n`;
|
|
1556
|
+
} else if (remaining <= 2) {
|
|
1557
|
+
output += `\n📊 **Usage:** ${result.quota_used}/${result.quota_limit} LLM optimizations (${remaining} left) — [Upgrade for more](https://promptoptimizer.xyz/pricing)\n`;
|
|
1558
|
+
} else {
|
|
1559
|
+
output += `\n📊 **Usage:** ${result.quota_used}/${result.quota_limit} LLM optimizations this month — [Upgrade for more](https://promptoptimizer.xyz/pricing)\n`;
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
output += `\n🔗 **Quick Actions**\n- Dashboard: https://promptoptimizer.xyz/dashboard\n- Analytics: https://promptoptimizer.xyz/analytics\n`;
|
|
1564
|
+
} else {
|
|
1565
|
+
const confPct = Math.round((result.confidence_score || 0) * 100);
|
|
1566
|
+
output += `\n---\n`;
|
|
1567
|
+
output += `\n💡 **Unlock LLM Optimization — Free**\n\n`;
|
|
1568
|
+
output += `Local rules reached **${confPct}% confidence**. LLM optimization typically achieves **70–95%** — `;
|
|
1569
|
+
output += `more specific, context-aware, and effective for your actual intent.\n\n`;
|
|
1570
|
+
output += `**Get started free** (no credit card):\n`;
|
|
1571
|
+
output += `1. Sign up at https://promptoptimizer.xyz\n`;
|
|
1572
|
+
output += `2. Generate your API key at https://promptoptimizer.xyz/dashboard\n`;
|
|
1573
|
+
output += `3. Run in your terminal:\n\n`;
|
|
1574
|
+
output += `\`\`\`\nnpx mcp-prompt-optimizer connect\n\`\`\`\n\n`;
|
|
1575
|
+
output += `You get **7 LLM optimizations/month free**. Upgrade anytime for more.\n`;
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
return output;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
formatQuotaStatus(result) {
|
|
1582
|
+
let output = `# 📊 Account Status\n\n**Plan:** ${result.tier || 'free'}\n`;
|
|
1583
|
+
|
|
1584
|
+
const quota = result.quota || {};
|
|
1585
|
+
if (quota.unlimited) {
|
|
1586
|
+
output += `**Usage:** 🟢 Unlimited\n`;
|
|
1587
|
+
} else {
|
|
1588
|
+
const used = quota.used || 0;
|
|
1589
|
+
const limit = quota.limit || 5000;
|
|
1590
|
+
const percentage = limit > 0 ? ((used / limit) * 100).toFixed(1) : 0;
|
|
1591
|
+
|
|
1592
|
+
let statusIcon = '🟢';
|
|
1593
|
+
if (percentage >= 90) statusIcon = '🔴';
|
|
1594
|
+
else if (percentage >= 75) statusIcon = '🟡';
|
|
1595
|
+
|
|
1596
|
+
output += `**Usage:** ${statusIcon} ${used}/${limit} (${percentage}%)\n`;
|
|
1597
|
+
|
|
1598
|
+
const remaining = limit - used;
|
|
1599
|
+
if (remaining <= 0) {
|
|
1600
|
+
output += `\n❌ **Quota Exhausted** — You have no optimizations remaining this month.\n`;
|
|
1601
|
+
output += `Upgrade at https://promptoptimizer.xyz/local-license\n`;
|
|
1602
|
+
output += `*(Quota resets at the start of your next billing cycle)*\n`;
|
|
1603
|
+
} else if (percentage >= 90) {
|
|
1604
|
+
output += `\n⚠️ **Critical** — ${remaining} optimization${remaining === 1 ? '' : 's'} remaining. Upgrade at https://promptoptimizer.xyz/local-license\n`;
|
|
1605
|
+
} else if (percentage >= 75) {
|
|
1606
|
+
output += `\n⚠️ **Warning** — Approaching your monthly limit.\n`;
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
output += `\n## ✨ **Available Features**\n`;
|
|
1611
|
+
if (result.features) {
|
|
1612
|
+
if (result.features.optimization) output += `✅ Prompt Optimization\n`;
|
|
1613
|
+
if (result.features.template_search) output += `✅ Template Search & Management\n`;
|
|
1614
|
+
if (result.features.template_auto_save) output += `✅ Template Auto-Save\n`;
|
|
1615
|
+
if (result.features.optimization_insights) output += `✅ Optimization Insights\n`;
|
|
1616
|
+
if (this.bayesianOptimizationEnabled) output += `🧠 Bayesian Optimization\n`;
|
|
1617
|
+
if (this.aguiFeatures) output += `⚡ AG-UI Real-time Features\n`;
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
if (result.mode) {
|
|
1621
|
+
output += `\n## 🔧 **Mode Status**\n`;
|
|
1622
|
+
if (result.mode.development) output += `⚙️ Development Mode\n`;
|
|
1623
|
+
if (result.mode.mock) output += `🎭 Mock Mode\n`;
|
|
1624
|
+
if (result.mode.fallback) output += `🔄 Fallback Mode\n`;
|
|
1625
|
+
if (result.mode.offline) output += `📱 Offline Mode\n`;
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
output += `\n## 🔗 **Account Management**\n`;
|
|
1629
|
+
output += `- Dashboard: https://promptoptimizer-blog.vercel.app/dashboard\n`;
|
|
1630
|
+
output += `- Analytics: https://promptoptimizer-blog.vercel.app/analytics\n`;
|
|
1631
|
+
output += `- Upgrade: https://promptoptimizer.xyz/local-license\n`;
|
|
1632
|
+
|
|
1633
|
+
return output;
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
formatTemplateSearchResults(result, originalArgs) {
|
|
1637
|
+
let output = `# 🔍 Template Search Results\n\n`;
|
|
1638
|
+
|
|
1639
|
+
if (originalArgs.query || originalArgs.ai_context || originalArgs.sophistication_level) {
|
|
1640
|
+
output += `**Search Criteria:**\n`;
|
|
1641
|
+
if (originalArgs.query) output += `- Query: "${originalArgs.query}"\n`;
|
|
1642
|
+
if (originalArgs.ai_context) output += `- AI Context: ${originalArgs.ai_context}\n`;
|
|
1643
|
+
if (originalArgs.sophistication_level) output += `- Sophistication: ${originalArgs.sophistication_level}\n`;
|
|
1644
|
+
if (originalArgs.complexity_level) output += `- Complexity: ${originalArgs.complexity_level}\n`;
|
|
1645
|
+
output += `\n`;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
output += `Found **${result.total}** template(s)\n\n`;
|
|
1649
|
+
|
|
1650
|
+
if (!result.templates || result.templates.length === 0) {
|
|
1651
|
+
output += `📭 **No Templates Found**\n`;
|
|
1652
|
+
const hasActiveFilters = originalArgs.query || originalArgs.ai_context || originalArgs.sophistication_level || originalArgs.complexity_level;
|
|
1653
|
+
if (hasActiveFilters) {
|
|
1654
|
+
output += `No templates matched your filters. Try removing \`ai_context\` or \`query\` filters.\n`;
|
|
1655
|
+
} else {
|
|
1656
|
+
output += `You don't have any saved templates yet. Templates are automatically saved when optimization confidence is >70%.\n`;
|
|
1657
|
+
output += `Run \`optimize_prompt\` to start building your template library.\n`;
|
|
1658
|
+
}
|
|
1659
|
+
} else {
|
|
1660
|
+
output += `## 📋 **Template Results**\n`;
|
|
1661
|
+
result.templates.forEach((t, index) => {
|
|
1662
|
+
const confidence = t.confidence_score ? `${(t.confidence_score * 100).toFixed(1)}%` : 'N/A';
|
|
1663
|
+
const preview = t.optimized_prompt ? t.optimized_prompt.substring(0, 60) + '...' : 'Preview unavailable';
|
|
1664
|
+
|
|
1665
|
+
output += `### ${index + 1}. ${t.title}\n`;
|
|
1666
|
+
output += `- **Confidence:** ${confidence}\n`;
|
|
1667
|
+
output += `- **ID:** \`${t.id}\`\n`;
|
|
1668
|
+
output += `- **Preview:** ${preview}\n`;
|
|
1669
|
+
if (t.ai_context) output += `- **Context:** ${t.ai_context}\n`;
|
|
1670
|
+
if (t.optimization_goals && t.optimization_goals.length) {
|
|
1671
|
+
output += `- **Goals:** ${t.optimization_goals.join(', ')}\n`;
|
|
1672
|
+
}
|
|
1673
|
+
output += `\n`;
|
|
1674
|
+
});
|
|
1675
|
+
|
|
1676
|
+
output += `## 💡 **Template Usage Guide**\n`;
|
|
1677
|
+
output += `- Copy prompts for immediate use\n`;
|
|
1678
|
+
output += `- Use template IDs to reference specific templates\n`;
|
|
1679
|
+
output += `- High-confidence templates (>80%) are most reliable\n`;
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
if (result.fallback_mode) {
|
|
1683
|
+
output += `\n⚠️ **Search Temporarily Unavailable**\n${result.message}\n`;
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
return output;
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
formatOptimizationInsights(insights) {
|
|
1690
|
+
let output = `# 🧠 Bayesian Optimization Insights\n\n`;
|
|
1691
|
+
|
|
1692
|
+
if (insights.bayesian_status) {
|
|
1693
|
+
const status = insights.bayesian_status;
|
|
1694
|
+
output += `## 📊 **Status Overview**\n`;
|
|
1695
|
+
output += `- **Status:** ${status.optimization_active ? '🟢 Active' : '🔴 Inactive'}\n`;
|
|
1696
|
+
output += `- **Total Optimizations:** ${status.total_optimizations}\n`;
|
|
1697
|
+
output += `- **Improvement Rate:** ${status.improvement_rate}\n`;
|
|
1698
|
+
output += `- **System Confidence:** ${(status.confidence_score * 100).toFixed(1)}%\n\n`;
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
if (insights.parameter_insights) {
|
|
1702
|
+
const params = insights.parameter_insights;
|
|
1703
|
+
output += `## 🎯 **Parameter Analysis**\n`;
|
|
1704
|
+
|
|
1705
|
+
if (params.most_effective_goals) {
|
|
1706
|
+
output += `**Most Effective Goals:**\n`;
|
|
1707
|
+
params.most_effective_goals.forEach(goal => {
|
|
1708
|
+
output += `- ${goal}\n`;
|
|
1709
|
+
});
|
|
1710
|
+
output += `\n`;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
if (params.context_performance) {
|
|
1714
|
+
output += `**Context Performance:**\n`;
|
|
1715
|
+
Object.entries(params.context_performance).forEach(([context, score]) => {
|
|
1716
|
+
const percentage = (score * 100).toFixed(1);
|
|
1717
|
+
const icon = score >= 0.9 ? '🟢' : score >= 0.8 ? '🟡' : '🔴';
|
|
1718
|
+
output += `- ${context}: ${icon} ${percentage}%\n`;
|
|
1719
|
+
});
|
|
1720
|
+
output += `\n`;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
if (params.optimization_trends) {
|
|
1724
|
+
output += `**Trends:** ${params.optimization_trends}\n\n`;
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
if (insights.recommendations && insights.recommendations.length) {
|
|
1729
|
+
output += `## 💡 **Optimization Recommendations**\n`;
|
|
1730
|
+
insights.recommendations.forEach((rec, index) => {
|
|
1731
|
+
output += `${index + 1}. ${rec}\n`;
|
|
1732
|
+
});
|
|
1733
|
+
output += `\n`;
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
output += `## 🔗 **Advanced Analytics**\n`;
|
|
1737
|
+
output += `- Full Analytics: https://promptoptimizer-blog.vercel.app/analytics\n`;
|
|
1738
|
+
output += `- Performance Dashboard: https://promptoptimizer-blog.vercel.app/dashboard\n`;
|
|
1739
|
+
|
|
1740
|
+
return output;
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
formatRealTimeStatus(status) {
|
|
1744
|
+
let output = `# ⚡ AG-UI Real-Time Status\n\n`;
|
|
1745
|
+
|
|
1746
|
+
output += `## 🚀 **Service Status**\n`;
|
|
1747
|
+
output += `- **AG-UI Status:** ${status.agui_status === 'available' ? '🟢 Available' : '🔴 Unavailable'}\n`;
|
|
1748
|
+
output += `- **Streaming Optimization:** ${status.streaming_optimization ? '✅ Enabled' : '❌ Disabled'}\n`;
|
|
1749
|
+
output += `- **WebSocket Support:** ${status.websocket_support ? '✅ Enabled' : '❌ Disabled'}\n`;
|
|
1750
|
+
output += `- **Real-time Analytics:** ${status.real_time_analytics ? '✅ Enabled' : '❌ Disabled'}\n\n`;
|
|
1751
|
+
|
|
1752
|
+
if (status.active_optimizations !== undefined) {
|
|
1753
|
+
output += `## 📈 **Current Activity**\n`;
|
|
1754
|
+
output += `- **Active Optimizations:** ${status.active_optimizations}\n`;
|
|
1755
|
+
output += `- **Average Response Time:** ${status.average_response_time}\n\n`;
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
if (status.features) {
|
|
1759
|
+
const features = status.features;
|
|
1760
|
+
output += `## ⚡ **Available Features**\n`;
|
|
1761
|
+
if (features.live_optimization) output += `✅ Live Optimization\n`;
|
|
1762
|
+
if (features.collaborative_editing) output += `✅ Collaborative Editing\n`;
|
|
1763
|
+
if (features.instant_feedback) output += `✅ Instant Feedback\n`;
|
|
1764
|
+
if (features.performance_monitoring) output += `✅ Performance Monitoring\n`;
|
|
1765
|
+
output += `\n`;
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
output += `## 🔗 **Real-Time Access**\n`;
|
|
1769
|
+
output += `- Live Dashboard: https://promptoptimizer-blog.vercel.app/live\n`;
|
|
1770
|
+
output += `- WebSocket Endpoint: Available via API\n`;
|
|
1771
|
+
|
|
1772
|
+
return output;
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
async run() {
|
|
1776
|
+
const transport = new StdioServerTransport();
|
|
1777
|
+
await this.server.connect(transport);
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
async function startValidatedMCPServer() {
|
|
1782
|
+
console.error(`🚀 MCP Prompt Optimizer - Professional Cloud Server v${packageJson.version}\n`);
|
|
1783
|
+
console.error(`🧠 Bayesian Optimization: ${process.env.ENABLE_BAYESIAN_OPTIMIZATION === 'true' ? 'Enabled' : 'Disabled'}`);
|
|
1784
|
+
console.error(`⚡ AG-UI Features: ${process.env.ENABLE_AGUI_FEATURES === 'true' ? 'Enabled' : 'Disabled'}\n`);
|
|
1785
|
+
|
|
1786
|
+
try {
|
|
1787
|
+
const apiKey = process.env.OPTIMIZER_API_KEY;
|
|
1788
|
+
if (!apiKey) {
|
|
1789
|
+
console.error('❌ API key required. Get one at https://promptoptimizer.xyz/local-license');
|
|
1790
|
+
process.exit(1);
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
// SECURITY: No development mode bypass - backend validation required
|
|
1794
|
+
const manager = new CloudApiKeyManager(apiKey);
|
|
1795
|
+
console.error('🔧 Validating API key...\n');
|
|
1796
|
+
const validation = await manager.validateAndPrepare();
|
|
1797
|
+
|
|
1798
|
+
console.error('🔧 Starting MCP server...\n');
|
|
1799
|
+
const mcpServer = new MCPPromptOptimizer();
|
|
1800
|
+
console.error('✅ MCP server ready for connections');
|
|
1801
|
+
|
|
1802
|
+
// Enhanced status display
|
|
1803
|
+
const quotaDisplay = validation.quotaStatus.unlimited ?
|
|
1804
|
+
'Unlimited' :
|
|
1805
|
+
`${validation.quotaStatus.remaining}/${validation.quotaStatus.limit} remaining`;
|
|
1806
|
+
|
|
1807
|
+
console.error(`📊 Plan: ${validation.tier} | Quota: ${quotaDisplay}`);
|
|
1808
|
+
|
|
1809
|
+
if (validation.mode.mock) console.error('🎭 Running in mock mode');
|
|
1810
|
+
if (validation.mode.development) console.error('⚙️ Development mode active');
|
|
1811
|
+
if (validation.mode.fallback) console.error('🔄 Fallback mode active');
|
|
1812
|
+
if (validation.mode.offline) console.error('📱 Offline mode active');
|
|
1813
|
+
|
|
1814
|
+
await mcpServer.run();
|
|
1815
|
+
} catch (error) {
|
|
1816
|
+
console.error(`❌ Failed to start MCP server: ${error.message}`);
|
|
1817
|
+
process.exit(1);
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
async function runConnectWizard() {
|
|
1822
|
+
const readline = require('readline');
|
|
1823
|
+
const fs = require('fs');
|
|
1824
|
+
const path = require('path');
|
|
1825
|
+
const os = require('os');
|
|
1826
|
+
|
|
1827
|
+
// Known MCP client config locations keyed by [client, platform]
|
|
1828
|
+
const CLIENT_CONFIGS = [
|
|
1829
|
+
{
|
|
1830
|
+
name: 'Claude Desktop',
|
|
1831
|
+
paths: {
|
|
1832
|
+
win32: path.join(os.homedir(), 'AppData', 'Roaming', 'Claude', 'claude_desktop_config.json'),
|
|
1833
|
+
darwin: path.join(os.homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),
|
|
1834
|
+
linux: path.join(os.homedir(), '.config', 'Claude', 'claude_desktop_config.json'),
|
|
1835
|
+
},
|
|
1836
|
+
serverKey: 'mcp-prompt-optimizer',
|
|
1837
|
+
},
|
|
1838
|
+
{
|
|
1839
|
+
name: 'Cursor',
|
|
1840
|
+
paths: {
|
|
1841
|
+
win32: path.join(os.homedir(), '.cursor', 'mcp.json'),
|
|
1842
|
+
darwin: path.join(os.homedir(), '.cursor', 'mcp.json'),
|
|
1843
|
+
linux: path.join(os.homedir(), '.cursor', 'mcp.json'),
|
|
1844
|
+
},
|
|
1845
|
+
serverKey: 'mcp-prompt-optimizer',
|
|
1846
|
+
},
|
|
1847
|
+
{
|
|
1848
|
+
name: 'VS Code Cline / Roo',
|
|
1849
|
+
paths: {
|
|
1850
|
+
win32: path.join(os.homedir(), 'AppData', 'Roaming', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'),
|
|
1851
|
+
darwin: path.join(os.homedir(), 'Library', 'Application Support', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'),
|
|
1852
|
+
linux: path.join(os.homedir(), '.config', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'),
|
|
1853
|
+
},
|
|
1854
|
+
serverKey: 'mcp-prompt-optimizer',
|
|
1855
|
+
},
|
|
1856
|
+
{
|
|
1857
|
+
name: 'Continue.dev',
|
|
1858
|
+
paths: {
|
|
1859
|
+
win32: path.join(os.homedir(), '.continue', 'config.json'),
|
|
1860
|
+
darwin: path.join(os.homedir(), '.continue', 'config.json'),
|
|
1861
|
+
linux: path.join(os.homedir(), '.continue', 'config.json'),
|
|
1862
|
+
},
|
|
1863
|
+
serverKey: 'mcp-prompt-optimizer',
|
|
1864
|
+
},
|
|
1865
|
+
];
|
|
1866
|
+
|
|
1867
|
+
function safeWriteConfig(filePath, newConfig) {
|
|
1868
|
+
const backupPath = filePath + '.bak';
|
|
1869
|
+
// Backup
|
|
1870
|
+
if (fs.existsSync(filePath)) {
|
|
1871
|
+
fs.copyFileSync(filePath, backupPath);
|
|
1872
|
+
}
|
|
1873
|
+
try {
|
|
1874
|
+
const serialized = JSON.stringify(newConfig, null, 2);
|
|
1875
|
+
fs.writeFileSync(filePath, serialized, 'utf8');
|
|
1876
|
+
// Verify round-trip
|
|
1877
|
+
JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
1878
|
+
} catch (e) {
|
|
1879
|
+
// Restore backup on any failure
|
|
1880
|
+
if (fs.existsSync(backupPath)) {
|
|
1881
|
+
fs.copyFileSync(backupPath, filePath);
|
|
1882
|
+
}
|
|
1883
|
+
throw e;
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
function patchConfig(config, serverKey, apiKey) {
|
|
1888
|
+
if (!config.mcpServers) config.mcpServers = {};
|
|
1889
|
+
if (config.mcpServers[serverKey]) {
|
|
1890
|
+
if (!config.mcpServers[serverKey].env) config.mcpServers[serverKey].env = {};
|
|
1891
|
+
config.mcpServers[serverKey].env.OPTIMIZER_API_KEY = apiKey;
|
|
1892
|
+
} else {
|
|
1893
|
+
config.mcpServers[serverKey] = {
|
|
1894
|
+
command: 'npx',
|
|
1895
|
+
args: ['-y', 'mcp-prompt-optimizer'],
|
|
1896
|
+
env: { OPTIMIZER_API_KEY: apiKey },
|
|
1897
|
+
};
|
|
1898
|
+
}
|
|
1899
|
+
return config;
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
console.log('\n🔌 Prompt Optimizer — Connect Wizard\n');
|
|
1903
|
+
|
|
1904
|
+
// Detect which clients are installed
|
|
1905
|
+
const platform = process.platform;
|
|
1906
|
+
const found = CLIENT_CONFIGS
|
|
1907
|
+
.map(c => ({ ...c, configPath: c.paths[platform] || c.paths.linux }))
|
|
1908
|
+
.filter(c => fs.existsSync(c.configPath));
|
|
1909
|
+
|
|
1910
|
+
if (found.length === 0) {
|
|
1911
|
+
console.log('❌ No supported MCP client config found. Supported clients:');
|
|
1912
|
+
CLIENT_CONFIGS.forEach(c => {
|
|
1913
|
+
const p = c.paths[platform] || c.paths.linux;
|
|
1914
|
+
console.log(` ${c.name}: ${p}`);
|
|
1915
|
+
});
|
|
1916
|
+
console.log('\nOpen your MCP client first to create its config file, then re-run this command.');
|
|
1917
|
+
process.exit(1);
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1921
|
+
|
|
1922
|
+
function askApiKey(cb) {
|
|
1923
|
+
rl.question('Paste your API key (get one free at https://promptoptimizer.xyz/dashboard): ', (key) => {
|
|
1924
|
+
cb((key || '').trim());
|
|
1925
|
+
});
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
function askClient(clients, cb) {
|
|
1929
|
+
console.log('Multiple MCP clients detected. Which one should be configured?');
|
|
1930
|
+
clients.forEach((c, i) => console.log(` ${i + 1}) ${c.name}`));
|
|
1931
|
+
rl.question('Enter number (or press Enter for all): ', (ans) => {
|
|
1932
|
+
const n = parseInt(ans, 10);
|
|
1933
|
+
if (!ans.trim()) {
|
|
1934
|
+
cb(clients);
|
|
1935
|
+
} else if (n >= 1 && n <= clients.length) {
|
|
1936
|
+
cb([clients[n - 1]]);
|
|
1937
|
+
} else {
|
|
1938
|
+
console.log('Invalid selection, configuring all.');
|
|
1939
|
+
cb(clients);
|
|
1940
|
+
}
|
|
1941
|
+
});
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
function applyToClients(clients, apiKey) {
|
|
1945
|
+
rl.close();
|
|
1946
|
+
let ok = 0;
|
|
1947
|
+
for (const client of clients) {
|
|
1948
|
+
let config;
|
|
1949
|
+
try {
|
|
1950
|
+
config = JSON.parse(fs.readFileSync(client.configPath, 'utf8'));
|
|
1951
|
+
} catch (e) {
|
|
1952
|
+
console.log(`❌ Could not read ${client.name} config: ${e.message}`);
|
|
1953
|
+
continue;
|
|
1954
|
+
}
|
|
1955
|
+
try {
|
|
1956
|
+
const patched = patchConfig(config, client.serverKey, apiKey);
|
|
1957
|
+
safeWriteConfig(client.configPath, patched);
|
|
1958
|
+
console.log(`✅ ${client.name} — configured (${client.configPath})`);
|
|
1959
|
+
ok++;
|
|
1960
|
+
} catch (e) {
|
|
1961
|
+
console.log(`❌ Could not write ${client.name} config: ${e.message}`);
|
|
1962
|
+
console.log(' Try running as administrator, or edit the file manually.');
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
if (ok > 0) {
|
|
1966
|
+
console.log('\n👉 Restart your MCP client(s) to activate LLM optimization.');
|
|
1967
|
+
console.log(' Free plan: 7 LLM optimizations/month.');
|
|
1968
|
+
console.log(' Upgrade at https://promptoptimizer.xyz/pricing\n');
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
askApiKey((apiKey) => {
|
|
1973
|
+
if (!apiKey.startsWith('sk-')) {
|
|
1974
|
+
rl.close();
|
|
1975
|
+
console.log('\n❌ Invalid key — must start with "sk-". Get one at https://promptoptimizer.xyz/dashboard');
|
|
1976
|
+
process.exit(1);
|
|
1977
|
+
}
|
|
1978
|
+
if (found.length === 1) {
|
|
1979
|
+
applyToClients(found, apiKey);
|
|
1980
|
+
} else {
|
|
1981
|
+
askClient(found, (chosen) => applyToClients(chosen, apiKey));
|
|
1982
|
+
}
|
|
1983
|
+
});
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
if (require.main === module) {
|
|
1987
|
+
const args = process.argv.slice(2);
|
|
1988
|
+
if (args[0] === 'connect') {
|
|
1989
|
+
runConnectWizard();
|
|
1990
|
+
} else {
|
|
1991
|
+
startValidatedMCPServer();
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1989
1995
|
module.exports = { MCPPromptOptimizer };
|