fix new servers added bug in output processing

This commit is contained in:
TCUDIKEL
2025-05-11 01:03:02 +03:00
parent e381135caa
commit 123d50a08a
2 changed files with 47 additions and 114 deletions

View File

@@ -108,10 +108,37 @@ class MCPHostManager:
def _wait_for_ready(self) -> bool:
"""Wait for the process to be ready"""
try:
self.child.expect(self.config.PROMPT_INDICATOR)
logger.success("MCPHost started and ready")
self._clear_buffer()
return True
logger.info("Waiting for MCPHost to be ready...")
# Collect all output until we see the prompt
output = ""
start_time = time.time()
while time.time() - start_time < self.config.SPAWN_TIMEOUT:
try:
# Read any available data
chunk = self.child.read_nonblocking(size=1000, timeout=0.5)
output += chunk
# Check if we've seen the prompt indicator
if self.config.PROMPT_INDICATOR in output:
logger.success("MCPHost started and ready")
self._clear_buffer()
return True
except pexpect.TIMEOUT:
# No data available, continue waiting
continue
except pexpect.EOF:
logger.error("Process ended unexpectedly")
logger.debug("Output so far: {}", output)
return False
# If we get here, we've timed out
logger.error("Timeout waiting for MCPHost to be ready")
logger.debug("Output collected: {}", output[-500:]) # Last 500 chars
return False
except Exception as e:
logger.error("Error waiting for prompt: {}", e)
return False

View File

@@ -7,30 +7,12 @@ class Config:
# Patterns for cleaning debug output
ANSI_PATTERN = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
TUI_BORDER = ''
# Updated patterns to match the actual output format
SKIP_PATTERNS = [
'alt+enter / ctrl+j new line',
'ctrl+e open editor',
'enter submit',
'ctrl+c to quit',
'Enter your prompt',
'Type /help for commands'
]
# Updated log pattern to match the actual format: "2025/05/11 00:38:45 INFO <cmd/root.go:495> Model loaded..."
DEBUG_LOG_PATTERN = re.compile(r'^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \w+ <.*?>.*$', re.MULTILINE)
# Pattern for thinking spinner (if used)
SKIP_PATTERNS = ['alt+enter', 'Enter your prompt']
DEBUG_LOG_PATTERN = re.compile(r'^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \w+ <.*?>.*$')
THINKING_SPINNER_PATTERN = re.compile(r'[⣽⢿⡿⣟⣯⣷⣾⣻] Thinking\.\.\.')
# Markers and indicators
ASSISTANT_MARKER = "Assistant:"
PROMPT_INDICATOR = "Enter your prompt"
# Pattern to match control hints at the bottom
CONTROL_HINTS_PATTERN = re.compile(r'(alt\+enter|ctrl\+[a-z]).*?(•|$)', re.IGNORECASE)
def clean_response(response: str, original_prompt: str) -> str:
"""Clean and format MCP response"""
@@ -38,7 +20,7 @@ def clean_response(response: str, original_prompt: str) -> str:
return ""
# Debug log the raw response
logger.debug(f"Raw response before cleaning: {response[:500]}...")
logger.debug(f"Raw response before cleaning: {response}")
# Remove ANSI escape sequences
response = Config.ANSI_PATTERN.sub('', response)
@@ -82,125 +64,49 @@ def clean_assistant_section(assistant_response: str) -> str:
if Config.THINKING_SPINNER_PATTERN.search(line):
continue
# Skip control hints
if Config.CONTROL_HINTS_PATTERN.search(line):
continue
# Handle TUI borders
if stripped.startswith(Config.TUI_BORDER):
content = line.lstrip(Config.TUI_BORDER).strip()
# Only add if there's actual content after the border and it's not a skip pattern
if content and not any(skip_pattern.lower() in content.lower() for skip_pattern in Config.SKIP_PATTERNS):
content = stripped.strip(Config.TUI_BORDER).strip()
if content:
cleaned_lines.append(content)
else:
# Add if not a skip pattern
if not any(skip_pattern.lower() in stripped.lower() for skip_pattern in Config.SKIP_PATTERNS):
cleaned_lines.append(stripped)
cleaned_lines.append(stripped)
return '\n'.join(cleaned_lines).strip()
def clean_entire_response(response: str, original_prompt: str) -> str:
"""Clean the entire response when no Assistant: marker is found"""
# First remove all debug log lines
response = Config.DEBUG_LOG_PATTERN.sub('', response)
lines = response.split('\n')
cleaned_lines = []
# Flag to track if we've started seeing actual content
content_started = False
for line in lines:
stripped = line.strip()
# Skip empty lines before content starts
if not stripped:
if content_started:
cleaned_lines.append('')
# Skip empty lines and original prompt
if not stripped or stripped == original_prompt:
continue
# Skip lines that match the original prompt
if stripped == original_prompt:
content_started = True
# Skip debug log lines
if Config.DEBUG_LOG_PATTERN.match(line):
continue
# Skip thinking spinner lines
if Config.THINKING_SPINNER_PATTERN.search(line):
continue
# Skip control hints
if Config.CONTROL_HINTS_PATTERN.search(line):
continue
# Handle TUI decorations
if line.startswith(Config.TUI_BORDER):
content = line.lstrip(Config.TUI_BORDER).strip()
# Skip if it matches any skip pattern
if any(skip_pattern.lower() in content.lower() for skip_pattern in Config.SKIP_PATTERNS):
continue
# Skip if it's empty or just whitespace
if not content:
continue
# Skip if it's the original prompt
if content == original_prompt:
content_started = True
continue
# If we have actual content, add it
if content:
content_started = True
if stripped.startswith(Config.TUI_BORDER):
content = stripped.strip(Config.TUI_BORDER).strip()
if content and content != original_prompt:
cleaned_lines.append(content)
continue
# Skip navigation hints and other skip patterns
if any(skip_pattern.lower() in line.lower() for skip_pattern in Config.SKIP_PATTERNS):
# Skip navigation hints
if any(pattern in line for pattern in Config.SKIP_PATTERNS):
continue
# Add non-empty, non-decoration lines
content_started = True
cleaned_lines.append(stripped)
# Clean up any trailing empty lines
while cleaned_lines and not cleaned_lines[-1]:
cleaned_lines.pop()
return '\n'.join(cleaned_lines).strip()
def remove_tui_artifacts(text: str) -> str:
"""Remove any remaining TUI artifacts from the text"""
# Remove lines that are just TUI borders with spaces
lines = text.split('\n')
cleaned = []
for line in lines:
# Skip lines that are just TUI borders with spaces
if line.strip() == Config.TUI_BORDER or line.strip() == '':
if cleaned and cleaned[-1] != '': # Preserve single line breaks
cleaned.append('')
else:
cleaned.append(line)
return '\n'.join(cleaned).strip()
def post_process_response(response: str) -> str:
"""Final post-processing of the cleaned response"""
# Remove any remaining TUI artifacts
response = remove_tui_artifacts(response)
# Remove multiple consecutive newlines
response = re.sub(r'\n{3,}', '\n\n', response)
# Remove any remaining debug artifacts that might have slipped through
response = re.sub(r'DEBUG|INFO|ERROR|WARN.*?>', '', response)
return response.strip()
# Export the main cleaning function with additional post-processing
def clean_mcphost_response(response: str, original_prompt: str) -> str:
"""Main entry point for cleaning MCPHost responses"""
cleaned = clean_response(response, original_prompt)
return post_process_response(cleaned)
return '\n'.join(cleaned_lines).strip()