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
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:
@@ -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)
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user