|
|
|
|
|
""" |
|
|
Debug script to find where .lower() is being called on non-strings |
|
|
""" |
|
|
|
|
|
import os |
|
|
import sys |
|
|
|
|
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) |
|
|
|
|
|
|
|
|
os.environ["ANTHROPIC_API_KEY"] = "test-key" |
|
|
|
|
|
def find_lower_calls(): |
|
|
"""Find all .lower() calls in the code""" |
|
|
print("Searching for all .lower() calls in app.py...") |
|
|
print("-" * 60) |
|
|
|
|
|
with open('app.py', 'r') as f: |
|
|
lines = f.readlines() |
|
|
|
|
|
lower_calls = [] |
|
|
for i, line in enumerate(lines, 1): |
|
|
if '.lower()' in line: |
|
|
lower_calls.append((i, line.strip())) |
|
|
|
|
|
print(f"Found {len(lower_calls)} .lower() calls:\n") |
|
|
for line_num, line in lower_calls: |
|
|
print(f"Line {line_num}: {line}") |
|
|
|
|
|
if 'isinstance' in lines[line_num-2:line_num]: |
|
|
print(" β
Has type checking") |
|
|
else: |
|
|
print(" β οΈ No type checking nearby") |
|
|
print() |
|
|
|
|
|
def test_problematic_inputs(): |
|
|
"""Test inputs that might cause .lower() errors""" |
|
|
print("\nTesting problematic inputs...") |
|
|
print("-" * 60) |
|
|
|
|
|
|
|
|
test_inputs = [ |
|
|
"normal string", |
|
|
["list", "of", "strings"], |
|
|
{"dict": "value"}, |
|
|
123, |
|
|
None, |
|
|
[{"nested": "structure"}], |
|
|
b"bytes string", |
|
|
] |
|
|
|
|
|
for test_input in test_inputs: |
|
|
print(f"\nInput: {repr(test_input)} (type: {type(test_input)})") |
|
|
|
|
|
|
|
|
try: |
|
|
result = test_input.lower() |
|
|
print(f" β
.lower() works: {result}") |
|
|
except AttributeError as e: |
|
|
print(f" β .lower() fails: {e}") |
|
|
|
|
|
|
|
|
try: |
|
|
if isinstance(test_input, str): |
|
|
result = test_input.lower() |
|
|
print(f" β
With type check: {result}") |
|
|
else: |
|
|
result = str(test_input).lower() |
|
|
print(f" β
With str() conversion: {result}") |
|
|
except Exception as e: |
|
|
print(f" β Even with protection: {e}") |
|
|
|
|
|
def test_message_content(): |
|
|
"""Test what might be in message.content""" |
|
|
print("\n\nTesting message content scenarios...") |
|
|
print("-" * 60) |
|
|
|
|
|
|
|
|
class MockMessage: |
|
|
def __init__(self, content): |
|
|
self.content = content |
|
|
|
|
|
test_messages = [ |
|
|
MockMessage("Normal text content"), |
|
|
MockMessage(["List", "content"]), |
|
|
MockMessage({"type": "text", "content": "dict content"}), |
|
|
MockMessage(None), |
|
|
] |
|
|
|
|
|
for i, msg in enumerate(test_messages): |
|
|
print(f"\nMessage {i}: content = {repr(msg.content)}") |
|
|
|
|
|
|
|
|
if hasattr(msg, "content") and msg.content: |
|
|
content = msg.content |
|
|
print(f" Content type: {type(content)}") |
|
|
|
|
|
|
|
|
try: |
|
|
content = content.strip() |
|
|
print(f" β
.strip() works") |
|
|
except AttributeError: |
|
|
print(f" β .strip() fails - content is not a string!") |
|
|
|
|
|
|
|
|
if isinstance(content, list): |
|
|
content = " ".join(str(item) for item in content) |
|
|
print(f" β
Converted list to string: {content}") |
|
|
elif not isinstance(content, str): |
|
|
content = str(content) |
|
|
print(f" β
Converted to string: {content}") |
|
|
|
|
|
if __name__ == "__main__": |
|
|
print("=" * 80) |
|
|
print("DEBUG: Finding .lower() error sources") |
|
|
print("=" * 80) |
|
|
|
|
|
find_lower_calls() |
|
|
test_problematic_inputs() |
|
|
test_message_content() |
|
|
|
|
|
print("\n" + "=" * 80) |
|
|
print("CONCLUSION:") |
|
|
print("The error likely occurs when message.content is a list instead of string") |
|
|
print("This can happen with multimodal messages or tool responses") |
|
|
print("Solution: Always check type before calling .lower() or .strip()") |
|
|
print("=" * 80) |