feat: optimize analyze_code for Claude Code with improved formatting

BREAKING CHANGES:
- Remove verbose_output from tool schema (Claude Code can't accidentally use it)
- Always show minimal terminal output with file previews
- Improved file content formatting for Gemini with clear delimiters

Key improvements:
- Files formatted as "--- BEGIN FILE: path --- content --- END FILE: path ---"
- Direct code formatted as "--- BEGIN DIRECT CODE --- code --- END DIRECT CODE ---"
- Terminal shows file paths, sizes, and small previews (not full content)
- Clear prompt structure for Gemini: USER REQUEST | CODE TO ANALYZE sections
- Prevents terminal hangs/glitches with large files in Claude Code
- All tests updated and passing

This ensures Claude Code stays responsive while Gemini gets properly formatted content.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Fahad
2025-06-08 20:59:35 +04:00
parent c2c80dd828
commit 341022a35b
3 changed files with 131 additions and 68 deletions

View File

@@ -61,7 +61,6 @@ class TestModels:
assert request.max_tokens == 8192
assert request.temperature == 0.2
assert request.model == DEFAULT_MODEL
assert request.verbose_output == False
class TestFileOperations:
@@ -73,7 +72,8 @@ class TestFileOperations:
test_file.write_text("def hello():\n return 'world'", encoding='utf-8')
content = read_file_content(str(test_file))
assert "=== File:" in content
assert "--- BEGIN FILE:" in content
assert "--- END FILE:" in content
assert "def hello():" in content
assert "return 'world'" in content
@@ -84,12 +84,14 @@ class TestFileOperations:
os.path.sep, "nonexistent_dir_12345", "nonexistent_file.py"
)
content = read_file_content(nonexistent_path)
assert "Error: File not found" in content
assert "--- FILE NOT FOUND:" in content
assert "Error: File does not exist" in content
def test_read_file_content_directory(self, tmp_path):
"""Test reading a directory instead of file"""
content = read_file_content(str(tmp_path))
assert "Error: Not a file" in content
assert "--- NOT A FILE:" in content
assert "Error: Path is not a file" in content
def test_prepare_code_context_with_files(self, tmp_path):
"""Test preparing context from files"""
@@ -99,20 +101,23 @@ class TestFileOperations:
file2.write_text("print('file2')", encoding='utf-8')
context, summary = prepare_code_context([str(file1), str(file2)], None)
assert "--- BEGIN FILE:" in context
assert "file1.py" in context
assert "file2.py" in context
assert "print('file1')" in context
assert "print('file2')" in context
assert "Analyzing 2 file(s)" in summary
assert "--- END FILE:" in context
assert "📁 Analyzing 2 file(s)" in summary
assert "bytes)" in summary
def test_prepare_code_context_with_code(self):
"""Test preparing context from direct code"""
code = "def test():\n pass"
context, summary = prepare_code_context(None, code)
assert "=== Direct Code ===" in context
assert "--- BEGIN DIRECT CODE ---" in context
assert "--- END DIRECT CODE ---" in context
assert code in context
assert "Direct code provided" in summary
assert "💻 Direct code provided" in summary
def test_prepare_code_context_mixed(self, tmp_path):
"""Test preparing context from both files and code"""
@@ -123,8 +128,8 @@ class TestFileOperations:
context, summary = prepare_code_context([str(test_file)], code)
assert "# From file" in context
assert "# Direct code" in context
assert "Analyzing 1 file(s)" in summary
assert "Direct code provided" in summary
assert "📁 Analyzing 1 file(s)" in summary
assert "💻 Direct code provided" in summary
class TestToolHandlers:
@@ -227,8 +232,8 @@ class TestToolHandlers:
assert len(result) == 1
# Check that the response contains both summary and Gemini's response
response_text = result[0].text
assert "Analyzing 1 file(s)" in response_text
assert "Gemini's response:" in response_text
assert "📁 Analyzing 1 file(s)" in response_text
assert "🤖 Gemini's Analysis:" in response_text
assert "Analysis result" in response_text
@pytest.mark.asyncio

View File

@@ -14,36 +14,43 @@ if str(parent_dir) not in sys.path:
from gemini_server import prepare_code_context
class TestVerboseOutput:
"""Test verbose output functionality"""
class TestNewFormattingBehavior:
"""Test the improved formatting behavior"""
def test_verbose_true_shows_full_content(self, tmp_path):
"""Test that verbose=True shows full file content"""
def test_file_formatting_for_gemini(self, tmp_path):
"""Test that files are properly formatted for Gemini"""
test_file = tmp_path / "test.py"
content = "def hello():\n return 'world'"
test_file.write_text(content, encoding='utf-8')
context, summary = prepare_code_context([str(test_file)], None, verbose=True)
context, summary = prepare_code_context([str(test_file)], None)
# With verbose=True, summary should equal context
assert summary == context
assert content in summary
# Context should have clear markers for Gemini
assert "--- BEGIN FILE:" in context
assert "--- END FILE:" in context
assert str(test_file) in context
assert content in context
def test_verbose_false_shows_summary(self, tmp_path):
"""Test that verbose=False shows only summary"""
# Summary should be concise for terminal
assert "📁 Analyzing 1 file(s)" in summary
assert "bytes)" in summary
assert len(summary) < len(context) # Summary much smaller than full context
def test_terminal_summary_shows_preview(self, tmp_path):
"""Test that terminal summary shows small preview"""
test_file = tmp_path / "large_file.py"
content = "x = 1\n" * 1000 # Large content
content = "# This is a large file\n" + "x = 1\n" * 1000
test_file.write_text(content, encoding='utf-8')
context, summary = prepare_code_context([str(test_file)], None, verbose=False)
context, summary = prepare_code_context([str(test_file)], None)
# Summary should be much smaller than context
assert len(summary) < len(context)
assert "Analyzing 1 file(s)" in summary
# Summary should show preview but not full content
assert "📁 Analyzing 1 file(s)" in summary
assert str(test_file) in summary
assert "bytes)" in summary
# Content should not be in summary
assert content not in summary
assert "Preview:" in summary
# Full content should not be in summary
assert "x = 1" not in summary or summary.count("x = 1") < 5
def test_multiple_files_summary(self, tmp_path):
"""Test summary with multiple files"""
@@ -53,22 +60,46 @@ class TestVerboseOutput:
file.write_text(f"# File {i}\nprint({i})", encoding='utf-8')
files.append(str(file))
context, summary = prepare_code_context(files, None, verbose=False)
context, summary = prepare_code_context(files, None)
assert "Analyzing 3 file(s)" in summary
assert "📁 Analyzing 3 file(s)" in summary
for file in files:
assert file in summary
assert "bytes)" in summary
# Should have clear delimiters in context
assert context.count("--- BEGIN FILE:") == 3
assert context.count("--- END FILE:") == 3
def test_code_and_files_summary(self, tmp_path):
"""Test summary with both files and direct code"""
def test_direct_code_formatting(self):
"""Test direct code formatting"""
direct_code = "# Direct code\nprint('hello')"
context, summary = prepare_code_context(None, direct_code)
# Context should have clear markers
assert "--- BEGIN DIRECT CODE ---" in context
assert "--- END DIRECT CODE ---" in context
assert direct_code in context
# Summary should show preview
assert "💻 Direct code provided" in summary
assert f"({len(direct_code)} characters)" in summary
assert "Preview:" in summary
def test_mixed_content_formatting(self, tmp_path):
"""Test formatting with both files and direct code"""
test_file = tmp_path / "test.py"
test_file.write_text("# Test file", encoding='utf-8')
direct_code = "# Direct code\nprint('hello')"
context, summary = prepare_code_context([str(test_file)], direct_code, verbose=False)
context, summary = prepare_code_context([str(test_file)], direct_code)
assert "Analyzing 1 file(s)" in summary
assert str(test_file) in summary
assert "Direct code provided" in summary
assert f"({len(direct_code):,} characters)" in summary
# Context should have both with clear separation
assert "--- BEGIN FILE:" in context
assert "--- END FILE:" in context
assert "--- BEGIN DIRECT CODE ---" in context
assert "--- END DIRECT CODE ---" in context
# Summary should mention both
assert "📁 Analyzing 1 file(s)" in summary
assert "💻 Direct code provided" in summary