ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s

This commit is contained in:
2026-08-20 13:12:50 +00:00
commit b119135836
10275 changed files with 3284984 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
"""Pytest bootstrap for the context experiment tests."""
from pathlib import Path
import sys
PROJECT_ROOT = Path(__file__).resolve().parents[1]
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
@@ -0,0 +1,11 @@
"""Helpers for running manual smoke scripts from tests/manual."""
from pathlib import Path
import sys
def add_project_root() -> Path:
project_root = Path(__file__).resolve().parents[2]
if str(project_root) not in sys.path:
sys.path.insert(0, str(project_root))
return project_root
@@ -0,0 +1,137 @@
#!/usr/bin/env python3
"""
Test script to verify conversation history persistence
"""
import os
from _bootstrap import add_project_root
add_project_root()
from dotenv import load_dotenv
from agent import ContextAwareAgent, ContextMode
import json
# Load environment variables
load_dotenv()
def test_conversation_history():
"""Test that conversation history persists between tasks"""
print("🧪 Testing Conversation History Persistence")
print("=" * 50)
# Get API key (use any available provider)
api_key = (
os.getenv("ARK_API_KEY")
or os.getenv("DASHSCOPE_API_KEY")
or os.getenv("MOONSHOT_API_KEY")
or os.getenv("SILICONFLOW_API_KEY")
)
provider = (
"doubao"
if os.getenv("ARK_API_KEY")
else (
"dashscope"
if os.getenv("DASHSCOPE_API_KEY")
else ("kimi" if os.getenv("MOONSHOT_API_KEY") else "siliconflow")
)
)
if not api_key:
print("❌ No API key found. Please set one of:")
print(" - ARK_API_KEY")
print(" - DASHSCOPE_API_KEY")
print(" - MOONSHOT_API_KEY")
print(" - SILICONFLOW_API_KEY")
return False
print(f"Using provider: {provider}")
print("-" * 50)
try:
# Create agent
agent = ContextAwareAgent(
api_key=api_key,
provider=provider,
context_mode=ContextMode.FULL,
verbose=False
)
# Test 1: First query
print("\n📝 Test 1: First query")
query1 = "Remember that my favorite number is 42. What is 10 + 5?"
result1 = agent.execute_task(query1)
print(f"Query: {query1}")
print(f"Response: {result1.get('final_answer', 'No answer')}")
# Check conversation history
print(f"\n📚 Conversation history after first query:")
print(f" Total messages: {len(agent.conversation_history)}")
# Print message roles
for i, msg in enumerate(agent.conversation_history):
role = msg.get('role', 'unknown')
content_preview = str(msg.get('content', ''))[:50] + "..." if len(str(msg.get('content', ''))) > 50 else str(msg.get('content', ''))
print(f" Message {i}: Role={role}, Content={content_preview}")
# Test 2: Second query that references first
print("\n📝 Test 2: Second query (should remember context)")
query2 = "What was my favorite number that I mentioned earlier?"
result2 = agent.execute_task(query2)
print(f"Query: {query2}")
print(f"Response: {result2.get('final_answer', 'No answer')}")
# Check if 42 is mentioned in the response
if "42" in str(result2.get('final_answer', '')):
print("✅ SUCCESS: Agent remembered the favorite number from conversation history!")
else:
print("⚠️ WARNING: Agent might not have remembered the number. Check response above.")
# Check conversation history growth
print(f"\n📚 Conversation history after second query:")
print(f" Total messages: {len(agent.conversation_history)}")
# Test 3: Verify system prompt unchanged
print("\n📝 Test 3: Verify system prompt remains unchanged")
system_prompt = agent.conversation_history[0].get('content', '')
if "favorite number" not in system_prompt and "42" not in system_prompt:
print("✅ SUCCESS: System prompt remains unchanged!")
else:
print("❌ FAILURE: System prompt was modified!")
# Test 4: Reset and verify history cleared
print("\n📝 Test 4: Test reset functionality")
agent.reset()
print(f" Messages after reset: {len(agent.conversation_history)}")
if len(agent.conversation_history) == 1 and agent.conversation_history[0]['role'] == 'system':
print("✅ SUCCESS: Reset properly cleared history and kept system prompt!")
else:
print("❌ FAILURE: Reset did not work correctly!")
# Test 5: New conversation after reset
print("\n📝 Test 5: New conversation after reset")
query3 = "What was my favorite number?"
result3 = agent.execute_task(query3)
print(f"Query: {query3}")
print(f"Response: {result3.get('final_answer', 'No answer')}")
if "42" not in str(result3.get('final_answer', '')) and "don't" in str(result3.get('final_answer', '').lower()):
print("✅ SUCCESS: Agent correctly doesn't remember after reset!")
else:
print("⚠️ Check if agent properly forgot the previous conversation")
print("\n" + "=" * 50)
print("Conversation history tests complete!")
return True
except Exception as e:
print(f"\n❌ Error during test: {e}")
import traceback
traceback.print_exc()
return False
if __name__ == "__main__":
success = test_conversation_history()
exit(0 if success else 1)
@@ -0,0 +1,226 @@
#!/usr/bin/env python3
"""
Test script for DeepSeek model integration.
Tests deepseek-v4-flash (default) with conversation and tool calling.
"""
import os
import sys
from _bootstrap import add_project_root
add_project_root()
from dotenv import load_dotenv
from agent import ContextAwareAgent, ContextMode
from config import Config
# Load environment variables
load_dotenv()
def test_basic_conversation():
"""Test basic conversation capabilities"""
print("\n" + "=" * 60)
print("TEST 1: Basic Conversation")
print("=" * 60)
try:
api_key = os.getenv("DEEPSEEK_API_KEY")
if not api_key:
print("❌ ERROR: DEEPSEEK_API_KEY not set in environment")
print("Please set it in your .env file or as environment variable")
return False
agent = ContextAwareAgent(
api_key=api_key,
provider="deepseek",
context_mode=ContextMode.FULL,
verbose=False,
)
query = "What is 25 * 4 + 10? Reply with FINAL ANSWER: and the number."
print(f"\n📝 Query: {query}")
response = agent.process(query)
print(f"\n🤖 Response: {response}")
if "110" in response:
print("\n✅ Basic conversation test passed!")
return True
else:
print("\n❌ Test failed - incorrect answer")
return False
except Exception as e:
print(f"\n❌ Error during test: {e}")
return False
def test_tool_usage():
"""Test tool calling capabilities"""
print("\n" + "=" * 60)
print("TEST 2: Tool Usage (Calculator)")
print("=" * 60)
try:
api_key = os.getenv("DEEPSEEK_API_KEY")
if not api_key:
print("❌ ERROR: DEEPSEEK_API_KEY not set")
return False
agent = ContextAwareAgent(
api_key=api_key,
provider="deepseek",
context_mode=ContextMode.FULL,
verbose=False,
)
query = (
"Calculate: (123.45 * 67.89) / 12.34 + sqrt(144) - 2^8. "
"Use the calculate tool. End with FINAL ANSWER:"
)
print(f"\n📝 Query: {query}")
response = agent.process(query)
print(f"\n🤖 Response: {response}")
if agent.trajectory.tool_calls:
print(f"\n🔧 Tools used: {len(agent.trajectory.tool_calls)}")
for call in agent.trajectory.tool_calls:
print(f" - {call.tool_name}: {call.arguments}")
print("\n✅ Tool usage test passed!")
return True
else:
print("\n⚠️ No tools were used")
return False
except Exception as e:
print(f"\n❌ Error during test: {e}")
return False
def test_currency_conversion():
"""Test currency conversion tool"""
print("\n" + "=" * 60)
print("TEST 3: Currency Conversion")
print("=" * 60)
try:
api_key = os.getenv("DEEPSEEK_API_KEY")
if not api_key:
print("❌ ERROR: DEEPSEEK_API_KEY not set")
return False
agent = ContextAwareAgent(
api_key=api_key,
provider="deepseek",
context_mode=ContextMode.FULL,
verbose=False,
)
query = "Convert 100 USD to EUR and JPY. Use convert_currency. FINAL ANSWER: the amounts."
print(f"\n📝 Query: {query}")
response = agent.process(query)
print(f"\n🤖 Response: {response}")
tool_names = [call.tool_name for call in agent.trajectory.tool_calls]
if "convert_currency" in tool_names:
print("\n🔧 Currency converter was used")
print("\n✅ Currency conversion test passed!")
return True
else:
print("\n⚠️ Currency converter was not used")
return False
except Exception as e:
print(f"\n❌ Error during test: {e}")
return False
def test_model_info():
"""Test and display model information"""
print("\n" + "=" * 60)
print("TEST 4: Model Information")
print("=" * 60)
try:
api_key = os.getenv("DEEPSEEK_API_KEY")
if not api_key:
print("❌ ERROR: DEEPSEEK_API_KEY not set")
return False
agent = ContextAwareAgent(
api_key=api_key,
provider="deepseek",
context_mode=ContextMode.FULL,
verbose=False,
)
expected = Config.get_default_model("deepseek")
print("\n📊 Model Configuration:")
print(f" Provider: {agent.provider}")
print(f" Model: {agent.model}")
print(f" Expected default: {expected}")
print(f" Base URL: {agent.client.base_url}")
print(f" Context Mode: {agent.context_mode.value}")
if agent.provider != "deepseek" or agent.model != expected:
print("\n❌ Model config mismatch")
return False
print("\n✅ Model info test completed!")
return True
except Exception as e:
print(f"\n❌ Error during test: {e}")
return False
def main():
"""Run all tests"""
print("\n" + "=" * 60)
print("DEEPSEEK MODEL INTEGRATION TEST SUITE")
print("=" * 60)
print("\nModel: deepseek-v4-flash (default)")
print("Provider: DeepSeek")
print("API: https://api.deepseek.com")
if not os.getenv("DEEPSEEK_API_KEY"):
print("\n❌ ERROR: DEEPSEEK_API_KEY not found in environment")
print("\nPlease set up your .env file with:")
print(" DEEPSEEK_API_KEY=your_api_key_here")
print("\nYou can get an API key from: https://platform.deepseek.com/api_keys")
sys.exit(1)
results = []
results.append(("Model Information", test_model_info()))
results.append(("Basic Conversation", test_basic_conversation()))
results.append(("Tool Usage", test_tool_usage()))
results.append(("Currency Conversion", test_currency_conversion()))
print("\n" + "=" * 60)
print("TEST SUMMARY")
print("=" * 60)
passed = sum(1 for _, result in results if result)
total = len(results)
for test_name, result in results:
status = "✅ PASSED" if result else "❌ FAILED"
print(f" {test_name}: {status}")
print(f"\nTotal: {passed}/{total} tests passed")
if passed == total:
print("\n🎉 All tests passed! DeepSeek integration is working correctly.")
else:
print(f"\n⚠️ {total - passed} test(s) failed. Please check the errors above.")
return passed == total
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)
@@ -0,0 +1,66 @@
#!/usr/bin/env python3
"""
Quick smoke test for DeepSeek provider (deepseek-v4-flash).
"""
import os
import sys
import time
from _bootstrap import add_project_root
add_project_root()
from dotenv import load_dotenv
load_dotenv()
task = "What is 10 + 5? Provide FINAL ANSWER with just the number."
print("=" * 60)
print("QUICK TEST - DeepSeek Provider")
print("=" * 60)
deepseek_key = os.getenv("DEEPSEEK_API_KEY")
if not deepseek_key:
print("❌ DEEPSEEK_API_KEY not set")
print("Set it in .env or: export DEEPSEEK_API_KEY=your_key")
print("Get a key at: https://platform.deepseek.com/api_keys")
sys.exit(1)
from agent import ContextAwareAgent, ContextMode
agent = ContextAwareAgent(deepseek_key, ContextMode.FULL, provider="deepseek")
print(f"✅ Using: {agent.provider} / {agent.model}")
print(f" Base URL: {agent.client.base_url}")
print(f"\n📝 Task: {task}")
print("-" * 40)
start = time.time()
print("Processing...")
try:
result = agent.execute_task(task, max_iterations=3)
elapsed = time.time() - start
print(f"\n✅ Completed in {elapsed:.2f} seconds")
if result.get("success"):
print("Success: True")
if result.get("final_answer"):
print(f"Answer: {result['final_answer']}")
else:
print("Success: False")
if result.get("error"):
print(f"Error: {result['error']}")
print(f"Iterations: {result.get('iterations', 0)}")
print(f"Tool calls: {len(result['trajectory'].tool_calls)}")
except KeyboardInterrupt:
print("\n⚠️ Interrupted")
except Exception as e:
print(f"\n❌ Error: {str(e)}")
sys.exit(1)
print("=" * 60)
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
"""
Test that Doubao is the default provider
"""
import os
import sys
from _bootstrap import add_project_root
add_project_root()
# Test without any arguments - should use Doubao
print("Testing default provider...")
# Check if ARK_API_KEY is available
ark_key = os.getenv("ARK_API_KEY")
sf_key = os.getenv("SILICONFLOW_API_KEY")
print(f"ARK_API_KEY available: {'Yes' if ark_key else 'No'}")
print(f"SILICONFLOW_API_KEY available: {'Yes' if sf_key else 'No'}")
if ark_key:
from agent import ContextAwareAgent, ContextMode
from config import Config
# Check config default
print(f"\nConfig default provider: {Config.LLM_PROVIDER}")
# Create agent with default provider from config
agent = ContextAwareAgent(ark_key, ContextMode.FULL, provider=Config.LLM_PROVIDER)
print(f"\n✅ Default agent created successfully!")
print(f"Provider: {agent.provider}")
print(f"Model: {agent.model}")
print(f"Base URL: {agent.client.base_url}")
if agent.provider == "doubao":
print("\n🎉 SUCCESS: Doubao is the default provider!")
else:
print(f"\n❌ ERROR: Expected doubao, got {agent.provider}")
sys.exit(1)
else:
print("\n⚠️ ARK_API_KEY not set. Cannot test default provider.")
print("Please set: export ARK_API_KEY=your_key_here")
@@ -0,0 +1,64 @@
#!/usr/bin/env python3
"""
Quick test for Doubao provider
"""
import os
from _bootstrap import add_project_root
add_project_root()
from agent import ContextAwareAgent, ContextMode
def test_doubao():
"""Test Doubao provider with a simple task"""
print("\n" + "="*60)
print("🧪 DOUBAO PROVIDER TEST")
print("="*60)
# Check for API key
api_key = os.getenv("ARK_API_KEY")
if not api_key:
print("❌ ARK_API_KEY not found. Please set it to test Doubao provider.")
print(" export ARK_API_KEY=your_key_here")
return
print("✅ ARK API key found")
# Create agent with Doubao provider
try:
agent = ContextAwareAgent(api_key, ContextMode.FULL, provider="doubao")
print(f"✅ Agent created with Doubao provider")
print(f" Model: {agent.model}")
print(f" Base URL: {agent.client.base_url}")
# Simple test task (minimal to save tokens)
print("\n📝 Running simple test task...")
task = "Calculate: What is 15 + 27? Provide FINAL ANSWER with the result."
result = agent.execute_task(task, max_iterations=3)
if result.get('success'):
print("✅ Task executed successfully!")
if result.get('final_answer'):
print(f" Answer: {result['final_answer'][:100]}...")
else:
print(f"⚠️ Task did not complete successfully")
if result.get('error'):
print(f" Error: {result['error']}")
print(f"\n📊 Execution stats:")
print(f" Iterations: {result.get('iterations', 0)}")
print(f" Tool calls: {len(result['trajectory'].tool_calls)}")
except Exception as e:
print(f"❌ Error: {str(e)}")
print("\nNote: Make sure your ARK_API_KEY is valid and has access to the doubao model.")
print("\n" + "="*60)
if __name__ == "__main__":
test_doubao()
@@ -0,0 +1,60 @@
#!/usr/bin/env python3
"""
Quick test with Doubao as default
"""
import os
import sys
import time
from _bootstrap import add_project_root
add_project_root()
# Set a very simple task to test quickly
task = "What is 10 + 5? Provide FINAL ANSWER with just the number."
print("="*60)
print("QUICK TEST - Doubao Default Provider")
print("="*60)
ark_key = os.getenv("ARK_API_KEY")
if not ark_key:
print("❌ ARK_API_KEY not set")
sys.exit(1)
from agent import ContextAwareAgent, ContextMode
# Create agent with default Doubao
agent = ContextAwareAgent(ark_key, ContextMode.FULL, provider="doubao")
print(f"✅ Using: {agent.provider} / {agent.model}")
print(f"\n📝 Task: {task}")
print("-"*40)
start = time.time()
print("Processing...")
try:
result = agent.execute_task(task, max_iterations=2)
elapsed = time.time() - start
print(f"\n✅ Completed in {elapsed:.2f} seconds")
if result.get('success'):
print(f"Success: True")
if result.get('final_answer'):
print(f"Answer: {result['final_answer']}")
else:
print(f"Success: False")
if result.get('error'):
print(f"Error: {result['error']}")
print(f"Iterations: {result.get('iterations', 0)}")
print(f"Tool calls: {len(result['trajectory'].tool_calls)}")
except KeyboardInterrupt:
print("\n⚠️ Interrupted")
except Exception as e:
print(f"\n❌ Error: {str(e)}")
print("="*60)
+249
View File
@@ -0,0 +1,249 @@
#!/usr/bin/env python3
"""
Test script for Kimi K3 model integration
Tests the Kimi K3 model (kimi-k3) with various tasks
"""
import os
import sys
from _bootstrap import add_project_root
add_project_root()
from dotenv import load_dotenv
from agent import ContextAwareAgent, ContextMode
from config import Config
# Load environment variables
load_dotenv()
def test_basic_conversation():
"""Test basic conversation capabilities"""
print("\n" + "="*60)
print("TEST 1: Basic Conversation")
print("="*60)
try:
# Get API key
api_key = os.getenv("MOONSHOT_API_KEY")
if not api_key:
print("❌ ERROR: MOONSHOT_API_KEY not set in environment")
print("Please set it in your .env file or as environment variable")
return False
# Create agent
agent = ContextAwareAgent(
api_key=api_key,
provider="kimi",
context_mode=ContextMode.FULL,
verbose=False
)
# Test basic conversation
query = "What is 25 * 4 + 10?"
print(f"\n📝 Query: {query}")
response = agent.process(query)
print(f"\n🤖 Response: {response}")
# Verify response contains correct answer
if "110" in response:
print("\n✅ Basic conversation test passed!")
return True
else:
print("\n❌ Test failed - incorrect answer")
return False
except Exception as e:
print(f"\n❌ Error during test: {e}")
return False
def test_tool_usage():
"""Test tool calling capabilities"""
print("\n" + "="*60)
print("TEST 2: Tool Usage (Calculator)")
print("="*60)
try:
# Get API key
api_key = os.getenv("MOONSHOT_API_KEY")
if not api_key:
print("❌ ERROR: MOONSHOT_API_KEY not set")
return False
# Create agent
agent = ContextAwareAgent(
api_key=api_key,
provider="kimi",
context_mode=ContextMode.FULL,
verbose=False
)
# Test complex calculation requiring calculator tool
query = "Calculate: (123.45 * 67.89) / 12.34 + sqrt(144) - 2^8"
print(f"\n📝 Query: {query}")
response = agent.process(query)
print(f"\n🤖 Response: {response}")
# Check if calculator was used
if agent.trajectory.tool_calls:
print(f"\n🔧 Tools used: {len(agent.trajectory.tool_calls)}")
for call in agent.trajectory.tool_calls:
print(f" - {call.tool_name}: {call.arguments}")
print("\n✅ Tool usage test passed!")
return True
else:
print("\n⚠️ No tools were used")
return False
except Exception as e:
print(f"\n❌ Error during test: {e}")
return False
def test_currency_conversion():
"""Test currency conversion tool"""
print("\n" + "="*60)
print("TEST 3: Currency Conversion")
print("="*60)
try:
# Get API key
api_key = os.getenv("MOONSHOT_API_KEY")
if not api_key:
print("❌ ERROR: MOONSHOT_API_KEY not set")
return False
# Create agent
agent = ContextAwareAgent(
api_key=api_key,
provider="kimi",
context_mode=ContextMode.FULL,
verbose=False
)
# Test currency conversion
query = "Convert 100 USD to EUR and JPY"
print(f"\n📝 Query: {query}")
response = agent.process(query)
print(f"\n🤖 Response: {response}")
# Check if currency converter was used
tool_names = [call.tool_name for call in agent.trajectory.tool_calls]
if "convert_currency" in tool_names:
print(f"\n🔧 Currency converter was used")
print("\n✅ Currency conversion test passed!")
return True
else:
print("\n⚠️ Currency converter was not used")
return False
except Exception as e:
print(f"\n❌ Error during test: {e}")
return False
def test_model_info():
"""Test and display model information"""
print("\n" + "="*60)
print("TEST 4: Model Information")
print("="*60)
try:
# Get API key
api_key = os.getenv("MOONSHOT_API_KEY")
if not api_key:
print("❌ ERROR: MOONSHOT_API_KEY not set")
return False
# Create agent
agent = ContextAwareAgent(
api_key=api_key,
provider="kimi",
context_mode=ContextMode.FULL,
verbose=False
)
print(f"\n📊 Model Configuration:")
print(f" Provider: {agent.provider}")
print(f" Model: {agent.model}")
print(f" Base URL: {agent.client.base_url}")
print(f" Context Mode: {agent.context_mode.value}")
# Test model identification
query = "What model are you?"
print(f"\n📝 Query: {query}")
response = agent.process(query)
print(f"\n🤖 Response: {response}")
print("\n✅ Model info test completed!")
return True
except Exception as e:
print(f"\n❌ Error during test: {e}")
return False
def main():
"""Run all tests"""
print("\n" + "="*60)
print("KIMI K3 MODEL INTEGRATION TEST SUITE")
print("="*60)
print("\nModel: kimi-k3")
print("Provider: Moonshot AI")
print("API: https://api.moonshot.cn/v1")
# Check environment
if not os.getenv("MOONSHOT_API_KEY"):
print("\n❌ ERROR: MOONSHOT_API_KEY not found in environment")
print("\nPlease set up your .env file with:")
print(" MOONSHOT_API_KEY=your_api_key_here")
print("\nYou can get an API key from: https://platform.moonshot.cn/")
sys.exit(1)
# Run tests
results = []
# Test 1: Basic conversation
results.append(("Basic Conversation", test_basic_conversation()))
# Test 2: Tool usage
results.append(("Tool Usage", test_tool_usage()))
# Test 3: Currency conversion
results.append(("Currency Conversion", test_currency_conversion()))
# Test 4: Model information
results.append(("Model Information", test_model_info()))
# Summary
print("\n" + "="*60)
print("TEST SUMMARY")
print("="*60)
passed = sum(1 for _, result in results if result)
total = len(results)
for test_name, result in results:
status = "✅ PASSED" if result else "❌ FAILED"
print(f" {test_name}: {status}")
print(f"\nTotal: {passed}/{total} tests passed")
if passed == total:
print("\n🎉 All tests passed! Kimi K3 integration is working correctly.")
else:
print(f"\n⚠️ {total - passed} test(s) failed. Please check the errors above.")
return passed == total
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
"""
Quick test script to verify Kimi K3 model integration
"""
import os
from _bootstrap import add_project_root
add_project_root()
from dotenv import load_dotenv
from agent import ContextAwareAgent, ContextMode
# Load environment variables
load_dotenv()
def main():
# Get API key
api_key = os.getenv("MOONSHOT_API_KEY")
if not api_key:
print("❌ ERROR: MOONSHOT_API_KEY not set")
print("Please add to your .env file:")
print(" MOONSHOT_API_KEY=your_api_key_here")
return
print("🚀 Testing Kimi K3 Model (kimi-k3)")
print("=" * 50)
try:
# Create agent with Kimi provider
agent = ContextAwareAgent(
api_key=api_key,
provider="kimi",
context_mode=ContextMode.FULL,
verbose=False
)
print(f"✅ Agent created successfully")
print(f" Provider: {agent.provider}")
print(f" Model: {agent.model}")
print(f" Base URL: {agent.client.base_url}")
# Test simple query
print("\n📝 Testing basic query...")
query = "What is 2 + 2?"
response = agent.process(query)
print(f" Query: {query}")
print(f" Response: {response}")
print("\n✅ Kimi K3 integration is working!")
except Exception as e:
print(f"\n❌ Error: {e}")
if __name__ == "__main__":
main()
@@ -0,0 +1,101 @@
#!/usr/bin/env python3
"""
Test script to verify PDF parsing and currency conversion
"""
import os
import sys
from _bootstrap import add_project_root
add_project_root()
from agent import ContextAwareAgent, ContextMode
def test_pdf_with_currencies():
"""Test PDF parsing with currency conversion"""
print("\n" + "="*60)
print("🧪 PDF PARSING & CURRENCY CONVERSION TEST")
print("="*60)
# Check API key
api_key = os.getenv("SILICONFLOW_API_KEY")
if not api_key:
print("❌ No API key found. Set SILICONFLOW_API_KEY environment variable.")
return False
# Create agent
agent = ContextAwareAgent(api_key, ContextMode.FULL)
# Test task
task = """
Analyze the expense report at fixtures/pdfs/simple_expense_report.pdf
Extract the following expenses mentioned in the document:
- US Office: $2,500,000 USD
- UK Office: £1,800,000 GBP
- Japan Office: ¥380,000,000 JPY
- EU Office: €2,100,000 EUR
- Singapore Office: S$3,200,000 SGD
Convert all amounts to USD and calculate the total.
FINAL ANSWER: Provide the total expenses in USD.
"""
print("📋 Task: Parse PDF and convert multiple currencies to USD")
print("-"*40)
try:
# Execute task
result = agent.execute_task(task, max_iterations=5)
print("\n" + "="*40)
print("RESULTS:")
print("="*40)
print(f"Success: {result.get('success', False)}")
print(f"Iterations: {result.get('iterations', 0)}")
print(f"Tool Calls: {len(result['trajectory'].tool_calls)}")
# Show tool calls made
print("\n📊 Tool Calls Made:")
for i, tc in enumerate(result['trajectory'].tool_calls, 1):
print(f"{i}. {tc.tool_name}")
if tc.tool_name == "parse_pdf":
print(f" - PDF: {tc.arguments.get('url', 'N/A')}")
if tc.result and 'num_pages' in tc.result:
print(f" - Pages: {tc.result['num_pages']}")
elif tc.tool_name == "convert_currency":
print(f" - {tc.arguments.get('amount', 0)} {tc.arguments.get('from_currency', '')}{tc.arguments.get('to_currency', '')}")
if tc.result and 'converted_amount' in tc.result:
print(f" - Result: {tc.result['converted_amount']}")
elif tc.tool_name == "calculate":
print(f" - Expression: {tc.arguments.get('expression', '')}")
if tc.result and 'result' in tc.result:
print(f" - Result: {tc.result['result']}")
if result.get('final_answer'):
print("\n✅ Final Answer:")
print("-"*40)
print(result['final_answer'])
if result.get('error'):
print(f"\n❌ Error: {result['error']}")
return result.get('success', False)
except Exception as e:
print(f"\n❌ Exception: {str(e)}")
return False
if __name__ == "__main__":
# Ensure PDFs exist
if not os.path.exists("fixtures/pdfs/simple_expense_report.pdf"):
print("⚠️ Creating sample PDFs...")
os.system("python create_sample_pdf.py")
# Run test
success = test_pdf_with_currencies()
sys.exit(0 if success else 1)
@@ -0,0 +1,129 @@
#!/usr/bin/env python3
"""
Test script to verify provider configuration
"""
import os
from _bootstrap import add_project_root
add_project_root()
from agent import ContextAwareAgent, ContextMode
def test_providers():
"""Test different provider configurations"""
print("\n" + "="*60)
print("🧪 PROVIDER CONFIGURATION TEST")
print("="*60)
# Test Alibaba Cloud Model Studio / Bailian
dashscope_key = os.getenv("DASHSCOPE_API_KEY")
if dashscope_key:
print("\n✅ Alibaba Cloud Model Studio API key found")
try:
agent = ContextAwareAgent(
dashscope_key, ContextMode.FULL, provider="dashscope"
)
print(f" Provider: {agent.provider}")
print(f" Model: {agent.model}")
print(f" Base URL: {agent.client.base_url}")
except Exception as e:
print(f" ❌ Error: {str(e)}")
else:
print("\n⚠️ Alibaba Cloud Model Studio API key not found (DASHSCOPE_API_KEY)")
# Test SiliconFlow
sf_key = os.getenv("SILICONFLOW_API_KEY")
if sf_key:
print("\n✅ SiliconFlow API key found")
try:
agent = ContextAwareAgent(sf_key, ContextMode.FULL, provider="siliconflow")
print(f" Provider: {agent.provider}")
print(f" Model: {agent.model}")
print(f" Base URL: {agent.client.base_url}")
except Exception as e:
print(f" ❌ Error: {str(e)}")
else:
print("\n⚠️ SiliconFlow API key not found (SILICONFLOW_API_KEY)")
# Test Doubao
ark_key = os.getenv("ARK_API_KEY")
if ark_key:
print("\n✅ Doubao/ARK API key found")
try:
agent = ContextAwareAgent(ark_key, ContextMode.FULL, provider="doubao")
print(f" Provider: {agent.provider}")
print(f" Model: {agent.model}")
print(f" Base URL: {agent.client.base_url}")
except Exception as e:
print(f" ❌ Error: {str(e)}")
else:
print("\n⚠️ Doubao/ARK API key not found (ARK_API_KEY)")
# Test DeepSeek
deepseek_key = os.getenv("DEEPSEEK_API_KEY")
if deepseek_key:
print("\n✅ DeepSeek API key found")
try:
agent = ContextAwareAgent(deepseek_key, ContextMode.FULL, provider="deepseek")
print(f" Provider: {agent.provider}")
print(f" Model: {agent.model}")
print(f" Base URL: {agent.client.base_url}")
except Exception as e:
print(f" ❌ Error: {str(e)}")
else:
print("\n⚠️ DeepSeek API key not found (DEEPSEEK_API_KEY)")
# Test custom model
if sf_key:
print("\n🔧 Testing custom model specification:")
try:
agent = ContextAwareAgent(sf_key, ContextMode.FULL,
provider="siliconflow",
model="Qwen/QwQ-32B")
print(f" Provider: {agent.provider}")
print(f" Custom Model: {agent.model}")
except Exception as e:
print(f" ❌ Error: {str(e)}")
print("\n" + "="*60)
print("Test complete!")
# Show usage examples
print("\n📖 Usage Examples:")
print("-"*40)
if dashscope_key:
print("\n# Using Qwen directly through Alibaba Cloud Model Studio:")
print("python main.py --provider dashscope")
print("python main.py --provider dashscope --model qwen3.7-plus")
if sf_key:
print("\n# Using SiliconFlow:")
print("python main.py --provider siliconflow")
print("python main.py --provider siliconflow --model Qwen/QwQ-32B")
if ark_key:
print("\n# Using Doubao:")
print("python main.py --provider doubao")
print("python main.py --provider doubao --model doubao-seed-1-6-thinking-250715")
if deepseek_key:
print("\n# Using DeepSeek:")
print("python main.py --provider deepseek")
print("python main.py --provider deepseek --model deepseek-v4-pro")
if not dashscope_key and not sf_key and not ark_key and not deepseek_key:
print("\n⚠️ No API keys found. Please set one of:")
print(" export DASHSCOPE_API_KEY=your_key")
print(" export SILICONFLOW_API_KEY=your_key")
print(" export ARK_API_KEY=your_key")
print(" export DEEPSEEK_API_KEY=your_key")
print("\n" + "="*60)
if __name__ == "__main__":
test_providers()
@@ -0,0 +1,117 @@
#!/usr/bin/env python3
"""
Test script to verify provider switching functionality
"""
import os
from _bootstrap import add_project_root
add_project_root()
from dotenv import load_dotenv
from agent import ContextAwareAgent, ContextMode
from config import Config
# Load environment variables
load_dotenv()
def test_provider_switching():
"""Test switching between different providers"""
print("🧪 Testing Provider Switching")
print("=" * 50)
providers_to_test = []
# Check which providers have API keys configured
if os.getenv("DASHSCOPE_API_KEY"):
providers_to_test.append(("dashscope", os.getenv("DASHSCOPE_API_KEY")))
print("✅ Alibaba Cloud Model Studio API key found")
else:
print("⏭️ Skipping Alibaba Cloud Model Studio (no API key)")
if os.getenv("SILICONFLOW_API_KEY"):
providers_to_test.append(("siliconflow", os.getenv("SILICONFLOW_API_KEY")))
print("✅ SiliconFlow API key found")
else:
print("⏭️ Skipping SiliconFlow (no API key)")
if os.getenv("ARK_API_KEY"):
providers_to_test.append(("doubao", os.getenv("ARK_API_KEY")))
print("✅ Doubao API key found")
else:
print("⏭️ Skipping Doubao (no API key)")
if os.getenv("MOONSHOT_API_KEY"):
providers_to_test.append(("kimi", os.getenv("MOONSHOT_API_KEY")))
print("✅ Kimi API key found")
else:
print("⏭️ Skipping Kimi (no API key)")
if os.getenv("DEEPSEEK_API_KEY"):
providers_to_test.append(("deepseek", os.getenv("DEEPSEEK_API_KEY")))
print("✅ DeepSeek API key found")
else:
print("⏭️ Skipping DeepSeek (no API key)")
if not providers_to_test:
print("\n❌ No API keys configured. Please set at least one:")
print(" - DASHSCOPE_API_KEY")
print(" - SILICONFLOW_API_KEY")
print(" - ARK_API_KEY")
print(" - MOONSHOT_API_KEY")
print(" - DEEPSEEK_API_KEY")
return
print(f"\nTesting {len(providers_to_test)} provider(s)...")
print("-" * 50)
# Test each available provider
for provider_name, api_key in providers_to_test:
print(f"\n📌 Testing {provider_name.upper()}")
try:
# Create agent with provider
agent = ContextAwareAgent(
api_key=api_key,
provider=provider_name,
context_mode=ContextMode.FULL,
verbose=False
)
# Get default model from config
default_model = Config.get_default_model(provider_name)
print(f" Provider: {agent.provider}")
print(f" Model: {agent.model}")
print(f" Expected: {default_model}")
print(f" Base URL: {agent.client.base_url}")
# Test with a simple query
query = "What is 5 + 3?"
print(f" Testing query: {query}")
response = agent.process(query)
if "8" in response:
print(f"{provider_name} working correctly!")
else:
print(f" ⚠️ {provider_name} response didn't contain expected answer")
print(f" Response: {response[:100]}...")
except Exception as e:
print(f" ❌ Error with {provider_name}: {e}")
print("\n" + "=" * 50)
print("Provider switching test complete!")
# Show summary
print("\n📊 Summary:")
print(f" Providers tested: {len(providers_to_test)}")
print(" Available providers include: dashscope (qwen/bailian), siliconflow, doubao, kimi, moonshot, deepseek")
if len(providers_to_test) < 3:
print("\n💡 Tip: Configure more API keys to test all providers")
if __name__ == "__main__":
test_provider_switching()
@@ -0,0 +1,87 @@
#!/usr/bin/env python3
"""
Test with a simpler task to diagnose the issue
"""
import os
import sys
import time
from _bootstrap import add_project_root
add_project_root()
from agent import ContextAwareAgent, ContextMode
def test_simple_task():
"""Test with a very simple task to check if the agent is working"""
print("\n" + "="*60)
print("🧪 SIMPLE TASK TEST")
print("="*60)
# Get API key
api_key = os.getenv("SILICONFLOW_API_KEY")
if not api_key:
print("❌ SILICONFLOW_API_KEY not found")
return
print("✅ API key found")
# Create agent
agent = ContextAwareAgent(api_key, ContextMode.FULL, provider="siliconflow")
print(f"✅ Agent created")
print(f" Model: {agent.model}")
# Very simple task - no tools needed
print("\n📝 Test 1: Simple question (no tools)")
task1 = "What is 2 + 2? Just tell me the answer. FINAL ANSWER: provide the result."
start = time.time()
print("Executing...")
try:
result = agent.execute_task(task1, max_iterations=1)
elapsed = time.time() - start
print(f"✅ Completed in {elapsed:.2f} seconds")
if result.get('final_answer'):
print(f" Answer: {result['final_answer'][:100]}")
print(f" Tool calls: {len(result['trajectory'].tool_calls)}")
except Exception as e:
print(f"❌ Error: {str(e)}")
return
# Task with a single tool
print("\n📝 Test 2: Simple calculation (with tool)")
task2 = "Use the calculate tool to compute 15 * 3. FINAL ANSWER: provide the result."
start = time.time()
print("Executing...")
try:
result = agent.execute_task(task2, max_iterations=2)
elapsed = time.time() - start
print(f"✅ Completed in {elapsed:.2f} seconds")
if result.get('final_answer'):
print(f" Answer: {result['final_answer'][:100]}")
print(f" Tool calls: {len(result['trajectory'].tool_calls)}")
except KeyboardInterrupt:
print("\n⚠️ Interrupted by user")
print("The model might be taking too long to respond.")
print("\nSuggestions:")
print("1. Try using --provider doubao for faster responses")
print("2. Check your internet connection")
print("3. The model might be overloaded - try again later")
except Exception as e:
print(f"❌ Error: {str(e)}")
print("\n" + "="*60)
if __name__ == "__main__":
test_simple_task()
@@ -0,0 +1,85 @@
#!/usr/bin/env python3
"""
Demo script showing conversation history persistence
"""
import os
from _bootstrap import add_project_root
add_project_root()
from dotenv import load_dotenv
from agent import ContextAwareAgent, ContextMode
# Load environment variables
load_dotenv()
def main():
# Get API key (use any available provider)
if os.getenv("ARK_API_KEY"):
api_key, provider = os.getenv("ARK_API_KEY"), "doubao"
elif os.getenv("DASHSCOPE_API_KEY"):
api_key, provider = os.getenv("DASHSCOPE_API_KEY"), "dashscope"
elif os.getenv("MOONSHOT_API_KEY"):
api_key, provider = os.getenv("MOONSHOT_API_KEY"), "kimi"
elif os.getenv("DEEPSEEK_API_KEY"):
api_key, provider = os.getenv("DEEPSEEK_API_KEY"), "deepseek"
elif os.getenv("SILICONFLOW_API_KEY"):
api_key, provider = os.getenv("SILICONFLOW_API_KEY"), "siliconflow"
else:
api_key, provider = None, None
if not api_key:
print("❌ No API key found. Please set one of:")
print(" - ARK_API_KEY")
print(" - DASHSCOPE_API_KEY")
print(" - MOONSHOT_API_KEY")
print(" - DEEPSEEK_API_KEY")
print(" - SILICONFLOW_API_KEY")
return
print("🎭 Conversation History Demo")
print("=" * 50)
print(f"Provider: {provider.upper()}")
print("-" * 50)
# Create agent
agent = ContextAwareAgent(
api_key=api_key,
provider=provider,
context_mode=ContextMode.FULL,
verbose=False
)
# Conversation 1: Set context
print("\n💬 Turn 1: Setting context...")
result = agent.execute_task("My name is Alice and I have a budget of $5,000. What is 20% of my budget?")
print(f"Agent: {result.get('final_answer', 'No answer')}")
# Conversation 2: Reference previous context
print("\n💬 Turn 2: Referencing previous context...")
result = agent.execute_task("Convert that 20% amount to EUR please.")
print(f"Agent: {result.get('final_answer', 'No answer')}")
# Conversation 3: Recall information
print("\n💬 Turn 3: Recalling information...")
result = agent.execute_task("What was my name and total budget that I mentioned?")
print(f"Agent: {result.get('final_answer', 'No answer')}")
print("\n" + "-" * 50)
print(f"📊 Final Statistics:")
print(f" Total messages in history: {len(agent.conversation_history)}")
print(f" Total tool calls made: {len(agent.trajectory.tool_calls)}")
# Show that system prompt is unchanged
system_prompt = agent.conversation_history[0]['content']
if "Alice" not in system_prompt and "5000" not in system_prompt:
print(" ✅ System prompt remained unchanged")
else:
print(" ❌ System prompt was modified")
print("\n✨ Demo complete!")
if __name__ == "__main__":
main()
+114
View File
@@ -0,0 +1,114 @@
#!/usr/bin/env python3
"""
Quick Start Script for Context-Aware Agent
Run this to test the agent with a simple example
"""
import os
import sys
from _bootstrap import add_project_root
add_project_root()
from agent import ContextAwareAgent, ContextMode
from config import Config
def main():
"""Quick start demonstration"""
print("\n" + "="*60)
print("CONTEXT-AWARE AGENT - QUICK START")
print("="*60)
# Check for API key
api_key = os.getenv("SILICONFLOW_API_KEY")
if not api_key:
print("\n❌ ERROR: SILICONFLOW_API_KEY not found!")
print("\nPlease set your API key:")
print("1. Copy env.example to .env")
print("2. Add your API key to .env")
print("3. Or export SILICONFLOW_API_KEY=your_key_here")
sys.exit(1)
print("\n✅ API key found!")
# Simple demonstration task
demo_task = """
Please help me with the following financial calculation:
1. I have $10,000 USD that I want to convert to EUR, GBP, and JPY
2. Calculate the average amount across all three currencies (converted back to USD)
3. If I invest this average amount with a 5% annual return, what will it be worth in 2 years?
Show all your calculations step by step.
"""
print("\n📋 Demo Task:")
print("-"*40)
print(demo_task)
print("-"*40)
# Run with full context (baseline)
print("\n🚀 Running agent with FULL context...")
agent_full = ContextAwareAgent(api_key, ContextMode.FULL)
result_full = agent_full.execute_task(demo_task)
print("\n✨ Results with FULL Context:")
print(f"Success: {result_full.get('success', False)}")
print(f"Tool calls made: {len(result_full['trajectory'].tool_calls)}")
print(f"Iterations: {result_full.get('iterations', 0)}")
if result_full.get('final_answer'):
print(f"\nFinal Answer:")
print("-"*40)
print(result_full['final_answer'])
# Demonstrate context ablation effect
print("\n" + "="*60)
print("DEMONSTRATING CONTEXT ABLATION")
print("="*60)
print("\n🔬 Running same task with NO TOOL RESULTS context...")
print("(Agent won't see the results of its tool calls)")
agent_ablated = ContextAwareAgent(api_key, ContextMode.NO_TOOL_RESULTS)
result_ablated = agent_ablated.execute_task(demo_task)
print("\n⚠️ Results with NO TOOL RESULTS:")
print(f"Success: {result_ablated.get('success', False)}")
print(f"Tool calls made: {len(result_ablated['trajectory'].tool_calls)}")
print(f"Iterations: {result_ablated.get('iterations', 0)}")
if result_ablated.get('final_answer'):
print(f"\nFinal Answer (likely incorrect):")
print("-"*40)
print(result_ablated['final_answer'][:500] + "...")
# Summary
print("\n" + "="*60)
print("COMPARISON SUMMARY")
print("="*60)
print("\n📊 Key Observations:")
print(f"1. Full Context: {'✅ Success' if result_full.get('success') else '❌ Failed'}")
print(f"2. No Tool Results: {'✅ Success' if result_ablated.get('success') else '❌ Failed'}")
print(f"3. Efficiency difference: {result_ablated.get('iterations', 0) - result_full.get('iterations', 0)} more iterations without tool results")
print("\n💡 Insight:")
print("Without seeing tool results, the agent operates blind and may:")
print("- Make incorrect calculations")
print("- Repeat operations unnecessarily")
print("- Fail to validate its work")
print("\n" + "="*60)
print("Quick start complete! 🎉")
print("\nNext steps:")
print("1. Run full ablation study: python main.py --mode ablation")
print("2. Try interactive mode: python main.py --mode interactive")
print("3. Read the README.md for more details")
print("="*60 + "\n")
if __name__ == "__main__":
main()
@@ -0,0 +1,86 @@
#!/usr/bin/env python3
"""
Demo script to showcase sample tasks with PDF functionality
"""
import os
import sys
from pathlib import Path
from _bootstrap import add_project_root
add_project_root()
from main import get_sample_tasks, ensure_sample_pdfs
def main():
"""Demo the sample tasks"""
print("\n" + "="*60)
print("🎯 CONTEXT-AWARE AGENT - SAMPLE TASKS DEMO")
print("="*60)
# Ensure PDFs exist
print("\n📄 Checking for sample PDFs...")
if ensure_sample_pdfs():
print("✅ Sample PDFs are ready!")
else:
print("⚠️ Could not create sample PDFs, will use online alternatives")
# Get sample tasks
tasks = get_sample_tasks()
print(f"\n📋 Found {len(tasks)} sample tasks:")
print("-"*60)
for i, task in enumerate(tasks, 1):
print(f"\n{i}. {task['name']}")
print(f" 📝 {task['description']}")
print(f" 📊 Complexity: {'' * (i if i <= 3 else 3)}")
# Show a preview of the task
task_preview = task['task'].replace('\n', ' ')[:100] + "..."
print(f" 💬 Preview: {task_preview}")
print("\n" + "="*60)
print("💡 USAGE TIPS:")
print("-"*60)
print("1. Run 'python main.py' to enter interactive mode")
print("2. Type 'sample 2' to test PDF parsing capabilities")
print("3. Type 'sample 5' for the most comprehensive test")
print("4. Switch modes with 'mode no_reasoning' to see ablation effects")
print("\n" + "="*60)
print("🔬 ABLATION TESTING:")
print("-"*60)
print("Try running the same task in different modes:")
print(" • full - Everything works perfectly")
print(" • no_history - Agent forgets what it did")
print(" • no_reasoning - No planning, chaotic execution")
print(" • no_tool_calls - Can't do anything!")
print(" • no_tool_results - Works blind, gets confused")
print("\n" + "="*60)
print("📊 PDF TASKS:")
print("-"*60)
# Check if local PDFs exist
pdf_dir = Path("fixtures/pdfs")
if pdf_dir.exists():
pdfs = list(pdf_dir.glob("*.pdf"))
if pdfs:
print(f"✅ Found {len(pdfs)} local PDF files:")
for pdf in pdfs:
print(f"{pdf.name}")
print("\nTask #2 will use these local PDFs for testing.")
else:
print("⚠️ No PDFs found in fixtures/pdfs/")
else:
print("📥 PDF directory not found. Run 'create_pdfs' command to generate samples.")
print("\n" + "="*60)
print("Ready to test! Run 'python main.py' to start.")
print("="*60 + "\n")
if __name__ == "__main__":
main()
+305
View File
@@ -0,0 +1,305 @@
#!/usr/bin/env python3
"""
Test script for Context-Aware Agent
Validates installation and basic functionality
"""
import sys
from agent import ContextAwareAgent, ContextMode, ToolRegistry
import unittest
from unittest.mock import MagicMock, patch
class TestToolRegistry(unittest.TestCase):
"""Test the tool registry functions"""
def test_calculator(self):
"""Test calculator tool"""
tools = ToolRegistry()
# Basic arithmetic
result = tools.calculate("2 + 2")
self.assertEqual(result["result"], 4)
# Complex expression
result = tools.calculate("(10 * 5) + (20 / 4)")
self.assertEqual(result["result"], 55.0)
# With math functions
result = tools.calculate("sqrt(16) + abs(-5)")
self.assertEqual(result["result"], 9.0)
def test_currency_converter(self):
"""Test currency conversion tool"""
tools = ToolRegistry()
# USD to EUR
result = tools.convert_currency(100, "USD", "EUR")
self.assertIn("converted_amount", result)
self.assertIn("exchange_rate", result)
self.assertGreater(result["converted_amount"], 0)
# Currency symbol normalization (US$, S$, A$, C$, $)
result_us = tools.convert_currency(100, "US$", "EUR")
self.assertEqual(result_us["from_currency"], "USD")
self.assertEqual(result_us["converted_amount"], 92.0)
result_s = tools.convert_currency(100, "S$", "USD")
self.assertEqual(result_s["from_currency"], "SGD")
self.assertIn("converted_amount", result_s)
result_a = tools.convert_currency(100, "A$", "USD")
self.assertEqual(result_a["from_currency"], "AUD")
self.assertIn("converted_amount", result_a)
result_c = tools.convert_currency(100, "C$", "USD")
self.assertEqual(result_c["from_currency"], "CAD")
self.assertIn("converted_amount", result_c)
# Invalid currency
result = tools.convert_currency(100, "XXX", "YYY")
self.assertIn("error", result)
result_invalid_s = tools.convert_currency(100, "S$INVALID", "USD")
self.assertIn("error", result_invalid_s)
def test_convert_currency_string_and_formatted_amounts(self):
"""
Prove that convert_currency accepts string and formatted numeric amounts.
LLM tool calls frequently pass numeric arguments as strings (e.g., "100", "$1,000.00").
Previously, passing a string raised a TypeError during float division. This test locks
out regressions by asserting that numeric strings and formatted currency strings convert correctly.
"""
tools = ToolRegistry()
result_str = tools.convert_currency("100", "USD", "EUR")
self.assertEqual(result_str["converted_amount"], 92.0)
self.assertEqual(result_str["original_amount"], 100.0)
result_formatted = tools.convert_currency("$1,000.00", "USD", "EUR")
self.assertEqual(result_formatted["converted_amount"], 920.0)
self.assertEqual(result_formatted["original_amount"], 1000.0)
result_us_dollar = tools.convert_currency("US$100", "USD", "EUR")
self.assertEqual(result_us_dollar["converted_amount"], 92.0)
self.assertEqual(result_us_dollar["original_amount"], 100.0)
result_currency_code = tools.convert_currency("USD$1,000", "USD$", "EUR")
self.assertEqual(result_currency_code["converted_amount"], 920.0)
self.assertEqual(result_currency_code["original_amount"], 1000.0)
result_comma_large = tools.convert_currency("1,234,567.89", "USD", "EUR")
self.assertEqual(result_comma_large["original_amount"], 1234567.89)
result_euro_sym = tools.convert_currency("€ 500.25", "EUR", "USD")
self.assertIn("converted_amount", result_euro_sym)
result_invalid_str = tools.convert_currency("invalid_str", "USD", "EUR")
self.assertIn("error", result_invalid_str)
def test_pdf_parser_structure(self):
"""Test PDF parser structure (without actual PDF)"""
tools = ToolRegistry()
# Test with invalid URL (should handle gracefully)
result = tools.parse_pdf("http://invalid-url-for-testing.com/test.pdf")
self.assertIn("error", result)
class TestContextModes(unittest.TestCase):
"""Test different context modes"""
@patch.dict('os.environ', {'SILICONFLOW_API_KEY': 'test_key'})
def setUp(self):
"""Set up test fixtures"""
self.api_key = "test_key"
def test_context_mode_initialization(self):
"""Test agent initialization with different context modes"""
for mode in ContextMode:
agent = ContextAwareAgent(self.api_key, mode)
self.assertEqual(agent.context_mode, mode)
self.assertEqual(agent.trajectory.context_mode, mode)
def test_context_building(self):
"""Test context building for different modes"""
# Full context mode
agent = ContextAwareAgent(self.api_key, ContextMode.FULL)
agent.trajectory.reasoning_steps = ["Step 1", "Step 2"]
agent.trajectory.tool_calls.append(
MagicMock(tool_name="test", arguments={}, result={"test": "result"})
)
context = agent._build_context()
self.assertIn("Previous Reasoning Steps", context)
self.assertIn("Tool Call History", context)
# No reasoning mode
agent_no_reasoning = ContextAwareAgent(self.api_key, ContextMode.NO_REASONING)
agent_no_reasoning.trajectory.reasoning_steps = ["Step 1"]
context = agent_no_reasoning._build_context()
self.assertNotIn("Previous Reasoning Steps", context)
# No history mode
agent_no_history = ContextAwareAgent(self.api_key, ContextMode.NO_HISTORY)
agent_no_history.trajectory.tool_calls.append(
MagicMock(tool_name="test", arguments={}, result={"test": "result"})
)
context = agent_no_history._build_context()
self.assertEqual(context, "")
class TestAblationScenarios(unittest.TestCase):
"""Test ablation scenarios"""
def test_tool_execution(self):
"""Test tool execution"""
agent = ContextAwareAgent("test_key", ContextMode.FULL)
# Test calculator execution
result = agent._execute_tool("calculate", {"expression": "2 + 2"})
self.assertEqual(result["result"], 4)
# Test unknown tool
result = agent._execute_tool("unknown_tool", {})
self.assertIn("error", result)
def test_trajectory_reset(self):
"""Test trajectory reset"""
agent = ContextAwareAgent("test_key", ContextMode.FULL)
# Add some data to trajectory
agent.trajectory.reasoning_steps.append("Test step")
agent.trajectory.tool_calls.append(
MagicMock(tool_name="test", arguments={})
)
# Reset
agent.reset()
# Check if cleared
self.assertEqual(len(agent.trajectory.reasoning_steps), 0)
self.assertEqual(len(agent.trajectory.tool_calls), 0)
self.assertEqual(agent.trajectory.context_mode, ContextMode.FULL)
def run_integration_test():
"""Run a simple integration test"""
print("\n" + "="*60)
print("INTEGRATION TEST")
print("="*60)
# Check if API key is available
import os
api_key = os.getenv("SILICONFLOW_API_KEY")
if not api_key:
print("⚠️ Skipping integration test (no API key found)")
print("Set SILICONFLOW_API_KEY to run integration tests")
return False
print("✅ API key found, running integration test...")
try:
# Create agent
agent = ContextAwareAgent(api_key, ContextMode.FULL)
# Simple task that doesn't require external PDFs
simple_task = "Calculate: What is 15% of $2500? Then convert the result to EUR."
print(f"\nTest task: {simple_task}")
print("Running...")
# Execute with timeout
import signal
def timeout_handler(signum, frame):
raise TimeoutError("Integration test timed out")
# Set 30 second timeout
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(30)
try:
result = agent.execute_task(simple_task, max_iterations=3)
signal.alarm(0) # Cancel alarm
print("\n✅ Integration test completed!")
print(f"Success: {result.get('success', False)}")
print(f"Tool calls: {len(result['trajectory'].tool_calls)}")
if result.get('final_answer'):
print(f"Answer preview: {result['final_answer'][:100]}...")
return True
except TimeoutError:
print("❌ Integration test timed out")
return False
except Exception as e:
print(f"❌ Integration test failed: {str(e)}")
return False
def main():
"""Main test runner"""
print("\n" + "="*60)
print("CONTEXT-AWARE AGENT TEST SUITE")
print("="*60)
# Run unit tests
print("\n📋 Running unit tests...")
# Create test suite
loader = unittest.TestLoader()
suite = unittest.TestSuite()
# Add test cases
suite.addTests(loader.loadTestsFromTestCase(TestToolRegistry))
suite.addTests(loader.loadTestsFromTestCase(TestContextModes))
suite.addTests(loader.loadTestsFromTestCase(TestAblationScenarios))
# Run tests
runner = unittest.TextTestRunner(verbosity=2)
result = runner.run(suite)
# Summary
print("\n" + "="*60)
print("UNIT TEST SUMMARY")
print("="*60)
print(f"Tests run: {result.testsRun}")
print(f"Failures: {len(result.failures)}")
print(f"Errors: {len(result.errors)}")
if result.wasSuccessful():
print("✅ All unit tests passed!")
else:
print("❌ Some tests failed")
sys.exit(1)
# Run integration test if possible
print("\n" + "="*60)
integration_success = run_integration_test()
# Final summary
print("\n" + "="*60)
print("FINAL TEST SUMMARY")
print("="*60)
if result.wasSuccessful():
print("✅ Unit tests: PASSED")
else:
print("❌ Unit tests: FAILED")
if integration_success:
print("✅ Integration test: PASSED")
else:
print("⚠️ Integration test: SKIPPED or FAILED")
print("\n🎉 Testing complete!")
print("="*60 + "\n")
return 0 if result.wasSuccessful() else 1
if __name__ == "__main__":
sys.exit(main())
@@ -0,0 +1,125 @@
#!/usr/bin/env python3
"""
Test the code_interpreter tool with the agent
"""
import os
from agent import ContextAwareAgent, ContextMode
def test_code_interpreter():
"""Test code interpreter integration"""
print("\n" + "="*60)
print("🧪 CODE INTERPRETER TEST")
print("="*60)
# Check API key
api_key = os.getenv("SILICONFLOW_API_KEY")
if not api_key:
print("⚠️ No API key set, using mock test")
# Test just the tool directly
from agent import ToolRegistry
tools = ToolRegistry()
code = """
# Calculate total expenses
expenses_usd = {
'US Office': 2500000,
'UK Office (converted)': 2278481.01,
'Japan Office (converted)': 2541806.02,
'EU Office (converted)': 2282608.70,
'Singapore Office (converted)': 2388059.70
}
# Calculate total
total = sum(expenses_usd.values())
# Calculate percentages
for office, amount in expenses_usd.items():
percentage = (amount / total) * 100
print(f"{office}: ${amount:,.2f} ({percentage:.2f}%)")
print(f"\\nTotal Expenses: ${total:,.2f}")
# Calculate after 12% reduction
reduced_total = total * 0.88
savings = total - reduced_total
print(f"After 12% reduction: ${reduced_total:,.2f}")
print(f"Savings: ${savings:,.2f}")
result = {
'total': total,
'reduced': reduced_total,
'savings': savings
}
"""
result = tools.code_interpreter(code)
if result['success']:
print("✅ Code interpreter executed successfully!")
print("\nOutput:")
print(result['output'])
print(f"\nResult dictionary: {result['result']}")
else:
print(f"❌ Error: {result['error']}")
return
# Test with full agent
agent = ContextAwareAgent(api_key, ContextMode.FULL)
task = """
Calculate the following:
Given these expenses:
- US: $2,500,000
- UK: $2,278,481
- Japan: $2,541,806
- EU: $2,282,609
- Singapore: $2,388,060
Use the code_interpreter tool to:
1. Calculate the total expenses
2. Calculate what percentage each office represents
3. Calculate the new totals if we apply a 12% cost reduction
FINAL ANSWER: Provide the total, the percentage breakdown, and the reduced total.
"""
print("Running task with agent...")
print("Task: Calculate totals and percentages using code_interpreter")
print("-"*40)
result = agent.execute_task(task, max_iterations=3)
print(f"\nSuccess: {result.get('success', False)}")
print(f"Tool calls made: {len(result['trajectory'].tool_calls)}")
# Check if code_interpreter was used
code_interpreter_used = any(
tc.tool_name == 'code_interpreter'
for tc in result['trajectory'].tool_calls
)
if code_interpreter_used:
print("✅ Code interpreter was used!")
# Show the code that was executed
for tc in result['trajectory'].tool_calls:
if tc.tool_name == 'code_interpreter':
print("\nExecuted code:")
print("-"*40)
print(tc.arguments.get('code', 'N/A'))
print("-"*40)
if tc.result and tc.result.get('output'):
print("\nOutput:")
print(tc.result['output'])
else:
print("⚠️ Code interpreter was not used")
if result.get('final_answer'):
print("\n📝 Final Answer:")
print(result['final_answer'])
if __name__ == "__main__":
test_code_interpreter()
@@ -0,0 +1,74 @@
"""Regression: malformed tool-argument JSON must not abort the ReAct loop."""
from types import SimpleNamespace
from unittest.mock import MagicMock
from agent import ContextAwareAgent, ContextMode
def _choice(*, content=None, tool_calls=None):
msg = SimpleNamespace(
content=content,
tool_calls=tool_calls,
reasoning_content=None,
model_dump=lambda: {
"role": "assistant",
"content": content,
"tool_calls": [
{
"id": tc.id,
"type": "function",
"function": {
"name": tc.function.name,
"arguments": tc.function.arguments,
},
}
for tc in (tool_calls or [])
],
},
)
return SimpleNamespace(message=msg)
def test_execute_task_survives_malformed_tool_arguments_json():
agent = ContextAwareAgent("test-key", ContextMode.FULL, verbose=False)
bad_call = SimpleNamespace(
id="call-bad",
function=SimpleNamespace(
name="calculate",
arguments='{"expression": "1+1",}', # trailing comma
),
)
tool_turn = SimpleNamespace(choices=[_choice(tool_calls=[bad_call])])
final_turn = SimpleNamespace(
choices=[_choice(content="FINAL ANSWER: recovered")]
)
agent.client = MagicMock()
agent.client.chat.completions.create = MagicMock(
side_effect=[tool_turn, final_turn]
)
result = agent.execute_task("compute", max_iterations=5)
assert result.get("error") is None
assert result["completed"] is True
assert result["task_success"] is None
assert result["success"] is True # backwards-compatible completion alias
assert "recovered" in (result.get("final_answer") or result.get("answer") or "")
tool_roles = [m for m in agent.conversation_history if m.get("role") == "tool"]
assert tool_roles
assert "Invalid tool arguments" in tool_roles[0]["content"]
assert agent.client.chat.completions.create.call_count == 2
def test_execute_task_does_not_complete_on_empty_terminal_content():
agent = ContextAwareAgent("test-key", ContextMode.NO_TOOL_CALLS, verbose=False)
empty_turn = SimpleNamespace(choices=[_choice(content="")])
agent.client = MagicMock()
agent.client.chat.completions.create = MagicMock(return_value=empty_turn)
result = agent.execute_task("say something", max_iterations=5)
assert result["final_answer"] is None
assert result["completed"] is False
assert result["task_success"] is None
assert result["success"] is False