Files
ragmcp/enhanced_toon.py
2025-11-04 00:23:51 +00:00

220 lines
8.9 KiB
Python

# enhanced_toon.py
"""
Official TOON (Token-Oriented Object Notation) formatter following the spec from github.com/toon-format/toon
Provides 30-60% token savings compared to JSON for LLM communication.
"""
import re
from typing import List, Dict, Any, Optional
class EnhancedToon:
"""
TOON formatter implementing the official specification from toon-format/toon
Optimized for uniform arrays of objects with significant token reduction.
"""
@staticmethod
def search_results(search_output: str, query: str) -> str:
"""
Convert search results to proper TOON format following official spec.
Args:
search_output: Raw search results from search_codebase
query: Original search query
Returns:
Proper TOON formatted results
"""
if not search_output or "No results" in search_output:
return f"# Search: {query}\nNo results found.\n"
# If it's already an error message, return as is
if "Error reading file" in search_output:
return search_output
try:
# Parse individual results
results = []
current_result = {}
lines = search_output.split('\n')
i = 0
while i < len(lines):
line = lines[i].strip()
if line.startswith('### Result'):
# Save previous result if exists
if current_result and current_result.get('file'):
results.append(current_result)
# Start new result
current_result = {
'file': '',
'line': '',
'type': '',
'content': []
}
# Extract score from header (remove relevance text, keep only score)
score_match = re.search(r'score:\s*([\d.]+)', line)
if score_match:
current_result['score'] = float(score_match.group(1))
else:
current_result['score'] = 0.0
i += 1
elif line.startswith('File:') and current_result:
# Only take the first File: line, ignore duplicates
if not current_result['file']:
current_result['file'] = line.replace('File:', '').strip()
i += 1
elif line.startswith('Line:') and current_result:
# Only take the first Line: line, ignore duplicates
if not current_result['line']:
current_result['line'] = line.replace('Line:', '').strip()
i += 1
elif line.startswith('Type:') and current_result:
# Only take the first Type: line, ignore duplicates
if not current_result['type']:
current_result['type'] = line.replace('Type:', '').strip()
i += 1
elif line == '---':
# End of result
i += 1
elif line and not line.startswith('###') and current_result:
# Skip all metadata lines (File:, Type:, Name:, Language:, Doc:, SQL:, Code:)
if not any(line.startswith(prefix) for prefix in
['File:', 'Line:', 'Type:', 'Name:', 'Language:', 'Doc:', 'SQL:', 'Code:']):
current_result['content'].append(line)
i += 1
else:
i += 1
# Add the last result if valid
if current_result and current_result.get('file'):
results.append(current_result)
# Convert to proper TOON format
return EnhancedToon._format_search_toon(results, query)
except Exception as e:
# If parsing fails, return original output but clean it up
return EnhancedToon._clean_raw_output(search_output, query)
@staticmethod
def _clean_raw_output(raw_output: str, query: str) -> str:
"""
Fallback: Clean up raw output by removing duplicate metadata lines.
"""
lines = raw_output.split('\n')
cleaned_lines = []
skip_next_metadata = False
for line in lines:
stripped = line.strip()
# Skip duplicate metadata lines that appear after the first occurrence
if any(stripped.startswith(prefix) for prefix in ['File:', 'Type:', 'Name:', 'Language:', 'Doc:']):
if skip_next_metadata:
continue
skip_next_metadata = True
elif stripped.startswith('### Result') or stripped == '---':
skip_next_metadata = False
cleaned_lines.append(line)
else:
cleaned_lines.append(line)
# Also remove relevance text, keep only score
final_lines = []
for line in cleaned_lines:
# Remove "relevance: HIGH/MEDIUM/LOW" text, keep only score
line = re.sub(r'relevance:\s*\w+,\s*', '', line)
final_lines.append(line)
return "\n".join(final_lines)
@staticmethod
def _format_search_toon(results: List[Dict], query: str) -> str:
"""
Format search results following official TOON specification.
"""
if not results:
return f"# Search: {query}\nNo results found.\n"
lines = [f"# Search: {query}", f"results[{len(results)}]{{file,line,score,content}}:"]
for i, result in enumerate(results, 1):
# Prepare content - join and clean
content = ' '.join(result.get('content', [])).strip()
content = re.sub(r'\s+', ' ', content) # Normalize whitespace
# Remove any remaining metadata patterns
content = re.sub(r'^File:.*$', '', content, flags=re.MULTILINE)
content = re.sub(r'^Type:.*$', '', content, flags=re.MULTILINE)
content = re.sub(r'^Name:.*$', '', content, flags=re.MULTILINE)
content = re.sub(r'^Language:.*$', '', content, flags=re.MULTILINE)
content = re.sub(r'^Doc:.*$', '', content, flags=re.MULTILINE)
content = re.sub(r'^SQL:.*$', '', content, flags=re.MULTILINE)
content = re.sub(r'^Code:.*$', '', content, flags=re.MULTILINE)
content = content.strip()
# Build TOON row - simple format without relevance text
row = [
result.get('file', ''),
result.get('line', ''),
f"{result.get('score', 0.0):.2f}",
content[:300] # Reasonable limit
]
# Escape fields if needed and join with comma
escaped_row = [EnhancedToon._escape_toon_field(str(field)) for field in row]
lines.append(" " + ",".join(escaped_row))
return "\n".join(lines)
@staticmethod
def _escape_toon_field(field: str) -> str:
"""
Escape TOON field according to specification.
Only quote fields that contain commas, quotes, or newlines.
"""
if any(char in field for char in [',', '"', '\n', '\r']):
# Escape quotes and wrap in quotes
escaped = field.replace('"', '\\"')
return f'"{escaped}"'
return field
@staticmethod
def reference_results(reference_output: str, symbol: str) -> str:
"""
Convert reference results to clean format.
"""
if "Error reading file" in reference_output:
return reference_output
# Clean up reference output similarly
return EnhancedToon._clean_raw_output(reference_output, f"References: {symbol}")
@staticmethod
def file_content_results(file_output: str, path: str) -> str:
"""
Convert file content results, preserving the full content without truncation.
"""
# Remove any truncation messages and return full content
if "truncated to 100 lines" in file_output:
# This indicates the file was truncated, we want to avoid that
# For now, just return the original output but remove the truncation notice
lines = file_output.split('\n')
cleaned_lines = []
for line in lines:
if "truncated to" not in line and "Context:" not in line:
cleaned_lines.append(line)
return "\n".join(cleaned_lines)
return file_output