This is page 6 of 12. Use http://codebase.md/minipuft/claude-prompts-mcp?page={x} to view the full context.
# Directory Structure
```
├── .actrc
├── .gitattributes
├── .github
│ └── workflows
│ ├── ci.yml
│ ├── mcp-compliance.yml
│ └── pr-validation.yml
├── .gitignore
├── agent.md
├── assets
│ └── logo.png
├── CLAUDE.md
├── config
│ └── framework-state.json
├── docs
│ ├── architecture.md
│ ├── chain-modification-examples.md
│ ├── contributing.md
│ ├── enhanced-gate-system.md
│ ├── execution-architecture-guide.md
│ ├── installation-guide.md
│ ├── mcp-tool-usage-guide.md
│ ├── mcp-tools-reference.md
│ ├── prompt-format-guide.md
│ ├── prompt-management.md
│ ├── prompt-vs-template-guide.md
│ ├── README.md
│ ├── template-development-guide.md
│ ├── TODO.md
│ ├── troubleshooting.md
│ └── version-history.md
├── LICENSE
├── local-test.sh
├── plans
│ ├── nunjucks-dynamic-chain-orchestration.md
│ ├── outputschema-realtime-progress-and-validation.md
│ ├── parallel-conditional-execution-analysis.md
│ ├── sqlite-storage-migration.md
│ └── symbolic-command-language-implementation.md
├── README.md
├── scripts
│ ├── setup-windows-testing.sh
│ ├── test_server.js
│ ├── test-all-platforms.sh
│ └── windows-tests
│ ├── test-windows-paths.js
│ ├── test-windows-startup.sh
│ └── windows-env.sh
└── server
├── config
│ ├── framework-state.json
│ └── tool-descriptions.json
├── config.json
├── jest.config.cjs
├── LICENSE
├── package-lock.json
├── package.json
├── prompts
│ ├── analysis
│ │ ├── advanced_analysis_engine.md
│ │ ├── content_analysis.md
│ │ ├── deep_analysis.md
│ │ ├── deep_research.md
│ │ ├── markdown_notebook.md
│ │ ├── note_integration.md
│ │ ├── note_refinement.md
│ │ ├── notes.md
│ │ ├── progressive_research.md
│ │ ├── prompts.json
│ │ ├── query_refinement.md
│ │ └── review.md
│ ├── architecture
│ │ ├── prompts.json
│ │ └── strategic-system-alignment.md
│ ├── content_processing
│ │ ├── format_enhancement.md
│ │ ├── noteIntegration.md
│ │ ├── obsidian_metadata_optimizer.md
│ │ ├── prompts.json
│ │ ├── vault_related_notes_finder.md
│ │ └── video_notes_enhanced.md
│ ├── debugging
│ │ ├── analyze_logs.md
│ │ └── prompts.json
│ ├── development
│ │ ├── analyze_code_structure.md
│ │ ├── analyze_file_structure.md
│ │ ├── code_review_optimization_chain.md
│ │ ├── component_flow_analysis.md
│ │ ├── create_modularization_plan.md
│ │ ├── detect_code_issues.md
│ │ ├── detect_project_commands.md
│ │ ├── expert_code_implementation.md
│ │ ├── generate_comprehensive_claude_md.md
│ │ ├── prompts.json
│ │ ├── strategicImplement.md
│ │ ├── suggest_code_improvements.md
│ │ └── transform_code_to_modules.md
│ ├── documentation
│ │ ├── create_docs_chain.md
│ │ ├── docs-content-creation.md
│ │ ├── docs-content-planning.md
│ │ ├── docs-final-assembly.md
│ │ ├── docs-project-analysis.md
│ │ ├── docs-review-refinement.md
│ │ └── prompts.json
│ ├── education
│ │ ├── prompts.json
│ │ └── vault_integrated_notes.md
│ ├── general
│ │ ├── diagnose.md
│ │ └── prompts.json
│ ├── promptsConfig.json
│ └── testing
│ ├── final_verification_test.md
│ └── prompts.json
├── README.md
├── scripts
│ └── validate-dependencies.js
├── src
│ ├── api
│ │ └── index.ts
│ ├── chain-session
│ │ └── manager.ts
│ ├── config
│ │ └── index.ts
│ ├── Dockerfile
│ ├── execution
│ │ ├── context
│ │ │ ├── context-resolver.ts
│ │ │ ├── framework-injector.ts
│ │ │ └── index.ts
│ │ ├── index.ts
│ │ ├── parsers
│ │ │ ├── argument-parser.ts
│ │ │ ├── index.ts
│ │ │ └── unified-command-parser.ts
│ │ └── types.ts
│ ├── frameworks
│ │ ├── framework-manager.ts
│ │ ├── framework-state-manager.ts
│ │ ├── index.ts
│ │ ├── integration
│ │ │ ├── framework-semantic-integration.ts
│ │ │ └── index.ts
│ │ ├── methodology
│ │ │ ├── guides
│ │ │ │ ├── 5w1h-guide.ts
│ │ │ │ ├── cageerf-guide.ts
│ │ │ │ ├── react-guide.ts
│ │ │ │ └── scamper-guide.ts
│ │ │ ├── index.ts
│ │ │ ├── interfaces.ts
│ │ │ └── registry.ts
│ │ ├── prompt-guidance
│ │ │ ├── index.ts
│ │ │ ├── methodology-tracker.ts
│ │ │ ├── service.ts
│ │ │ ├── system-prompt-injector.ts
│ │ │ └── template-enhancer.ts
│ │ └── types
│ │ ├── index.ts
│ │ ├── integration-types.ts
│ │ ├── methodology-types.ts
│ │ └── prompt-guidance-types.ts
│ ├── gates
│ │ ├── constants.ts
│ │ ├── core
│ │ │ ├── gate-definitions.ts
│ │ │ ├── gate-loader.ts
│ │ │ ├── gate-validator.ts
│ │ │ ├── index.ts
│ │ │ └── temporary-gate-registry.ts
│ │ ├── definitions
│ │ │ ├── code-quality.json
│ │ │ ├── content-structure.json
│ │ │ ├── educational-clarity.json
│ │ │ ├── framework-compliance.json
│ │ │ ├── research-quality.json
│ │ │ ├── security-awareness.json
│ │ │ └── technical-accuracy.json
│ │ ├── gate-state-manager.ts
│ │ ├── guidance
│ │ │ ├── FrameworkGuidanceFilter.ts
│ │ │ └── GateGuidanceRenderer.ts
│ │ ├── index.ts
│ │ ├── intelligence
│ │ │ ├── GatePerformanceAnalyzer.ts
│ │ │ └── GateSelectionEngine.ts
│ │ ├── templates
│ │ │ ├── code_quality_validation.md
│ │ │ ├── educational_clarity_validation.md
│ │ │ ├── framework_compliance_validation.md
│ │ │ ├── research_self_validation.md
│ │ │ ├── security_validation.md
│ │ │ ├── structure_validation.md
│ │ │ └── technical_accuracy_validation.md
│ │ └── types.ts
│ ├── index.ts
│ ├── logging
│ │ └── index.ts
│ ├── mcp-tools
│ │ ├── config-utils.ts
│ │ ├── constants.ts
│ │ ├── index.ts
│ │ ├── prompt-engine
│ │ │ ├── core
│ │ │ │ ├── engine.ts
│ │ │ │ ├── executor.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── types.ts
│ │ │ ├── index.ts
│ │ │ ├── processors
│ │ │ │ ├── response-formatter.ts
│ │ │ │ └── template-processor.ts
│ │ │ └── utils
│ │ │ ├── category-extractor.ts
│ │ │ ├── classification.ts
│ │ │ ├── context-builder.ts
│ │ │ └── validation.ts
│ │ ├── prompt-manager
│ │ │ ├── analysis
│ │ │ │ ├── comparison-engine.ts
│ │ │ │ ├── gate-analyzer.ts
│ │ │ │ └── prompt-analyzer.ts
│ │ │ ├── core
│ │ │ │ ├── index.ts
│ │ │ │ ├── manager.ts
│ │ │ │ └── types.ts
│ │ │ ├── index.ts
│ │ │ ├── operations
│ │ │ │ └── file-operations.ts
│ │ │ ├── search
│ │ │ │ ├── filter-parser.ts
│ │ │ │ └── prompt-matcher.ts
│ │ │ └── utils
│ │ │ ├── category-manager.ts
│ │ │ └── validation.ts
│ │ ├── shared
│ │ │ └── structured-response-builder.ts
│ │ ├── system-control.ts
│ │ ├── tool-description-manager.ts
│ │ └── types
│ │ └── shared-types.ts
│ ├── metrics
│ │ ├── analytics-service.ts
│ │ ├── index.ts
│ │ └── types.ts
│ ├── performance
│ │ ├── index.ts
│ │ └── monitor.ts
│ ├── prompts
│ │ ├── category-manager.ts
│ │ ├── converter.ts
│ │ ├── file-observer.ts
│ │ ├── hot-reload-manager.ts
│ │ ├── index.ts
│ │ ├── loader.ts
│ │ ├── promptUtils.ts
│ │ ├── registry.ts
│ │ └── types.ts
│ ├── runtime
│ │ ├── application.ts
│ │ └── startup.ts
│ ├── semantic
│ │ ├── configurable-semantic-analyzer.ts
│ │ └── integrations
│ │ ├── index.ts
│ │ └── llm-clients.ts
│ ├── server
│ │ ├── index.ts
│ │ └── transport
│ │ └── index.ts
│ ├── smithery.yaml
│ ├── text-references
│ │ ├── conversation.ts
│ │ └── index.ts
│ ├── types
│ │ └── index.ts
│ ├── types.ts
│ └── utils
│ ├── chainUtils.ts
│ ├── errorHandling.ts
│ ├── global-resource-tracker.ts
│ ├── index.ts
│ └── jsonUtils.ts
├── tests
│ ├── ci-startup-validation.js
│ ├── enhanced-validation
│ │ ├── contract-validation
│ │ │ ├── contract-test-suite.js
│ │ │ ├── interface-contracts.js
│ │ │ └── interface-contracts.ts
│ │ ├── environment-validation
│ │ │ ├── environment-parity-checker.js
│ │ │ └── environment-test-suite.js
│ │ ├── lifecycle-validation
│ │ │ ├── lifecycle-test-suite.js
│ │ │ └── process-lifecycle-validator.js
│ │ └── validation-orchestrator.js
│ ├── helpers
│ │ └── test-helpers.js
│ ├── integration
│ │ ├── mcp-tools.test.ts
│ │ ├── server-startup.test.ts
│ │ └── unified-parsing-integration.test.ts
│ ├── performance
│ │ ├── parsing-system-benchmark.test.ts
│ │ └── server-performance.test.ts
│ ├── scripts
│ │ ├── consolidated-tools.js
│ │ ├── establish-performance-baselines.js
│ │ ├── functional-mcp-validation.js
│ │ ├── integration-mcp-tools.js
│ │ ├── integration-routing-system.js
│ │ ├── integration-server-startup.js
│ │ ├── integration-unified-parsing.js
│ │ ├── methodology-guides.js
│ │ ├── performance-memory.js
│ │ ├── runtime-integration.js
│ │ ├── unit-conversation-manager.js
│ │ ├── unit-semantic-analyzer.js
│ │ └── unit-unified-parsing.js
│ ├── setup.ts
│ ├── test-enhanced-parsing.js
│ └── unit
│ ├── conversation-manager.test.ts
│ ├── semantic-analyzer-three-tier.test.ts
│ └── unified-parsing-system.test.ts
├── tsconfig.json
└── tsconfig.test.json
```
# Files
--------------------------------------------------------------------------------
/server/tests/unit/semantic-analyzer-three-tier.test.ts:
--------------------------------------------------------------------------------
```typescript
/**
* Semantic Analyzer Three-Tier Model Unit Tests
* Tests the enhanced semantic analyzer for prompt/template/chain/workflow classification
*/
import { describe, test, expect, beforeEach, jest } from '@jest/globals';
import { SemanticAnalyzer } from '../../dist/analysis/semantic-analyzer.js';
import { Logger } from '../../dist/logging/index.js';
import { ConvertedPrompt } from '../../dist/types/index.js';
// Mock logger for testing
const mockLogger = {
debug: jest.fn(),
info: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
} as unknown as Logger;
describe('Semantic Analyzer Three-Tier Model', () => {
let analyzer: SemanticAnalyzer;
beforeEach(() => {
analyzer = new SemanticAnalyzer(mockLogger, {
enableCaching: false // Disable caching for consistent testing
});
});
describe('Basic Prompt Classification', () => {
test('should classify simple variable substitution as "prompt"', async () => {
const prompt: ConvertedPrompt = {
id: 'test_simple',
name: 'Simple Test',
description: 'Simple variable substitution',
category: 'test',
userMessageTemplate: 'Hello {{name}}, how are you?',
arguments: [{ name: 'name', required: true, description: 'User name' }]
};
const analysis = await analyzer.analyzePrompt(prompt);
expect(analysis.executionType).toBe('prompt');
expect(analysis.requiresFramework).toBe(false);
expect(analysis.confidence).toBeGreaterThan(0.5);
expect(analysis.frameworkRecommendation.shouldUseFramework).toBe(false);
});
test('should classify basic prompts with minimal arguments as "prompt"', async () => {
const prompt: ConvertedPrompt = {
id: 'test_basic',
name: 'Basic Greeting',
description: 'Basic greeting template',
category: 'test',
userMessageTemplate: 'Welcome {{user}}! Today is {{date}}.',
arguments: [
{ name: 'user', required: true, description: 'Username' },
{ name: 'date', required: false, description: 'Current date' }
]
};
const analysis = await analyzer.analyzePrompt(prompt);
expect(analysis.executionType).toBe('prompt');
expect(analysis.requiresFramework).toBe(false);
});
});
describe('Framework-Aware Template Classification', () => {
test('should classify structured reasoning prompts as "template"', async () => {
const prompt: ConvertedPrompt = {
id: 'test_analysis',
name: 'Deep Analysis Template',
description: 'Analyze and evaluate complex situations systematically',
category: 'analysis',
systemMessage: 'You are a systematic analyst using structured reasoning approaches.',
userMessageTemplate: `
Please analyze {{topic}} using the following structured approach:
1. **Context Analysis**: Examine the background and environment
2. **Goal Definition**: Identify key objectives and success criteria
3. **Systematic Evaluation**: Break down the problem methodically
4. **Refinement**: Iterate and improve your analysis
Provide comprehensive reasoning for {{requirements}}.
`,
arguments: [
{ name: 'topic', required: true, description: 'Topic to analyze' },
{ name: 'requirements', required: true, description: 'Analysis requirements' }
]
};
const analysis = await analyzer.analyzePrompt(prompt);
expect(analysis.executionType).toBe('template');
expect(analysis.requiresFramework).toBe(true);
expect(analysis.executionCharacteristics.hasStructuredReasoning).toBe(true);
expect(analysis.executionCharacteristics.hasMethodologyKeywords).toBe(true);
expect(analysis.frameworkRecommendation.shouldUseFramework).toBe(true);
expect(analysis.frameworkRecommendation.confidence).toBeGreaterThan(0.7);
});
test('should classify methodology-heavy prompts as "template"', async () => {
const prompt: ConvertedPrompt = {
id: 'test_methodology',
name: 'CAGEERF Methodology Template',
description: 'Apply CAGEERF framework for systematic analysis',
category: 'methodology',
userMessageTemplate: `
Apply the CAGEERF methodology to evaluate {{subject}}:
**Context**: What is the relevant background and environment?
**Analysis**: How should we approach this systematically?
**Goals**: What are the key objectives and evaluation criteria?
**Execution**: What steps should be taken?
**Evaluation**: How do we assess progress and outcomes?
**Refinement**: What improvements can be made?
**Framework**: How does this align with our overall approach?
`,
arguments: [
{ name: 'subject', required: true, description: 'Subject to evaluate' }
]
};
const analysis = await analyzer.analyzePrompt(prompt);
expect(analysis.executionType).toBe('template');
expect(analysis.requiresFramework).toBe(true);
expect(analysis.executionCharacteristics.hasMethodologyKeywords).toBe(true);
expect(analysis.executionCharacteristics.hasComplexAnalysis).toBe(true);
});
test('should classify complex prompts without methodology as "template"', async () => {
const prompt: ConvertedPrompt = {
id: 'test_complex',
name: 'Complex Multi-Argument Template',
description: 'Complex template with many arguments',
category: 'complex',
userMessageTemplate: 'Process {{arg1}} with {{arg2}} considering {{arg3}}, {{arg4}}, and {{arg5}} while maintaining {{arg6}} standards.',
arguments: [
{ name: 'arg1', required: true, description: 'First parameter' },
{ name: 'arg2', required: true, description: 'Second parameter' },
{ name: 'arg3', required: true, description: 'Third parameter' },
{ name: 'arg4', required: true, description: 'Fourth parameter' },
{ name: 'arg5', required: true, description: 'Fifth parameter' },
{ name: 'arg6', required: false, description: 'Quality standards' }
]
};
const analysis = await analyzer.analyzePrompt(prompt);
expect(analysis.executionType).toBe('template');
expect(analysis.frameworkRecommendation.shouldUseFramework).toBe(true);
expect(analysis.frameworkRecommendation.confidence).toBeLessThanOrEqual(0.9); // Lower confidence due to lack of methodology keywords
});
});
describe('Chain Classification', () => {
test('should classify chain prompts as "chain"', async () => {
const prompt: ConvertedPrompt = {
id: 'test_chain',
name: 'Analysis Chain',
description: 'Multi-step analysis process',
category: 'chain',
userMessageTemplate: 'Execute analysis steps sequentially',
chainSteps: [
{ promptId: 'step1', stepName: 'Initial Analysis', executionType: 'template' },
{ promptId: 'step2', stepName: 'Deep Dive', executionType: 'template' },
{ promptId: 'step3', stepName: 'Summary', executionType: 'prompt' }
],
arguments: [{ name: 'input', required: true, description: 'Input data' }]
};
const analysis = await analyzer.analyzePrompt(prompt);
expect(analysis.executionType).toBe('chain');
expect(analysis.executionCharacteristics.hasChainSteps).toBe(true);
expect(analysis.frameworkRecommendation.shouldUseFramework).toBe(true);
});
test('should detect chain-like patterns in content', async () => {
const prompt: ConvertedPrompt = {
id: 'test_steps',
name: 'Step-by-Step Process',
description: 'Sequential step process',
category: 'process',
userMessageTemplate: `
Please follow these steps to analyze {{topic}}:
Step 1: Gather context information
Step 2: Define analysis goals
Step 3: Execute systematic evaluation
Then proceed to the next action based on results.
`,
arguments: [{ name: 'topic', required: true, description: 'Analysis topic' }]
};
const analysis = await analyzer.analyzePrompt(prompt);
expect(analysis.executionCharacteristics.hasChainSteps).toBe(true);
});
});
describe('Workflow Classification', () => {
test('should classify complex workflow prompts as "workflow"', async () => {
const prompt: ConvertedPrompt = {
id: 'test_workflow',
name: 'Complex Workflow',
description: 'Complex conditional workflow with loops',
category: 'workflow',
userMessageTemplate: `
{% for item in items %}
{% if item.condition %}
Process {{item.name}} with special handling
{% else %}
Standard processing for {{item.name}}
{% endif %}
{% endfor %}
`,
arguments: [
{ name: 'items', required: true, description: 'Items to process' },
{ name: 'config', required: false, description: 'Configuration' },
{ name: 'options', required: false, description: 'Processing options' },
{ name: 'validation', required: false, description: 'Validation rules' },
{ name: 'output', required: false, description: 'Output format' },
{ name: 'metadata', required: false, description: 'Additional metadata' }
]
};
const analysis = await analyzer.analyzePrompt(prompt);
expect(analysis.executionType).toBe('workflow');
expect(analysis.executionCharacteristics.hasConditionals).toBe(true);
expect(analysis.executionCharacteristics.hasLoops).toBe(true);
expect(analysis.complexity).toBe('high');
});
});
describe('Framework Recommendation Logic', () => {
test('should recommend framework for templates but not prompts', async () => {
const basicPrompt: ConvertedPrompt = {
id: 'basic',
name: 'Basic',
description: 'Basic prompt',
category: 'test',
userMessageTemplate: 'Hello {{name}}',
arguments: [{ name: 'name', required: true, description: 'Name' }]
};
const templatePrompt: ConvertedPrompt = {
id: 'template',
name: 'Analysis Template',
description: 'Structured analysis template',
category: 'test',
userMessageTemplate: 'Analyze {{topic}} systematically using structured reasoning approach',
arguments: [{ name: 'topic', required: true, description: 'Topic' }]
};
const basicAnalysis = await analyzer.analyzePrompt(basicPrompt);
const templateAnalysis = await analyzer.analyzePrompt(templatePrompt);
expect(basicAnalysis.frameworkRecommendation.shouldUseFramework).toBe(false);
expect(templateAnalysis.frameworkRecommendation.shouldUseFramework).toBe(true);
expect(basicAnalysis.frameworkRecommendation.confidence).toBeGreaterThan(0.8);
expect(templateAnalysis.frameworkRecommendation.confidence).toBeGreaterThan(0.7);
});
});
describe('Performance and Caching', () => {
test('should handle analysis without caching enabled', async () => {
const prompt: ConvertedPrompt = {
id: 'perf_test',
name: 'Performance Test',
description: 'Test prompt for performance',
category: 'test',
userMessageTemplate: 'Test {{input}}',
arguments: [{ name: 'input', required: true, description: 'Input' }]
};
const analysis1 = await analyzer.analyzePrompt(prompt);
const analysis2 = await analyzer.analyzePrompt(prompt);
expect(analysis1.analysisMetadata.cacheHit).toBe(false);
expect(analysis2.analysisMetadata.cacheHit).toBe(false);
expect(analysis1.analysisMetadata.version).toBe('2.0.0');
});
test('should provide performance stats', () => {
const stats = analyzer.getPerformanceStats();
expect(stats).toHaveProperty('cacheSize');
expect(stats).toHaveProperty('cacheEnabled');
expect(typeof stats.cacheSize).toBe('number');
expect(typeof stats.cacheEnabled).toBe('boolean');
});
});
describe('Error Handling', () => {
test('should handle prompts with missing fields gracefully', async () => {
const incompletePrompt: ConvertedPrompt = {
id: 'incomplete',
name: 'Incomplete',
description: 'Missing template',
category: 'test',
userMessageTemplate: '',
arguments: []
};
const analysis = await analyzer.analyzePrompt(incompletePrompt);
expect(analysis).toBeDefined();
expect(analysis.executionType).toBeDefined();
expect(analysis.confidence).toBeGreaterThan(0);
});
});
});
```
--------------------------------------------------------------------------------
/docs/prompt-format-guide.md:
--------------------------------------------------------------------------------
```markdown
# Prompt Format Guide
This document explains the format and structure of prompts in the Claude Custom Prompts server, including the new standardized execution headers and gate validation features introduced in v1.1.0.
## Prompt Configuration System
Prompts are organized in a distributed configuration system:
1. **promptsConfig.json**: The main configuration file that defines categories and imports
2. **Category-specific prompts.json files**: Each category has its own prompts.json file
3. **Markdown template files**: The actual prompt templates are stored as markdown files
### Configuration Structure
For a complete explanation of the configuration structure, see the [Prompt Management](prompt-management.md) documentation.
## Intelligent Prompt File Structure (v1.1.0)
Prompt templates are stored as markdown files with a specific structure. The system now uses **intelligent semantic analysis** to automatically detect execution requirements, making manual configuration unnecessary.
**Key Enhancement**: Execution headers are now **purely optional hints** - the system automatically detects execution types and requirements from prompt content using advanced semantic analysis.
### Intelligent Structure (Recommended)
```markdown
# Prompt Title
Brief description of what the prompt does and its purpose.
## System Message
System instructions for Claude.
## User Message Template
Template for the user message with {{placeholders}}.
## Arguments
- argument1: Description of the first argument
- argument2: Description of the second argument
```
**🧠 Automatic Detection**: The system automatically analyzes your prompt content to determine:
- **Execution Type**: Whether it's a basic prompt, template, or chain
- **Quality Gates**: Appropriate validation based on complexity
- **Execution Requirements**: Whether execution or template return is needed
### Optional Enhancement Headers (Legacy)
If you want to provide explicit hints to Claude (completely optional):
```markdown
# Prompt Title
_Optional execution hints for Claude:_
**🎯 EXECUTION TYPE**: Chain Template | Multi-Step Chain | Template
**⚡ EXECUTION REQUIRED**: This template requires execution / outputs instructions
## Description
Brief description of what the prompt does and its purpose.
## System Message
System instructions for Claude.
## User Message Template
Template for the user message with {{placeholders}}.
## Arguments
- argument1: Description of the first argument
- argument2: Description of the second argument
```
**Note**: Headers like AUTO-EXECUTION, TOOL INTEGRATION, etc. are no longer needed - the system handles execution intelligently.
## Intelligent Analysis System (v1.1.0)
The system now uses advanced semantic analysis to automatically understand prompts without manual configuration:
### Automatic Detection Features
#### **🧠 Semantic Content Analysis**
The system analyzes prompt content using advanced patterns:
- **Chain Detection**: Identifies systematic, multi-step approaches
- **Action Detection**: Recognizes analysis, processing, and execution requirements
- **Instruction Generation**: Detects templates that output step-by-step guidance
- **Template Information**: Identifies prompts that return data vs. executable content
#### **🎯 Intelligent Classification**
Prompts are automatically classified into types:
- **`chain`**: Requires execution with quality validation (confidence-based)
- **`chain`**: Multi-step sequential execution with step tracking
- **`template`**: Returns information or configuration data
#### **🛡️ Auto-Assigned Quality Gates**
Quality gates are intelligently assigned based on:
- **Content Complexity**: More arguments = more validation
- **Analysis Requirements**: Analysis prompts get keyword presence checks
- **Chain Patterns**: Step-by-step content gets completion validation
- **Chain Operations**: Multi-step chains get step completion gates
#### **⚡ Smart Execution Decisions**
The system automatically decides whether to:
- **Execute immediately**: For high-confidence chains
- **Return template info**: For information-only prompts
- **Apply quality gates**: Based on prompt complexity and type
- **Enable step confirmation**: For sensitive or complex chains
### Usage Examples
#### **Simple Usage (Recommended)**
```bash
# System automatically detects and executes appropriately
>>content_analysis "your content here"
# System auto-detects this is a chain, applies quality gates, executes
>>notes "research data to analyze"
# System detects this is a template info request, returns guidance
>>listprompts
```
#### **Manual Override (When Needed)**
```bash
# Force specific execution mode
>>execute_prompt {"command": ">>content_analysis data", "execution_mode": "chain"}
# Enable step confirmation for sensitive chains
>>execute_prompt {"command": ">>notes data", "step_confirmation": true}
```
### Required Sections
1. **Title** (Level 1 Heading): The name of the prompt
2. **Description** (Level 2 Heading): Brief explanation of the prompt's purpose
3. **User Message Template** (Level 2 Heading): The template for the user message with placeholders
### Optional Sections
1. **System Message** (Level 2 Heading): Instructions for Claude's behavior
2. **Execution Headers** (Bold formatted): New standardized execution guidance
3. **Chain Steps** (Level 2 Heading): For chain prompts, defines the steps in the chain
## Placeholders and Arguments
Placeholders in templates are denoted by double curly braces: `{{argument_name}}`.
### Argument Registration
Arguments are defined in the category's prompts.json file for each prompt:
```json
{
"prompts": [
{
"id": "friendly_greeting",
"name": "Friendly Greeting",
"category": "general",
"description": "A warm, personalized greeting that makes the user feel welcome and valued.",
"file": "friendly_greeting.md",
"arguments": [
{
"name": "name",
"description": "The name of the person to greet",
"required": false
}
]
}
]
}
```
Each argument has the following properties:
- `name`: The name of the argument, used in placeholders
- `description`: Description of the argument's purpose
- `required`: Whether the argument is required (boolean)
## Example Prompt
````markdown
# Code Review
This prompt helps Claude review code and provide feedback.
## System Message
You are an expert code reviewer with deep knowledge of software engineering principles and best practices. Your task is to review code snippets and provide constructive feedback.
## User Message Template
Please review the following {{language}} code:
```{{language}}
{{code}}
```
````
Focus on:
- Code quality
- Potential bugs
- Performance issues
- Security concerns
- Readability and maintainability
{% if best_practices %}
Also check for adherence to {{language}} best practices.
{% endif %}
## Arguments
- language: The programming language of the code (e.g., JavaScript, Python, etc.)
- code: The code snippet to review
- best_practices: Whether to check for language-specific best practices (optional)
````
## Chain Prompt Format
Chain prompts include an additional section that defines the steps in the chain:
```markdown
## Chain Steps
1. promptId: first-step-prompt
stepName: Initial Analysis
inputMapping:
topic: input_topic
outputMapping:
keyPoints: analysis_results
2. promptId: second-step-prompt
stepName: Detailed Exploration
inputMapping:
analysisResults: analysis_results
depth: exploration_depth
outputMapping:
detailedFindings: detailed_results
````
Each step includes:
1. **promptId**: The ID of the prompt to execute
2. **stepName**: A descriptive name for the step
3. **inputMapping**: How to map chain inputs to step inputs
4. **outputMapping**: How to map step outputs to chain outputs
## Advanced Templating with Nunjucks (Replacing Conditional Logic)
The template system now uses **Nunjucks** for advanced templating features, providing more power and flexibility than the previous Handlebars-style syntax. This allows for conditional logic, loops, and more, directly within your prompt templates.
### Key Nunjucks Features:
- **Conditional Logic (`{% if %}` ... `{% else %}` ... `{% endif %}`):**
Control which parts of your template are rendered based on the presence or value of arguments.
```nunjucks
{% if user_role == "admin" %}
Welcome, Admin! You have full access.
{% elif user_role == "editor" %}
Welcome, Editor! You can manage content.
{% else %}
Welcome, {{user_name | default("Guest")}}!
{% endif %}
```
- **Loops (`{% for %}` ... `{% endfor %}`):**
Iterate over arrays or lists. If you pass an argument that is an array (e.g., from a JSON object in your calling code), Nunjucks can loop through it.
```nunjucks
Your selected topics:
{% for topic in selected_topics %}
- {{ topic }}
{% else %}
No topics selected.
{% endfor %}
```
_(Note: Ensure list/array arguments are passed in a format Nunjucks can iterate, e.g., as actual arrays in the context.)_
- **Standard Variable Placeholders (`{{variable}}`):**
Simple variable replacement is handled by Nunjucks as well.
```nunjucks
The current task is: {{task_description}}.
```
- \*\*Filters (`{{ variable | filter }}`):
Nunjucks offers many built-in filters (e.g., `{{ name | lower }}`, `{{ items | length }}`, `{{ title | default("Untitled") }}`) and custom filters can be added globally if needed.
* **Macros (`{% macro %}`), Template Inheritance (`{% extends %}`), and Setting Variables (`{% set %}`):**
Nunjucks also supports defining reusable macros, template inheritance for creating base templates, and setting temporary variables within templates. These powerful features allow for highly modular and maintainable prompt designs.
```nunjucks
{# Example of setting a variable #}
{% set greeting = "Hello" %}
{% if hour > 12 %}{% set greeting = "Good afternoon" %}{% endif %}
{{ greeting }}, {{ user_name }}!
{# For macros and inheritance, refer to detailed examples and Nunjucks documentation #}
```
For detailed examples and usage of these advanced features, please see the [Prompt Management](prompt-management.md) guide or the [official Nunjucks documentation](https://mozilla.github.io/nunjucks/templating.html).
### Processing Order:
1. The entire template is processed by Nunjucks, resolving all Nunjucks tags (`{% ... %}`) and variable placeholders (`{{ ... }}`).
2. After Nunjucks processing, any text references (e.g., `ref:xyz` for long arguments) are expanded to their full content.
For more details on Nunjucks syntax and features, refer to the official [Nunjucks documentation](https://mozilla.github.io/nunjucks/templating.html).
## File Organization
Prompts are organized in directories by category:
```
prompts/
category1/
prompt1.md
prompt2.md
category2/
prompt3.md
prompt4.md
```
The category is determined by the directory name.
## Prompt IDs
Prompt IDs are generated based on the file path and name:
- For a file at `prompts/category/file.md`, the ID would be `category/file`
- IDs are used to reference prompts in API calls and chain definitions
## Best Practices
1. **Clear Descriptions**: Provide clear descriptions of what the prompt does
2. **Descriptive Arguments**: Clearly describe each argument and whether it's required
3. **Organized Structure**: Use consistent formatting and organization
4. **Meaningful Names**: Use descriptive names for prompts and arguments
5. **Documentation**: Include examples and usage notes where helpful
6. **Testing**: Test prompts with various inputs to ensure they work as expected
## Common Issues
### Missing Placeholders
If a placeholder in the template doesn't have a corresponding argument, it will remain as is in the output.
### Invalid Markdown
If the markdown structure is invalid (missing sections, incorrect headings), the prompt may not load correctly.
### Circular References
In chain prompts, avoid circular references where prompts depend on each other in a loop.
## Advanced Usage
### Multi-paragraph Arguments
For arguments that may contain multiple paragraphs, use triple backticks in the template:
```markdown
## User Message Template
Please analyze the following text:
```
{{long_text}}
```
## Arguments
- long_text: A potentially long text that may contain multiple paragraphs
```
### Dynamic Templates
You can create dynamic templates that adapt based on the provided arguments:
```markdown
## User Message Template
{% if detailed %}
Please provide a detailed analysis of {{topic}}, covering all aspects in depth.
{% else %}
Please provide a brief overview of {{topic}}, highlighting only the key points.
{% endif %}
## Arguments
- topic: The subject to analyze
- detailed: Whether to provide a detailed analysis (true/false)
```
```
--------------------------------------------------------------------------------
/server/src/prompts/index.ts:
--------------------------------------------------------------------------------
```typescript
/**
* Prompt Management System
* Main module that orchestrates prompt loading, conversion, and registration
*/
// Import the individual modules
export * from "./converter.js";
export * from "./loader.js";
export * from "./registry.js";
// Template processor moved to /execution/processor/template-processor.js for better organization
export * from "./category-manager.js";
export * from "./file-observer.js";
export * from "./hot-reload-manager.js";
// Framework-aware components removed in Phase 3 simplification
import { ConfigManager } from "../config/index.js";
import { Logger } from "../logging/index.js";
import { TextReferenceManager } from "../text-references/index.js";
import path from "path";
import {
Category,
CategoryPromptsResult,
ConvertedPrompt,
PromptData,
} from "../types/index.js";
// Import the actual modules
import { PromptConverter } from "./converter.js";
import { PromptLoader } from "./loader.js";
import { PromptRegistry } from "./registry.js";
// TemplateProcessor functionality consolidated into UnifiedPromptProcessor
import { HotReloadManager, createHotReloadManager } from "./hot-reload-manager.js";
// Phase 1: Framework capabilities integrated into enhanced HotReloadManager
/**
* Main Prompt Manager class that coordinates all prompt operations
*/
export class PromptManager {
private logger: Logger;
private textReferenceManager: TextReferenceManager;
private configManager: ConfigManager;
private mcpServer: any;
// Individual module instances
private converter: PromptConverter;
private loader: PromptLoader;
private registry?: PromptRegistry;
// templateProcessor removed - functionality consolidated into UnifiedPromptProcessor
private hotReloadManager?: HotReloadManager;
// Framework-aware components removed in Phase 3 simplification
constructor(
logger: Logger,
textReferenceManager: TextReferenceManager,
configManager: ConfigManager,
mcpServer?: any,
// Framework parameters removed in Phase 3 simplification
) {
this.logger = logger;
this.textReferenceManager = textReferenceManager;
this.configManager = configManager;
this.mcpServer = mcpServer;
// Framework initialization removed in Phase 3 simplification
// Initialize individual modules
this.loader = new PromptLoader(logger);
// templateProcessor removed - functionality consolidated into UnifiedPromptProcessor
this.converter = new PromptConverter(logger, this.loader);
if (mcpServer) {
this.registry = new PromptRegistry(
logger,
mcpServer,
configManager
);
// Initialize HotReloadManager with CategoryManager integration
const categoryManager = this.loader.getCategoryManager();
// Phase 1: Enhanced HotReloadManager with framework capabilities
this.hotReloadManager = createHotReloadManager(
logger,
categoryManager,
{
enabled: true,
autoReload: false, // Will be controlled by external triggers
debounceMs: 500,
batchChanges: true,
batchTimeoutMs: 2000,
frameworkCapabilities: {
enabled: true,
frameworkAnalysis: true,
performanceMonitoring: true,
preWarmAnalysis: true,
invalidateFrameworkCaches: true
}
},
this.configManager
);
this.logger.info('🔄 Hot reload manager initialized');
}
}
/**
* Load prompts from category-specific configuration files
*/
async loadCategoryPrompts(
configPath: string
): Promise<CategoryPromptsResult> {
return this.loader.loadCategoryPrompts(configPath);
}
/**
* Convert markdown prompts to JSON structure
*/
async convertMarkdownPromptsToJson(
promptsData: PromptData[],
basePath?: string
): Promise<ConvertedPrompt[]> {
return this.converter.convertMarkdownPromptsToJson(promptsData, basePath);
}
// Removed: processTemplateAsync - deprecated method no longer needed
// Template processing now handled directly using processTemplate from utils/jsonUtils.js
/**
* Register prompts with MCP server
*/
async registerAllPrompts(prompts: ConvertedPrompt[]): Promise<number> {
if (!this.registry) {
throw new Error("MCP server not provided - cannot register prompts");
}
return this.registry.registerAllPrompts(prompts);
}
/**
* Notify clients that prompt list has changed (for hot-reload)
*/
async notifyPromptsListChanged(): Promise<void> {
if (!this.registry) {
throw new Error("MCP server not provided - cannot send notifications");
}
await this.registry.notifyPromptsListChanged();
}
/**
* Load and convert prompts in one operation
*/
async loadAndConvertPrompts(
configPath: string,
basePath?: string
): Promise<{
promptsData: PromptData[];
categories: Category[];
convertedPrompts: ConvertedPrompt[];
}> {
try {
this.logger.info(`📁 PromptManager: Loading prompts from: ${configPath}`);
// Verify config path exists
const fs = await import("fs/promises");
try {
const stats = await fs.stat(configPath);
this.logger.info(
`✓ Config file found, size: ${
stats.size
} bytes, modified: ${stats.mtime.toISOString()}`
);
} catch (error) {
this.logger.error(`✗ Config file access error:`, error);
throw error;
}
this.logger.info("🔄 Calling PromptLoader.loadCategoryPrompts()...");
// Load the raw prompt data
const { promptsData, categories } = await this.loadCategoryPrompts(
configPath
);
this.logger.info(
"✅ PromptLoader.loadCategoryPrompts() completed successfully"
);
this.logger.info(
`📊 Raw data loaded: ${promptsData.length} prompts from ${categories.length} categories`
);
// Log detailed breakdown by category
if (categories.length > 0) {
this.logger.info("📋 Category breakdown:");
categories.forEach((category) => {
const categoryPrompts = promptsData.filter(
(p) => p.category === category.id
);
this.logger.info(
` ${category.name} (${category.id}): ${categoryPrompts.length} prompts`
);
});
} else {
this.logger.warn("⚠️ No categories found in loaded data!");
}
if (promptsData.length === 0) {
this.logger.warn("⚠️ No prompts found in loaded data!");
}
this.logger.info("🔄 Converting prompts to JSON structure...");
// Convert to JSON structure
const convertedPrompts = await this.convertMarkdownPromptsToJson(
promptsData,
basePath
);
this.logger.info(
`✅ Conversion completed: ${convertedPrompts.length} prompts converted`
);
if (convertedPrompts.length !== promptsData.length) {
this.logger.warn(
`⚠️ Conversion count mismatch! Input: ${promptsData.length}, Output: ${convertedPrompts.length}`
);
}
this.logger.info(
"🎉 PromptManager.loadAndConvertPrompts() completed successfully"
);
return { promptsData, categories, convertedPrompts };
} catch (error) {
this.logger.error("❌ PromptManager.loadAndConvertPrompts() FAILED:");
this.logger.error("Error type:", error?.constructor?.name);
this.logger.error(
"Error message:",
error instanceof Error ? error.message : String(error)
);
this.logger.error(
"Stack trace:",
error instanceof Error ? error.stack : "No stack trace available"
);
throw error;
}
}
/**
* Complete prompt system initialization
*/
async initializePromptSystem(
configPath: string,
basePath?: string
): Promise<{
promptsData: PromptData[];
categories: Category[];
convertedPrompts: ConvertedPrompt[];
registeredCount: number;
}> {
try {
// Load and convert prompts
const result = await this.loadAndConvertPrompts(configPath, basePath);
// Register with MCP server if available
let registeredCount = 0;
if (this.registry) {
registeredCount = await this.registerAllPrompts(
result.convertedPrompts
);
} else {
this.logger.warn(
"MCP server not available - skipping prompt registration"
);
}
return { ...result, registeredCount };
} catch (error) {
this.logger.error("Error initializing prompt system:", error);
throw error;
}
}
/**
* Reload prompts (useful for hot-reloading)
*/
async reloadPrompts(
configPath: string,
basePath?: string
): Promise<{
promptsData: PromptData[];
categories: Category[];
convertedPrompts: ConvertedPrompt[];
registeredCount: number;
}> {
this.logger.info("Reloading prompt system...");
// Note: MCP protocol doesn't support unregistering prompts
// Hot-reload will be handled via list_changed notifications
// Reinitialize the system
return this.initializePromptSystem(configPath, basePath);
}
/**
* Start automatic file watching for hot reload
*/
async startHotReload(promptsConfigPath: string, onReloadCallback?: () => Promise<void>): Promise<void> {
if (!this.hotReloadManager) {
this.logger.warn("HotReloadManager not available - hot reload not started");
return;
}
// Set up reload callback
if (onReloadCallback) {
this.hotReloadManager.setReloadCallback(async (event) => {
this.logger.info(`Hot reload triggered: ${event.reason}`);
try {
await onReloadCallback();
} catch (error) {
this.logger.error("Hot reload callback failed:", error);
}
});
}
// Start monitoring
await this.hotReloadManager.start();
// Watch prompts directory and config files
const promptsDir = path.dirname(promptsConfigPath);
const promptsCategoryDirs = await this.discoverPromptDirectories(promptsDir);
await this.hotReloadManager.watchDirectories([
{ path: promptsDir }, // Watch main prompts directory
...promptsCategoryDirs.map(dir => ({ path: dir.path, category: dir.category }))
]);
this.logger.info(`🔄 Hot reload monitoring started for ${promptsCategoryDirs.length + 1} directories`);
}
/**
* Stop automatic file watching
*/
async stopHotReload(): Promise<void> {
if (this.hotReloadManager) {
await this.hotReloadManager.stop();
this.logger.info("Hot reload monitoring stopped");
}
}
/**
* Discover prompt directories for watching
*/
private async discoverPromptDirectories(promptsDir: string): Promise<Array<{ path: string; category?: string }>> {
const directories: Array<{ path: string; category?: string }> = [];
try {
const fs = await import("fs/promises");
const entries = await fs.readdir(promptsDir, { withFileTypes: true });
for (const entry of entries) {
if (entry.isDirectory() && entry.name !== 'node_modules' && !entry.name.startsWith('.')) {
const fullPath = path.join(promptsDir, entry.name);
// Check if this directory contains prompts.json (indicating it's a category directory)
try {
const categoryPromptsPath = path.join(fullPath, 'prompts.json');
await fs.access(categoryPromptsPath);
directories.push({ path: fullPath, category: entry.name });
} catch {
// Directory doesn't have prompts.json, but still watch it
directories.push({ path: fullPath });
}
}
}
} catch (error) {
this.logger.error("Failed to discover prompt directories:", error);
}
return directories;
}
// Phase 1: Framework capabilities integrated into enhanced HotReloadManager
// Framework-specific reload functionality removed in Phase 3 simplification
// Framework statistics functionality removed in Phase 3 simplification
/**
* Get all individual module instances for external access
*/
getModules() {
return {
converter: this.converter,
loader: this.loader,
registry: this.registry,
// templateProcessor: removed - functionality consolidated into UnifiedPromptProcessor
categoryManager: this.loader.getCategoryManager(),
hotReloadManager: this.hotReloadManager,
// Framework-aware modules removed in Phase 3 simplification
};
}
/**
* Get TextReferenceManager for direct access
* Added for UnifiedPromptProcessor consolidation
*/
getTextReferenceManager(): TextReferenceManager {
return this.textReferenceManager;
}
/**
* Get system statistics
*/
getStats(prompts?: ConvertedPrompt[]) {
const stats: any = {
textReferences: this.textReferenceManager.getStats(),
};
if (prompts && this.registry) {
stats.registration = this.registry.getRegistrationStats(prompts);
stats.conversation = this.registry.getConversationStats();
}
if (prompts && this.converter) {
stats.conversion = this.converter.getConversionStats(
prompts.length,
prompts
);
}
return stats;
}
}
```
--------------------------------------------------------------------------------
/server/src/execution/parsers/unified-command-parser.ts:
--------------------------------------------------------------------------------
```typescript
/**
* Unified Command Parser
*
* Robust multi-strategy command parsing system that replaces fragile regex-based parsing
* with intelligent format detection, fallback strategies, and comprehensive validation.
*
* Features:
* - Multi-format detection (simple >>prompt, JSON objects, structured commands)
* - Fallback parsing strategies with confidence scoring
* - Comprehensive error messages with suggestions
* - Command validation and sanitization
*/
import { Logger } from "../../logging/index.js";
import { PromptData } from "../../types/index.js";
import { ValidationError, PromptError, safeJsonParse } from "../../utils/index.js";
/**
* Command parsing result with metadata
*/
export interface CommandParseResult {
promptId: string;
rawArgs: string;
format: 'simple' | 'json' | 'structured' | 'legacy';
confidence: number;
metadata: {
originalCommand: string;
parseStrategy: string;
detectedFormat: string;
warnings: string[];
};
}
/**
* Parsing strategy interface
*/
interface ParsingStrategy {
name: string;
canHandle: (command: string) => boolean;
parse: (command: string) => CommandParseResult | null;
confidence: number;
}
/**
* Unified Command Parser Class
*/
export class UnifiedCommandParser {
private logger: Logger;
private strategies: ParsingStrategy[];
// Parsing statistics for monitoring
private stats = {
totalParses: 0,
successfulParses: 0,
failedParses: 0,
strategyUsage: new Map<string, number>(),
averageConfidence: 0
};
constructor(logger: Logger) {
this.logger = logger;
this.strategies = this.initializeStrategies();
this.logger.debug(`UnifiedCommandParser initialized with ${this.strategies.length} parsing strategies`);
}
/**
* Parse command string using multi-strategy approach
*/
async parseCommand(command: string, availablePrompts: PromptData[]): Promise<CommandParseResult> {
this.stats.totalParses++;
if (!command || command.trim().length === 0) {
this.stats.failedParses++;
throw new ValidationError("Command cannot be empty");
}
const normalizedCommand = command.trim();
this.logger.debug(`Parsing command: "${normalizedCommand.substring(0, 100)}..."`);
// Try each strategy in order of confidence
const sortedStrategies = [...this.strategies].sort((a, b) => b.confidence - a.confidence);
for (const strategy of sortedStrategies) {
if (strategy.canHandle(normalizedCommand)) {
try {
const result = strategy.parse(normalizedCommand);
if (result) {
// Validate that the prompt ID exists
await this.validatePromptExists(result.promptId, availablePrompts);
// Update statistics
this.stats.successfulParses++;
this.updateStrategyStats(strategy.name);
this.updateConfidenceStats(result.confidence);
this.logger.debug(`Command parsed successfully using strategy: ${strategy.name} (confidence: ${result.confidence})`);
return result;
}
} catch (error) {
this.logger.debug(`Strategy ${strategy.name} failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
continue;
}
}
}
// If no strategy succeeded, provide helpful error message
this.stats.failedParses++;
const errorMessage = this.generateHelpfulError(normalizedCommand, availablePrompts);
throw new ValidationError(errorMessage);
}
/**
* Initialize parsing strategies (STREAMLINED: 2 core strategies)
*/
private initializeStrategies(): ParsingStrategy[] {
return [
this.createSimpleCommandStrategy(),
this.createJsonCommandStrategy()
];
}
/**
* Simple command strategy: >>prompt_name arguments (ENHANCED: More AI-friendly)
*/
private createSimpleCommandStrategy(): ParsingStrategy {
return {
name: 'simple',
confidence: 0.95, // Increased confidence for primary strategy
canHandle: (command: string) => {
// More flexible pattern - handles spaces in prompt names via underscore conversion
return /^(>>|\/)[a-zA-Z0-9_\-\s]+(\s|$)/.test(command.trim());
},
parse: (command: string): CommandParseResult | null => {
// Enhanced regex to handle more natural command formats
const match = command.trim().match(/^(>>|\/)([a-zA-Z0-9_\-\s]+?)(?:\s+([\s\S]*))?$/);
if (!match) return null;
const [, prefix, rawPromptId, rawArgs] = match;
// Clean up prompt ID: convert spaces and hyphens to underscores, normalize
const promptId = rawPromptId.trim()
.toLowerCase()
.replace(/[\s-]+/g, '_') // Spaces and hyphens to underscores
.replace(/[^a-z0-9_]/g, '') // Remove invalid characters (except underscores)
.replace(/_+/g, '_') // Collapse multiple underscores
.replace(/^_|_$/g, ''); // Trim leading/trailing underscores
const warnings: string[] = [];
if (rawPromptId !== promptId) {
warnings.push(`Normalized prompt name: "${rawPromptId}" → "${promptId}"`);
}
return {
promptId: promptId,
rawArgs: (rawArgs || '').trim(),
format: 'simple',
confidence: 0.98, // High confidence for enhanced parsing
metadata: {
originalCommand: command,
parseStrategy: 'simple_enhanced',
detectedFormat: `${prefix}prompt format (normalized)`,
warnings
}
};
}
};
}
/**
* JSON command strategy: {"command": ">>prompt", "args": {...}}
*/
private createJsonCommandStrategy(): ParsingStrategy {
return {
name: 'json',
confidence: 0.85,
canHandle: (command: string) => {
const trimmed = command.trim();
return trimmed.startsWith('{') && trimmed.endsWith('}');
},
parse: (command: string): CommandParseResult | null => {
const parseResult = safeJsonParse(command);
if (!parseResult.success || !parseResult.data) {
return null;
}
const data = parseResult.data;
// Handle different JSON formats
let actualCommand = '';
let confidence = 0.8;
if (data.command) {
actualCommand = data.command;
confidence = 0.9;
} else if (data.prompt) {
actualCommand = data.prompt;
confidence = 0.85;
} else {
return null;
}
// Recursively parse the inner command
const simpleStrategy = this.createSimpleCommandStrategy();
if (!simpleStrategy.canHandle(actualCommand)) {
return null;
}
const innerResult = simpleStrategy.parse(actualCommand);
if (!innerResult) return null;
return {
promptId: innerResult.promptId,
rawArgs: data.args ? JSON.stringify(data.args) : innerResult.rawArgs,
format: 'json',
confidence,
metadata: {
originalCommand: command,
parseStrategy: 'json',
detectedFormat: 'JSON wrapper with inner command',
warnings: []
}
};
}
};
}
/**
* Validate that the prompt ID exists in available prompts
*/
private async validatePromptExists(promptId: string, availablePrompts: PromptData[]): Promise<void> {
// Check if this is a built-in command that should be routed (handled by prompt engine)
if (this.isBuiltinCommand(promptId)) {
return; // Built-in commands are valid and will be routed by the prompt engine
}
// Use case-insensitive matching to find the prompt
const found = availablePrompts.find(p =>
p.id.toLowerCase() === promptId.toLowerCase() ||
p.name?.toLowerCase() === promptId.toLowerCase()
);
if (!found) {
const suggestions = this.generatePromptSuggestions(promptId, availablePrompts);
const builtinHint = this.getBuiltinCommandHint(promptId);
throw new PromptError(
`Unknown prompt: "${promptId}". ${suggestions}${builtinHint}\n\nTry: >>listprompts, >>help, >>status`
);
}
}
/**
* Check if command is a built-in system command
*/
private isBuiltinCommand(promptId: string): boolean {
const builtinCommands = [
'listprompts', 'listprompt', 'list_prompts',
'help', 'commands',
'status', 'health',
'analytics', 'metrics'
];
return builtinCommands.includes(promptId.toLowerCase());
}
/**
* Generate hint for built-in commands that might have been mistyped
*/
private getBuiltinCommandHint(promptId: string): string {
const lower = promptId.toLowerCase();
// Check for common variations/typos of built-in commands
if (lower.includes('list') && lower.includes('prompt')) {
return '\n\nDid you mean >>listprompts?';
}
if (lower === 'commands' || lower === 'help') {
return '\n\nTry >>help for available commands.';
}
if (lower === 'stat' || lower === 'status') {
return '\n\nTry >>status for system status.';
}
return '';
}
/**
* Generate helpful prompt suggestions for typos
*/
private generatePromptSuggestions(promptId: string, availablePrompts: PromptData[]): string {
// Simple Levenshtein distance for suggestions
const suggestions = availablePrompts
.map(prompt => ({
prompt,
distance: this.levenshteinDistance(promptId.toLowerCase(), prompt.id.toLowerCase())
}))
.filter(item => item.distance <= 3)
.sort((a, b) => a.distance - b.distance)
.slice(0, 3)
.map(item => item.prompt.id);
if (suggestions.length > 0) {
return `Did you mean: ${suggestions.join(', ')}?`;
}
return '';
}
/**
* Simple Levenshtein distance calculation
*/
private levenshteinDistance(a: string, b: string): number {
const matrix = Array(b.length + 1).fill(null).map(() => Array(a.length + 1).fill(null));
for (let i = 0; i <= a.length; i++) matrix[0][i] = i;
for (let j = 0; j <= b.length; j++) matrix[j][0] = j;
for (let j = 1; j <= b.length; j++) {
for (let i = 1; i <= a.length; i++) {
const indicator = a[i - 1] === b[j - 1] ? 0 : 1;
matrix[j][i] = Math.min(
matrix[j][i - 1] + 1,
matrix[j - 1][i] + 1,
matrix[j - 1][i - 1] + indicator
);
}
}
return matrix[b.length][a.length];
}
/**
* Generate helpful error message for parsing failures
*/
private generateHelpfulError(command: string, availablePrompts: PromptData[]): string {
let message = `Could not parse command: "${command}"\n\n`;
message += 'Supported command formats:\n';
message += '• Simple: >>prompt_name arguments\n';
message += '• Simple: /prompt_name arguments\n';
message += '• JSON: {"command": ">>prompt_name", "args": "arguments"}\n';
message += '• JSON: {"command": ">>prompt_name", "args": {"key": "value"}}\n\n';
// Try to give specific suggestions based on command analysis
if (command.includes('>>') || command.includes('/')) {
const promptMatch = command.match(/^(>>|\/)([a-zA-Z0-9_\-]+)/);
if (promptMatch) {
const promptName = promptMatch[2];
message += `Prompt name "${promptName}" not found. `;
message += 'Prompt names are case-insensitive.\n\n';
// Show some available prompts as examples
const examplePrompts = availablePrompts.slice(0, 5).map(p => p.id).join(', ');
message += `Available prompts include: ${examplePrompts}...\n\n`;
} else {
message += 'Invalid prompt name format. Use letters, numbers, underscores, and hyphens only.\n\n';
}
} else if (command.startsWith('{')) {
message += 'JSON format detected but could not parse. Check JSON syntax and structure.\n\n';
} else {
message += 'Command format not recognized. Use >>prompt_name or /prompt_name format.\n\n';
}
message += 'Use >>listprompts to see all available prompts, or >>help for assistance.';
return message;
}
/**
* Update strategy usage statistics
*/
private updateStrategyStats(strategyName: string): void {
const current = this.stats.strategyUsage.get(strategyName) || 0;
this.stats.strategyUsage.set(strategyName, current + 1);
}
/**
* Update confidence statistics
*/
private updateConfidenceStats(confidence: number): void {
const totalSuccessful = this.stats.successfulParses;
this.stats.averageConfidence =
(this.stats.averageConfidence * (totalSuccessful - 1) + confidence) / totalSuccessful;
}
/**
* Get parsing statistics for monitoring
*/
getStats(): typeof this.stats {
return {
...this.stats,
strategyUsage: new Map(this.stats.strategyUsage)
};
}
/**
* Reset statistics (useful for testing or fresh starts)
*/
resetStats(): void {
this.stats = {
totalParses: 0,
successfulParses: 0,
failedParses: 0,
strategyUsage: new Map(),
averageConfidence: 0
};
}
}
/**
* Factory function to create unified command parser
*/
export function createUnifiedCommandParser(logger: Logger): UnifiedCommandParser {
return new UnifiedCommandParser(logger);
}
```
--------------------------------------------------------------------------------
/server/src/mcp-tools/types/shared-types.ts:
--------------------------------------------------------------------------------
```typescript
/**
* Shared Type Definitions for MCP Tools
*
* This file contains proper TypeScript interfaces to replace 'any' types
* throughout the MCP tools system, improving type safety and development experience.
*
* Updated: 2025-09-28 - Consolidated with unified error handling system
*/
// Import consolidated error handling types
import { ErrorContext, ValidationResult } from '../../utils/errorHandling.js';
/**
* MCP Tool callback extra parameter
*/
export interface ToolExtra {
requestId?: string;
clientInfo?: {
name: string;
version: string;
};
metadata?: Record<string, unknown>;
}
/**
* Structured response interface for all MCP tools (compatible with ToolResponse)
*/
export interface StructuredToolResponse {
content: Array<{
type: "text";
text: string;
}>;
isError?: boolean;
metadata?: {
tool: string;
action: string;
timestamp: string;
executionTime?: number;
framework?: string;
errorCode?: string;
[key: string]: unknown;
};
}
/**
* Analytics data structure for system metrics
*/
export interface AnalyticsData {
executions: {
total: number;
successful: number;
failed: number;
byTool: Record<string, number>;
byAction: Record<string, number>;
};
performance: {
averageExecutionTime: number;
memoryUsage: {
heapUsed: number;
heapTotal: number;
external: number;
};
cacheHitRate?: number;
};
frameworks: {
activeFramework: string;
switchCount: number;
switchHistory: Array<{
from: string;
to: string;
timestamp: string;
reason?: string;
}>;
};
timestamp: string;
}
/**
* Response formatter interface with proper typing
*/
export interface TypedResponseFormatter {
formatResponse<T>(content: T): StructuredToolResponse;
formatErrorResponse(error: TypedError, context?: ResponseContext): StructuredToolResponse;
setAnalyticsService(service: AnalyticsService): void;
}
/**
* Response context for error formatting
*/
export interface ResponseContext {
tool: string;
action: string;
requestId?: string;
executionTime?: number;
additionalInfo?: MetadataFields;
}
// ============================================================================
// PROPER ERROR TYPES (Phase 1: Replace error: any)
// ============================================================================
/**
* Base typed error interface
*/
export interface TypedError {
name: string;
message: string;
code?: string;
context?: ErrorContext;
stack?: string;
cause?: TypedError;
}
// Re-export ErrorContext from consolidated error handling
export type { ErrorContext, ValidationResult };
/**
* Validation error with detailed information
*/
export interface ValidationError extends TypedError {
name: 'ValidationError';
field?: string;
value?: unknown;
constraint?: string;
example?: string;
}
/**
* Execution error with runtime context
*/
export interface ExecutionError extends TypedError {
name: 'ExecutionError';
executionId?: string;
step?: string;
retryCount?: number;
isRetryable?: boolean;
}
/**
* Configuration error
*/
export interface ConfigurationError extends TypedError {
name: 'ConfigurationError';
configKey?: string;
configValue?: unknown;
validValues?: unknown[];
}
/**
* Framework error
*/
export interface FrameworkError extends TypedError {
name: 'FrameworkError';
framework?: string;
operation?: string;
supportedFrameworks?: string[];
}
/**
* Type guard functions for errors
*/
export function isTypedError(error: unknown): error is TypedError {
return typeof error === 'object' && error !== null &&
'name' in error && 'message' in error;
}
export function isValidationError(error: unknown): error is ValidationError {
return isTypedError(error) && error.name === 'ValidationError';
}
export function isExecutionError(error: unknown): error is ExecutionError {
return isTypedError(error) && error.name === 'ExecutionError';
}
export function isConfigurationError(error: unknown): error is ConfigurationError {
return isTypedError(error) && error.name === 'ConfigurationError';
}
export function isFrameworkError(error: unknown): error is FrameworkError {
return isTypedError(error) && error.name === 'FrameworkError';
}
/**
* Analytics service interface (matches MetricsCollector)
*/
export interface AnalyticsService {
recordExecution(executionData: ExecutionData): void;
getAnalyticsSummary(options?: AnalyticsOptions): AnalyticsSummary;
recordFrameworkSwitch?(data: FrameworkSwitchData): void;
recordGateValidation?(data: GateValidationData): void;
}
/**
* Execution data for analytics
*/
export interface ExecutionData {
executionId: string;
tool: string;
action: string;
success: boolean;
duration: number;
executionType: 'prompt' | 'template' | 'chain';
startTime: number;
endTime: number;
framework?: string;
errorCode?: string;
}
/**
* Analytics options
*/
export interface AnalyticsOptions {
timeRange?: {
start: Date;
end: Date;
};
includeDetails?: boolean;
groupBy?: 'tool' | 'action' | 'framework';
}
/**
* Analytics summary result
*/
export interface AnalyticsSummary {
totalExecutions: number;
successRate: number;
averageExecutionTime: number;
breakdown: {
byTool: Record<string, number>;
byAction: Record<string, number>;
byFramework: Record<string, number>;
};
performance: {
slowestExecutions: Array<{
tool: string;
action: string;
duration: number;
timestamp: string;
}>;
errorRate: number;
memoryUsage: {
average: number;
peak: number;
};
};
}
/**
* Framework switch data
*/
export interface FrameworkSwitchData {
from: string;
to: string;
timestamp: string;
reason?: string;
success: boolean;
duration?: number;
}
/**
* Gate validation data
*/
export interface GateValidationData {
gateId: string;
gateName: string;
passed: boolean;
score?: number;
executionTime: number;
requirements: string[];
context: {
promptId: string;
executionType: 'prompt' | 'template' | 'chain';
framework?: string;
};
}
/**
* Configuration value types
*/
export type ConfigValue = string | number | boolean | null | ConfigObject | ConfigArray;
export interface ConfigObject {
[key: string]: ConfigValue;
}
export interface ConfigArray extends Array<ConfigValue> {}
// ============================================================================
// SPECIFIC ARGUMENT TYPES (Phase 1: Replace any types)
// ============================================================================
/**
* Prompt argument definition with strict typing
*/
export interface PromptArgumentDefinition {
name: string;
description?: string;
required: boolean;
type?: 'string' | 'number' | 'boolean' | 'object' | 'array';
defaultValue?: ConfigValue;
validation?: {
pattern?: string;
minLength?: number;
maxLength?: number;
allowedValues?: ConfigValue[];
};
}
/**
* Chain step definition with strict typing
*/
export interface ChainStepDefinition {
promptId: string;
stepName: string;
inputMapping?: Record<string, string>;
outputMapping?: Record<string, string>;
conditions?: {
skipIf?: string;
stopIf?: string;
};
}
/**
* Prompt Manager action argument types
*/
export interface BasePromptManagerArgs {
id?: string;
name?: string;
category?: string;
description?: string;
system_message?: string;
user_message_template?: string;
arguments?: PromptArgumentDefinition[];
chain_steps?: ChainStepDefinition[];
filter?: string;
detail?: 'overview' | 'steps' | 'structure' | 'gates' | 'flow' | 'analysis' | 'raw' | 'full';
format?: 'compact' | 'detailed' | 'json';
}
export type PromptManagerAction =
| { action: 'create'; id: string; name: string; user_message_template: string } & BasePromptManagerArgs
| { action: 'create_prompt'; id: string; name: string; user_message_template: string } & BasePromptManagerArgs
| { action: 'create_template'; id: string; name: string; user_message_template: string } & BasePromptManagerArgs
| { action: 'update'; id: string } & BasePromptManagerArgs & {
migrate_to?: 'prompt' | 'template';
section?: 'name' | 'description' | 'system_message' | 'user_message_template' | 'arguments' | 'chain_steps';
section_content?: string;
}
| { action: 'delete'; id: string }
| { action: 'reload' }
| { action: 'list' } & Pick<BasePromptManagerArgs, 'filter' | 'format'>
| { action: 'inspect'; id: string } & Pick<BasePromptManagerArgs, 'detail' | 'format'>;
/**
* Prompt Engine argument types
*/
export interface PromptEngineArgs {
command: string;
execution_mode?: 'auto' | 'prompt' | 'template' | 'chain';
force_restart?: boolean;
session_id?: string;
options?: ExecutionOptions;
}
/**
* Execution options with proper typing
*/
export interface ExecutionOptions {
framework?: 'CAGEERF' | 'ReACT' | '5W1H' | 'SCAMPER';
gateValidation?: boolean;
timeout?: number;
retryCount?: number;
debugMode?: boolean;
stepConfirmation?: boolean;
context?: ExecutionContext;
}
/**
* Execution context
*/
export interface ExecutionContext {
sessionId?: string;
previousResults?: Record<string, unknown>;
userPreferences?: {
outputFormat?: 'compact' | 'detailed' | 'json' | 'markdown';
verboseMode?: boolean;
autoExecution?: boolean;
};
systemState?: {
activeFramework?: string;
memoryUsage?: {
heapUsed: number;
heapTotal: number;
external: number;
};
};
}
/**
* System Control argument types
*/
export interface BaseSystemControlArgs {
include_history?: boolean;
include_metrics?: boolean;
show_details?: boolean;
reason?: string;
confirm?: boolean;
limit?: number;
reset_analytics?: boolean;
operation?: string;
}
export type SystemControlAction =
| { action: 'status' } & Pick<BaseSystemControlArgs, 'include_history' | 'include_metrics' | 'operation'>
| { action: 'framework'; framework?: string } & Pick<BaseSystemControlArgs, 'reason' | 'show_details' | 'operation'>
| { action: 'analytics' } & Pick<BaseSystemControlArgs, 'include_history' | 'reset_analytics' | 'limit' | 'confirm' | 'operation'>
| { action: 'config'; config?: ConfigObject; backup_path?: string } & Pick<BaseSystemControlArgs, 'confirm' | 'operation'>
| { action: 'maintenance' } & Pick<BaseSystemControlArgs, 'reason' | 'confirm' | 'operation'>;
// ============================================================================
// REPLACEMENT TYPES FOR Record<string, any>
// ============================================================================
/**
* Prompt execution arguments (replaces Record<string, any>)
*/
export interface PromptExecutionArgs {
[key: string]: string | number | boolean | null | PromptExecutionArgs | PromptExecutionArgs[];
}
/**
* Metadata fields (replaces Record<string, any>)
*/
export interface MetadataFields {
tool: string;
action: string;
timestamp: string;
executionTime?: number;
framework?: string;
errorCode?: string;
[key: string]: string | number | boolean | null | undefined;
}
/**
* Configuration update values
*/
export interface ConfigurationValues {
[key: string]: ConfigValue;
}
/**
* Chain execution results
*/
export interface ChainExecutionResults {
[stepIndex: string]: {
result: string;
metadata: {
startTime: number;
endTime: number;
status: 'completed' | 'failed' | 'skipped';
error?: string;
};
};
}
/**
* Enhanced configuration management
*/
export interface ConfigChangeResult {
valid: boolean;
error?: string;
convertedValue?: ConfigValue;
suggestion?: string;
}
/**
* Prompt data with proper typing
*/
export interface TypedPromptData {
id: string;
name: string;
description: string;
category: string;
system_message?: string;
user_message_template: string;
arguments: Array<{
name: string;
description?: string;
required: boolean;
type?: string;
default?: ConfigValue;
}>;
chain_steps?: Array<{
promptId: string;
stepName: string;
inputMapping?: Record<string, string>;
outputMapping?: Record<string, string>;
}>;
metadata?: {
created: string;
modified: string;
version: string;
tags?: string[];
};
}
/**
* Filter parsing result with structured data
*/
export interface FilterParseResult {
textSearch?: string;
structured: {
type?: string[];
category?: string[];
gates?: boolean;
confidence?: {
operator: '>' | '<' | '>=' | '<=' | '=';
value: number;
};
created?: {
operator: '>' | '<' | '>=' | '<=' | '=';
value: Date;
};
complexity?: string[];
};
operators?: {
and?: FilterParseResult[];
or?: FilterParseResult[];
not?: FilterParseResult;
};
}
// ValidationResult now imported from execution/types.js - provides unified validation interface
// Import at top of file if needed for MCP tool usage
/**
* Output formatting options
*/
export interface OutputOptions {
format: "compact" | "detailed" | "json" | "markdown";
includeMetadata: boolean;
maxResults?: number;
sortBy?: string;
sortOrder?: "asc" | "desc";
}
/**
* Enhanced tool response with formatting options
*/
export interface EnhancedToolResponse extends StructuredToolResponse {
outputOptions?: OutputOptions;
pagination?: {
page: number;
pageSize: number;
total: number;
hasNext: boolean;
hasPrevious: boolean;
};
}
```
--------------------------------------------------------------------------------
/server/src/text-references/conversation.ts:
--------------------------------------------------------------------------------
```typescript
/**
* Conversation Management Module
* Handles conversation history tracking and context management
*/
import { Logger } from "../logging/index.js";
/**
* Conversation history item interface
*/
export interface ConversationHistoryItem {
role: "user" | "assistant" | "system";
content: string;
timestamp: number;
isProcessedTemplate?: boolean; // Flag to indicate if this is a processed template rather than original user input
}
/**
* Conversation Manager class
*/
export class ConversationManager {
private logger: Logger;
private conversationHistory: ConversationHistoryItem[] = [];
private maxHistorySize: number;
// NEW: Session manager integration for coordinated state management
private chainSessionManager?: any; // ChainSessionManager (injected to avoid circular dependency)
// NEW: Text reference manager for step storage delegation
private textReferenceManager?: any; // TextReferenceManager (injected to avoid circular dependency)
constructor(logger: Logger, maxHistorySize: number = 100) {
this.logger = logger;
this.maxHistorySize = maxHistorySize;
}
/**
* NEW: Set chain session manager for coordinated state management
*/
setChainSessionManager(sessionManager: any): void {
this.chainSessionManager = sessionManager;
this.logger.debug("Chain session manager integrated with conversation manager");
}
/**
* NEW: Set text reference manager for step storage delegation
*/
setTextReferenceManager(textReferenceManager: any): void {
this.textReferenceManager = textReferenceManager;
this.logger.debug("Text reference manager integrated with conversation manager");
}
/**
* Add an item to conversation history with size management
*/
addToConversationHistory(item: ConversationHistoryItem): void {
this.conversationHistory.push(item);
// Trim history if it exceeds maximum size
if (this.conversationHistory.length > this.maxHistorySize) {
// Remove oldest entries, keeping recent ones
this.conversationHistory.splice(
0,
this.conversationHistory.length - this.maxHistorySize
);
this.logger.debug(
`Trimmed conversation history to ${this.maxHistorySize} entries to prevent memory leaks`
);
}
}
/**
* Get the previous message from conversation history
*/
getPreviousMessage(): string {
// Try to find the last user message in conversation history
if (this.conversationHistory.length > 0) {
// Start from the end and find the first non-template user message
for (let i = this.conversationHistory.length - 1; i >= 0; i--) {
const historyItem = this.conversationHistory[i];
// Only consider user messages that aren't processed templates
if (historyItem.role === "user" && !historyItem.isProcessedTemplate) {
this.logger.debug(
`Found previous user message for context: ${historyItem.content.substring(
0,
50
)}...`
);
return historyItem.content;
}
}
}
// Return a default prompt if no suitable history item is found
return "[Please check previous messages in the conversation for context]";
}
/**
* Get conversation history
*/
getConversationHistory(): ConversationHistoryItem[] {
return [...this.conversationHistory];
}
/**
* Get conversation statistics
*/
getConversationStats(): {
totalMessages: number;
userMessages: number;
assistantMessages: number;
systemMessages: number;
templatedMessages: number;
} {
const stats = {
totalMessages: this.conversationHistory.length,
userMessages: 0,
assistantMessages: 0,
systemMessages: 0,
templatedMessages: 0,
};
this.conversationHistory.forEach((item) => {
switch (item.role) {
case "user":
stats.userMessages++;
break;
case "assistant":
stats.assistantMessages++;
break;
case "system":
stats.systemMessages++;
break;
}
if (item.isProcessedTemplate) {
stats.templatedMessages++;
}
});
return stats;
}
/**
* Clear conversation history
*/
clearHistory(): void {
this.conversationHistory = [];
this.logger.info("Conversation history cleared");
}
/**
* Get recent messages (useful for context)
*/
getRecentMessages(count: number = 5): ConversationHistoryItem[] {
return this.conversationHistory.slice(-count);
}
// Enhanced: Chain context storage for LLM-driven iterative workflow with proper result capture
private chainContext: Record<string, Record<number, string>> = {};
private chainStates: Record<string, { currentStep: number; totalSteps: number; lastUpdated: number }> = {};
// NEW: Track actual execution results vs placeholders
private chainExecutionResults: Record<string, Record<number, {
result: string;
timestamp: number;
isPlaceholder: boolean;
executionMetadata?: any;
}>> = {};
/**
* Save step result for a chain execution with enhanced metadata
* REFACTORED: Now delegates to TextReferenceManager for storage
*/
saveStepResult(chainId: string, step: number, result: string, isPlaceholder: boolean = false, metadata?: any): void {
// Delegate to TextReferenceManager for actual storage (single source of truth)
if (this.textReferenceManager) {
this.textReferenceManager.storeChainStepResult(chainId, step, result, {
...metadata,
isPlaceholder,
executionMetadata: metadata
});
} else {
// Fallback to local storage if TextReferenceManager not available
if (!this.chainContext[chainId]) {
this.chainContext[chainId] = {};
}
if (!this.chainExecutionResults[chainId]) {
this.chainExecutionResults[chainId] = {};
}
this.chainContext[chainId][step] = result;
this.chainExecutionResults[chainId][step] = {
result,
timestamp: Date.now(),
isPlaceholder,
executionMetadata: metadata
};
}
this.logger.debug(`Saved step ${step} result for chain ${chainId} (placeholder: ${isPlaceholder})`);
}
/**
* Get step result with metadata indicating if it's a placeholder
*/
getStepResultWithMetadata(chainId: string, step: number): {
result: string;
isPlaceholder: boolean;
timestamp: number;
metadata?: any;
} | undefined {
return this.chainExecutionResults[chainId]?.[step];
}
/**
* Get all step results for a chain
* REFACTORED: Now delegates to TextReferenceManager for retrieval
*/
getStepResults(chainId: string): Record<number, string> {
if (this.textReferenceManager) {
return this.textReferenceManager.getChainStepResults(chainId);
}
// Fallback to local storage if TextReferenceManager not available
return this.chainContext[chainId] || {};
}
/**
* Get specific step result for a chain
* REFACTORED: Now delegates to TextReferenceManager for retrieval
*/
getStepResult(chainId: string, step: number): string | undefined {
if (this.textReferenceManager) {
return this.textReferenceManager.getChainStepResult(chainId, step) || undefined;
}
// Fallback to local storage if TextReferenceManager not available
return this.chainContext[chainId]?.[step];
}
/**
* Set chain state (current step and total steps) with timestamp
*/
setChainState(chainId: string, currentStep: number, totalSteps: number): void {
this.chainStates[chainId] = { currentStep, totalSteps, lastUpdated: Date.now() };
this.logger.debug(`Chain ${chainId}: step ${currentStep}/${totalSteps}`);
}
/**
* Validate chain state integrity and recover if needed
*/
validateChainState(chainId: string): { valid: boolean; issues?: string[]; recovered?: boolean } {
const state = this.chainStates[chainId];
const context = this.chainContext[chainId];
const results = this.chainExecutionResults[chainId];
const issues: string[] = [];
let recovered = false;
if (!state) {
issues.push("No chain state found");
return { valid: false, issues };
}
// Check for stale state (older than 1 hour)
if (Date.now() - state.lastUpdated > 3600000) {
issues.push("Chain state is stale (>1 hour old)");
}
// Validate step consistency
if (state.currentStep > state.totalSteps) {
issues.push(`Current step ${state.currentStep} exceeds total steps ${state.totalSteps}`);
// Auto-recover by resetting to final step
this.setChainState(chainId, state.totalSteps, state.totalSteps);
recovered = true;
}
// Check for missing results in expected steps
if (context && results) {
for (let i = 0; i < Math.min(state.currentStep, state.totalSteps); i++) {
const hasResult = context[i] || results[i];
if (!hasResult) {
issues.push(`Missing result for completed step ${i}`);
}
}
}
this.logger.debug(`Chain ${chainId} validation: ${issues.length} issues found${recovered ? ' (auto-recovered)' : ''}`);
return {
valid: issues.length === 0,
issues: issues.length > 0 ? issues : undefined,
recovered
};
}
/**
* Get chain state
*/
getChainState(chainId: string): { currentStep: number; totalSteps: number; lastUpdated: number } | undefined {
return this.chainStates[chainId];
}
/**
* Clear chain context and state with session manager coordination
* REFACTORED: Now delegates step result clearing to TextReferenceManager
*/
clearChainContext(chainId: string): void {
// Clear local state
delete this.chainContext[chainId];
delete this.chainStates[chainId];
delete this.chainExecutionResults[chainId];
// Clear step results from TextReferenceManager
if (this.textReferenceManager) {
this.textReferenceManager.clearChainStepResults(chainId);
}
// Also clear session manager state if available
if (this.chainSessionManager) {
try {
this.chainSessionManager.clearSessionsForChain(chainId);
} catch (error) {
this.logger.warn(`Failed to clear session manager state for ${chainId}:`, error);
}
}
this.logger.info(`Cleared all chain state for ${chainId}`);
}
/**
* Clear all chain contexts and states
*/
clearAllChainContexts(): void {
this.chainContext = {};
this.chainStates = {};
this.chainExecutionResults = {};
this.logger.info("Cleared all chain contexts");
}
/**
* Get chain execution summary with metadata
*/
getChainSummary(chainId: string): {
state?: { currentStep: number; totalSteps: number; lastUpdated: number };
completedSteps: number;
placeholderSteps: number;
realSteps: number;
totalResults: number;
} {
const state = this.chainStates[chainId];
const results = this.chainExecutionResults[chainId] || {};
let placeholderSteps = 0;
let realSteps = 0;
Object.values(results).forEach(result => {
if (result.isPlaceholder) {
placeholderSteps++;
} else {
realSteps++;
}
});
return {
state,
completedSteps: Object.keys(results).length,
placeholderSteps,
realSteps,
totalResults: Object.keys(results).length
};
}
/**
* NEW: Comprehensive state validation with session manager coordination
*/
validateChainStateIntegrity(chainId: string): {
conversationState: boolean;
sessionState: boolean;
synchronized: boolean;
recommendations: string[];
sessionInfo?: any;
} {
const hasConversationState = !!this.chainStates[chainId];
let hasSessionState = false;
let sessionInfo: any = undefined;
// Check session manager state if available
if (this.chainSessionManager) {
try {
hasSessionState = this.chainSessionManager.hasActiveSessionForChain(chainId);
if (hasSessionState) {
const session = this.chainSessionManager.getActiveSessionForChain(chainId);
sessionInfo = {
sessionId: session?.sessionId,
state: session?.state,
currentStepId: session?.currentStepId,
executionOrder: session?.executionOrder
};
}
} catch (error) {
this.logger.warn(`Failed to check session state for ${chainId}:`, error);
}
}
const recommendations: string[] = [];
if (hasConversationState && !hasSessionState) {
recommendations.push("Orphaned conversation state - consider force restart to clear stale LLM context");
}
if (!hasConversationState && hasSessionState) {
recommendations.push("Missing conversation state - session may be from different execution type");
}
if (hasConversationState && hasSessionState) {
// Both exist - check for consistency
const conversationState = this.chainStates[chainId];
if (conversationState && sessionInfo) {
recommendations.push("States synchronized - both conversation and session managers have active state");
}
}
if (!hasConversationState && !hasSessionState) {
recommendations.push("Clean state - no active chain execution detected");
}
return {
conversationState: hasConversationState,
sessionState: hasSessionState,
synchronized: hasConversationState === hasSessionState,
recommendations,
sessionInfo
};
}
}
/**
* Create and configure a conversation manager
*/
export function createConversationManager(
logger: Logger,
maxHistorySize?: number
): ConversationManager {
return new ConversationManager(logger, maxHistorySize);
}
```
--------------------------------------------------------------------------------
/server/tests/scripts/integration-mcp-tools.js:
--------------------------------------------------------------------------------
```javascript
#!/usr/bin/env node
/**
* MCP Tools Integration Tests - Node.js Script Version
* Tests for the current 3 intelligent MCP tools with enhanced command routing
*/
async function runMcpToolsIntegrationTests() {
try {
console.log('🧪 Running MCP Tools Integration tests...');
console.log('📋 Testing intelligent MCP tool architecture with command routing functionality');
// Import global resource tracker for process cleanup
const { globalResourceTracker } = await import('../../dist/utils/global-resource-tracker.js');
// Import modules - Updated to match current export structure
const { createConsolidatedPromptEngine } = await import('../../dist/mcp-tools/prompt-engine/index.js');
const { createConsolidatedPromptManager } = await import('../../dist/mcp-tools/prompt-manager/index.js');
const { createConsolidatedSystemControl } = await import('../../dist/mcp-tools/system-control.js');
// Mock logger
const mockLogger = {
debug: () => {},
info: () => {},
warn: () => {},
error: () => {}
};
// Mock MCP server
const mockMcpServer = {
registeredTools: [],
registerTool: function(toolName, config) {
this.registeredTools.push(toolName);
return this;
},
tool: function(toolName) {
this.registeredTools.push(toolName);
return this;
},
getRegisteredToolNames: function() {
return this.registeredTools.map(tool => typeof tool === 'string' ? tool : tool.name || 'unknown');
},
clear: function() {
this.registeredTools = [];
}
};
// Test data
const testPrompts = {
simple: {
id: 'test_simple',
name: 'Simple Test',
description: 'Simple test prompt',
userMessageTemplate: 'Hello {{name}}',
arguments: [{ name: 'name', required: true, description: 'Name' }],
category: 'test'
}
};
let promptEngine, promptManager, systemControl;
// Setup for each test
function setupTest() {
// Updated mock dependencies to match current architecture
const mockPromptManager = {
processTemplateAsync: () => Promise.resolve('mocked template result'),
convertedPrompts: [testPrompts.simple],
promptsData: [testPrompts.simple],
loadAndConvertPrompts: () => Promise.resolve([testPrompts.simple])
};
const mockSemanticAnalyzer = {
analyzePrompt: () => Promise.resolve({
executionType: 'template',
requiresExecution: true,
confidence: 0.8
}),
getConfig: () => ({
llmIntegration: { enabled: false }
})
};
const mockFrameworkManager = {
getCurrentFramework: () => ({ frameworkId: 'CAGEERF', frameworkName: 'CAGEERF' }),
generateExecutionContext: () => ({
systemPrompt: 'test system prompt',
framework: 'CAGEERF'
})
};
// Complete mock parameters for ConsolidatedPromptEngine
const mockConfigManager = {
getConfig: () => ({
server: { name: 'test-server', version: '1.0.0' },
gates: { definitionsDirectory: "src/gates/definitions", templatesDirectory: "src/gates/templates" }
}),
getPromptsFilePath: () => '/test/prompts.json'
};
const mockConversationManager = {
addToConversationHistory: () => {},
getConversationHistory: () => [],
saveStepResult: () => {},
getStepResult: () => null,
setChainSessionManager: () => {}
};
const mockTextReferenceManager = {
extractReferences: () => [],
resolveReferences: () => {},
addReference: () => {}
};
const mockMcpToolsManager = {
initialize: () => {},
getTools: () => [],
promptManagerTool: { handleAction: () => Promise.resolve({ content: [], isError: false }) },
systemControl: {
handleAction: () => Promise.resolve({ content: [], isError: false }),
setAdvancedGateOrchestrator: () => {},
updateAnalytics: () => {}
}
};
// Clear mock server
mockMcpServer.clear();
// Create consolidated tools with all required parameters (updated for current constructor signatures)
promptEngine = createConsolidatedPromptEngine(
mockLogger,
mockMcpServer,
mockPromptManager,
mockConfigManager,
mockSemanticAnalyzer,
mockConversationManager,
mockTextReferenceManager,
mockMcpToolsManager
);
// Check prompt manager constructor signature for proper parameters
promptManager = createConsolidatedPromptManager(
mockLogger,
mockMcpServer,
mockConfigManager,
mockSemanticAnalyzer,
undefined, // frameworkStateManager
mockFrameworkManager,
() => Promise.resolve(), // onRefresh
() => Promise.resolve() // onRestart
);
systemControl = createConsolidatedSystemControl(
mockLogger,
mockMcpServer,
mockFrameworkManager,
undefined, // frameworkStateManager
mockMcpToolsManager
);
// Note: Tools are no longer registered individually - they are registered by ConsolidatedMcpToolsManager
// For testing, we'll simulate the registration that would normally happen in the manager
mockMcpServer.registerTool('prompt_engine', { title: 'Prompt Engine', description: 'Test engine' }, async () => {});
mockMcpServer.registerTool('prompt_manager', { title: 'Prompt Manager', description: 'Test manager' }, async () => {});
mockMcpServer.registerTool('system_control', { title: 'System Control', description: 'Test control' }, async () => {});
}
// Simple assertion helpers
function assertEqual(actual, expected, testName) {
if (actual === expected) {
console.log(`✅ ${testName}: PASSED`);
return true;
} else {
console.error(`❌ ${testName}: FAILED`);
console.error(` Expected: ${expected}`);
console.error(` Actual: ${actual}`);
return false;
}
}
function assertTruthy(value, testName) {
if (value) {
console.log(`✅ ${testName}: PASSED`);
return true;
} else {
console.error(`❌ ${testName}: FAILED - Expected truthy value, got: ${value}`);
return false;
}
}
function assertType(value, expectedType, testName) {
if (typeof value === expectedType) {
console.log(`✅ ${testName}: PASSED`);
return true;
} else {
console.error(`❌ ${testName}: FAILED - Expected type ${expectedType}, got: ${typeof value}`);
return false;
}
}
function assertContains(array, item, testName) {
if (Array.isArray(array) && array.includes(item)) {
console.log(`✅ ${testName}: PASSED`);
return true;
} else {
console.error(`❌ ${testName}: FAILED - Array does not contain: ${item}`);
console.error(` Array: ${JSON.stringify(array)}`);
return false;
}
}
function assertLessThan(actual, expected, testName) {
if (actual < expected) {
console.log(`✅ ${testName}: PASSED (${actual} < ${expected})`);
return true;
} else {
console.error(`❌ ${testName}: FAILED (${actual} >= ${expected})`);
return false;
}
}
function assertGreaterThanOrEqual(actual, expected, testName) {
if (actual >= expected) {
console.log(`✅ ${testName}: PASSED (${actual} >= ${expected})`);
return true;
} else {
console.error(`❌ ${testName}: FAILED (${actual} < ${expected})`);
return false;
}
}
let testResults = [];
// Test 1: Consolidated Prompt Engine
console.log('🔍 Test 1: Consolidated Prompt Engine');
setupTest();
testResults.push(assertTruthy(promptEngine, 'Prompt engine created'));
const registeredTools1 = mockMcpServer.getRegisteredToolNames();
testResults.push(assertContains(registeredTools1, 'prompt_engine', 'Prompt engine tool registered'));
testResults.push(assertType(promptEngine.executePromptCommand, 'function', 'Execute prompt command function exists'));
// Test 2: Consolidated Prompt Manager
console.log('🔍 Test 2: Consolidated Prompt Manager');
setupTest();
testResults.push(assertTruthy(promptManager, 'Prompt manager created'));
const registeredTools2 = mockMcpServer.getRegisteredToolNames();
testResults.push(assertContains(registeredTools2, 'prompt_manager', 'Prompt manager tool registered'));
testResults.push(assertType(promptManager.handleAction, 'function', 'Handle action function exists'));
// Test 3: Consolidated System Control
console.log('🔍 Test 3: Consolidated System Control');
setupTest();
testResults.push(assertTruthy(systemControl, 'System control created'));
const registeredTools3 = mockMcpServer.getRegisteredToolNames();
testResults.push(assertContains(registeredTools3, 'system_control', 'System control tool registered'));
testResults.push(assertType(systemControl.handleAction, 'function', 'Handle action function exists'));
// Test 4: Consolidated Tools Integration
console.log('🔍 Test 4: Consolidated Tools Integration');
setupTest();
const allRegisteredTools = mockMcpServer.getRegisteredToolNames();
const consolidatedTools = ['prompt_engine', 'prompt_manager', 'system_control'];
for (const toolName of consolidatedTools) {
testResults.push(assertContains(allRegisteredTools, toolName, `${toolName} registered`));
}
const actualConsolidatedTools = allRegisteredTools.filter(name =>
consolidatedTools.includes(name)
);
testResults.push(assertEqual(actualConsolidatedTools.length, 3, 'Exactly 3 consolidated tools registered'));
// Test 5: Tool Consolidation Benefits
console.log('🔍 Test 5: Tool Consolidation Benefits');
const totalRegisteredTools = mockMcpServer.registeredTools.length;
testResults.push(assertLessThan(totalRegisteredTools, 10, 'Much fewer tools than legacy 24+ system'));
testResults.push(assertGreaterThanOrEqual(totalRegisteredTools, 3, 'At least 3 consolidated tools'));
// Test 6: Error Handling
console.log('🔍 Test 6: Error Handling');
try {
const invalidEngine = createConsolidatedPromptEngine(null, mockMcpServer, null, null, null, null, null);
testResults.push(assertTruthy(true, 'Invalid tool creation handled gracefully'));
} catch (error) {
// It's actually acceptable for tools to throw with invalid parameters
// This demonstrates proper parameter validation
testResults.push(assertTruthy(true, 'Invalid tool creation properly validates parameters'));
}
testResults.push(assertTruthy(promptEngine, 'Prompt engine handles empty data gracefully'));
testResults.push(assertTruthy(promptManager, 'Prompt manager handles empty data gracefully'));
testResults.push(assertTruthy(systemControl, 'System control handles empty data gracefully'));
// Test 7: Performance
console.log('🔍 Test 7: Performance Validation');
const start = Date.now();
setupTest(); // Tools registered during setup
const duration = Date.now() - start;
testResults.push(assertLessThan(duration, 1000, 'Consolidated tools register efficiently'));
const finalRegisteredTools = mockMcpServer.registeredTools.length;
testResults.push(assertLessThan(finalRegisteredTools, 10, 'Performance benefits of consolidation maintained'));
testResults.push(assertGreaterThanOrEqual(finalRegisteredTools, 3, 'Required consolidated tools present'));
// Results Summary
const passedTests = testResults.filter(result => result).length;
const totalTests = testResults.length;
console.log('\n📊 MCP Tools Integration Tests Summary:');
console.log(` ✅ Passed: ${passedTests}/${totalTests} tests`);
console.log(` 📊 Success Rate: ${((passedTests/totalTests)*100).toFixed(1)}%`);
// Check for remaining resources before exit
console.log('\n🔍 Checking for remaining global resources...');
globalResourceTracker.logDiagnostics();
const cleared = globalResourceTracker.emergencyCleanup();
if (cleared > 0) {
console.log(`💀 Emergency cleanup cleared ${cleared} additional resources`);
}
if (passedTests === totalTests) {
console.log('🎉 All MCP Tools Integration tests passed!');
// Emergency process exit to prevent hanging due to global Node.js resources
console.log('💀 Forcing process exit to prevent hanging from global timers...');
setTimeout(() => process.exit(0), 100); // Small delay to ensure log output
return true;
} else {
console.error('❌ Some MCP Tools Integration tests failed');
// Emergency process exit for failure case as well
console.log('💀 Forcing process exit to prevent hanging from global timers...');
setTimeout(() => process.exit(1), 100); // Small delay to ensure log output
return false;
}
} catch (error) {
console.error('❌ MCP Tools Integration tests failed with error:', error.message);
if (error.stack) {
console.error('Stack trace:', error.stack);
}
// Emergency process exit for error case as well
console.log('💀 Forcing process exit due to test error to prevent hanging from global timers...');
setTimeout(() => process.exit(1), 100); // Small delay to ensure log output
return false;
}
}
// Run the tests
if (import.meta.url === `file://${process.argv[1]}`) {
runMcpToolsIntegrationTests().catch(error => {
console.error('❌ Test execution failed:', error);
process.exit(1);
});
}
export { runMcpToolsIntegrationTests };
```
--------------------------------------------------------------------------------
/server/src/utils/errorHandling.ts:
--------------------------------------------------------------------------------
```typescript
/**
* Consolidated Error Handling System
* Combines basic error classes with MCP structured response capabilities
*/
// Define StructuredToolResponse locally to avoid circular dependency
interface StructuredToolResponse {
content: Array<{
type: "text";
text: string;
}>;
isError?: boolean;
metadata?: {
tool: string;
action: string;
timestamp: string;
executionTime?: number;
framework?: string;
errorCode?: string;
[key: string]: unknown;
};
}
// Error context interface for enhanced error handling
export interface ErrorContext {
tool?: string;
action?: string;
operation?: string;
userInput?: unknown;
suggestions?: string[];
recoveryOptions?: string[];
// Extended properties for MCP compatibility
systemState?: {
framework?: string;
memoryUsage?: number;
uptime?: number;
};
errorType?: "validation" | "execution" | "system" | "client" | "configuration";
severity?: "low" | "medium" | "high" | "critical";
suggestedActions?: string[];
relatedComponents?: string[];
details?: any;
}
// Validation result types
export interface ValidationResult {
valid: boolean;
errors?: Array<{
field: string;
message: string;
code: string;
suggestion?: string;
example?: string;
}>;
warnings?: Array<{
field: string;
message: string;
suggestion?: string;
}>;
}
/**
* Base error class with MCP structured response capability
*/
export abstract class BaseError extends Error {
public readonly code: string;
public readonly context: ErrorContext;
public readonly timestamp: string;
constructor(message: string, code: string, context: ErrorContext = {}) {
super(message);
this.name = this.constructor.name;
this.code = code;
this.context = context;
this.timestamp = new Date().toISOString();
Error.captureStackTrace(this, this.constructor);
}
/**
* Get structured error response for MCP protocol
*/
toStructuredResponse(): StructuredToolResponse {
return {
content: [{
type: "text",
text: this.getEnhancedMessage()
}],
isError: true,
metadata: {
tool: this.context.tool || 'unknown',
action: this.context.action || 'unknown',
timestamp: this.timestamp,
errorCode: this.code
}
};
}
/**
* Get enhanced error message with context and suggestions
*/
getEnhancedMessage(): string {
let message = `❌ **${this.message}**\n\n`;
// Show available context information
if (this.context.action) {
message += `**Action**: ${this.context.action}\n`;
}
if (this.context.operation) {
message += `**Operation**: ${this.context.operation}\n`;
}
if (this.context.userInput !== undefined) {
message += `**Input**: ${JSON.stringify(this.context.userInput)}\n\n`;
}
if (this.context.suggestions && this.context.suggestions.length > 0) {
message += `💡 **Suggestions**:\n`;
this.context.suggestions.forEach((suggestion, index) => {
message += `${index + 1}. ${suggestion}\n`;
});
message += '\n';
}
if (this.context.recoveryOptions && this.context.recoveryOptions.length > 0) {
message += `🔄 **Recovery Options**:\n`;
this.context.recoveryOptions.forEach((option, index) => {
message += `${index + 1}. ${option}\n`;
});
} else {
message += `⚠️ **Impact**: Please contact support if the issue persists.\n`;
}
return message;
}
}
// Custom error classes extending BaseError
export class PromptError extends BaseError {
constructor(message: string, context: ErrorContext = {}) {
super(message, 'PROMPT_ERROR', context);
}
}
export class ArgumentError extends BaseError {
constructor(message: string, context: ErrorContext = {}) {
super(message, 'ARGUMENT_ERROR', context);
}
}
export class ValidationError extends BaseError {
public readonly validationResult?: ValidationResult;
public readonly validationErrors?: string[]; // Keep for backwards compatibility
constructor(message: string, validationErrorsOrContext?: string[] | ErrorContext, validationResult?: ValidationResult) {
// Handle backwards compatibility with old constructor signature
let context: ErrorContext = {};
let validationErrors: string[] | undefined;
if (Array.isArray(validationErrorsOrContext)) {
// Old signature: (message, validationErrors)
validationErrors = validationErrorsOrContext;
} else if (validationErrorsOrContext) {
// New signature: (message, context, validationResult)
context = validationErrorsOrContext;
}
super(message, 'VALIDATION_ERROR', context);
this.validationErrors = validationErrors;
this.validationResult = validationResult;
}
getEnhancedMessage(): string {
let message = super.getEnhancedMessage();
// Enhanced validation error details
if (this.validationResult?.errors) {
message += `\n**Validation Errors**:\n`;
this.validationResult.errors.forEach((error, index) => {
message += `${index + 1}. **${error.field}**: ${error.message}\n`;
if (error.suggestion) {
message += ` 💡 ${error.suggestion}\n`;
}
if (error.example) {
message += ` 📝 Example: ${error.example}\n`;
}
});
}
if (this.validationResult?.warnings) {
message += `\n**Warnings**:\n`;
this.validationResult.warnings.forEach((warning, index) => {
message += `${index + 1}. **${warning.field}**: ${warning.message}\n`;
if (warning.suggestion) {
message += ` 💡 ${warning.suggestion}\n`;
}
});
}
// Backwards compatibility with old validationErrors array
if (this.validationErrors && this.validationErrors.length > 0) {
message += `\n**Legacy Validation Errors**: ${this.validationErrors.join(', ')}\n`;
}
return message;
}
}
// Additional specialized error classes
export class ConfigError extends BaseError {
constructor(message: string, context: ErrorContext = {}) {
super(message, 'CONFIG_ERROR', {
...context,
suggestions: context.suggestions || ["Check your configuration file syntax and required fields", "See config documentation for valid options"]
});
}
}
export class FrameworkError extends BaseError {
constructor(message: string, context: ErrorContext = {}) {
super(message, 'FRAMEWORK_ERROR', {
...context,
suggestions: context.suggestions || ["Verify framework is enabled and properly configured", "See framework documentation for setup instructions"]
});
}
}
export class ExecutionError extends BaseError {
public readonly executionContext?: Record<string, unknown>;
constructor(message: string, context: ErrorContext = {}, executionContext?: Record<string, unknown>) {
super(message, 'EXECUTION_ERROR', context);
this.executionContext = executionContext;
}
getEnhancedMessage(): string {
let message = super.getEnhancedMessage();
if (this.executionContext) {
message += `\n**Execution Context**:\n`;
Object.entries(this.executionContext).forEach(([key, value]) => {
message += `- **${key}**: ${JSON.stringify(value)}\n`;
});
}
return message;
}
}
// Logger interface to ensure compatibility with the existing logger
export interface Logger {
info: (message: string, ...args: any[]) => void;
error: (message: string, ...args: any[]) => void;
warn: (message: string, ...args: any[]) => void;
debug: (message: string, ...args: any[]) => void;
}
/**
* Enhanced error handler with recovery strategies and MCP support
*/
export class ErrorHandler {
private static instance: ErrorHandler;
private retryStrategies = new Map<string, (error: BaseError) => boolean>();
private constructor() {
this.setupDefaultRetryStrategies();
}
public static getInstance(): ErrorHandler {
if (!ErrorHandler.instance) {
ErrorHandler.instance = new ErrorHandler();
}
return ErrorHandler.instance;
}
/**
* Handle error with context and return structured response
*/
handleError(error: unknown, context: ErrorContext): StructuredToolResponse {
if (error instanceof BaseError) {
return error.toStructuredResponse();
}
// Convert unknown errors to BaseError
const message = error instanceof Error ? error.message : String(error);
const baseError = new (class extends BaseError {
constructor(message: string, code: string, context: ErrorContext) {
super(message, code, context);
}
})(message, 'UNKNOWN_ERROR', {
...context,
suggestions: ["An unexpected error occurred. Please try again or contact support."],
recoveryOptions: ["Try the operation again", "Check system status", "Contact support"]
});
return baseError.toStructuredResponse();
}
/**
* Create validation error with enhanced context
*/
createValidationError(
message: string,
context: ErrorContext,
validationResult?: ValidationResult
): ValidationError {
return new ValidationError(message, context, validationResult);
}
/**
* Add retry strategy for specific error patterns
*/
addRetryStrategy(errorCode: string, strategy: (error: BaseError) => boolean): void {
this.retryStrategies.set(errorCode, strategy);
}
/**
* Check if error is retryable
*/
isRetryable(error: BaseError): boolean {
const strategy = this.retryStrategies.get(error.code);
return strategy ? strategy(error) : Boolean(error.context.recoveryOptions && error.context.recoveryOptions.length > 0);
}
/**
* Setup default retry strategies
*/
private setupDefaultRetryStrategies(): void {
this.addRetryStrategy('VALIDATION_ERROR', () => false); // User must fix input
this.addRetryStrategy('CONFIG_ERROR', () => false); // User must fix config
this.addRetryStrategy('FRAMEWORK_ERROR', (error) => Boolean(error.context.recoveryOptions && error.context.recoveryOptions.length > 0));
this.addRetryStrategy('EXECUTION_ERROR', (error) => Boolean(error.context.recoveryOptions && error.context.recoveryOptions.length > 0));
}
}
/**
* Validation helper functions
*/
export class ValidationHelpers {
/**
* Create validation result from errors
*/
static createValidationResult(errors: Array<{
field: string;
message: string;
code: string;
suggestion?: string;
example?: string;
}>): ValidationResult {
return {
valid: errors.length === 0,
errors: errors.length > 0 ? errors : undefined
};
}
/**
* Validate required fields with enhanced messages
*/
static validateRequiredFields(
data: Record<string, unknown>,
requiredFields: string[]
): ValidationResult {
const errors: ValidationResult['errors'] = [];
requiredFields.forEach(field => {
if (!(field in data) || data[field] === undefined || data[field] === null || data[field] === '') {
errors!.push({
field,
message: `Field '${field}' is required but was not provided`,
code: 'REQUIRED_FIELD_MISSING',
suggestion: `Please provide a value for '${field}'`,
example: `"${field}": "example_value"`
});
}
});
return this.createValidationResult(errors || []);
}
/**
* Create "did you mean" suggestions for typos
*/
static createDidYouMeanSuggestion(input: string, validOptions: string[]): string | undefined {
const suggestions = validOptions.filter(option =>
this.levenshteinDistance(input.toLowerCase(), option.toLowerCase()) <= 2
);
if (suggestions.length > 0) {
return `Did you mean: ${suggestions.slice(0, 3).join(', ')}?`;
}
return undefined;
}
/**
* Calculate Levenshtein distance for typo detection
*/
private static levenshteinDistance(str1: string, str2: string): number {
const matrix = Array(str2.length + 1).fill(null).map(() => Array(str1.length + 1).fill(null));
for (let i = 0; i <= str1.length; i += 1) {
matrix[0][i] = i;
}
for (let j = 0; j <= str2.length; j += 1) {
matrix[j][0] = j;
}
for (let j = 1; j <= str2.length; j += 1) {
for (let i = 1; i <= str1.length; i += 1) {
const indicator = str1[i - 1] === str2[j - 1] ? 0 : 1;
matrix[j][i] = Math.min(
matrix[j][i - 1] + 1, // deletion
matrix[j - 1][i] + 1, // insertion
matrix[j - 1][i - 1] + indicator // substitution
);
}
}
return matrix[str2.length][str1.length];
}
}
// Export default error handler instance
export const errorHandler = ErrorHandler.getInstance();
// Standardized error handling (backwards compatible)
export function handleError(
error: unknown,
context: string,
logger: Logger
): { message: string; isError: boolean } {
// Enhanced handling with new error types
if (error instanceof BaseError) {
const logLevel = error.code === 'VALIDATION_ERROR' || error.code === 'ARGUMENT_ERROR' ? 'warn' : 'error';
logger[logLevel](`${context}: ${error.message}`);
return { message: error.getEnhancedMessage(), isError: error.code !== 'ARGUMENT_ERROR' };
} else if (error instanceof PromptError) {
logger.error(`${context}: ${error.message}`);
return { message: error.message, isError: true };
} else if (error instanceof ArgumentError) {
logger.warn(`${context}: ${error.message}`);
return { message: error.message, isError: false };
} else if (error instanceof ValidationError) {
logger.warn(`${context}: ${error.message}`);
const errors = error.validationErrors ? `: ${error.validationErrors.join(', ')}` : '';
return { message: `${error.message}${errors}`, isError: false };
} else {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.error(`${context}: ${errorMessage}`);
return { message: `Unexpected error: ${errorMessage}`, isError: true };
}
}
```
--------------------------------------------------------------------------------
/server/src/performance/monitor.ts:
--------------------------------------------------------------------------------
```typescript
/**
* Performance Monitoring System
*
* Comprehensive performance tracking and optimization for the MCP server
* Focuses on execution metrics, memory usage, and system health monitoring
*/
import * as os from "os";
import { Logger } from "../logging/index.js";
// REMOVED: ExecutionCoordinator - modular chain system removed
export interface PerformanceMetrics {
timestamp: number;
// Memory metrics
memory: {
heapUsed: number;
heapTotal: number;
external: number;
rss: number;
};
// Execution metrics
execution: {
totalExecutions: number;
averageExecutionTime: number;
successRate: number;
activeExecutions: number;
};
// System metrics
system: {
uptime: number;
cpuUsage: number[]; // [user percentage, system percentage]
loadAverage: number[];
};
// Chain-specific metrics
chains: {
activeChains: number;
averageChainLength: number;
chainSuccessRate: number;
averageChainExecutionTime: number;
};
}
export interface PerformanceThresholds {
memoryThreshold: number; // MB
executionTimeThreshold: number; // ms
successRateThreshold: number; // percentage
chainExecutionTimeThreshold: number; // ms
}
export interface PerformanceAlert {
level: 'warning' | 'error' | 'critical';
category: 'memory' | 'execution' | 'chains' | 'system';
message: string;
timestamp: number;
metrics?: Partial<PerformanceMetrics>;
recommendation?: string;
}
/**
* Performance monitoring and optimization system
*/
export class PerformanceMonitor {
private logger: Logger;
// REMOVED: executionCoordinator - modular chain system removed
// Performance tracking
private metricsHistory: PerformanceMetrics[] = [];
private maxHistorySize = 1000; // Keep last 1000 measurements
private monitoringInterval?: NodeJS.Timeout;
private alertingCallbacks: ((alert: PerformanceAlert) => void)[] = [];
// Performance thresholds
private thresholds: PerformanceThresholds = {
memoryThreshold: 512, // MB
executionTimeThreshold: 5000, // 5 seconds
successRateThreshold: 95, // 95%
chainExecutionTimeThreshold: 30000 // 30 seconds
};
// CPU tracking for delta calculation
private previousCpuUsage: NodeJS.CpuUsage | null = null;
private previousCpuTime = 0;
// Optimization state
private optimizationScheduled = false;
private lastOptimization = 0;
private optimizationInterval = 300000; // 5 minutes
constructor(logger: Logger, thresholds?: Partial<PerformanceThresholds>) {
this.logger = logger;
if (thresholds) {
this.thresholds = { ...this.thresholds, ...thresholds };
}
}
// REMOVED: setExecutionCoordinator - ExecutionCoordinator removed
/**
* Check if we're running in a test environment
*/
private isTestEnvironment(): boolean {
return (
process.env.NODE_ENV === 'test' ||
process.argv.includes('--suppress-debug') ||
process.argv.includes('--test-mode') ||
// Detect GitHub Actions CI environment
process.env.GITHUB_ACTIONS === 'true' ||
process.env.CI === 'true' ||
// Detect common test runner patterns
process.argv.some(arg => arg.includes('test') || arg.includes('jest') || arg.includes('mocha')) ||
// Detect if called from integration test scripts
process.argv[1]?.includes('tests/scripts/')
);
}
/**
* Start performance monitoring
* SUPPRESSED in test environments to prevent hanging processes
*/
startMonitoring(intervalMs: number = 30000): void { // Default: 30 seconds
if (this.monitoringInterval) {
this.stopMonitoring();
}
// Skip performance monitoring in test environments to prevent hanging processes
if (this.isTestEnvironment()) {
this.logger.debug("Performance monitoring suppressed in test environment");
return;
}
this.logger.info(`Starting performance monitoring (interval: ${intervalMs}ms)`);
// Take initial measurement
this.collectMetrics();
// Set up regular monitoring
this.monitoringInterval = setInterval(() => {
this.collectMetrics();
this.checkThresholds();
this.scheduleOptimization();
}, intervalMs);
}
/**
* Stop performance monitoring
*/
stopMonitoring(): void {
if (this.monitoringInterval) {
clearInterval(this.monitoringInterval);
this.monitoringInterval = undefined;
this.logger.info("Performance monitoring stopped");
}
}
/**
* Collect current performance metrics
*/
collectMetrics(): PerformanceMetrics {
const timestamp = Date.now();
const memoryUsage = process.memoryUsage();
const currentCpuUsage = process.cpuUsage();
// Calculate CPU percentage from deltas
let cpuPercentage = [0, 0]; // [user%, system%]
if (this.previousCpuUsage && this.previousCpuTime) {
const timeDelta = timestamp - this.previousCpuTime; // milliseconds
const userDelta = currentCpuUsage.user - this.previousCpuUsage.user; // microseconds
const systemDelta = currentCpuUsage.system - this.previousCpuUsage.system; // microseconds
if (timeDelta > 0) {
// Convert to percentages (microseconds to milliseconds, then percentage)
const userPercent = (userDelta / 1000) / timeDelta * 100;
const systemPercent = (systemDelta / 1000) / timeDelta * 100;
cpuPercentage = [Math.min(userPercent, 100), Math.min(systemPercent, 100)];
}
}
// Store current values for next calculation
this.previousCpuUsage = currentCpuUsage;
this.previousCpuTime = timestamp;
// Get execution metrics if available
let executionMetrics = {
totalExecutions: 0,
averageExecutionTime: 0,
successRate: 100,
activeExecutions: 0
};
// REMOVED: ExecutionCoordinator metrics - execution handled by ConsolidatedPromptEngine
// Default execution metrics since ExecutionCoordinator removed
const metrics: PerformanceMetrics = {
timestamp,
memory: {
heapUsed: Math.round(memoryUsage.heapUsed / 1024 / 1024), // MB
heapTotal: Math.round(memoryUsage.heapTotal / 1024 / 1024), // MB
external: Math.round(memoryUsage.external / 1024 / 1024), // MB
rss: Math.round(memoryUsage.rss / 1024 / 1024) // MB
},
execution: executionMetrics,
system: {
uptime: Math.round(process.uptime()),
cpuUsage: cpuPercentage, // CPU percentage [user%, system%]
loadAverage: process.platform !== 'win32' ? os.loadavg() : [0, 0, 0]
},
chains: this.calculateChainMetrics()
};
// Store metrics with history management
this.metricsHistory.push(metrics);
if (this.metricsHistory.length > this.maxHistorySize) {
this.metricsHistory.shift();
}
this.logger.debug(`Performance metrics collected - Memory: ${metrics.memory.heapUsed}MB, Executions: ${metrics.execution.totalExecutions}`);
return metrics;
}
/**
* Get performance metrics history
*/
getMetricsHistory(count?: number): PerformanceMetrics[] {
if (count && count < this.metricsHistory.length) {
return this.metricsHistory.slice(-count);
}
return [...this.metricsHistory];
}
/**
* Get latest performance metrics
*/
getLatestMetrics(): PerformanceMetrics | undefined {
return this.metricsHistory[this.metricsHistory.length - 1];
}
/**
* Register alerting callback
*/
onAlert(callback: (alert: PerformanceAlert) => void): void {
this.alertingCallbacks.push(callback);
}
/**
* Get performance summary over time period
*/
getPerformanceSummary(periodMs: number = 3600000): { // Default: 1 hour
averageMemory: number;
peakMemory: number;
averageExecutionTime: number;
totalExecutions: number;
successRate: number;
alertsGenerated: number;
} | undefined {
const cutoffTime = Date.now() - periodMs;
const relevantMetrics = this.metricsHistory.filter(m => m.timestamp >= cutoffTime);
if (relevantMetrics.length === 0) {
return undefined;
}
const avgMemory = relevantMetrics.reduce((sum, m) => sum + m.memory.heapUsed, 0) / relevantMetrics.length;
const peakMemory = Math.max(...relevantMetrics.map(m => m.memory.heapUsed));
const latestMetrics = relevantMetrics[relevantMetrics.length - 1];
const earliestMetrics = relevantMetrics[0];
const totalExecutions = latestMetrics.execution.totalExecutions - earliestMetrics.execution.totalExecutions;
return {
averageMemory: Math.round(avgMemory),
peakMemory,
averageExecutionTime: latestMetrics.execution.averageExecutionTime,
totalExecutions,
successRate: latestMetrics.execution.successRate,
alertsGenerated: 0 // Could be implemented with alert history
};
}
/**
* Force performance optimization
*/
async optimizePerformance(): Promise<{
memoryFreed: number;
optimizationsApplied: string[];
}> {
const beforeMemory = process.memoryUsage().heapUsed;
const optimizations: string[] = [];
this.logger.info("Starting performance optimization");
// 1. Trigger garbage collection if available
if (global.gc) {
global.gc();
optimizations.push("Garbage collection executed");
}
// REMOVED: Execution history cleanup - ExecutionCoordinator removed
// 3. Trim metrics history if needed
if (this.metricsHistory.length > this.maxHistorySize * 0.8) {
const trimCount = Math.floor(this.metricsHistory.length * 0.2);
this.metricsHistory.splice(0, trimCount);
optimizations.push(`Metrics history trimmed (${trimCount} entries)`);
}
const afterMemory = process.memoryUsage().heapUsed;
const memoryFreed = Math.max(0, beforeMemory - afterMemory);
this.lastOptimization = Date.now();
this.optimizationScheduled = false;
this.logger.info(`Performance optimization completed - ${optimizations.length} optimizations applied, ${Math.round(memoryFreed / 1024 / 1024)}MB freed`);
return {
memoryFreed: Math.round(memoryFreed / 1024 / 1024), // MB
optimizationsApplied: optimizations
};
}
/**
* Calculate chain-specific metrics
*/
private calculateChainMetrics(): PerformanceMetrics['chains'] {
// REMOVED: ExecutionCoordinator chain metrics - using defaults
// Chain metrics now tracked by ConsolidatedPromptEngine if needed
return {
activeChains: 0,
averageChainLength: 0,
chainSuccessRate: 100,
averageChainExecutionTime: 0
};
}
/**
* Check performance thresholds and generate alerts
*/
private checkThresholds(): void {
const latest = this.getLatestMetrics();
if (!latest) return;
const alerts: PerformanceAlert[] = [];
// Memory threshold check
if (latest.memory.heapUsed > this.thresholds.memoryThreshold) {
alerts.push({
level: latest.memory.heapUsed > this.thresholds.memoryThreshold * 1.5 ? 'critical' : 'warning',
category: 'memory',
message: `High memory usage: ${latest.memory.heapUsed}MB (threshold: ${this.thresholds.memoryThreshold}MB)`,
timestamp: latest.timestamp,
metrics: { memory: latest.memory },
recommendation: 'Consider running performance optimization or reducing execution concurrency'
});
}
// Execution time threshold check
if (latest.execution.averageExecutionTime > this.thresholds.executionTimeThreshold) {
alerts.push({
level: 'warning',
category: 'execution',
message: `Slow execution times: ${latest.execution.averageExecutionTime}ms average (threshold: ${this.thresholds.executionTimeThreshold}ms)`,
timestamp: latest.timestamp,
metrics: { execution: latest.execution },
recommendation: 'Review prompt complexity and chain configurations'
});
}
// Success rate threshold check
if (latest.execution.successRate < this.thresholds.successRateThreshold) {
alerts.push({
level: 'error',
category: 'execution',
message: `Low success rate: ${latest.execution.successRate.toFixed(1)}% (threshold: ${this.thresholds.successRateThreshold}%)`,
timestamp: latest.timestamp,
metrics: { execution: latest.execution },
recommendation: 'Investigate execution failures and improve error handling'
});
}
// Chain execution time threshold check
if (latest.chains.averageChainExecutionTime > this.thresholds.chainExecutionTimeThreshold) {
alerts.push({
level: 'warning',
category: 'chains',
message: `Slow chain execution: ${latest.chains.averageChainExecutionTime}ms average (threshold: ${this.thresholds.chainExecutionTimeThreshold}ms)`,
timestamp: latest.timestamp,
metrics: { chains: latest.chains },
recommendation: 'Optimize chain steps and reduce chain complexity'
});
}
// Send alerts
alerts.forEach(alert => {
this.logger.warn(`Performance alert [${alert.level}]: ${alert.message}`);
this.alertingCallbacks.forEach(callback => callback(alert));
});
}
/**
* Schedule performance optimization if needed
*/
private scheduleOptimization(): void {
if (this.optimizationScheduled) return;
const timeSinceLastOptimization = Date.now() - this.lastOptimization;
const latest = this.getLatestMetrics();
if (!latest) return;
// Schedule optimization if:
// 1. It's been long enough since last optimization
// 2. Memory usage is high
// 3. Execution history is large
const shouldOptimize = (
timeSinceLastOptimization > this.optimizationInterval ||
latest.memory.heapUsed > this.thresholds.memoryThreshold * 0.8
// REMOVED: Execution history check - ExecutionCoordinator removed
);
if (shouldOptimize) {
this.optimizationScheduled = true;
// Schedule optimization in next tick to avoid blocking current operations
setImmediate(() => {
this.optimizePerformance().catch(error => {
this.logger.error("Performance optimization failed:", error);
this.optimizationScheduled = false;
});
});
}
}
}
/**
* Factory function to create a performance monitor
*/
export function createPerformanceMonitor(
logger: Logger,
thresholds?: Partial<PerformanceThresholds>
): PerformanceMonitor {
return new PerformanceMonitor(logger, thresholds);
}
```
--------------------------------------------------------------------------------
/server/src/frameworks/prompt-guidance/service.ts:
--------------------------------------------------------------------------------
```typescript
/**
* Prompt Guidance Service - Phase 3 Implementation
*
* Unified service that orchestrates all prompt guidance components.
* Provides a single integration point for MCP tools to access methodology guidance.
*/
import { Logger } from "../../logging/index.js";
import { ConvertedPrompt } from "../../types/index.js";
import { ContentAnalysisResult } from "../../semantic/configurable-semantic-analyzer.js";
import {
SystemPromptInjector,
createSystemPromptInjector
} from "./system-prompt-injector.js";
import {
MethodologyTracker,
createMethodologyTracker,
type MethodologyTrackerConfig
} from "./methodology-tracker.js";
import {
TemplateEnhancer,
createTemplateEnhancer
} from "./template-enhancer.js";
import {
SystemPromptInjectionResult,
TemplateEnhancementResult,
MethodologyState,
MethodologySwitchRequest
} from "../types/index.js";
import {
FrameworkDefinition,
IMethodologyGuide
} from "../types/index.js";
import { FrameworkManager } from "../framework-manager.js";
/**
* Prompt guidance service configuration
*/
type MethodologyTrackingServiceConfig = Partial<MethodologyTrackerConfig> & {
enabled: boolean;
};
export interface PromptGuidanceServiceConfig {
systemPromptInjection: {
enabled: boolean;
injectionMethod: 'template' | 'append' | 'prepend' | 'smart';
enableTemplateVariables: boolean;
enableContextualEnhancement: boolean;
};
templateEnhancement: {
enabled: boolean;
enhancementLevel: 'minimal' | 'moderate' | 'comprehensive';
enableArgumentSuggestions: boolean;
enableStructureOptimization: boolean;
};
methodologyTracking: MethodologyTrackingServiceConfig;
}
/**
* Comprehensive prompt guidance result
*/
export interface PromptGuidanceResult {
originalPrompt: ConvertedPrompt;
enhancedPrompt?: ConvertedPrompt;
systemPromptInjection?: SystemPromptInjectionResult;
templateEnhancement?: TemplateEnhancementResult;
activeMethodology: string;
guidanceApplied: boolean;
processingTimeMs: number;
metadata: {
frameworkUsed: string;
enhancementsApplied: string[];
confidenceScore: number;
// Phase 4: Semantic analysis metadata
semanticAware?: boolean;
semanticComplexity?: 'low' | 'medium' | 'high';
semanticConfidence?: number;
};
}
/**
* Prompt Guidance Service
*
* Orchestrates all prompt guidance components to provide intelligent
* methodology-driven prompt enhancement for MCP tools.
*/
export class PromptGuidanceService {
private logger: Logger;
private config: PromptGuidanceServiceConfig;
private systemPromptInjector: SystemPromptInjector;
private methodologyTracker!: MethodologyTracker;
private templateEnhancer: TemplateEnhancer;
private frameworkManager?: FrameworkManager;
private initialized: boolean = false;
constructor(logger: Logger, config?: Partial<PromptGuidanceServiceConfig>) {
this.logger = logger;
this.config = {
systemPromptInjection: {
enabled: true,
injectionMethod: 'smart',
enableTemplateVariables: true,
enableContextualEnhancement: true
},
templateEnhancement: {
enabled: true,
enhancementLevel: 'moderate',
enableArgumentSuggestions: true,
enableStructureOptimization: true
},
methodologyTracking: {
enabled: true,
persistStateToDisk: true,
enableHealthMonitoring: true,
healthCheckIntervalMs: 30000,
maxSwitchHistory: 100,
enableMetrics: true
},
...config
};
// Initialize components
this.systemPromptInjector = createSystemPromptInjector(logger, this.config.systemPromptInjection);
this.templateEnhancer = createTemplateEnhancer(logger, this.config.templateEnhancement);
}
/**
* Initialize the prompt guidance service
*/
async initialize(frameworkManager?: FrameworkManager): Promise<void> {
if (this.initialized) {
this.logger.debug("PromptGuidanceService already initialized");
return;
}
this.logger.info("Initializing PromptGuidanceService...");
try {
// Initialize methodology tracker
const { enabled: trackingEnabled, ...trackerConfig } =
this.config.methodologyTracking;
this.methodologyTracker = await createMethodologyTracker(
this.logger,
trackerConfig
);
if (!trackingEnabled) {
this.logger.info(
"Prompt guidance methodology tracking initialized but marked disabled in config"
);
}
// Set framework manager if provided
if (frameworkManager) {
this.frameworkManager = frameworkManager;
}
this.initialized = true;
this.logger.info("PromptGuidanceService initialized successfully");
} catch (error) {
this.logger.error("Failed to initialize PromptGuidanceService:", error);
throw error;
}
}
/**
* Apply comprehensive prompt guidance to a prompt
* Phase 4: Enhanced with semantic analysis integration
*/
async applyGuidance(
prompt: ConvertedPrompt,
options: {
includeSystemPromptInjection?: boolean;
includeTemplateEnhancement?: boolean;
frameworkOverride?: string;
semanticAnalysis?: ContentAnalysisResult;
} = {}
): Promise<PromptGuidanceResult> {
const startTime = Date.now();
if (!this.initialized) {
throw new Error("PromptGuidanceService not initialized. Call initialize() first.");
}
this.logger.debug(`Applying prompt guidance for prompt: ${prompt.name}${options.semanticAnalysis ? ' with semantic analysis' : ''}`);
try {
// Get current methodology state
const methodologyState = this.methodologyTracker.getCurrentState();
const activeFramework = await this.getActiveFramework(options.frameworkOverride);
const methodologyGuide = await this.getMethodologyGuide(activeFramework.methodology);
const result: PromptGuidanceResult = {
originalPrompt: prompt,
activeMethodology: methodologyState.activeMethodology,
guidanceApplied: false,
processingTimeMs: 0,
metadata: {
frameworkUsed: activeFramework.methodology,
enhancementsApplied: [],
confidenceScore: 0,
// Phase 4: Semantic analysis metadata
semanticAware: options.semanticAnalysis !== undefined,
semanticComplexity: options.semanticAnalysis?.complexity,
semanticConfidence: options.semanticAnalysis?.confidence
}
};
let enhancedPrompt = { ...prompt };
let totalConfidence = 0;
let enhancementCount = 0;
// Apply system prompt injection if enabled
if (this.config.systemPromptInjection.enabled &&
(options.includeSystemPromptInjection !== false)) {
try {
const injectionResult = this.systemPromptInjector.injectMethodologyGuidance(
prompt,
activeFramework,
methodologyGuide,
options.semanticAnalysis
);
result.systemPromptInjection = injectionResult;
// FIXED: Combine original system message with framework-injected guidance
// This preserves the original prompt's system message while adding framework context
const originalSystemMessage = prompt.systemMessage || '';
const frameworkGuidance = injectionResult.enhancedPrompt;
// Combine both: framework guidance first (sets context), then original system message
enhancedPrompt.systemMessage = originalSystemMessage
? `${frameworkGuidance}\n\n${originalSystemMessage}`
: frameworkGuidance;
result.metadata.enhancementsApplied.push('system_prompt_injection');
totalConfidence += injectionResult.metadata.confidence;
enhancementCount++;
result.guidanceApplied = true;
this.logger.debug(`System prompt injection applied with confidence: ${injectionResult.metadata.confidence}`);
} catch (error) {
this.logger.warn("System prompt injection failed:", error);
}
}
// Apply template enhancement if enabled
if (this.config.templateEnhancement.enabled &&
(options.includeTemplateEnhancement !== false)) {
try {
const enhancementResult = await this.templateEnhancer.enhanceTemplate(
enhancedPrompt.userMessageTemplate,
enhancedPrompt,
methodologyGuide,
activeFramework,
undefined, // context
options.semanticAnalysis
);
result.templateEnhancement = enhancementResult;
// Update enhanced prompt with enhanced template
enhancedPrompt.userMessageTemplate = enhancementResult.enhancedTemplate;
result.metadata.enhancementsApplied.push('template_enhancement');
totalConfidence += enhancementResult.validation.score / 100; // Convert to 0-1 scale
enhancementCount++;
result.guidanceApplied = true;
this.logger.debug(`Template enhancement applied with score: ${enhancementResult.validation.score}`);
} catch (error) {
this.logger.warn("Template enhancement failed:", error);
}
}
// Set enhanced prompt and calculate metrics
if (result.guidanceApplied) {
result.enhancedPrompt = enhancedPrompt;
result.metadata.confidenceScore = enhancementCount > 0 ? totalConfidence / enhancementCount : 0;
}
result.processingTimeMs = Date.now() - startTime;
this.logger.debug(`Prompt guidance completed in ${result.processingTimeMs}ms with confidence: ${result.metadata.confidenceScore}`);
return result;
} catch (error) {
this.logger.error("Failed to apply prompt guidance:", error);
// Return minimal result on error
return {
originalPrompt: prompt,
activeMethodology: this.methodologyTracker?.getCurrentState()?.activeMethodology || 'CAGEERF',
guidanceApplied: false,
processingTimeMs: Date.now() - startTime,
metadata: {
frameworkUsed: 'error',
enhancementsApplied: [],
confidenceScore: 0
}
};
}
}
/**
* Switch methodology using the tracker
*/
async switchMethodology(request: MethodologySwitchRequest): Promise<boolean> {
if (!this.initialized) {
throw new Error("PromptGuidanceService not initialized");
}
this.logger.info(`Switching methodology to: ${request.targetMethodology}`);
return await this.methodologyTracker.switchMethodology(request);
}
/**
* Get current methodology state
*/
getCurrentMethodologyState(): MethodologyState {
if (!this.initialized) {
throw new Error("PromptGuidanceService not initialized");
}
return this.methodologyTracker.getCurrentState();
}
/**
* Get methodology system health
*/
getSystemHealth() {
if (!this.initialized) {
throw new Error("PromptGuidanceService not initialized");
}
return this.methodologyTracker.getSystemHealth();
}
/**
* Enable or disable the entire guidance system
*/
setGuidanceEnabled(enabled: boolean): void {
this.config.systemPromptInjection.enabled = enabled;
this.config.templateEnhancement.enabled = enabled;
this.config.methodologyTracking.enabled = enabled;
this.logger.info(`Prompt guidance system ${enabled ? 'enabled' : 'disabled'}`);
}
/**
* Update service configuration
*/
updateConfig(config: Partial<PromptGuidanceServiceConfig>): void {
this.config = { ...this.config, ...config };
// Update component configurations
this.systemPromptInjector.updateConfig(config.systemPromptInjection || {});
this.templateEnhancer.updateConfig(config.templateEnhancement || {});
if (config.methodologyTracking && this.methodologyTracker) {
const { enabled: trackingEnabled, ...trackerConfig } =
config.methodologyTracking;
if (typeof trackingEnabled === 'boolean') {
this.config.methodologyTracking.enabled = trackingEnabled;
}
this.methodologyTracker.updateConfig(trackerConfig);
}
this.logger.debug("PromptGuidanceService configuration updated");
}
/**
* Shutdown the service and cleanup resources
*/
async shutdown(): Promise<void> {
if (!this.initialized) {
return;
}
this.logger.info("Shutting down PromptGuidanceService...");
if (this.methodologyTracker) {
await this.methodologyTracker.shutdown();
}
this.initialized = false;
this.logger.info("PromptGuidanceService shutdown complete");
}
/**
* Set framework manager for guidance operations
*/
setFrameworkManager(frameworkManager: FrameworkManager): void {
this.frameworkManager = frameworkManager;
this.logger.debug("FrameworkManager set for PromptGuidanceService");
}
/**
* Check if service is initialized and ready
*/
isInitialized(): boolean {
return this.initialized;
}
/**
* Get current service configuration
*/
getConfig(): PromptGuidanceServiceConfig {
return { ...this.config };
}
/**
* Get active framework definition
*/
private async getActiveFramework(frameworkOverride?: string): Promise<FrameworkDefinition> {
if (!this.frameworkManager) {
throw new Error("FrameworkManager not set");
}
const methodologyState = this.methodologyTracker.getCurrentState();
const targetMethodology = frameworkOverride || methodologyState.activeMethodology;
const framework = this.frameworkManager.getFramework(targetMethodology);
if (!framework) {
throw new Error(`Framework ${targetMethodology} not found`);
}
return framework;
}
/**
* Get methodology guide for framework
*/
private async getMethodologyGuide(methodology: string): Promise<IMethodologyGuide> {
if (!this.frameworkManager) {
throw new Error("FrameworkManager not set");
}
const guide = this.frameworkManager.getMethodologyGuide(methodology);
if (!guide) {
throw new Error(`Methodology guide for ${methodology} not found`);
}
return guide;
}
}
/**
* Create and initialize a PromptGuidanceService instance
*/
export async function createPromptGuidanceService(
logger: Logger,
config?: Partial<PromptGuidanceServiceConfig>,
frameworkManager?: FrameworkManager
): Promise<PromptGuidanceService> {
const service = new PromptGuidanceService(logger, config);
await service.initialize(frameworkManager);
return service;
}
```
--------------------------------------------------------------------------------
/server/src/frameworks/framework-manager.ts:
--------------------------------------------------------------------------------
```typescript
/**
* Framework Manager - Phase 2 Implementation
* Manages methodology selection and system prompt guidelines
* Framework = Constitutional guidelines for HOW to execute prompts, not analysis tools
*/
import { Logger } from "../logging/index.js";
import { ConvertedPrompt } from "../types/index.js";
import {
IMethodologyGuide,
FrameworkMethodology,
FrameworkDefinition,
FrameworkExecutionContext,
FrameworkSelectionCriteria
} from "./types/index.js";
import { MethodologyRegistry, createMethodologyRegistry } from "./methodology/index.js";
import type { FrameworkStateManager } from "./framework-state-manager.js";
/**
* Framework Manager Implementation
* Provides methodology selection and system prompt generation
*/
export class FrameworkManager {
private frameworks: Map<string, FrameworkDefinition> = new Map();
private methodologyRegistry: MethodologyRegistry | null = null;
private defaultFramework: string = "CAGEERF";
private logger: Logger;
private initialized: boolean = false;
private frameworkStateManager?: FrameworkStateManager;
constructor(logger: Logger) {
this.logger = logger;
}
/**
* Set the framework state manager for synchronization
* FIXED: Allows Framework Manager to sync with active framework state
*/
setFrameworkStateManager(frameworkStateManager: FrameworkStateManager): void {
this.frameworkStateManager = frameworkStateManager;
this.logger.debug("Framework State Manager synchronized with Framework Manager");
}
/**
* Initialize framework definitions and system templates
*/
async initialize(): Promise<void> {
if (this.initialized) {
this.logger.debug("FrameworkManager already initialized");
return;
}
this.logger.info("Initializing FrameworkManager with methodology registry...");
// Initialize methodology registry (Phase 2: NEW)
this.methodologyRegistry = await createMethodologyRegistry(this.logger);
// Generate framework definitions from methodology guides
await this.generateFrameworkDefinitions();
this.initialized = true;
this.logger.info(`FrameworkManager initialized with ${this.frameworks.size} frameworks`);
}
/**
* Select appropriate framework based on criteria
* Simplified selection since frameworks are user-controlled via MCP tools
*/
selectFramework(criteria: FrameworkSelectionCriteria = {}): FrameworkDefinition {
this.ensureInitialized();
// User preference takes priority (this is the primary selection mechanism)
if (criteria.userPreference && criteria.userPreference !== "AUTO") {
const preferred = this.getFramework(criteria.userPreference);
if (preferred && preferred.enabled) {
this.logger.debug(`Framework selected by user preference: ${preferred.name}`);
return preferred;
} else {
this.logger.warn(`Requested framework ${criteria.userPreference} not found or disabled, using default`);
}
}
// FIXED: Check Framework State Manager for active framework before using hardcoded default
// This ensures all injection points get the same active framework
if (this.frameworkStateManager?.isFrameworkSystemEnabled()) {
const activeFramework = this.frameworkStateManager.getActiveFramework();
if (activeFramework) {
const framework = this.getFramework(activeFramework.methodology);
if (framework && framework.enabled) {
this.logger.debug(`Framework selected: ${framework.name} (from active state manager)`);
return framework;
}
}
}
// Fallback to default framework only if state manager is not available
const defaultFramework = this.getFramework(this.defaultFramework);
if (!defaultFramework) {
throw new Error(`Default framework ${this.defaultFramework} not found`);
}
this.logger.debug(`Framework selected: ${defaultFramework.name} (default fallback)`);
return defaultFramework;
}
/**
* Generate execution context with system prompts and guidelines
*/
generateExecutionContext(
prompt: ConvertedPrompt,
criteria: FrameworkSelectionCriteria = {}
): FrameworkExecutionContext {
const selectedFramework = this.selectFramework(criteria);
// Generate framework-specific system prompt
const systemPrompt = this.generateSystemPrompt(selectedFramework, prompt);
return {
selectedFramework,
systemPrompt,
executionGuidelines: [...selectedFramework.executionGuidelines],
metadata: {
selectionReason: this.getSelectionReason(selectedFramework, criteria),
confidence: 1.0, // High confidence since frameworks are user-selected
appliedAt: new Date()
}
};
}
/**
* Get framework by methodology type
* Supports case-insensitive lookup for robust framework switching
*/
getFramework(methodology: string): FrameworkDefinition | undefined {
this.ensureInitialized();
// Try exact match first (fastest path)
let framework = this.frameworks.get(methodology);
if (framework) {
this.logger.debug(`Framework found via exact match: ${methodology} -> ${framework.name}`);
return framework;
}
// Try uppercase match (most common conversion)
const upperCaseId = methodology.toUpperCase();
framework = this.frameworks.get(upperCaseId);
if (framework) {
this.logger.debug(`Framework found via uppercase match: ${methodology} -> ${framework.name}`);
return framework;
}
// Try case-insensitive search through all frameworks
for (const [id, def] of this.frameworks) {
if (id.toLowerCase() === methodology.toLowerCase()) {
this.logger.debug(`Framework found via case-insensitive match: ${methodology} -> ${def.name}`);
return def;
}
// Also check methodology field for additional matching
if (def.methodology.toLowerCase() === methodology.toLowerCase()) {
this.logger.debug(`Framework found via methodology match: ${methodology} -> ${def.name}`);
return def;
}
}
// Log available frameworks for debugging
const availableIds = Array.from(this.frameworks.keys());
this.logger.warn(`Framework '${methodology}' not found. Available frameworks: [${availableIds.join(', ')}]`);
return undefined;
}
/**
* List available frameworks
*/
listFrameworks(enabledOnly: boolean = false): FrameworkDefinition[] {
const frameworks = Array.from(this.frameworks.values());
return enabledOnly ? frameworks.filter(f => f.enabled) : frameworks;
}
/**
* Get methodology guide by framework ID
*/
getMethodologyGuide(frameworkId: string): IMethodologyGuide | undefined {
this.ensureInitialized();
return this.methodologyRegistry!.getGuide(frameworkId.toLowerCase());
}
/**
* List available methodology guides
*/
listMethodologyGuides(): IMethodologyGuide[] {
this.ensureInitialized();
return this.methodologyRegistry!.getAllGuides(true);
}
/**
* Check if framework is applicable for given criteria
*/
private isApplicable(framework: FrameworkDefinition, criteria: FrameworkSelectionCriteria): boolean {
// Check execution type compatibility
if (criteria.executionType && framework.applicableTypes.length > 0) {
if (!framework.applicableTypes.includes(criteria.executionType)) {
return false;
}
}
// All enabled frameworks are generally applicable
return framework.enabled;
}
/**
* Calculate fit score for framework selection
*/
private calculateFitScore(framework: FrameworkDefinition, criteria: FrameworkSelectionCriteria): number {
let score = framework.priority;
// Execution type match bonus
if (criteria.executionType && framework.applicableTypes.includes(criteria.executionType)) {
score += 10;
}
// Complexity match bonus
if (criteria.complexity) {
switch (criteria.complexity) {
case 'high':
if (framework.methodology === 'CAGEERF') score += 15;
break;
case 'medium':
if (framework.methodology === 'ReACT' || framework.methodology === '5W1H') score += 10;
break;
case 'low':
if (framework.methodology === 'SCAMPER') score += 5;
break;
}
}
return score;
}
/**
* Generate framework-specific system prompt
*/
private generateSystemPrompt(framework: FrameworkDefinition, prompt: ConvertedPrompt): string {
let systemPrompt = framework.systemPromptTemplate;
// Replace template variables
systemPrompt = systemPrompt.replace(/\{PROMPT_NAME\}/g, prompt.name || 'Prompt');
systemPrompt = systemPrompt.replace(/\{PROMPT_CATEGORY\}/g, prompt.category || 'general');
systemPrompt = systemPrompt.replace(/\{FRAMEWORK_NAME\}/g, framework.name);
return systemPrompt;
}
/**
* Get selection reason for context metadata (simplified)
*/
private getSelectionReason(framework: FrameworkDefinition, criteria: FrameworkSelectionCriteria): string {
if (criteria.userPreference && criteria.userPreference !== "AUTO") {
return `User preference: ${criteria.userPreference}`;
}
return "Default framework selection";
}
/**
* Initialize methodology guides registry (REMOVED - Phase 2)
* Functionality moved to MethodologyRegistry for better separation of concerns
*/
/**
* Generate framework definitions from methodology guides
*/
private async generateFrameworkDefinitions(): Promise<void> {
try {
const guides = this.methodologyRegistry!.getAllGuides(true);
for (const guide of guides) {
// Generate system prompt template from methodology guide
const systemPromptTemplate = this.generateSystemPromptTemplate(guide);
// Create framework definition from methodology guide
const frameworkDefinition: FrameworkDefinition = {
id: guide.frameworkId.toUpperCase(),
name: guide.frameworkName,
description: this.getFrameworkDescription(guide),
methodology: guide.methodology as FrameworkMethodology,
systemPromptTemplate,
executionGuidelines: this.getExecutionGuidelines(guide),
applicableTypes: this.getApplicableTypes(guide),
priority: this.getFrameworkPriority(guide),
enabled: true
};
this.frameworks.set(frameworkDefinition.id, frameworkDefinition);
this.logger.debug(`Generated framework definition for ${guide.frameworkName}`);
}
this.logger.info(`Generated ${this.frameworks.size} framework definitions from methodology guides`);
} catch (error) {
this.logger.error("Failed to generate framework definitions:", error);
throw error;
}
}
/**
* Generate system prompt template from methodology guide
*/
private generateSystemPromptTemplate(guide: IMethodologyGuide): string {
const baseGuidance = guide.getSystemPromptGuidance({});
return `You are operating under the ${guide.frameworkName} methodology for {PROMPT_NAME}.
${baseGuidance}
Apply this methodology systematically to ensure comprehensive and structured responses.`;
}
/**
* Get framework description from methodology guide
*/
private getFrameworkDescription(guide: IMethodologyGuide): string {
// Generate descriptions based on methodology type
switch (guide.methodology) {
case "CAGEERF":
return "Comprehensive structured approach: Context, Analysis, Goals, Execution, Evaluation, Refinement, Framework";
case "ReACT":
return "Reasoning and Acting pattern for systematic problem-solving";
case "5W1H":
return "Who, What, When, Where, Why, How systematic analysis";
case "SCAMPER":
return "Creative problem-solving: Substitute, Combine, Adapt, Modify, Put to other uses, Eliminate, Reverse";
default:
return `${guide.methodology} methodology for systematic approach`;
}
}
/**
* Get execution guidelines from methodology guide
*/
private getExecutionGuidelines(guide: IMethodologyGuide): string[] {
// Generate basic guidelines from methodology guide context
const processingGuidance = guide.guideTemplateProcessing("", "template");
return processingGuidance.templateEnhancements.systemPromptAdditions;
}
/**
* Get applicable types for framework based on methodology
*/
private getApplicableTypes(guide: IMethodologyGuide): string[] {
switch (guide.methodology) {
case "CAGEERF":
return ["chain", "template"];
case "ReACT":
return ["chain"];
case "5W1H":
return ["template", "chain"];
case "SCAMPER":
return ["template"];
default:
return ["template"];
}
}
/**
* Get framework priority based on methodology
*/
private getFrameworkPriority(guide: IMethodologyGuide): number {
switch (guide.methodology) {
case "CAGEERF":
return 10;
case "ReACT":
return 8;
case "5W1H":
return 7;
case "SCAMPER":
return 6;
default:
return 5;
}
}
/**
* Ensure manager is initialized before use
*/
private ensureInitialized(): void {
if (!this.initialized) {
throw new Error("FrameworkManager not initialized. Call initialize() first.");
}
}
/**
* Get initialization status
*/
get isInitialized(): boolean {
return this.initialized;
}
/**
* Enable/disable specific framework
*/
setFrameworkEnabled(methodology: FrameworkMethodology, enabled: boolean): void {
const framework = this.frameworks.get(methodology);
if (framework) {
framework.enabled = enabled;
this.logger.info(`Framework ${methodology} ${enabled ? 'enabled' : 'disabled'}`);
}
}
/**
* Set default framework
*/
setDefaultFramework(methodology: FrameworkMethodology): void {
if (this.frameworks.has(methodology)) {
this.defaultFramework = methodology;
this.logger.info(`Default framework set to: ${methodology}`);
} else {
throw new Error(`Framework ${methodology} not found`);
}
}
}
/**
* Create and initialize a FrameworkManager instance
*/
export async function createFrameworkManager(logger: Logger): Promise<FrameworkManager> {
const manager = new FrameworkManager(logger);
await manager.initialize();
return manager;
}
// Export types that are used by other modules
export type { FrameworkDefinition, FrameworkExecutionContext, FrameworkSelectionCriteria };
```
--------------------------------------------------------------------------------
/server/src/mcp-tools/prompt-manager/analysis/gate-analyzer.ts:
--------------------------------------------------------------------------------
```typescript
/**
* Gate Analyzer Module
*
* Analyzes prompt content to suggest appropriate gates and temporary gate definitions.
* Integrates with the temporary gate system to provide intelligent gate recommendations.
*/
import { Logger } from '../../../logging/index.js';
import type { ConvertedPrompt } from '../../../execution/types.js';
import type { TemporaryGateDefinition } from '../../../execution/types.js';
import type { PromptManagerDependencies } from '../core/types.js';
/**
* Gate analysis result
*/
export interface GateAnalysisResult {
/** Recommended persistent gates */
recommendedGates: string[];
/** Suggested temporary gates */
suggestedTemporaryGates: TemporaryGateDefinition[];
/** Analysis reasoning */
reasoning: string[];
/** Confidence score (0.0-1.0) */
confidence: number;
/** Gate configuration preview */
gateConfigurationPreview: {
include?: string[];
exclude?: string[];
framework_gates?: boolean;
temporary_gates?: TemporaryGateDefinition[];
};
}
/**
* Gate suggestion context
*/
export interface GateSuggestionContext {
/** Execution context type */
executionType: 'prompt' | 'template' | 'chain';
/** Prompt category */
category: string;
/** Framework context */
framework?: string;
/** User intent keywords */
intentKeywords?: string[];
/** Complexity level */
complexity: 'low' | 'medium' | 'high';
}
/**
* Analyzes prompts for gate recommendations
*/
export class GateAnalyzer {
private logger: Logger;
private dependencies: PromptManagerDependencies;
constructor(dependencies: PromptManagerDependencies) {
this.logger = dependencies.logger;
this.dependencies = dependencies;
}
/**
* Analyze a prompt for gate recommendations
*/
async analyzePromptForGates(prompt: ConvertedPrompt): Promise<GateAnalysisResult> {
this.logger.debug('[GATE ANALYZER] Analyzing prompt for gate recommendations:', {
promptId: prompt.id,
category: prompt.category,
hasChainSteps: !!(prompt.chainSteps?.length),
argumentsCount: prompt.arguments?.length || 0
});
// Extract context from prompt
const context = this.extractGateSuggestionContext(prompt);
// Analyze content for gate requirements
const contentAnalysis = this.analyzePromptContent(prompt);
// Generate gate recommendations
const recommendedGates = this.generateGateRecommendations(context, contentAnalysis);
// Generate temporary gate suggestions
const temporaryGates = this.generateTemporaryGateSuggestions(context, contentAnalysis);
// Calculate confidence based on analysis depth
const confidence = this.calculateConfidence(context, contentAnalysis, recommendedGates.length + temporaryGates.length);
// Create reasoning
const reasoning = this.generateReasoning(context, contentAnalysis, recommendedGates, temporaryGates);
// Generate gate configuration preview
const gateConfigurationPreview = this.generateGateConfigurationPreview(recommendedGates, temporaryGates);
const result: GateAnalysisResult = {
recommendedGates,
suggestedTemporaryGates: temporaryGates,
reasoning,
confidence,
gateConfigurationPreview
};
this.logger.debug('[GATE ANALYZER] Analysis complete:', {
promptId: prompt.id,
recommendedGatesCount: recommendedGates.length,
temporaryGatesCount: temporaryGates.length,
confidence
});
return result;
}
/**
* Suggest gates for a specific execution context
*/
async suggestGatesForContext(context: GateSuggestionContext): Promise<string[]> {
const gates: string[] = [];
// Category-based recommendations
const categoryGates = this.getCategoryGateMapping()[context.category] || [];
gates.push(...categoryGates);
// Execution type specific gates
if (context.executionType === 'template') {
gates.push('framework-compliance');
}
if (context.executionType === 'chain') {
gates.push('content-structure');
}
// Framework-specific gates
if (context.framework) {
const frameworkGates = this.getFrameworkGates(context.framework);
gates.push(...frameworkGates);
}
// Complexity-based gates
if (context.complexity === 'high') {
gates.push('technical-accuracy', 'research-quality');
}
// Intent-based gates
if (context.intentKeywords) {
const intentGates = this.getIntentBasedGates(context.intentKeywords);
gates.push(...intentGates);
}
// Remove duplicates and return
return [...new Set(gates)];
}
/**
* Extract gate suggestion context from prompt
*/
private extractGateSuggestionContext(prompt: ConvertedPrompt): GateSuggestionContext {
// Determine execution type
let executionType: 'prompt' | 'template' | 'chain' = 'prompt';
if (prompt.chainSteps && prompt.chainSteps.length > 0) {
executionType = 'chain';
} else if (prompt.systemMessage || (prompt.arguments && prompt.arguments.length > 2)) {
executionType = 'template';
}
// Determine complexity
let complexity: 'low' | 'medium' | 'high' = 'low';
const complexityIndicators = [
prompt.arguments?.length || 0,
prompt.chainSteps?.length || 0,
prompt.userMessageTemplate.length / 100
];
const complexityScore = complexityIndicators.reduce((a, b) => a + b, 0);
if (complexityScore > 10) {
complexity = 'high';
} else if (complexityScore > 5) {
complexity = 'medium';
}
// Extract intent keywords
const intentKeywords = this.extractIntentKeywords(prompt.userMessageTemplate);
return {
executionType,
category: prompt.category,
framework: this.dependencies.frameworkStateManager?.getActiveFramework()?.methodology,
intentKeywords,
complexity
};
}
/**
* Analyze prompt content for gate indicators
*/
private analyzePromptContent(prompt: ConvertedPrompt): {
hasDataRequirements: boolean;
hasCodeRequirements: boolean;
hasResearchRequirements: boolean;
hasEducationalContent: boolean;
hasTechnicalContent: boolean;
requiresAccuracy: boolean;
requiresStructure: boolean;
} {
const content = (prompt.userMessageTemplate + ' ' + (prompt.systemMessage || '')).toLowerCase();
return {
hasDataRequirements: /data|statistics|numbers|metrics|analytics/.test(content),
hasCodeRequirements: /code|programming|function|class|method|variable/.test(content),
hasResearchRequirements: /research|analyze|investigate|study|examine/.test(content),
hasEducationalContent: /learn|teach|explain|understand|clarify/.test(content),
hasTechnicalContent: /technical|specification|implementation|architecture/.test(content),
requiresAccuracy: /accurate|precise|correct|verify|validate/.test(content),
requiresStructure: /structure|organize|format|outline|steps/.test(content)
};
}
/**
* Generate gate recommendations based on analysis
*/
private generateGateRecommendations(
context: GateSuggestionContext,
contentAnalysis: any
): string[] {
const gates: string[] = [];
// Content-based recommendations
if (contentAnalysis.hasCodeRequirements) {
gates.push('code-quality');
}
if (contentAnalysis.hasResearchRequirements) {
gates.push('research-quality');
}
if (contentAnalysis.hasEducationalContent) {
gates.push('educational-clarity');
}
if (contentAnalysis.hasTechnicalContent) {
gates.push('technical-accuracy');
}
if (contentAnalysis.requiresStructure) {
gates.push('content-structure');
}
// Category-based recommendations
const categoryGates = this.getCategoryGateMapping()[context.category] || [];
gates.push(...categoryGates);
// Remove duplicates
return [...new Set(gates)];
}
/**
* Generate temporary gate suggestions
*/
private generateTemporaryGateSuggestions(
context: GateSuggestionContext,
contentAnalysis: any
): TemporaryGateDefinition[] {
const temporaryGates: TemporaryGateDefinition[] = [];
// Data accuracy temporary gate
if (contentAnalysis.hasDataRequirements) {
temporaryGates.push({
name: 'Data Source Verification',
type: 'validation',
scope: 'execution',
description: 'Verify all statistical claims and data sources',
guidance: 'Ensure all numerical data includes proper citations and verification of accuracy',
pass_criteria: [
{
type: 'content_check',
message: 'Data sources must be cited',
passed: false
}
],
source: 'automatic'
});
}
// Code review temporary gate
if (contentAnalysis.hasCodeRequirements && context.complexity === 'high') {
temporaryGates.push({
name: 'Code Review Standards',
type: 'validation',
scope: 'execution',
description: 'Enhanced code quality validation for complex implementations',
guidance: 'Apply rigorous code review standards including performance, security, and maintainability',
pass_criteria: [
{
type: 'pattern_check',
message: 'Code must include error handling',
passed: false
}
],
source: 'automatic'
});
}
// Research depth temporary gate
if (contentAnalysis.hasResearchRequirements && context.executionType === 'chain') {
temporaryGates.push({
name: 'Research Depth Validation',
type: 'quality',
scope: 'chain',
description: 'Ensure comprehensive research across all chain steps',
guidance: 'Each research step must provide multiple perspectives and credible sources',
source: 'automatic'
});
}
return temporaryGates;
}
/**
* Calculate confidence score
*/
private calculateConfidence(
context: GateSuggestionContext,
contentAnalysis: any,
totalGatesRecommended: number
): number {
let confidence = 0.5; // Base confidence
// Increase confidence for clear indicators
const indicators = Object.values(contentAnalysis).filter(Boolean).length;
confidence += (indicators * 0.05);
// Adjust for context clarity
if (context.category !== 'general') confidence += 0.1;
if (context.framework) confidence += 0.1;
if (context.intentKeywords && context.intentKeywords.length > 0) confidence += 0.1;
// Adjust for recommendation count
if (totalGatesRecommended > 0) confidence += 0.1;
if (totalGatesRecommended > 3) confidence += 0.1;
return Math.min(confidence, 1.0);
}
/**
* Generate reasoning for recommendations
*/
private generateReasoning(
context: GateSuggestionContext,
contentAnalysis: any,
recommendedGates: string[],
temporaryGates: TemporaryGateDefinition[]
): string[] {
const reasoning: string[] = [];
reasoning.push(`Analyzed ${context.executionType} with ${context.complexity} complexity in ${context.category} category`);
if (contentAnalysis.hasCodeRequirements) {
reasoning.push('Detected code requirements - recommended code quality gates');
}
if (contentAnalysis.hasResearchRequirements) {
reasoning.push('Detected research requirements - recommended research quality gates');
}
if (contentAnalysis.hasEducationalContent) {
reasoning.push('Detected educational content - recommended clarity-focused gates');
}
if (temporaryGates.length > 0) {
reasoning.push(`Suggested ${temporaryGates.length} temporary gates for execution-specific quality control`);
}
if (recommendedGates.length === 0 && temporaryGates.length === 0) {
reasoning.push('No specific gate requirements detected - default gates will apply');
}
return reasoning;
}
/**
* Generate gate configuration preview
*/
private generateGateConfigurationPreview(
recommendedGates: string[],
temporaryGates: TemporaryGateDefinition[]
): any {
const preview: any = {};
if (recommendedGates.length > 0) {
preview.include = recommendedGates;
}
if (temporaryGates.length > 0) {
preview.temporary_gates = temporaryGates;
}
// Default to including framework gates unless specifically disabled
preview.framework_gates = true;
return preview;
}
/**
* Extract intent keywords from content
*/
private extractIntentKeywords(content: string): string[] {
const keywords: string[] = [];
const intentPatterns = {
'analysis': /analyz|investigat|examin|study/gi,
'creation': /creat|generat|build|develop/gi,
'explanation': /explain|clarify|describe|detail/gi,
'validation': /validat|verify|check|confirm/gi,
'optimization': /optim|improv|enhanc|refin/gi
};
for (const [intent, pattern] of Object.entries(intentPatterns)) {
if (pattern.test(content)) {
keywords.push(intent);
}
}
return keywords;
}
/**
* Get intent-based gate recommendations
*/
private getIntentBasedGates(intentKeywords: string[]): string[] {
const intentGateMapping: Record<string, string[]> = {
'analysis': ['research-quality', 'technical-accuracy'],
'creation': ['content-structure', 'code-quality'],
'explanation': ['educational-clarity', 'content-structure'],
'validation': ['technical-accuracy'],
'optimization': ['code-quality', 'technical-accuracy']
};
const gates: string[] = [];
for (const intent of intentKeywords) {
const intentGates = intentGateMapping[intent] || [];
gates.push(...intentGates);
}
return [...new Set(gates)];
}
/**
* Get category-based gate mapping
*/
private getCategoryGateMapping(): Record<string, string[]> {
return {
'analysis': ['research-quality', 'technical-accuracy'],
'education': ['educational-clarity', 'content-structure'],
'development': ['code-quality', 'security-awareness'],
'research': ['research-quality', 'technical-accuracy'],
'debugging': ['technical-accuracy', 'code-quality'],
'documentation': ['content-structure', 'educational-clarity'],
'content_processing': ['content-structure'],
'general': ['content-structure']
};
}
/**
* Get framework-specific gates
*/
private getFrameworkGates(framework: string): string[] {
const frameworkGateMapping: Record<string, string[]> = {
'CAGEERF': ['framework-compliance', 'content-structure'],
'ReACT': ['technical-accuracy', 'research-quality'],
'5W1H': ['content-structure', 'research-quality'],
'SCAMPER': ['educational-clarity']
};
return frameworkGateMapping[framework] || ['framework-compliance'];
}
}
```
--------------------------------------------------------------------------------
/server/src/metrics/analytics-service.ts:
--------------------------------------------------------------------------------
```typescript
/**
* Metrics Collector - Centralized Performance and Usage Metrics Collection
*
* Provides comprehensive metrics collection and reporting for all MCP tools
* without coupling to execution logic. Uses event-driven architecture to
* observe tool operations and provide detailed insights.
*/
import { EventEmitter } from 'events';
import { Logger } from '../logging/index.js';
import {
ExecutionData,
GateValidationData,
FrameworkSwitchData,
ExecutionStats,
SystemMetrics,
FrameworkUsage,
AnalyticsEvent,
AnalyticsQueryOptions,
AnalyticsSummary,
PerformanceTrend
} from './types.js';
/**
* Centralized Metrics Collector
*/
export class MetricsCollector extends EventEmitter {
private logger: Logger;
private startTime: number;
// Analytics data storage
private executionStats: ExecutionStats;
private systemMetrics: SystemMetrics;
private frameworkUsage: FrameworkUsage;
private gateValidationStats = {
totalValidations: 0,
successfulValidations: 0,
totalValidationTime: 0,
validationHistory: [] as GateValidationData[]
};
// Raw data storage for queries
private executionHistory: ExecutionData[] = [];
private frameworkSwitchHistory: FrameworkSwitchData[] = [];
private performanceTrends: PerformanceTrend[] = [];
// Performance monitoring
private memoryCheckInterval?: NodeJS.Timeout;
private readonly MAX_HISTORY_SIZE = 1000;
constructor(logger: Logger) {
super();
this.logger = logger;
this.startTime = Date.now();
// Initialize analytics data
this.executionStats = {
totalExecutions: 0,
successfulExecutions: 0,
failedExecutions: 0,
averageExecutionTime: 0,
executionsByMode: {
prompt: 0,
template: 0,
chain: 0
},
executionsByTool: {
prompt_engine: 0,
prompt_manager: 0,
system_control: 0
},
lastUpdated: Date.now()
};
this.systemMetrics = {
uptime: 0,
memoryUsage: {
heapUsed: 0,
heapTotal: 0,
external: 0,
rss: 0
},
averageResponseTime: 0,
requestsPerMinute: 0,
errorRate: 0,
performanceTrends: []
};
this.frameworkUsage = {
currentFramework: 'CAGEERF', // Default framework
frameworkSwitches: 0,
frameworkUsageTime: {},
frameworkSwitchHistory: [],
frameworkPerformance: {}
};
this.setupEventListeners();
this.startPerformanceMonitoring();
this.logger.info('AnalyticsService initialized with event-driven collection');
}
/**
* Set up event listeners for analytics collection
*/
private setupEventListeners(): void {
this.on('execution:complete', this.handleExecutionComplete.bind(this));
this.on('execution:error', this.handleExecutionError.bind(this));
this.on('gate:validation', this.handleGateValidation.bind(this));
this.on('framework:switch', this.handleFrameworkSwitch.bind(this));
this.on('system:performance', this.handlePerformanceTrend.bind(this));
}
/**
* Start performance monitoring
*/
private startPerformanceMonitoring(): void {
// Monitor memory usage every 30 seconds
this.memoryCheckInterval = setInterval(() => {
this.recordMemoryUsage();
}, 30000);
}
/**
* Record execution completion
*/
recordExecution(executionData: ExecutionData): void {
this.emit('execution:complete', executionData);
}
/**
* Record execution error
*/
recordExecutionError(executionData: ExecutionData): void {
this.emit('execution:error', executionData);
}
/**
* Record gate validation
*/
recordGateValidation(gateData: GateValidationData): void {
this.emit('gate:validation', gateData);
}
/**
* Record framework switch
*/
recordFrameworkSwitch(switchData: FrameworkSwitchData): void {
this.emit('framework:switch', switchData);
}
/**
* Handle execution completion event
*/
private handleExecutionComplete(executionData: ExecutionData): void {
// Update execution statistics
this.executionStats.totalExecutions++;
if (executionData.success) {
this.executionStats.successfulExecutions++;
} else {
this.executionStats.failedExecutions++;
}
// Update average execution time
const totalTime = this.executionStats.averageExecutionTime * (this.executionStats.totalExecutions - 1);
this.executionStats.averageExecutionTime =
(totalTime + executionData.executionTime) / this.executionStats.totalExecutions;
// Update execution by mode
if (this.executionStats.executionsByMode[executionData.executionType] !== undefined) {
this.executionStats.executionsByMode[executionData.executionType]++;
}
// Update execution by tool
if (this.executionStats.executionsByTool[executionData.toolName as keyof typeof this.executionStats.executionsByTool] !== undefined) {
this.executionStats.executionsByTool[executionData.toolName as keyof typeof this.executionStats.executionsByTool]++;
}
// Update framework performance
if (executionData.frameworkUsed) {
if (!this.frameworkUsage.frameworkPerformance[executionData.frameworkUsed]) {
this.frameworkUsage.frameworkPerformance[executionData.frameworkUsed] = {
averageExecutionTime: 0,
successRate: 0,
usageCount: 0
};
}
const perf = this.frameworkUsage.frameworkPerformance[executionData.frameworkUsed];
const totalTime = perf.averageExecutionTime * perf.usageCount;
perf.usageCount++;
perf.averageExecutionTime = (totalTime + executionData.executionTime) / perf.usageCount;
// Update success rate
const prevSuccesses = perf.successRate * (perf.usageCount - 1);
const newSuccesses = prevSuccesses + (executionData.success ? 1 : 0);
perf.successRate = newSuccesses / perf.usageCount;
}
// Store execution history
this.executionHistory.push(executionData);
this.trimHistory(this.executionHistory);
// Record performance trend
this.recordPerformanceTrend('execution_time', executionData.executionTime, executionData.toolName);
this.executionStats.lastUpdated = Date.now();
this.logger.debug(`Analytics updated: Total executions: ${this.executionStats.totalExecutions}, Success rate: ${this.getSuccessRate()}%`);
}
/**
* Handle execution error event
*/
private handleExecutionError(executionData: ExecutionData): void {
// Error handling is included in handleExecutionComplete
this.handleExecutionComplete(executionData);
}
/**
* Handle gate validation event
*/
private handleGateValidation(gateData: GateValidationData): void {
this.gateValidationStats.totalValidations++;
if (gateData.passedGates === gateData.totalGates) {
this.gateValidationStats.successfulValidations++;
}
this.gateValidationStats.totalValidationTime += gateData.validationTime;
this.gateValidationStats.validationHistory.push(gateData);
this.trimHistory(this.gateValidationStats.validationHistory);
this.logger.debug(`Gate validation recorded: ${gateData.passedGates}/${gateData.totalGates} passed`);
}
/**
* Handle framework switch event
*/
private handleFrameworkSwitch(switchData: FrameworkSwitchData): void {
this.frameworkUsage.frameworkSwitches++;
this.frameworkUsage.currentFramework = switchData.toFramework;
this.frameworkUsage.frameworkSwitchHistory.push({
timestamp: switchData.switchTime,
fromFramework: switchData.fromFramework,
toFramework: switchData.toFramework,
reason: switchData.reason
});
this.frameworkSwitchHistory.push(switchData);
this.trimHistory(this.frameworkSwitchHistory);
this.logger.debug(`Framework switch recorded: ${switchData.fromFramework} → ${switchData.toFramework}`);
}
/**
* Handle performance trend event
*/
private handlePerformanceTrend(trend: PerformanceTrend): void {
this.performanceTrends.push(trend);
this.systemMetrics.performanceTrends.push(trend);
this.trimHistory(this.performanceTrends);
this.trimHistory(this.systemMetrics.performanceTrends);
}
/**
* Record memory usage
*/
private recordMemoryUsage(): void {
const usage = process.memoryUsage();
this.systemMetrics.memoryUsage = {
heapUsed: usage.heapUsed,
heapTotal: usage.heapTotal,
external: usage.external,
rss: usage.rss
};
this.recordPerformanceTrend('memory_usage', usage.heapUsed, 'system');
}
/**
* Record performance trend
*/
private recordPerformanceTrend(
metric: PerformanceTrend['metric'],
value: number,
context?: string
): void {
const trend: PerformanceTrend = {
timestamp: Date.now(),
metric,
value,
context
};
this.emit('system:performance', trend);
}
/**
* Trim history arrays to max size
*/
private trimHistory<T>(array: T[]): void {
if (array.length > this.MAX_HISTORY_SIZE) {
array.splice(0, array.length - this.MAX_HISTORY_SIZE);
}
}
/**
* Get execution statistics
*/
getExecutionStats(): ExecutionStats {
return { ...this.executionStats };
}
/**
* Get system metrics
*/
getSystemMetrics(): SystemMetrics {
this.systemMetrics.uptime = Date.now() - this.startTime;
this.systemMetrics.errorRate = this.getErrorRate();
this.systemMetrics.averageResponseTime = this.executionStats.averageExecutionTime;
return { ...this.systemMetrics };
}
/**
* Get framework usage
*/
getFrameworkUsage(): FrameworkUsage {
return { ...this.frameworkUsage };
}
/**
* Get comprehensive analytics summary
*/
getAnalyticsSummary(options?: AnalyticsQueryOptions): AnalyticsSummary {
const gateStats = {
totalValidations: this.gateValidationStats.totalValidations,
validationSuccessRate: this.getGateValidationSuccessRate(),
averageValidationTime: this.getAverageGateValidationTime(),
gateAdoptionRate: this.getGateAdoptionRate()
};
const recommendations = this.generateRecommendations();
return {
executionStats: this.getExecutionStats(),
systemMetrics: this.getSystemMetrics(),
frameworkUsage: this.getFrameworkUsage(),
gateValidationStats: gateStats,
recommendations
};
}
/**
* Reset analytics data
*/
resetAnalytics(): void {
this.executionStats = {
totalExecutions: 0,
successfulExecutions: 0,
failedExecutions: 0,
averageExecutionTime: 0,
executionsByMode: {
prompt: 0,
template: 0,
chain: 0
},
executionsByTool: {
prompt_engine: 0,
prompt_manager: 0,
system_control: 0
},
lastUpdated: Date.now()
};
this.gateValidationStats = {
totalValidations: 0,
successfulValidations: 0,
totalValidationTime: 0,
validationHistory: []
};
this.frameworkUsage.frameworkSwitches = 0;
this.frameworkUsage.frameworkSwitchHistory = [];
this.frameworkUsage.frameworkPerformance = {};
this.executionHistory = [];
this.frameworkSwitchHistory = [];
this.performanceTrends = [];
this.systemMetrics.performanceTrends = [];
this.logger.info('Analytics data reset');
}
/**
* Calculate success rate
*/
private getSuccessRate(): number {
if (this.executionStats.totalExecutions === 0) return 100;
return Math.round((this.executionStats.successfulExecutions / this.executionStats.totalExecutions) * 100);
}
/**
* Calculate error rate
*/
private getErrorRate(): number {
if (this.executionStats.totalExecutions === 0) return 0;
return this.executionStats.failedExecutions / this.executionStats.totalExecutions;
}
/**
* Calculate gate validation success rate
*/
private getGateValidationSuccessRate(): number {
if (this.gateValidationStats.totalValidations === 0) return 100;
return (this.gateValidationStats.successfulValidations / this.gateValidationStats.totalValidations) * 100;
}
/**
* Calculate average gate validation time
*/
private getAverageGateValidationTime(): number {
if (this.gateValidationStats.totalValidations === 0) return 0;
return this.gateValidationStats.totalValidationTime / this.gateValidationStats.totalValidations;
}
/**
* Calculate gate adoption rate
*/
private getGateAdoptionRate(): number {
if (this.executionStats.totalExecutions === 0) return 0;
return (this.gateValidationStats.totalValidations / this.executionStats.totalExecutions) * 100;
}
/**
* Generate recommendations based on analytics
*/
private generateRecommendations(): string[] {
const recommendations: string[] = [];
// Performance recommendations
if (this.executionStats.averageExecutionTime > 5000) {
recommendations.push('Average execution time is high (>5s). Consider optimizing prompt complexity or system resources.');
}
// Memory recommendations
const memoryUtilization = this.systemMetrics.memoryUsage.heapUsed / this.systemMetrics.memoryUsage.heapTotal;
if (memoryUtilization > 0.8) {
recommendations.push('High memory utilization detected (>80%). Monitor for memory leaks.');
}
// Gate adoption recommendations
const gateAdoption = this.getGateAdoptionRate();
if (gateAdoption < 50) {
recommendations.push('Low gate validation adoption (<50%). Consider enabling gates for better quality assurance.');
}
// Error rate recommendations
if (this.getErrorRate() > 0.1) {
recommendations.push('High error rate detected (>10%). Review failed executions for patterns.');
}
// Framework recommendations
const frameworks = Object.keys(this.frameworkUsage.frameworkPerformance);
if (frameworks.length > 1) {
const bestFramework = frameworks.reduce((best, current) => {
const bestPerf = this.frameworkUsage.frameworkPerformance[best];
const currentPerf = this.frameworkUsage.frameworkPerformance[current];
return currentPerf.successRate > bestPerf.successRate ? current : best;
});
if (this.frameworkUsage.currentFramework !== bestFramework) {
recommendations.push(`Consider switching to ${bestFramework} framework for better performance (${Math.round(this.frameworkUsage.frameworkPerformance[bestFramework].successRate * 100)}% success rate).`);
}
}
return recommendations;
}
/**
* Cleanup on shutdown
*/
shutdown(): void {
if (this.memoryCheckInterval) {
clearInterval(this.memoryCheckInterval);
}
this.removeAllListeners();
this.logger.info('AnalyticsService shutdown complete');
}
}
/**
* Create analytics service instance
*/
export function createMetricsCollector(logger: Logger): MetricsCollector {
return new MetricsCollector(logger);
}
```
--------------------------------------------------------------------------------
/server/src/mcp-tools/tool-description-manager.ts:
--------------------------------------------------------------------------------
```typescript
/**
* Tool Description Manager
*
* Manages externalized tool descriptions with graceful fallback to defaults.
* Follows established ConfigManager pattern for consistency with existing architecture.
*/
import { Logger } from '../logging/index.js';
import { ConfigManager } from '../config/index.js';
import { ToolDescription, ToolDescriptionsConfig } from '../types/index.js';
import * as fs from 'fs/promises';
import * as path from 'path';
import { watch, FSWatcher } from 'fs';
import { EventEmitter } from 'events';
import {
CAGEERFMethodologyGuide,
ReACTMethodologyGuide,
FiveW1HMethodologyGuide,
SCAMPERMethodologyGuide
} from '../frameworks/methodology/index.js';
import { MethodologyToolDescriptions } from '../frameworks/types/index.js';
/**
* Manages tool descriptions loaded from external configuration with hot-reload support
*/
export class ToolDescriptionManager extends EventEmitter {
private logger: Logger;
private configPath: string;
private descriptions: Map<string, ToolDescription>;
private defaults: Map<string, ToolDescription>;
private methodologyDescriptions: Map<string, MethodologyToolDescriptions>;
private isInitialized: boolean = false;
private fileWatcher?: FSWatcher;
private isWatching: boolean = false;
private reloadDebounceTimer?: NodeJS.Timeout;
constructor(logger: Logger, configManager: ConfigManager) {
super();
this.logger = logger;
this.configPath = path.join(configManager.getServerRoot(), 'config', 'tool-descriptions.json');
this.descriptions = new Map();
this.defaults = this.createDefaults();
this.methodologyDescriptions = new Map();
}
/**
* Normalize methodology keys for consistent lookup (case-insensitive)
*/
private normalizeMethodologyKey(methodology?: string): string | undefined {
if (!methodology) return undefined;
return methodology.trim().toUpperCase();
}
/**
* Create default descriptions as fallback
*/
private createDefaults(): Map<string, ToolDescription> {
return new Map([
['prompt_engine', {
description: '🚀 PROMPT ENGINE [HOT-RELOAD]: Processes Nunjucks templates, returns executable instructions. WARNING: Output contains instructions YOU must execute (code gen, analysis, multi-step tasks) - not just information. IMPORTANT: Prompt names are case-insensitive and hyphens are converted to underscores. When your arguments include newlines or multi-line payloads, wrap the call in JSON so the parser receives a single-line command shell.',
shortDescription: 'Execute prompts, templates, and chains',
category: 'execution'
}],
['prompt_manager', {
description: '🧰 PROMPT MANAGER: Create, update, delete, list, and analyze prompts. Supports gate configuration, temporary gates, and prompt-type migration for full lifecycle control.',
shortDescription: 'Manage prompt lifecycle, gates, and discovery',
category: 'management'
}],
['system_control', {
description: '⚙️ SYSTEM CONTROL: Unified interface for status reporting, framework and gate controls, analytics, configuration management, and maintenance operations.',
shortDescription: 'Manage framework state, metrics, and maintenance',
category: 'system'
}]
]);
}
/**
* Pre-load all methodology descriptions for dynamic switching
*/
private preloadMethodologyDescriptions(): void {
try {
// Initialize all methodology guides
const guides = [
new CAGEERFMethodologyGuide(),
new ReACTMethodologyGuide(),
new FiveW1HMethodologyGuide(),
new SCAMPERMethodologyGuide()
];
// Pre-load tool descriptions for each methodology using normalized keys
for (const guide of guides) {
const descriptions = guide.getToolDescriptions?.() || {};
const methodologyKey = this.normalizeMethodologyKey(guide.methodology);
const frameworkKey = this.normalizeMethodologyKey(guide.frameworkId);
if (methodologyKey) {
this.methodologyDescriptions.set(methodologyKey, descriptions);
}
if (frameworkKey) {
this.methodologyDescriptions.set(frameworkKey, descriptions);
}
}
this.logger.info(`✅ Pre-loaded tool descriptions for ${this.methodologyDescriptions.size} methodologies`);
} catch (error) {
this.logger.error(`Failed to pre-load methodology descriptions: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Initialize by loading descriptions from external config file
*/
async initialize(): Promise<void> {
try {
this.logger.info(`Loading tool descriptions from ${this.configPath}...`);
const content = await fs.readFile(this.configPath, 'utf-8');
const config: ToolDescriptionsConfig = JSON.parse(content);
// Validate config structure
if (!config.tools || typeof config.tools !== 'object') {
throw new Error('Invalid tool descriptions config: missing or invalid tools section');
}
// Load descriptions
this.descriptions.clear();
for (const [name, description] of Object.entries(config.tools)) {
this.descriptions.set(name, description);
}
this.isInitialized = true;
this.logger.info(`✅ Loaded ${this.descriptions.size} tool descriptions from external config (version: ${config.version})`);
// Pre-load methodology descriptions for dynamic switching
this.preloadMethodologyDescriptions();
} catch (error) {
this.logger.warn(`⚠️ Failed to load tool descriptions from ${this.configPath}: ${error instanceof Error ? error.message : String(error)}`);
this.logger.info('🔄 Using hardcoded default descriptions as fallback');
// Use defaults as fallback
this.descriptions = new Map(this.defaults);
this.isInitialized = true;
// Pre-load methodology descriptions for dynamic switching
this.preloadMethodologyDescriptions();
}
}
/**
* Get description for a specific tool with corrected priority hierarchy
*/
getDescription(
toolName: string,
frameworkEnabled?: boolean,
activeMethodology?: string,
options?: { applyMethodologyOverride?: boolean }
): string {
const applyMethodologyOverride = options?.applyMethodologyOverride ?? true;
this.logger.debug(`Getting description for ${toolName} (framework: ${frameworkEnabled}, methodology: ${activeMethodology})`);
const methodologyKey = this.normalizeMethodologyKey(activeMethodology);
const methodologyLogName = activeMethodology ?? methodologyKey;
// PRIORITY 1: Methodology-specific descriptions from guides (HIGHEST PRIORITY)
if (applyMethodologyOverride && methodologyKey) {
const methodologyDescs = this.methodologyDescriptions.get(methodologyKey);
if (methodologyDescs?.[toolName as keyof MethodologyToolDescriptions]?.description) {
const methodologyDesc = methodologyDescs[toolName as keyof MethodologyToolDescriptions]!.description!;
this.logger.debug(`✅ Using methodology-specific description from ${methodologyLogName} guide for ${toolName}`);
return methodologyDesc;
}
this.logger.debug(`⚠️ No methodology-specific description found for ${toolName} in ${methodologyLogName} guide`);
}
// Get config/default descriptions for fallback priority checks
const toolDesc = this.descriptions.get(toolName) || this.defaults.get(toolName);
if (!toolDesc) {
this.logger.warn(`No description found for tool: ${toolName}`);
return `Tool: ${toolName}`;
}
// PRIORITY 2: Framework-aware descriptions from config (if methodology desc not available)
if (frameworkEnabled !== undefined && toolDesc.frameworkAware) {
if (frameworkEnabled && toolDesc.frameworkAware.enabled) {
this.logger.debug(`✅ Using framework-aware enabled description from config for ${toolName}`);
return toolDesc.frameworkAware.enabled;
} else if (!frameworkEnabled && toolDesc.frameworkAware.disabled) {
this.logger.debug(`✅ Using framework-aware disabled description from config for ${toolName}`);
return toolDesc.frameworkAware.disabled;
}
// Check for static methodology descriptions in config as fallback
if (frameworkEnabled && methodologyKey && toolDesc.frameworkAware?.methodologies) {
const configMethodologyDescription =
toolDesc.frameworkAware.methodologies[methodologyKey] ??
(activeMethodology
? toolDesc.frameworkAware.methodologies[activeMethodology]
: undefined);
if (configMethodologyDescription) {
this.logger.debug(
`✅ Using static methodology description from config for ${toolName} (${methodologyLogName})`
);
return configMethodologyDescription;
}
}
}
// PRIORITY 3: Basic config file descriptions (LOWER PRIORITY)
this.logger.debug(`✅ Using basic config/default description for ${toolName}`);
return toolDesc.description;
}
/**
* Get parameter description for a specific tool parameter
*/
getParameterDescription(
toolName: string,
paramName: string,
frameworkEnabled?: boolean,
activeMethodology?: string,
options?: { applyMethodologyOverride?: boolean }
): string | undefined {
const applyMethodologyOverride = options?.applyMethodologyOverride ?? true;
const toolDesc = this.descriptions.get(toolName) || this.defaults.get(toolName);
if (!toolDesc?.parameters) return undefined;
const methodologyKey = this.normalizeMethodologyKey(activeMethodology);
// Check for methodology-specific parameter descriptions first (from pre-loaded cache)
if (applyMethodologyOverride && methodologyKey) {
const methodologyDescs = this.methodologyDescriptions.get(methodologyKey);
const methodologyTool = methodologyDescs?.[toolName as keyof MethodologyToolDescriptions];
if (methodologyTool?.parameters?.[paramName]) {
return methodologyTool.parameters[paramName];
}
// Fallback to static config if available
const methodologyParameters = toolDesc.frameworkAware?.methodologyParameters;
const methodologyParamConfig = methodologyParameters?.[methodologyKey] ??
(activeMethodology ? methodologyParameters?.[activeMethodology] : undefined);
if (methodologyParamConfig?.[paramName]) {
const param = methodologyParamConfig[paramName];
return typeof param === 'string' ? param : param?.description;
}
}
// Check for framework-aware parameter descriptions
if (frameworkEnabled !== undefined && toolDesc.frameworkAware) {
const frameworkParams = frameworkEnabled
? toolDesc.frameworkAware.parametersEnabled
: toolDesc.frameworkAware.parametersDisabled;
if (frameworkParams?.[paramName]) {
const param = frameworkParams[paramName];
return typeof param === 'string' ? param : param?.description;
}
}
// Fall back to default parameters
const param = toolDesc.parameters[paramName];
return typeof param === 'string' ? param : param?.description;
}
/**
* Get all available tool names
*/
getAvailableTools(): string[] {
return Array.from(this.descriptions.keys());
}
/**
* Check if manager is properly initialized
*/
isReady(): boolean {
return this.isInitialized;
}
/**
* Get configuration path for debugging
*/
getConfigPath(): string {
return this.configPath;
}
/**
* Get statistics about loaded descriptions
*/
getStats(): {
totalDescriptions: number;
loadedFromFile: number;
usingDefaults: number;
configPath: string;
isInitialized: boolean;
} {
const loadedFromFile = this.descriptions.size;
const defaultCount = this.defaults.size;
return {
totalDescriptions: this.descriptions.size,
loadedFromFile: loadedFromFile > defaultCount ? loadedFromFile : 0,
usingDefaults: loadedFromFile <= defaultCount ? defaultCount : 0,
configPath: this.configPath,
isInitialized: this.isInitialized
};
}
/**
* Start watching the tool descriptions file for changes
*/
startWatching(): void {
if (this.isWatching) {
this.logger.debug('Tool description file watcher already active');
return;
}
try {
this.logger.info(`🔍 Starting file watcher for tool descriptions: ${this.configPath}`);
this.fileWatcher = watch(this.configPath, (eventType) => {
if (eventType === 'change') {
this.handleFileChange();
}
});
this.fileWatcher.on('error', (error) => {
this.logger.error(`Tool description file watcher error: ${error.message}`);
this.isWatching = false;
});
this.isWatching = true;
this.logger.info('✅ Tool description hot-reload watcher started successfully');
} catch (error) {
this.logger.error(`Failed to start tool description file watcher: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Stop watching the tool descriptions file
*/
stopWatching(): void {
if (this.fileWatcher) {
this.logger.info('🛑 Stopping tool description file watcher...');
this.fileWatcher.close();
this.fileWatcher = undefined;
}
if (this.reloadDebounceTimer) {
clearTimeout(this.reloadDebounceTimer);
this.reloadDebounceTimer = undefined;
}
this.isWatching = false;
this.logger.info('✅ Tool description file watcher stopped');
}
/**
* Handle file change event with debouncing
*/
private handleFileChange(): void {
// Clear existing timer to debounce rapid file changes
if (this.reloadDebounceTimer) {
clearTimeout(this.reloadDebounceTimer);
}
// Debounce file changes (wait 500ms after last change)
this.reloadDebounceTimer = setTimeout(async () => {
try {
this.logger.info('📝 Tool descriptions file changed, reloading...');
await this.reload();
this.emit('descriptions-changed', this.getStats());
this.logger.info('✅ Tool descriptions reloaded successfully');
} catch (error) {
this.logger.error(`Failed to reload tool descriptions: ${error instanceof Error ? error.message : String(error)}`);
this.emit('descriptions-error', error);
}
}, 500);
}
/**
* Reload descriptions from file
*/
async reload(): Promise<void> {
await this.initialize();
}
/**
* Check if file watching is active
*/
isWatchingFile(): boolean {
return this.isWatching;
}
/**
* Cleanup resources on shutdown
*/
shutdown(): void {
this.stopWatching();
this.removeAllListeners();
}
}
/**
* Factory function following established pattern
*/
export function createToolDescriptionManager(
logger: Logger,
configManager: ConfigManager
): ToolDescriptionManager {
return new ToolDescriptionManager(logger, configManager);
}
```
--------------------------------------------------------------------------------
/server/src/gates/core/gate-validator.ts:
--------------------------------------------------------------------------------
```typescript
/**
* Core Gate Validator
* Provides validation capabilities with practical checks for prompt execution
*/
import { Logger } from '../../logging/index.js';
import type { GateLoader } from './gate-loader.js';
import type {
LightweightGateDefinition,
ValidationCheck,
ValidationContext,
GatePassCriteria
} from '../types.js';
import type { ValidationResult } from '../../execution/types.js';
import type { LLMIntegrationConfig } from '../../types.js';
/**
* Gate validation statistics
*/
export interface GateValidationStatistics {
totalValidations: number;
successfulValidations: number;
failedValidations: number;
averageValidationTime: number;
retryRequests: number;
}
/**
* Core gate validator with pass/fail logic
*/
export class GateValidator {
private logger: Logger;
private gateLoader: GateLoader;
private llmConfig?: LLMIntegrationConfig;
private validationStats: GateValidationStatistics = {
totalValidations: 0,
successfulValidations: 0,
failedValidations: 0,
averageValidationTime: 0,
retryRequests: 0
};
private validationTimes: number[] = [];
constructor(logger: Logger, gateLoader: GateLoader, llmConfig?: LLMIntegrationConfig) {
this.logger = logger;
this.gateLoader = gateLoader;
this.llmConfig = llmConfig;
}
/**
* Validate content against a gate
*/
async validateGate(
gateId: string,
context: ValidationContext
): Promise<ValidationResult | null> {
const startTime = Date.now();
try {
const gate = await this.gateLoader.loadGate(gateId);
if (!gate) {
this.logger.warn(`Gate not found for validation: ${gateId}`);
return null;
}
if (gate.type !== 'validation') {
this.logger.debug(`Gate ${gateId} is guidance-only, skipping validation`);
return {
valid: true,
passed: true,
gateId,
checks: [],
retryHints: [],
metadata: {
validationTime: Date.now() - startTime,
checksPerformed: 0,
llmValidationUsed: false
}
};
}
this.logger.debug(`Validating content against gate: ${gateId}`);
// Run validation checks
const checks: ValidationCheck[] = [];
let llmValidationUsed = false;
if (gate.pass_criteria) {
for (const criteria of gate.pass_criteria) {
const check = await this.runValidationCheck(criteria, context);
checks.push(check);
if (criteria.type === 'llm_self_check') {
llmValidationUsed = true;
}
}
}
// Determine overall pass/fail
const passed = checks.length === 0 || checks.every(check => check.passed);
// Generate retry hints for failures
const retryHints = passed ? [] : this.generateRetryHints(gate, checks);
const result: ValidationResult = {
valid: passed,
passed,
gateId,
checks,
retryHints,
metadata: {
validationTime: Date.now() - startTime,
checksPerformed: checks.length,
llmValidationUsed
}
};
this.logger.debug(
`Gate validation complete: ${gateId} - ${passed ? 'PASSED' : 'FAILED'} (${checks.length} checks)`
);
return result;
} catch (error) {
this.logger.error(`Gate validation failed for ${gateId}:`, error);
return {
valid: false,
passed: false,
gateId,
checks: [{
type: 'system_error',
passed: false,
message: `Validation error: ${error instanceof Error ? error.message : String(error)}`
}],
retryHints: [`Gate validation encountered an error. Please try again.`],
metadata: {
validationTime: Date.now() - startTime,
checksPerformed: 0,
llmValidationUsed: false
}
};
}
}
/**
* Validate content against multiple gates
*/
async validateGates(
gateIds: string[],
context: ValidationContext
): Promise<ValidationResult[]> {
const startTime = Date.now();
const results: ValidationResult[] = [];
for (const gateId of gateIds) {
const result = await this.validateGate(gateId, context);
if (result) {
results.push(result);
// Update statistics based on result
if (result.passed) {
this.validationStats.successfulValidations++;
} else {
this.validationStats.failedValidations++;
}
}
}
// Update overall statistics
const executionTime = Date.now() - startTime;
this.validationTimes.push(executionTime);
this.validationStats.totalValidations++;
this.updateAverageValidationTime();
return results;
}
/**
* Run a single validation check
*/
private async runValidationCheck(
criteria: GatePassCriteria,
context: ValidationContext
): Promise<ValidationCheck> {
try {
switch (criteria.type) {
case 'content_check':
return await this.runContentCheck(criteria, context);
case 'pattern_check':
return await this.runPatternCheck(criteria, context);
case 'llm_self_check':
return await this.runLLMSelfCheck(criteria, context);
default:
return {
type: criteria.type,
passed: false,
message: `Unknown validation type: ${criteria.type}`
};
}
} catch (error) {
this.logger.error(`Validation check failed for ${criteria.type}:`, error);
return {
type: criteria.type,
passed: false,
message: `Check failed: ${error instanceof Error ? error.message : String(error)}`
};
}
}
/**
* Run basic content checks (length, basic requirements)
*/
private async runContentCheck(
criteria: GatePassCriteria,
context: ValidationContext
): Promise<ValidationCheck> {
const content = context.content;
const issues: string[] = [];
// Length checks
if (criteria.min_length && content.length < criteria.min_length) {
issues.push(`Content too short: ${content.length} < ${criteria.min_length} characters`);
}
if (criteria.max_length && content.length > criteria.max_length) {
issues.push(`Content too long: ${content.length} > ${criteria.max_length} characters`);
}
// Required patterns (simple string matching)
if (criteria.required_patterns) {
for (const pattern of criteria.required_patterns) {
if (!content.toLowerCase().includes(pattern.toLowerCase())) {
issues.push(`Missing required content: "${pattern}"`);
}
}
}
// Forbidden patterns
if (criteria.forbidden_patterns) {
for (const pattern of criteria.forbidden_patterns) {
if (content.toLowerCase().includes(pattern.toLowerCase())) {
issues.push(`Contains forbidden content: "${pattern}"`);
}
}
}
const passed = issues.length === 0;
return {
type: 'content_check',
passed,
score: passed ? 1.0 : Math.max(0, 1 - (issues.length * 0.25)),
message: passed ? 'Content checks passed' : issues.join('; '),
details: {
contentLength: content.length,
issuesFound: issues.length
}
};
}
/**
* Run pattern matching checks
*/
private async runPatternCheck(
criteria: GatePassCriteria,
context: ValidationContext
): Promise<ValidationCheck> {
const content = context.content;
const issues: string[] = [];
// Regex pattern matching
if (criteria.regex_patterns) {
for (const pattern of criteria.regex_patterns) {
try {
const regex = new RegExp(pattern, 'i');
if (!regex.test(content)) {
issues.push(`Content doesn't match pattern: ${pattern}`);
}
} catch (error) {
issues.push(`Invalid regex pattern: ${pattern}`);
}
}
}
// Keyword count checking
if (criteria.keyword_count) {
for (const [keyword, requiredCount] of Object.entries(criteria.keyword_count)) {
const matches = (content.toLowerCase().match(new RegExp(keyword.toLowerCase(), 'g')) || []).length;
if (matches < requiredCount) {
issues.push(`Insufficient keyword "${keyword}": found ${matches}, required ${requiredCount}`);
}
}
}
const passed = issues.length === 0;
return {
type: 'pattern_check',
passed,
score: passed ? 1.0 : Math.max(0, 1 - (issues.length * 0.3)),
message: passed ? 'Pattern checks passed' : issues.join('; '),
details: { issuesFound: issues.length }
};
}
/**
* Run LLM self-check validation
*
* TODO: IMPLEMENT LLM API INTEGRATION
* This requires connecting to the LLM client configured at:
* config.analysis.semanticAnalysis.llmIntegration
*
* Requirements for implementation:
* - LLM client instance (from semantic analyzer)
* - Validation prompt templates
* - Quality assessment criteria
* - Confidence threshold enforcement
*
* Current behavior: Gracefully skips when LLM not configured
*/
private async runLLMSelfCheck(
criteria: GatePassCriteria,
context: ValidationContext
): Promise<ValidationCheck> {
// Check if LLM integration is configured and enabled
if (!this.llmConfig?.enabled) {
this.logger.debug('[LLM GATE] LLM self-check skipped - LLM integration disabled in config');
return {
type: 'llm_self_check',
passed: true, // Auto-pass when not configured
score: 1.0,
message: 'LLM validation skipped (not configured - set analysis.semanticAnalysis.llmIntegration.enabled=true)',
details: {
skipped: true,
reason: 'LLM integration disabled in config',
configPath: 'config.analysis.semanticAnalysis.llmIntegration.enabled'
}
};
}
if (!this.llmConfig.endpoint) {
this.logger.warn('[LLM GATE] LLM self-check skipped - no endpoint configured');
return {
type: 'llm_self_check',
passed: true,
score: 1.0,
message: 'LLM validation skipped (no endpoint configured)',
details: {
skipped: true,
reason: 'No LLM endpoint configured',
configPath: 'config.analysis.semanticAnalysis.llmIntegration.endpoint'
}
};
}
// TODO: Once LLM API client is available, implement actual validation here
// For now, log that it's not yet implemented even though config is enabled
this.logger.warn('[LLM GATE] LLM self-check requested but API client not yet implemented');
this.logger.debug(`[LLM GATE] Would validate with template: ${criteria.prompt_template}`);
return {
type: 'llm_self_check',
passed: true, // Auto-pass until implementation complete
score: 1.0,
message: 'LLM validation not yet implemented (API client integration pending)',
details: {
skipped: true,
reason: 'LLM API client not yet implemented',
configEnabled: this.llmConfig.enabled,
endpoint: this.llmConfig.endpoint,
templateRequested: criteria.prompt_template || 'default',
implementation: 'TODO: Wire LLM client from semantic analyzer'
}
};
}
/**
* Generate retry hints based on failed checks
*/
private generateRetryHints(
gate: LightweightGateDefinition,
checks: ValidationCheck[]
): string[] {
const hints: string[] = [];
const failedChecks = checks.filter(check => !check.passed);
if (failedChecks.length === 0) {
return hints;
}
// Add gate-specific guidance as a hint
if (gate.guidance) {
hints.push(`Remember the ${gate.name} guidelines:\n${gate.guidance}`);
}
// Add specific failure hints
for (const check of failedChecks) {
switch (check.type) {
case 'content_check':
if (check.message.includes('too short')) {
hints.push('Add more detail, examples, or explanations to meet length requirements');
}
if (check.message.includes('too long')) {
hints.push('Condense your response by removing redundant information');
}
if (check.message.includes('Missing required content')) {
hints.push(`Ensure your response includes: ${check.message.split(': ')[1]}`);
}
break;
case 'pattern_check':
hints.push('Review pattern matching requirements and adjust content structure');
break;
case 'llm_self_check':
hints.push('Review the quality criteria and improve content structure and depth');
break;
}
}
// Ensure we have at least one helpful hint
if (hints.length === 0) {
hints.push(`${gate.name} validation failed. Please review the requirements and try again.`);
}
return hints;
}
/**
* Check if content should be retried based on validation results
*
* @param validationResults - Results from gate validation
* @param currentAttempt - Current attempt number
* @param maxAttempts - Maximum allowed attempts
* @returns true if retry should be attempted
*/
shouldRetry(
validationResults: ValidationResult[],
currentAttempt: number,
maxAttempts: number = 3
): boolean {
if (currentAttempt >= maxAttempts) {
this.logger.debug('[GATE VALIDATOR] Max attempts reached, no retry');
return false;
}
// Retry if any validation gate failed
const shouldRetry = validationResults.some(result => !result.valid);
if (shouldRetry) {
this.validationStats.retryRequests++;
this.logger.debug('[GATE VALIDATOR] Retry recommended:', {
currentAttempt,
maxAttempts,
failedGates: validationResults.filter(r => !r.valid).map(r => r.gateId)
});
}
return shouldRetry;
}
/**
* Update average validation time
*/
private updateAverageValidationTime(): void {
if (this.validationTimes.length > 0) {
const sum = this.validationTimes.reduce((a, b) => a + b, 0);
this.validationStats.averageValidationTime = sum / this.validationTimes.length;
}
// Keep only last 100 measurements for rolling average
if (this.validationTimes.length > 100) {
this.validationTimes = this.validationTimes.slice(-100);
}
}
/**
* Get validation statistics
*/
getStatistics(): GateValidationStatistics {
return { ...this.validationStats };
}
/**
* Reset validation statistics
*/
resetStatistics(): void {
this.validationStats = {
totalValidations: 0,
successfulValidations: 0,
failedValidations: 0,
averageValidationTime: 0,
retryRequests: 0
};
this.validationTimes = [];
this.logger.debug('[GATE VALIDATOR] Statistics reset');
}
}
/**
* Create a gate validator instance
*/
export function createGateValidator(logger: Logger, gateLoader: GateLoader, llmConfig?: LLMIntegrationConfig): GateValidator {
return new GateValidator(logger, gateLoader, llmConfig);
}
```