connectonion 0.4.12__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. connectonion/__init__.py +11 -5
  2. connectonion/agent.py +44 -42
  3. connectonion/cli/commands/init.py +1 -1
  4. connectonion/cli/commands/project_cmd_lib.py +4 -4
  5. connectonion/cli/commands/reset_commands.py +1 -1
  6. connectonion/cli/docs/co-vibecoding-principles-docs-contexts-all-in-one.md +15 -11
  7. connectonion/cli/templates/minimal/agent.py +2 -2
  8. connectonion/console.py +55 -3
  9. connectonion/events.py +96 -17
  10. connectonion/llm.py +21 -3
  11. connectonion/logger.py +289 -0
  12. connectonion/prompt_files/eval_expected.md +12 -0
  13. connectonion/tool_executor.py +43 -32
  14. connectonion/usage.py +4 -0
  15. connectonion/useful_events_handlers/reflect.py +13 -9
  16. connectonion/useful_plugins/__init__.py +2 -1
  17. connectonion/useful_plugins/calendar_plugin.py +2 -2
  18. connectonion/useful_plugins/eval.py +130 -0
  19. connectonion/useful_plugins/gmail_plugin.py +4 -4
  20. connectonion/useful_plugins/image_result_formatter.py +4 -3
  21. connectonion/useful_plugins/re_act.py +14 -56
  22. connectonion/useful_plugins/shell_approval.py +2 -2
  23. connectonion/useful_tools/memory.py +4 -0
  24. {connectonion-0.4.12.dist-info → connectonion-0.5.0.dist-info}/METADATA +48 -48
  25. {connectonion-0.4.12.dist-info → connectonion-0.5.0.dist-info}/RECORD +27 -71
  26. {connectonion-0.4.12.dist-info → connectonion-0.5.0.dist-info}/WHEEL +1 -2
  27. connectonion/cli/templates/email-agent/.env.example +0 -23
  28. connectonion/cli/templates/email-agent/README.md +0 -240
  29. connectonion/cli/templates/email-agent/agent.py +0 -374
  30. connectonion/cli/templates/email-agent/demo.py +0 -71
  31. connectonion/cli/templates/meta-agent/.env.example +0 -11
  32. connectonion/cli/templates/minimal/.env.example +0 -5
  33. connectonion/cli/templates/playwright/.env.example +0 -5
  34. connectonion-0.4.12.dist-info/top_level.txt +0 -2
  35. tests/__init__.py +0 -0
  36. tests/cli/__init__.py +0 -1
  37. tests/cli/argparse_runner.py +0 -85
  38. tests/cli/conftest.py +0 -5
  39. tests/cli/test_browser_cli.py +0 -61
  40. tests/cli/test_cli.py +0 -143
  41. tests/cli/test_cli_auth_google.py +0 -344
  42. tests/cli/test_cli_auth_microsoft.py +0 -256
  43. tests/cli/test_cli_create.py +0 -283
  44. tests/cli/test_cli_help.py +0 -200
  45. tests/cli/test_cli_init.py +0 -318
  46. tests/conftest.py +0 -283
  47. tests/debug_gemini_models.py +0 -23
  48. tests/fixtures/__init__.py +0 -1
  49. tests/fixtures/test_tools.py +0 -112
  50. tests/fixtures/trust_fixtures.py +0 -257
  51. tests/real_api/__init__.py +0 -0
  52. tests/real_api/conftest.py +0 -9
  53. tests/real_api/test_llm_do.py +0 -174
  54. tests/real_api/test_llm_do_comprehensive.py +0 -527
  55. tests/real_api/test_production_client.py +0 -94
  56. tests/real_api/test_real_anthropic.py +0 -100
  57. tests/real_api/test_real_api.py +0 -113
  58. tests/real_api/test_real_auth.py +0 -130
  59. tests/real_api/test_real_email.py +0 -95
  60. tests/real_api/test_real_gemini.py +0 -96
  61. tests/real_api/test_real_llm_do.py +0 -81
  62. tests/real_api/test_real_managed.py +0 -208
  63. tests/real_api/test_real_multi_llm.py +0 -454
  64. tests/real_api/test_real_openai.py +0 -100
  65. tests/real_api/test_responses_parse.py +0 -88
  66. tests/test_diff_writer.py +0 -126
  67. tests/test_events.py +0 -677
  68. tests/test_gemini_co.py +0 -70
  69. tests/test_image_result_formatter.py +0 -88
  70. tests/test_plugin_system.py +0 -110
  71. tests/utils/__init__.py +0 -1
  72. tests/utils/config_helpers.py +0 -188
  73. tests/utils/mock_helpers.py +0 -237
  74. {connectonion-0.4.12.dist-info → connectonion-0.5.0.dist-info}/entry_points.txt +0 -0
@@ -1,94 +0,0 @@
1
- """Test connectonion client against production API"""
2
- import os
3
- import time
4
- import requests
5
- from pydantic import BaseModel
6
- from nacl.signing import SigningKey
7
- from nacl.encoding import HexEncoder
8
- from connectonion import llm_do
9
-
10
-
11
- # Production URL
12
- PRODUCTION_URL = "http://3.24.102.245"
13
-
14
-
15
- class EmailDraft(BaseModel):
16
- """Email draft with subject and body"""
17
- subject: str
18
- body: str
19
-
20
-
21
- def get_test_token():
22
- """Generate test auth token for production backend"""
23
- signing_key = SigningKey.generate()
24
- public_key = "0x" + signing_key.verify_key.encode(encoder=HexEncoder).decode()
25
- timestamp = int(time.time())
26
- message = f"ConnectOnion-Auth-{public_key}-{timestamp}"
27
- signature = signing_key.sign(message.encode()).signature.hex()
28
-
29
- response = requests.post(
30
- f"{PRODUCTION_URL}/api/v1/auth",
31
- json={
32
- "public_key": public_key,
33
- "message": message,
34
- "signature": signature
35
- }
36
- )
37
-
38
- if response.status_code != 200:
39
- raise Exception(f"Auth failed: {response.status_code} - {response.text}")
40
-
41
- return response.json()["token"]
42
-
43
-
44
- def test_production_llm_do_structured():
45
- """Test llm_do() with structured output against production API"""
46
- print("\n" + "=" * 80)
47
- print("TESTING CONNECTONION CLIENT AGAINST PRODUCTION")
48
- print(f"Target: {PRODUCTION_URL}")
49
- print("=" * 80)
50
-
51
- # Point to production instead of localhost
52
- os.environ["OPENONION_API_URL"] = PRODUCTION_URL
53
-
54
- # Get auth token from production
55
- token = get_test_token()
56
- os.environ["OPENONION_API_KEY"] = token
57
-
58
- print("\n✓ Authentication successful")
59
- print(f" Using production API: {PRODUCTION_URL}")
60
-
61
- # Test structured output with co/ model
62
- print("\nTesting llm_do() with structured output (EmailDraft)...")
63
- draft = llm_do(
64
- "Write a friendly hello email to a new colleague",
65
- output=EmailDraft,
66
- temperature=0.7,
67
- model="co/gpt-4o-mini"
68
- )
69
-
70
- # Verify we got a valid Pydantic model
71
- assert isinstance(draft, EmailDraft)
72
- assert isinstance(draft.subject, str)
73
- assert isinstance(draft.body, str)
74
- assert len(draft.subject) > 0
75
- assert len(draft.body) > 0
76
-
77
- print("\n✓ Structured output test PASSED!")
78
- print(f" Subject: {draft.subject}")
79
- print(f" Body preview: {draft.body[:150]}...")
80
-
81
- print("\n" + "=" * 80)
82
- print("✅ CONNECTONION CLIENT WORKS WITH PRODUCTION API!")
83
- print(" Issue #9 is fully resolved in production")
84
- print("=" * 80)
85
-
86
-
87
- if __name__ == "__main__":
88
- try:
89
- test_production_llm_do_structured()
90
- except Exception as e:
91
- print(f"\n❌ Production client test failed: {e}")
92
- import traceback
93
- traceback.print_exc()
94
- exit(1)
@@ -1,100 +0,0 @@
1
- """
2
- Real Anthropic API tests.
3
-
4
- These tests make actual API calls to Anthropic and cost real money.
5
- Run with: pytest test_real_anthropic.py -v
6
-
7
- Requires: ANTHROPIC_API_KEY environment variable
8
- """
9
-
10
- import os
11
- import pytest
12
- from pathlib import Path
13
- from dotenv import load_dotenv
14
- from connectonion import Agent
15
- from connectonion.llm import AnthropicLLM
16
-
17
- # Load environment variables from tests/.env
18
- env_path = Path(__file__).parent / ".env"
19
- if env_path.exists():
20
- load_dotenv(env_path)
21
-
22
-
23
- def text_processor(text: str) -> str:
24
- """Simple text processor for testing."""
25
- return f"Processed: {text.upper()}"
26
-
27
-
28
- class TestRealAnthropic:
29
- """Test real Anthropic API integration."""
30
-
31
- def test_anthropic_basic_completion(self):
32
- """Test basic completion with Anthropic."""
33
- llm = AnthropicLLM(model="claude-3-5-haiku-latest")
34
- agent = Agent(name="anthropic_test", llm=llm)
35
-
36
- response = agent.input("Say 'Hello from Claude' exactly")
37
- assert response is not None
38
- assert "Hello from Claude" in response
39
-
40
- def test_anthropic_with_tools(self):
41
- """Test Anthropic with tool calling."""
42
- agent = Agent(
43
- name="anthropic_tools",
44
- model="claude-3-5-haiku-latest",
45
- tools=[text_processor]
46
- )
47
-
48
- response = agent.input("Process the text 'hello world'")
49
- assert response is not None
50
- assert "HELLO WORLD" in response or "processed" in response.lower()
51
-
52
- def test_anthropic_multi_turn(self):
53
- """Test multi-turn conversation with Anthropic."""
54
- agent = Agent(
55
- name="anthropic_conversation",
56
- model="claude-3-5-haiku-latest"
57
- )
58
-
59
- # First turn
60
- response = agent.input("I'm learning Python. Remember this.")
61
- assert response is not None
62
-
63
- # Second turn - should remember context
64
- response = agent.input("What programming language am I learning?")
65
- assert response is not None
66
- assert "Python" in response
67
-
68
- def test_anthropic_different_models(self):
69
- """Test different Anthropic models."""
70
- models = [
71
- "claude-3-5-haiku-latest",
72
- "claude-3-5-sonnet-latest",
73
- ]
74
-
75
- for model in models:
76
- if "opus" in model and not os.getenv("TEST_EXPENSIVE_MODELS"):
77
- continue # Skip expensive models unless explicitly enabled
78
-
79
- agent = Agent(
80
- name=f"anthropic_{model.split('-')[2]}",
81
- model=model
82
- )
83
-
84
- response = agent.input("Reply with OK")
85
- assert response is not None
86
- assert len(response) > 0
87
-
88
- def test_anthropic_system_prompt(self):
89
- """Test Anthropic with custom system prompt."""
90
- agent = Agent(
91
- name="anthropic_system",
92
- model="claude-3-5-haiku-latest",
93
- system_prompt="You are a helpful poetry assistant. Always respond in haiku format."
94
- )
95
-
96
- response = agent.input("Tell me about the weather")
97
- assert response is not None
98
- # Check it's attempting haiku format (3 lines, roughly)
99
- lines = response.strip().split('\n')
100
- assert len(lines) >= 1 # At least has content
@@ -1,113 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Test with the actual deployed OpenOnion API."""
3
-
4
- import os
5
- import sys
6
- import requests
7
- from pathlib import Path
8
- from dotenv import load_dotenv
9
-
10
- # Load test environment
11
- env_path = Path(__file__).parent / '.env.test'
12
- if env_path.exists():
13
- load_dotenv(env_path)
14
-
15
- def test_deployed_api():
16
- """Test the actual deployed API endpoints."""
17
-
18
- print("\n" + "="*60)
19
- print("🌐 TESTING DEPLOYED OPENONION API")
20
- print("="*60)
21
-
22
- backend_url = "https://oo.openonion.ai"
23
-
24
- # Test 1: Health Check
25
- print("\n✅ Testing health endpoint...")
26
- response = requests.get(f"{backend_url}/health")
27
- if response.status_code == 200:
28
- data = response.json()
29
- print(f" Status: {data.get('status')}")
30
- print(f" Timestamp: {data.get('timestamp')}")
31
-
32
- # Test 2: Check available email endpoints
33
- print("\n📋 Available email endpoints:")
34
- endpoints = [
35
- "/api/email/send",
36
- "/api/email/webhook/incoming",
37
- "/api/email/tier",
38
- "/api/email/upgrade",
39
- "/api/email/received", # Admin endpoint
40
- "/api/emails", # New endpoint (if deployed)
41
- "/api/emails/mark-read" # New endpoint (if deployed)
42
- ]
43
-
44
- for endpoint in endpoints:
45
- # Try OPTIONS request to check if endpoint exists
46
- try:
47
- response = requests.options(f"{backend_url}{endpoint}", timeout=2)
48
- if response.status_code < 500:
49
- print(f" ✅ {endpoint} - Available")
50
- else:
51
- print(f" ❌ {endpoint} - Server error")
52
- except:
53
- print(f" ⚠️ {endpoint} - Not responding")
54
-
55
- # Test 3: Try to authenticate
56
- print("\n🔐 Testing authentication...")
57
-
58
- # Note: The deployed API might not accept test signatures
59
- auth_data = {
60
- "public_key": os.getenv("TEST_PUBLIC_KEY"),
61
- "message": "test_message",
62
- "signature": "test_signature"
63
- }
64
-
65
- response = requests.post(f"{backend_url}/auth", json=auth_data)
66
- if response.status_code == 200:
67
- print(" ✅ Authentication successful")
68
- token = response.json().get("token")
69
- if token:
70
- print(f" Token: {token[:30]}...")
71
- else:
72
- print(f" ⚠️ Authentication failed: {response.status_code}")
73
- if response.status_code == 400:
74
- print(" Note: Test signatures not accepted in production")
75
-
76
- # Test 4: Check if new endpoints are deployed
77
- print("\n🆕 Checking new email endpoints...")
78
-
79
- jwt_token = os.getenv("TEST_JWT_TOKEN")
80
- headers = {
81
- "Authorization": f"Bearer {jwt_token}",
82
- "Content-Type": "application/json"
83
- }
84
-
85
- # Try GET /api/emails
86
- response = requests.get(f"{backend_url}/api/emails", headers=headers)
87
- if response.status_code == 404:
88
- print(" ℹ️ GET /api/emails - Not deployed yet")
89
- print(" The new email inbox endpoints need to be deployed to production")
90
- elif response.status_code == 200:
91
- print(" ✅ GET /api/emails - Working!")
92
- data = response.json()
93
- print(f" Emails: {len(data.get('emails', []))}")
94
- else:
95
- print(f" ⚠️ GET /api/emails - Status: {response.status_code}")
96
-
97
- # Summary
98
- print("\n" + "="*60)
99
- print("📊 SUMMARY")
100
- print("="*60)
101
- print("\nThe deployed API has the following email capabilities:")
102
- print(" ✅ Send emails via /api/email/send")
103
- print(" ✅ Receive emails via webhook")
104
- print(" ✅ Email tier management")
105
- print("\nThe new inbox features (get_emails, mark_read) are:")
106
- print(" ⚠️ Implemented locally but not yet deployed")
107
- print("\nNext steps:")
108
- print(" 1. Deploy the updated oo-api with new endpoints")
109
- print(" 2. Test with real authentication flow")
110
- print(" 3. Verify email retrieval and marking as read")
111
-
112
- if __name__ == "__main__":
113
- test_deployed_api()
@@ -1,130 +0,0 @@
1
- """End-to-end test for ConnectOnion authentication with production API."""
2
-
3
- import time
4
- import json
5
- import requests
6
- from nacl.signing import SigningKey
7
- from nacl.encoding import HexEncoder
8
-
9
- def test_production_auth():
10
- """Test authentication against production API."""
11
-
12
- # Generate test keys
13
- signing_key = SigningKey.generate()
14
- public_key = "0x" + signing_key.verify_key.encode(encoder=HexEncoder).decode()
15
-
16
- # Create ConnectOnion format message
17
- timestamp = int(time.time())
18
- message = f"ConnectOnion-Auth-{public_key}-{timestamp}"
19
-
20
- # Sign the message
21
- signature = signing_key.sign(message.encode()).signature.hex()
22
-
23
- # Prepare request exactly as CLI does
24
- payload = {
25
- "public_key": public_key,
26
- "message": message,
27
- "signature": signature
28
- }
29
-
30
- print("Testing Production API Authentication")
31
- print("="*50)
32
- print(f"Public Key: {public_key[:20]}...")
33
- print(f"Message: {message[:50]}...")
34
- print(f"Timestamp: {timestamp}")
35
-
36
- # Test against production API
37
- api_url = "https://oo.openonion.ai/auth"
38
-
39
- try:
40
- print(f"\nCalling: POST {api_url}")
41
- response = requests.post(
42
- api_url,
43
- json=payload,
44
- timeout=10,
45
- headers={"Content-Type": "application/json"}
46
- )
47
-
48
- print(f"Response Status: {response.status_code}")
49
-
50
- if response.status_code == 200:
51
- data = response.json()
52
- print("✅ Authentication successful!")
53
- print(f" Token: {data.get('token', '')[:20]}...")
54
- print(f" Public Key Confirmed: {data.get('public_key', '')[:20]}...")
55
-
56
- # Test token validation
57
- if 'token' in data:
58
- validate_url = "https://oo.openonion.ai/api/validate"
59
- val_response = requests.get(
60
- validate_url,
61
- headers={"Authorization": f"Bearer {data['token']}"},
62
- timeout=5
63
- )
64
- if val_response.status_code == 200:
65
- print("✅ Token validation successful!")
66
- else:
67
- print(f"⚠️ Token validation failed: {val_response.status_code}")
68
-
69
- return True
70
- else:
71
- print(f"❌ Authentication failed: {response.status_code}")
72
- print(f" Response: {response.text[:200]}")
73
- return False
74
-
75
- except requests.exceptions.ConnectionError as e:
76
- print(f"❌ Connection failed: {e}")
77
- return False
78
- except Exception as e:
79
- print(f"❌ Unexpected error: {e}")
80
- return False
81
-
82
-
83
- def test_llm_models_endpoint():
84
- """Test that LLM models endpoint is accessible."""
85
-
86
- print("\n\nTesting LLM Models Endpoint")
87
- print("="*50)
88
-
89
- api_url = "https://oo.openonion.ai/api/llm/models"
90
-
91
- try:
92
- response = requests.get(api_url, timeout=5)
93
- print(f"Response Status: {response.status_code}")
94
-
95
- if response.status_code == 200:
96
- data = response.json()
97
- models = data.get("models", [])
98
- print(f"✅ Found {len(models)} models")
99
-
100
- # Check for co/ models
101
- co_models = [m for m in models if m.get("id", "").startswith("co/")]
102
- if co_models:
103
- print(f" Co/ models available: {len(co_models)}")
104
- for model in co_models[:3]: # Show first 3
105
- print(f" - {model.get('id')}: {model.get('name')}")
106
- return True
107
- else:
108
- print(f"❌ Failed to get models: {response.status_code}")
109
- return False
110
-
111
- except Exception as e:
112
- print(f"❌ Error: {e}")
113
- return False
114
-
115
-
116
- if __name__ == "__main__":
117
- print("ConnectOnion <-> OpenOnion Production API Test\n")
118
-
119
- auth_ok = test_production_auth()
120
- models_ok = test_llm_models_endpoint()
121
-
122
- print("\n" + "="*50)
123
- print("Test Results:")
124
- print(f" Authentication: {'✅ PASSED' if auth_ok else '❌ FAILED'}")
125
- print(f" LLM Models: {'✅ PASSED' if models_ok else '❌ FAILED'}")
126
-
127
- if auth_ok and models_ok:
128
- print("\n🎉 All tests passed! Integration is working.")
129
- else:
130
- print("\n⚠️ Some tests failed. Check the logs above.")
@@ -1,95 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Test email functionality with live backend - uses environment variables safely."""
3
-
4
- import os
5
- import sys
6
- from pathlib import Path
7
-
8
- # Add parent to path
9
- sys.path.insert(0, str(Path(__file__).parent.parent))
10
-
11
- from connectonion import send_email, get_emails, mark_read
12
- from tests.utils.config_helpers import ProjectHelper
13
-
14
-
15
- def test_live_email():
16
- """Test with deployed backend using environment variables."""
17
-
18
- print("\n🧪 Live Email Test")
19
- print("=" * 50)
20
-
21
- # Use environment variables - NEVER hardcode credentials!
22
- backend_url = os.getenv("CONNECTONION_BACKEND_URL", "https://oo.openonion.ai")
23
-
24
- # Check if we have required environment variables
25
- if not os.getenv("OPENAI_API_KEY"):
26
- print("⚠️ Please set OPENAI_API_KEY environment variable")
27
- print(" export OPENAI_API_KEY=your-key-here")
28
- return
29
-
30
- print(f"🌐 Using backend: {backend_url}")
31
-
32
- with ProjectHelper() as project_dir:
33
- print(f"📁 Test project: {project_dir}")
34
-
35
- # The test project already has the test account configured
36
- # Now test the functionality
37
-
38
- # Test 1: Check current inbox
39
- print("\n📥 Checking inbox...")
40
- emails = get_emails()
41
-
42
- if emails:
43
- print(f"✅ Found {len(emails)} emails")
44
- for i, email in enumerate(emails[:3], 1):
45
- print(f"\n Email {i}:")
46
- print(f" From: {email.get('from')}")
47
- print(f" Subject: {email.get('subject')}")
48
- print(f" Read: {email.get('read')}")
49
- else:
50
- print("📭 No emails in inbox")
51
-
52
- # Test 2: Send a test email
53
- print("\n📤 Sending test email...")
54
- result = send_email(
55
- to="test@example.com",
56
- subject="Test from ConnectOnion",
57
- message="This is a test email sent via the ConnectOnion API"
58
- )
59
-
60
- if result.get("success"):
61
- print(f"✅ Email sent successfully!")
62
- print(f" Message ID: {result.get('message_id')}")
63
- print(f" From: {result.get('from')}")
64
- else:
65
- print(f"⚠️ Send failed: {result.get('error')}")
66
-
67
- # Test 3: Mark emails as read
68
- if emails and len(emails) > 0:
69
- unread = [e for e in emails if not e.get('read')]
70
- if unread:
71
- print(f"\n✔️ Marking {len(unread)} emails as read...")
72
- for email in unread[:3]: # Mark up to 3
73
- success = mark_read(email['id'])
74
- if success:
75
- print(f" ✅ Marked {email['id']} as read")
76
- else:
77
- print(f" ⚠️ Failed to mark {email['id']}")
78
-
79
- print("\n" + "=" * 50)
80
- print("✅ Test completed")
81
- print("\n⚠️ Remember: NEVER commit API keys to version control!")
82
-
83
-
84
- if __name__ == "__main__":
85
- # Safety check
86
- if len(sys.argv) > 1 and sys.argv[1] == "--confirm":
87
- test_live_email()
88
- else:
89
- print("⚠️ This test connects to the live backend.")
90
- print(" Run with --confirm flag to proceed:")
91
- print(" python test_email_live.py --confirm")
92
- print("\n📝 Required environment variables:")
93
- print(" - OPENAI_API_KEY")
94
- print(" - CONNECTONION_BACKEND_URL (optional)")
95
- print("\n🔒 Security: Use environment variables, never hardcode keys!")
@@ -1,96 +0,0 @@
1
- """
2
- Real Google Gemini API tests.
3
-
4
- These tests make actual API calls to Google Gemini and cost real money.
5
- Run with: pytest test_real_gemini.py -v
6
-
7
- Requires: GEMINI_API_KEY environment variable (GOOGLE_API_KEY also supported for backward compatibility)
8
- """
9
-
10
- import os
11
- import pytest
12
- from pathlib import Path
13
- from dotenv import load_dotenv
14
- from connectonion import Agent
15
- from connectonion.llm import GeminiLLM
16
-
17
- # Load environment variables from tests/.env
18
- env_path = Path(__file__).parent / ".env"
19
- if env_path.exists():
20
- load_dotenv(env_path)
21
-
22
-
23
- def word_counter(text: str) -> str:
24
- """Count words in text for testing."""
25
- words = text.split()
26
- return f"Word count: {len(words)}"
27
-
28
-
29
- class TestRealGemini:
30
- """Test real Google Gemini API integration."""
31
-
32
- def test_gemini_basic_completion(self):
33
- """Test basic completion with Gemini."""
34
- api_key = os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY")
35
- llm = GeminiLLM(api_key=api_key, model="gemini-2.5-pro")
36
- agent = Agent(name="gemini_test", llm=llm)
37
-
38
- response = agent.input("Say 'Hello from Gemini' exactly")
39
- assert response is not None
40
- assert "Hello from Gemini" in response
41
-
42
- def test_gemini_with_tools(self):
43
- """Test Gemini with tool calling."""
44
- agent = Agent(
45
- name="gemini_tools",
46
- model="gemini-2.5-pro",
47
- tools=[word_counter]
48
- )
49
-
50
- response = agent.input("Count the words in 'The quick brown fox'")
51
- assert response is not None
52
- assert "4" in response or "four" in response.lower()
53
-
54
- def test_gemini_multi_turn(self):
55
- """Test multi-turn conversation with Gemini."""
56
- agent = Agent(
57
- name="gemini_conversation",
58
- model="gemini-2.5-pro"
59
- )
60
-
61
- # First turn
62
- response = agent.input("My favorite color is blue. Remember this.")
63
- assert response is not None
64
-
65
- # Second turn - should remember context
66
- response = agent.input("What's my favorite color?")
67
- assert response is not None
68
- assert "blue" in response.lower()
69
-
70
- def test_gemini_different_models(self):
71
- """Test different Gemini models."""
72
- models = ["gemini-2.5-pro", "gemini-2.5-flash"]
73
-
74
- for model in models:
75
-
76
- api_key = os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY")
77
- agent = Agent(
78
- name=f"gemini_{model.replace('.', '_').replace('-', '_')}",
79
- llm=GeminiLLM(api_key=api_key, model=model)
80
- )
81
-
82
- response = agent.input("Reply with OK")
83
- assert response is not None
84
- assert len(response) > 0
85
-
86
- def test_gemini_system_prompt(self):
87
- """Test Gemini with custom system prompt."""
88
- agent = Agent(
89
- name="gemini_system",
90
- model="gemini-2.5-pro",
91
- system_prompt="You are a helpful math tutor. Always explain your reasoning step by step."
92
- )
93
-
94
- response = agent.input("What is 2 + 2?")
95
- assert response is not None
96
- assert "4" in response or "four" in response.lower()