Spaces:
Sleeping
Sleeping
Commit ·
aa73f1c
1
Parent(s): bed418d
Enhance README with detailed Google Custom Search API cost information and automatic fallback to DuckDuckGo. Introduce a new TEST_QUESTIONS.md file with comprehensive sample queries for various functionalities, including math, web search, and algorithms. Update agent configuration to improve news query handling and enhance calculator capabilities with natural language processing for percentages, divisions, and geometry queries. Improve logging for better debugging and user experience.
Browse files- README.md +54 -0
- TEST_QUESTIONS.md +696 -0
- config/agent_config.json +359 -6
- core/meetara_agent.py +624 -31
README.md
CHANGED
|
@@ -252,6 +252,41 @@ meeTARA Agent supports multiple search providers for web searches:
|
|
| 252 |
- Search Engine ID is not sensitive (designed to be public)
|
| 253 |
- No risk of hackers accessing your credentials through the Space URL
|
| 254 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 255 |
### Enabling Agent Mode
|
| 256 |
|
| 257 |
Agent Mode is **always enabled by default**. Just select your preferred model from the dropdown and ask questions:
|
|
@@ -261,6 +296,25 @@ Agent Mode is **always enabled by default**. Just select your preferred model fr
|
|
| 261 |
- **Combined**: *"What's 2^10 and search for news about quantum computing in 2025"*
|
| 262 |
- **Real-time**: *"Tell me current US stock trends and present day crypto prices"*
|
| 263 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 264 |
## 🚀 Usage
|
| 265 |
|
| 266 |
1. Click "Initialize" to load meeTARA (first time may take a few minutes to download models)
|
|
|
|
| 252 |
- Search Engine ID is not sensitive (designed to be public)
|
| 253 |
- No risk of hackers accessing your credentials through the Space URL
|
| 254 |
|
| 255 |
+
### 💰 Google Custom Search API - Cost Information
|
| 256 |
+
|
| 257 |
+
**Free Tier:**
|
| 258 |
+
- ✅ **100 queries per day** - **FREE** (no credit card needed initially, but billing account required)
|
| 259 |
+
- ⚠️ **Billing account required** even for free tier (you won't be charged for first 100/day)
|
| 260 |
+
|
| 261 |
+
**Automatic Fallback (When Quota Exceeded):**
|
| 262 |
+
- 🔄 **Automatic fallback to DuckDuckGo** when Google quota is exceeded (429 or quota-related 403 errors)
|
| 263 |
+
- DuckDuckGo is **free and unlimited** (no API key required)
|
| 264 |
+
- Seamless transition - users won't notice interruption
|
| 265 |
+
- Logs will indicate: `⚠️ Google Search quota exceeded → Auto-fallback to DuckDuckGo`
|
| 266 |
+
- **No code changes needed** - fallback happens automatically
|
| 267 |
+
- **No paid subscription required** - system gracefully handles quota limits
|
| 268 |
+
|
| 269 |
+
**Paid Tier (Optional - Beyond 100 queries/day):**
|
| 270 |
+
- 💵 **$5 per 1,000 queries** (after free tier)
|
| 271 |
+
- 📊 **Maximum**: 10,000 queries per day (requires billing enabled)
|
| 272 |
+
- **Note**: If you don't set up paid billing, the system automatically falls back to DuckDuckGo after 100 queries/day
|
| 273 |
+
|
| 274 |
+
**Cost Examples:**
|
| 275 |
+
- **100 queries/day** (3,000/month): **FREE** ✅ (auto-fallback after quota)
|
| 276 |
+
- **500 queries/day** (15,000/month): ~$70/month (14,000 additional queries × $5/1,000 = $70) OR use DuckDuckGo (free)
|
| 277 |
+
- **1,000 queries/day** (30,000/month): ~$145/month (29,000 additional queries × $5/1,000 = $145) OR use DuckDuckGo (free)
|
| 278 |
+
- **10,000 queries/day** (300,000/month): ~$1,485/month (299,000 additional queries × $5/1,000 = $1,485) OR use DuckDuckGo (free)
|
| 279 |
+
|
| 280 |
+
**Comparison with DuckDuckGo:**
|
| 281 |
+
- **DuckDuckGo**: ✅ **FREE, unlimited queries** (automatic fallback - excellent results!)
|
| 282 |
+
- **Google Custom Search**: Free for 100/day, then $5 per 1,000 queries (optional upgrade)
|
| 283 |
+
|
| 284 |
+
**Recommendation:**
|
| 285 |
+
- ✅ **For Development/Testing**: DuckDuckGo is perfect (free, unlimited, good results)
|
| 286 |
+
- 💰 **For Production**: Use Google API only if you need better results AND can afford $5 per 1,000 queries
|
| 287 |
+
- ✅ **Current Setup**: Hybrid approach - tries Google first, automatically falls back to DuckDuckGo when quota exceeded (best of both worlds!)
|
| 288 |
+
- 🎯 **Best Practice**: Let the system automatically fallback to DuckDuckGo - no paid subscription needed unless you specifically need Google's superior results
|
| 289 |
+
|
| 290 |
### Enabling Agent Mode
|
| 291 |
|
| 292 |
Agent Mode is **always enabled by default**. Just select your preferred model from the dropdown and ask questions:
|
|
|
|
| 296 |
- **Combined**: *"What's 2^10 and search for news about quantum computing in 2025"*
|
| 297 |
- **Real-time**: *"Tell me current US stock trends and present day crypto prices"*
|
| 298 |
|
| 299 |
+
### 📝 Sample Test Questions
|
| 300 |
+
|
| 301 |
+
For comprehensive test questions covering all areas (Math, Web Search, Current Events, Stock Market, Technology, etc.), see **[TEST_QUESTIONS.md](TEST_QUESTIONS.md)**.
|
| 302 |
+
|
| 303 |
+
The test questions file includes:
|
| 304 |
+
- 🧮 **Math & Calculator queries** (basic, geometry, advanced)
|
| 305 |
+
- 📰 **Current Events & News** (today's news, specific topics, global news)
|
| 306 |
+
- 💼 **Stock Market & Financial** (market trends, specific markets, combined queries)
|
| 307 |
+
- 💻 **Technology & AI** (AI trends, tech news, emerging technologies)
|
| 308 |
+
- 🎓 **Educational & Research** (science, academic topics, general knowledge)
|
| 309 |
+
- 🔄 **Combined Queries** (Math + Search in one question)
|
| 310 |
+
- 🌍 **Real-time Information** (time-sensitive queries, specific dates/years)
|
| 311 |
+
- 🎯 **Edge Cases** (complex multi-part questions, natural language variations)
|
| 312 |
+
|
| 313 |
+
**Quick Start Examples:**
|
| 314 |
+
- *"Calculate 25 * 48"* - Tests calculator tool
|
| 315 |
+
- *"Search for latest AI trends"* - Tests web search tool
|
| 316 |
+
- *"What's 2^10 and also search for current stock market trends"* - Tests combined tool usage
|
| 317 |
+
|
| 318 |
## 🚀 Usage
|
| 319 |
|
| 320 |
1. Click "Initialize" to load meeTARA (first time may take a few minutes to download models)
|
TEST_QUESTIONS.md
ADDED
|
@@ -0,0 +1,696 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# meeTARA Agent - Sample Test Questions
|
| 2 |
+
|
| 3 |
+
This file contains sample questions organized by category to test all meeTARA Agent capabilities (Calculator + Web Search + AI Processing).
|
| 4 |
+
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
## 🧮 Math & Calculator Queries
|
| 8 |
+
|
| 9 |
+
### Basic Calculations
|
| 10 |
+
- "Calculate 25 * 48"
|
| 11 |
+
- "What's 15% of 340?"
|
| 12 |
+
- "Solve: 2^10 + 3^5"
|
| 13 |
+
- "What is 144 divided by 12?"
|
| 14 |
+
- "Multiply 123 by 456"
|
| 15 |
+
- "What is 999 divided by 3?"
|
| 16 |
+
- "Add 50, 25, and 75"
|
| 17 |
+
- "Compute 1000 - 456 + 234 * 3"
|
| 18 |
+
- "Solve: (12 + 8) * (15 - 7)"
|
| 19 |
+
- "What is 2^8? Also calculate 3^4"
|
| 20 |
+
|
| 21 |
+
### Percentage & Division
|
| 22 |
+
- "What's 15% of 340?"
|
| 23 |
+
- "Calculate 25% of 200"
|
| 24 |
+
- "What is 20% times 150?"
|
| 25 |
+
- "999 divided by 3"
|
| 26 |
+
- "100 divided by 4"
|
| 27 |
+
- "50 ÷ 2"
|
| 28 |
+
- "What is 144 / 12?"
|
| 29 |
+
|
| 30 |
+
### Geometry & Formulas
|
| 31 |
+
- "Find the surface area of a rectangular prism with dimensions: length = 6 cm, width = 4 cm, height = 5 cm"
|
| 32 |
+
- "Calculate the area of a circle with radius 7 cm"
|
| 33 |
+
- "What's the volume of a cylinder with radius 5 cm and height 10 cm?"
|
| 34 |
+
- "Find the perimeter of a rectangle with length 12 cm and width 8 cm"
|
| 35 |
+
- "Calculate the circumference of a circle with radius 10 cm"
|
| 36 |
+
- "What is the volume of a sphere with radius 5 cm?"
|
| 37 |
+
|
| 38 |
+
### Powers & Roots
|
| 39 |
+
- "What is the square root of 256?"
|
| 40 |
+
- "Calculate square root of 144"
|
| 41 |
+
- "Find the square root of 16"
|
| 42 |
+
- "What is 2^8?"
|
| 43 |
+
- "Calculate 2 to the power of 10"
|
| 44 |
+
- "What's 3^4?"
|
| 45 |
+
- "Find cube root of 27"
|
| 46 |
+
- "Calculate cbrt(8)"
|
| 47 |
+
|
| 48 |
+
### Scientific Functions
|
| 49 |
+
|
| 50 |
+
#### Trigonometry
|
| 51 |
+
- "Calculate sine of pi/2"
|
| 52 |
+
- "What is sin(90)?" (Note: expects radians, but natural language may use degrees)
|
| 53 |
+
- "Find cosine of 0"
|
| 54 |
+
- "What is cos(pi/2)?"
|
| 55 |
+
- "Calculate tangent of pi/4"
|
| 56 |
+
- "What is tan(45)?"
|
| 57 |
+
- "Find arcsin of 1"
|
| 58 |
+
- "Calculate arccos(0)"
|
| 59 |
+
- "What is arctan(1)?"
|
| 60 |
+
- "Sine of pi/2"
|
| 61 |
+
|
| 62 |
+
#### Hyperbolic Functions
|
| 63 |
+
- "Calculate sinh(2)"
|
| 64 |
+
- "What is cosh(3)?"
|
| 65 |
+
- "Find tanh(1)"
|
| 66 |
+
- "Compute asinh(1.5)"
|
| 67 |
+
|
| 68 |
+
#### Logarithms
|
| 69 |
+
- "What is log(10)?"
|
| 70 |
+
- "Calculate natural log of e"
|
| 71 |
+
- "Find ln(e)"
|
| 72 |
+
- "What is log base 10 of 100?"
|
| 73 |
+
- "Calculate log10(100)"
|
| 74 |
+
- "What's log base 2 of 8?"
|
| 75 |
+
- "Find log2(8)"
|
| 76 |
+
- "What is exponential of 2?"
|
| 77 |
+
- "Calculate exp(2)"
|
| 78 |
+
- "What's e^2?"
|
| 79 |
+
|
| 80 |
+
#### Advanced Functions
|
| 81 |
+
- "Calculate factorial of 5"
|
| 82 |
+
- "What is 5!?"
|
| 83 |
+
- "Find factorial(5)"
|
| 84 |
+
- "Calculate gcd of 48 and 18"
|
| 85 |
+
- "What is gcd(48, 18)?"
|
| 86 |
+
- "Find greatest common divisor of 48 and 18"
|
| 87 |
+
- "Calculate lcm of 12 and 18"
|
| 88 |
+
- "What is lcm(12, 18)?"
|
| 89 |
+
- "Find least common multiple of 12 and 18"
|
| 90 |
+
- "What is floor(3.7)?"
|
| 91 |
+
- "Calculate ceil(3.2)"
|
| 92 |
+
- "Find trunc(3.9)"
|
| 93 |
+
- "Convert 180 degrees to radians"
|
| 94 |
+
- "What is degrees(pi)?"
|
| 95 |
+
- "Calculate radians(180)"
|
| 96 |
+
|
| 97 |
+
---
|
| 98 |
+
|
| 99 |
+
## 🧬 Algorithms & Data Structures (Calculator)
|
| 100 |
+
|
| 101 |
+
### Fibonacci Sequence
|
| 102 |
+
- "Calculate fibonacci of 10"
|
| 103 |
+
- "What is the 10th fibonacci number?"
|
| 104 |
+
- "Find fibonacci(10)"
|
| 105 |
+
- "What is fib(10)?"
|
| 106 |
+
- "Calculate the 15th fibonacci number"
|
| 107 |
+
- "Find fibonacci of 20"
|
| 108 |
+
|
| 109 |
+
### Permutations (nPr)
|
| 110 |
+
- "Calculate permutations of 5 taken 3"
|
| 111 |
+
- "What is npr(5, 3)?"
|
| 112 |
+
- "Find 5P3"
|
| 113 |
+
- "Calculate npr for 5 taken 3"
|
| 114 |
+
- "What are the permutations of 5 items taken 3 at a time?"
|
| 115 |
+
- "Compute perm(5, 3)"
|
| 116 |
+
- "Calculate number of ways to arrange 5 items taken 3 at a time"
|
| 117 |
+
|
| 118 |
+
### Combinations (nCr)
|
| 119 |
+
- "Calculate combinations of 5 choose 3"
|
| 120 |
+
- "What is ncr(5, 3)?"
|
| 121 |
+
- "Find 5C3"
|
| 122 |
+
- "Calculate ncr for 5 choose 3"
|
| 123 |
+
- "What are the combinations of 5 items choose 3?"
|
| 124 |
+
- "Compute comb(5, 3)"
|
| 125 |
+
- "Calculate choose(5, 3)"
|
| 126 |
+
- "How many ways to choose 3 items from 5?"
|
| 127 |
+
|
| 128 |
+
### Base Conversions
|
| 129 |
+
- "Convert 255 to binary"
|
| 130 |
+
- "What is 255 in binary?"
|
| 131 |
+
- "Calculate bin(255)"
|
| 132 |
+
- "Find binary of 255"
|
| 133 |
+
- "Convert 255 to hexadecimal"
|
| 134 |
+
- "What is 255 in hex?"
|
| 135 |
+
- "Calculate hex(255)"
|
| 136 |
+
- "Find hexadecimal of 255"
|
| 137 |
+
- "Convert 255 to octal"
|
| 138 |
+
- "What is 255 in octal?"
|
| 139 |
+
- "Calculate oct(255)"
|
| 140 |
+
- "Find octal of 255"
|
| 141 |
+
- "Convert 1010 from binary to decimal"
|
| 142 |
+
- "What is hex('ff') in decimal?"
|
| 143 |
+
- "Convert 377 from octal to decimal"
|
| 144 |
+
|
| 145 |
+
### Factorial & Advanced
|
| 146 |
+
- "Calculate factorial of 5"
|
| 147 |
+
- "What is 5!?"
|
| 148 |
+
- "Find factorial(5)"
|
| 149 |
+
- "Calculate factorial of 10"
|
| 150 |
+
- "What is 7!?"
|
| 151 |
+
- "Calculate factorial(20)"
|
| 152 |
+
|
| 153 |
+
### Complexity & Analysis (Detection Keywords)
|
| 154 |
+
- "What is the time complexity of binary search?"
|
| 155 |
+
- "Explain big O notation for merge sort"
|
| 156 |
+
- "What is the space complexity of quick sort?"
|
| 157 |
+
- "Analyze the complexity of bubble sort"
|
| 158 |
+
- "What is the time complexity of binary tree traversal?"
|
| 159 |
+
- "Explain big O for hash table operations"
|
| 160 |
+
- "What is the complexity of heap insert?"
|
| 161 |
+
- "Analyze tree height calculation complexity"
|
| 162 |
+
- "What is the time complexity of graph traversal?"
|
| 163 |
+
- "Explain complexity analysis for array operations"
|
| 164 |
+
|
| 165 |
+
### Data Structure Operations (Detection Keywords)
|
| 166 |
+
- "Calculate binary tree height with 15 nodes"
|
| 167 |
+
- "What is the depth of a tree with 31 nodes?"
|
| 168 |
+
- "Find the number of leaves in a binary tree"
|
| 169 |
+
- "Explain hash table time complexity"
|
| 170 |
+
- "What is the complexity of trie search?"
|
| 171 |
+
- "Analyze heap operations complexity"
|
| 172 |
+
- "What is binary search time complexity?"
|
| 173 |
+
- "Explain linear search complexity"
|
| 174 |
+
- "Calculate tree nodes for a given height"
|
| 175 |
+
- "What is the complexity of stack operations?"
|
| 176 |
+
|
| 177 |
+
### Algorithm Concepts
|
| 178 |
+
- "Explain recursion depth for fibonacci"
|
| 179 |
+
- "What is recursive complexity for factorial?"
|
| 180 |
+
- "Analyze dynamic programming complexity"
|
| 181 |
+
- "What is greedy algorithm time complexity?"
|
| 182 |
+
- "Explain backtracking space complexity"
|
| 183 |
+
- "What is divide and conquer complexity?"
|
| 184 |
+
- "Analyze sorting algorithm complexity"
|
| 185 |
+
- "What is searching algorithm complexity?"
|
| 186 |
+
|
| 187 |
+
---
|
| 188 |
+
|
| 189 |
+
## 📰 Current Events & News (Web Search)
|
| 190 |
+
|
| 191 |
+
**Note**: meeTARA Agent is configured to extract ACTUAL NEWS HEADLINES and CONTENT, not just descriptions of news sources. The agent filters out meta pages about news websites and focuses on real headlines and stories.
|
| 192 |
+
|
| 193 |
+
### Today's News (Headlines Extraction)
|
| 194 |
+
- "What are today's top news headlines?"
|
| 195 |
+
- "What happened in the news today?"
|
| 196 |
+
- "Tell me the latest breaking news"
|
| 197 |
+
- "Search for today's most important news stories"
|
| 198 |
+
- "What are the latest news headlines?"
|
| 199 |
+
- "Show me today's breaking news"
|
| 200 |
+
- "What's happening in the news right now?"
|
| 201 |
+
|
| 202 |
+
### Specific Topics
|
| 203 |
+
- "What are the latest AI developments in 2025?"
|
| 204 |
+
- "Search for news about quantum computing breakthroughs"
|
| 205 |
+
- "What are current climate change updates?"
|
| 206 |
+
- "Latest space exploration news"
|
| 207 |
+
- "What's happening in renewable energy?"
|
| 208 |
+
- "Current updates on electric vehicles"
|
| 209 |
+
|
| 210 |
+
### Global News
|
| 211 |
+
- "What are the latest global news stories?"
|
| 212 |
+
- "Search for international news today"
|
| 213 |
+
- "Tell me about current world events"
|
| 214 |
+
|
| 215 |
+
---
|
| 216 |
+
|
| 217 |
+
## 💼 Stock Market & Financial (Web Search)
|
| 218 |
+
|
| 219 |
+
### Market Trends
|
| 220 |
+
- "What is the current US stock market trend?"
|
| 221 |
+
- "What are today's stock market trends?"
|
| 222 |
+
- "Current stock market performance"
|
| 223 |
+
- "How is the S&P 500 performing today?"
|
| 224 |
+
- "What are the latest stock market trends?"
|
| 225 |
+
- "Search for current market conditions"
|
| 226 |
+
|
| 227 |
+
### Specific Markets
|
| 228 |
+
- "What is the current oil price?"
|
| 229 |
+
- "Tell me present day crypto prices"
|
| 230 |
+
- "Current Bitcoin and Ethereum prices"
|
| 231 |
+
- "What are the latest NASDAQ trends?"
|
| 232 |
+
- "How is the Dow Jones performing?"
|
| 233 |
+
- "Search for current commodity prices"
|
| 234 |
+
- "What are today's forex rates?"
|
| 235 |
+
|
| 236 |
+
### Combined Market Queries
|
| 237 |
+
- "What are current US stock market trends and oil market prices?"
|
| 238 |
+
- "Search for stock market news and cryptocurrency trends"
|
| 239 |
+
- "Tell me about current stock trends and present day crypto prices"
|
| 240 |
+
- "What are today's market trends and commodity prices?"
|
| 241 |
+
|
| 242 |
+
---
|
| 243 |
+
|
| 244 |
+
## 💻 Technology & AI (Web Search)
|
| 245 |
+
|
| 246 |
+
### AI Trends
|
| 247 |
+
- "What are the latest AI trends in 2025?"
|
| 248 |
+
- "Search for latest AI developments"
|
| 249 |
+
- "Current trends in artificial intelligence"
|
| 250 |
+
- "What's new in machine learning?"
|
| 251 |
+
- "Latest developments in neural networks"
|
| 252 |
+
- "What are the current AI breakthroughs?"
|
| 253 |
+
- "Search for recent AI research findings"
|
| 254 |
+
|
| 255 |
+
### Tech News
|
| 256 |
+
- "Latest technology news"
|
| 257 |
+
- "What are current tech industry trends?"
|
| 258 |
+
- "Search for quantum computing updates"
|
| 259 |
+
- "Latest developments in cloud computing"
|
| 260 |
+
- "What's new in software development?"
|
| 261 |
+
- "Current trends in cybersecurity"
|
| 262 |
+
|
| 263 |
+
### Emerging Technologies
|
| 264 |
+
- "Search for latest developments in quantum computing"
|
| 265 |
+
- "What are the newest trends in blockchain technology?"
|
| 266 |
+
- "Latest updates on 5G and 6G networks"
|
| 267 |
+
- "Current progress in autonomous vehicles"
|
| 268 |
+
|
| 269 |
+
---
|
| 270 |
+
|
| 271 |
+
## 🎓 Educational & Research (Web Search)
|
| 272 |
+
|
| 273 |
+
### Science
|
| 274 |
+
- "Latest research on climate change"
|
| 275 |
+
- "Recent discoveries in space exploration"
|
| 276 |
+
- "What are the newest medical breakthroughs?"
|
| 277 |
+
- "Current research on renewable energy"
|
| 278 |
+
- "Latest findings in marine biology"
|
| 279 |
+
- "Recent discoveries in astronomy"
|
| 280 |
+
|
| 281 |
+
### Academic Topics
|
| 282 |
+
- "Search for latest research on quantum physics"
|
| 283 |
+
- "What are recent findings in neuroscience?"
|
| 284 |
+
- "Latest developments in biotechnology"
|
| 285 |
+
- "Current research on artificial intelligence ethics"
|
| 286 |
+
- "Recent studies on renewable energy"
|
| 287 |
+
|
| 288 |
+
### General Knowledge
|
| 289 |
+
- "Search for educational content about ancient civilizations"
|
| 290 |
+
- "What are the latest findings in archaeology?"
|
| 291 |
+
- "Current research on human psychology"
|
| 292 |
+
|
| 293 |
+
---
|
| 294 |
+
|
| 295 |
+
## 🔬 Science & Health (Web Search)
|
| 296 |
+
|
| 297 |
+
### Health & Medicine
|
| 298 |
+
- "What are the latest medical breakthroughs?"
|
| 299 |
+
- "Search for current health research"
|
| 300 |
+
- "Latest developments in cancer treatment"
|
| 301 |
+
- "What's new in vaccine research?"
|
| 302 |
+
- "Current trends in mental health research"
|
| 303 |
+
|
| 304 |
+
### Science News
|
| 305 |
+
- "Latest scientific discoveries"
|
| 306 |
+
- "What are recent space exploration achievements?"
|
| 307 |
+
- "Current research on climate solutions"
|
| 308 |
+
- "Latest findings in physics"
|
| 309 |
+
- "Recent breakthroughs in chemistry"
|
| 310 |
+
|
| 311 |
+
---
|
| 312 |
+
|
| 313 |
+
## 🏢 Business & Economics (Web Search)
|
| 314 |
+
|
| 315 |
+
### Business News
|
| 316 |
+
- "What are current business trends?"
|
| 317 |
+
- "Latest corporate news"
|
| 318 |
+
- "Search for startup news"
|
| 319 |
+
- "What are today's business headlines?"
|
| 320 |
+
- "Current trends in entrepreneurship"
|
| 321 |
+
|
| 322 |
+
### Economic Data
|
| 323 |
+
- "What are current economic conditions?"
|
| 324 |
+
- "Search for latest economic indicators"
|
| 325 |
+
- "Tell me about present day economic conditions"
|
| 326 |
+
- "What are current inflation rates?"
|
| 327 |
+
- "Latest GDP growth data"
|
| 328 |
+
|
| 329 |
+
---
|
| 330 |
+
|
| 331 |
+
## 🌍 Real-time Information (Web Search)
|
| 332 |
+
|
| 333 |
+
### Time-Sensitive Queries
|
| 334 |
+
- "What's happening right now in the stock market?"
|
| 335 |
+
- "Current trends as of now"
|
| 336 |
+
- "Present day market conditions"
|
| 337 |
+
- "What are this week's tech trends?"
|
| 338 |
+
- "This month's biggest news stories"
|
| 339 |
+
- "What happened this year in AI?"
|
| 340 |
+
- "Search for right now's top stories"
|
| 341 |
+
- "As of now, what are the trends?"
|
| 342 |
+
|
| 343 |
+
### Specific Dates/Years
|
| 344 |
+
- "Latest news from 2025"
|
| 345 |
+
- "What are the trends in 2026?"
|
| 346 |
+
- "Search for 2025 technology predictions"
|
| 347 |
+
- "Current 2025 market analysis"
|
| 348 |
+
- "What's happening in January 2025?"
|
| 349 |
+
|
| 350 |
+
---
|
| 351 |
+
|
| 352 |
+
## 🔄 Combined Queries (Math + Search)
|
| 353 |
+
|
| 354 |
+
### Business + Finance
|
| 355 |
+
- "What are current market trends and stock prices? Also calculate ROI for an investment of $5000 with 8% return"
|
| 356 |
+
- "If a company's stock price is $150 and it increased by 15%, what's the new price? Also search for current market trends"
|
| 357 |
+
- "Search for today's stock market performance. Also calculate: if I invest $10,000 and it grows by 5%, what's my new total?"
|
| 358 |
+
- "Find current commodity prices and calculate 15% of 5000"
|
| 359 |
+
|
| 360 |
+
### Tech + Math
|
| 361 |
+
- "Search for latest AI trends and calculate: if AI adoption grows by 25% annually, what's the growth after 5 years from a base of 100?"
|
| 362 |
+
- "Calculate 100 * 45 and also search for current stock market trends"
|
| 363 |
+
- "What's 2^8? Also tell me the latest AI news"
|
| 364 |
+
- "Search for quantum computing updates and calculate factorial of 5"
|
| 365 |
+
- "Find latest tech trends and calculate pow(2, 10)"
|
| 366 |
+
|
| 367 |
+
### Scientific Calculator + Search
|
| 368 |
+
- "Calculate sin(pi/2) and search for latest mathematics research"
|
| 369 |
+
- "What is factorial(10)? Also find current computer science news"
|
| 370 |
+
- "Calculate fibonacci(15) and search for algorithm research"
|
| 371 |
+
- "Find permutations of 10 taken 3. Also search for combinatorics news"
|
| 372 |
+
- "Calculate gcd(48, 18) and search for number theory developments"
|
| 373 |
+
- "What is log10(1000)? Also find latest scientific discoveries"
|
| 374 |
+
|
| 375 |
+
### Algorithms + Search
|
| 376 |
+
- "Calculate fibonacci(20) and search for latest algorithm research"
|
| 377 |
+
- "Find ncr(10, 3) and search for combinatorics applications"
|
| 378 |
+
- "What is npr(5, 3)? Also find permutation algorithms in practice"
|
| 379 |
+
- "Calculate factorial(7) and search for factorial applications"
|
| 380 |
+
- "Find binary of 255 and search for binary computation methods"
|
| 381 |
+
|
| 382 |
+
### Current Events + Math
|
| 383 |
+
- "What's today's stock market performance? Also, if I invest $10,000 and it grows by 5%, what's my new total?"
|
| 384 |
+
- "Search for today's crypto prices and calculate: if Bitcoin is $50,000 and I have 0.5 BTC, what's my total value?"
|
| 385 |
+
- "Calculate 50 * 20 and search for today's cryptocurrency prices"
|
| 386 |
+
- "What are today's news headlines? Also calculate 25 * 48"
|
| 387 |
+
|
| 388 |
+
### Real-world Problems
|
| 389 |
+
- "If a portfolio worth $100,000 grows by 12% this year, what's the new value? Also search for current investment trends"
|
| 390 |
+
- "Calculate compound interest on $10,000 at 5% for 3 years, and search for investment trends"
|
| 391 |
+
- "Search for current market conditions and calculate: if a stock increases by 8% from $200, what's the new price?"
|
| 392 |
+
- "Find present day economic conditions and calculate 15% of 2500"
|
| 393 |
+
|
| 394 |
+
---
|
| 395 |
+
|
| 396 |
+
## 🎯 Edge Cases & Complex Queries
|
| 397 |
+
|
| 398 |
+
### Complex Detection
|
| 399 |
+
- "Calculate 100 * 5 and search for latest trends"
|
| 400 |
+
- "What's 25 * 48? Also tell me about present day economic conditions"
|
| 401 |
+
- "Solve 2^10 and search for current global market trends"
|
| 402 |
+
|
| 403 |
+
### Multi-Part Questions
|
| 404 |
+
- "Calculate the surface area of a 6x4x5 cm box. Also search for latest technology trends"
|
| 405 |
+
- "What's 15% of 340? Also tell me about current stock market performance"
|
| 406 |
+
- "Find the area of a circle with radius 7 cm. Also search for today's news"
|
| 407 |
+
|
| 408 |
+
### Natural Language Variations
|
| 409 |
+
- "Can you compute 123 * 456? Also find me the latest AI news"
|
| 410 |
+
- "I need to know what 25 * 48 equals. Also search for current market trends"
|
| 411 |
+
- "Please calculate 2^10 and tell me about present day trends"
|
| 412 |
+
|
| 413 |
+
---
|
| 414 |
+
|
| 415 |
+
## 🔍 Testing Specific Features
|
| 416 |
+
|
| 417 |
+
### Calculator Detection Patterns - Basic Math
|
| 418 |
+
- "What is 25 * 48?"
|
| 419 |
+
- "Compute 100 / 4"
|
| 420 |
+
- "Solve: 50 + 25 - 10"
|
| 421 |
+
- "Calculate 2^8"
|
| 422 |
+
- "What's the square root of 144?"
|
| 423 |
+
- "Multiply 15 by 20"
|
| 424 |
+
- "Divide 1000 by 25"
|
| 425 |
+
- "What's 15% of 340?"
|
| 426 |
+
- "999 divided by 3"
|
| 427 |
+
|
| 428 |
+
### Calculator Detection Patterns - Scientific Functions
|
| 429 |
+
- "Calculate sin(pi/2)"
|
| 430 |
+
- "What is cosine of 0?"
|
| 431 |
+
- "Find tangent of pi/4"
|
| 432 |
+
- "Calculate log10(100)"
|
| 433 |
+
- "What is natural log of e?"
|
| 434 |
+
- "Find factorial of 5"
|
| 435 |
+
- "Calculate sqrt(144)"
|
| 436 |
+
- "What is pow(2, 8)?"
|
| 437 |
+
- "Convert 180 degrees to radians"
|
| 438 |
+
|
| 439 |
+
### Calculator Detection Patterns - Algorithms
|
| 440 |
+
- "Calculate fibonacci of 10"
|
| 441 |
+
- "What is npr(5, 3)?"
|
| 442 |
+
- "Find ncr(10, 3)"
|
| 443 |
+
- "Calculate permutations of 5 taken 3"
|
| 444 |
+
- "What are combinations of 10 choose 3?"
|
| 445 |
+
- "Convert 255 to binary"
|
| 446 |
+
- "What is 255 in hexadecimal?"
|
| 447 |
+
- "Find binary of 128"
|
| 448 |
+
|
| 449 |
+
### Calculator Detection Patterns - Geometry
|
| 450 |
+
- "Find the surface area of a rectangular prism with length = 6, width = 4, height = 5"
|
| 451 |
+
- "Calculate the area of a circle with radius 7"
|
| 452 |
+
- "What's the volume of a cylinder with radius 5 and height 10?"
|
| 453 |
+
|
| 454 |
+
### Web Search Detection Patterns
|
| 455 |
+
- "Search for latest AI trends"
|
| 456 |
+
- "Find current stock market news"
|
| 457 |
+
- "Tell me about today's events"
|
| 458 |
+
- "What are present day conditions?"
|
| 459 |
+
- "Search for 2025 technology predictions"
|
| 460 |
+
- "Tell me the latest news"
|
| 461 |
+
- "What's happening right now?"
|
| 462 |
+
- "Current trends in technology"
|
| 463 |
+
- "Presently, what are the top stories?"
|
| 464 |
+
- "What are today's top news headlines?"
|
| 465 |
+
- "Search for latest breaking news"
|
| 466 |
+
- "Tell me about present day market conditions"
|
| 467 |
+
|
| 468 |
+
### Combined Detection - Basic Math + Search
|
| 469 |
+
- "Calculate 100 * 5 and search for latest trends"
|
| 470 |
+
- "What's 25 * 48? Also find me current stock prices"
|
| 471 |
+
- "Solve 2^10 and tell me about today's news"
|
| 472 |
+
- "Compute 50 * 20 and search for latest AI developments"
|
| 473 |
+
- "Calculate 15% of 340 and search for current trends"
|
| 474 |
+
|
| 475 |
+
### Combined Detection - Scientific Calculator + Search
|
| 476 |
+
- "Calculate sin(pi/2) and search for latest mathematics news"
|
| 477 |
+
- "What is factorial(10)? Also find algorithm research"
|
| 478 |
+
- "Calculate fibonacci(15) and search for computer science developments"
|
| 479 |
+
- "Find ncr(10, 3) and search for combinatorics applications"
|
| 480 |
+
- "Convert 255 to binary and search for binary computation methods"
|
| 481 |
+
|
| 482 |
+
### Combined Detection - Multiple Tools
|
| 483 |
+
- "Calculate 25 * 48, factorial of 5, and search for latest trends"
|
| 484 |
+
- "What's fibonacci(10) and npr(5, 3)? Also find algorithm news"
|
| 485 |
+
- "Calculate sqrt(144) and log10(100). Also search for current events"
|
| 486 |
+
|
| 487 |
+
---
|
| 488 |
+
|
| 489 |
+
## 📊 Performance Test Questions
|
| 490 |
+
|
| 491 |
+
### Quick Tests - Basic
|
| 492 |
+
1. "Calculate 25 * 48"
|
| 493 |
+
2. "Search for latest AI trends"
|
| 494 |
+
3. "What's 2^10 and also search for current stock market trends"
|
| 495 |
+
|
| 496 |
+
### Quick Tests - Scientific Calculator
|
| 497 |
+
1. "Calculate sin(pi/2)"
|
| 498 |
+
2. "What is factorial(5)?"
|
| 499 |
+
3. "Calculate fibonacci(10)"
|
| 500 |
+
|
| 501 |
+
### Quick Tests - Algorithms
|
| 502 |
+
1. "Calculate npr(5, 3)"
|
| 503 |
+
2. "What is ncr(10, 3)?"
|
| 504 |
+
3. "Convert 255 to binary"
|
| 505 |
+
|
| 506 |
+
### Comprehensive Tests - Basic Math + Search
|
| 507 |
+
1. "Find the surface area of a rectangular prism with dimensions: length = 6 cm, width = 4 cm, height = 5 cm. Also search for today's technology news"
|
| 508 |
+
2. "Calculate compound interest on $10,000 at 5% for 3 years. Also tell me about present day market conditions"
|
| 509 |
+
3. "What are current US stock market trends and oil market prices? Also calculate 100 * 45"
|
| 510 |
+
|
| 511 |
+
### Comprehensive Tests - Scientific Calculator + Search
|
| 512 |
+
1. "Calculate sin(pi/2), factorial(10), and gcd(48, 18). Also search for latest mathematics research"
|
| 513 |
+
2. "Find fibonacci(15) and npr(5, 3). Also search for algorithm applications"
|
| 514 |
+
3. "Calculate log10(1000), sqrt(144), and pow(2, 8). Also find current scientific developments"
|
| 515 |
+
|
| 516 |
+
### Comprehensive Tests - Algorithms + Search
|
| 517 |
+
1. "Calculate fibonacci(20), factorial(7), and ncr(10, 3). Also search for combinatorics research"
|
| 518 |
+
2. "Find permutations of 10 taken 4 and combinations of 10 choose 4. Also search for algorithm complexity analysis"
|
| 519 |
+
3. "Convert 255 to binary, hex, and octal. Also search for base conversion applications"
|
| 520 |
+
|
| 521 |
+
### Edge Case Tests
|
| 522 |
+
1. "Calculate 25 * 48, 15% of 340, and 999 divided by 3"
|
| 523 |
+
2. "Calculate sin(pi/2), cos(0), tan(pi/4), and log10(100)"
|
| 524 |
+
3. "Find fibonacci(10), npr(5, 3), ncr(5, 3), and factorial(5)"
|
| 525 |
+
4. "Calculate sqrt(144), pow(2, 8), gcd(48, 18), and lcm(12, 18)"
|
| 526 |
+
5. "Convert 255 to binary, hex, and octal. Also calculate factorial of 5"
|
| 527 |
+
|
| 528 |
+
---
|
| 529 |
+
|
| 530 |
+
## 🎓 Example Responses Expected
|
| 531 |
+
|
| 532 |
+
### Example 1: Basic Math + Search
|
| 533 |
+
When you ask: *"Calculate 25 * 48 and search for latest AI trends"*
|
| 534 |
+
|
| 535 |
+
meeTARA should:
|
| 536 |
+
1. ✅ Detect calculator need (matches "25 * 48")
|
| 537 |
+
2. ✅ Detect web search need (matches "latest" + "trends")
|
| 538 |
+
3. ✅ Execute calculator: `25 * 48 = 1200`
|
| 539 |
+
4. ✅ Execute web search: Get current AI trends from Google/DuckDuckGo
|
| 540 |
+
5. ✅ Feed both results to AI model
|
| 541 |
+
6. ✅ Generate structured response:
|
| 542 |
+
```
|
| 543 |
+
🎯 Answer: 25 × 48 = 1200. Based on recent search results...
|
| 544 |
+
📊 Details: Latest AI trends in 2025 include...
|
| 545 |
+
⚡ Steps: [Calculation steps + key findings]
|
| 546 |
+
💡 Note: [Additional insights]
|
| 547 |
+
```
|
| 548 |
+
|
| 549 |
+
### Example 2: Scientific Calculator
|
| 550 |
+
When you ask: *"Calculate sin(pi/2) and factorial of 5"*
|
| 551 |
+
|
| 552 |
+
meeTARA should:
|
| 553 |
+
1. ✅ Detect calculator need (matches "sin" and "factorial")
|
| 554 |
+
2. ✅ Execute calculator: `sin(pi/2) = 1.0` and `factorial(5) = 120`
|
| 555 |
+
3. ✅ Feed results to AI model
|
| 556 |
+
4. ✅ Generate structured response:
|
| 557 |
+
```
|
| 558 |
+
🎯 Answer: sin(π/2) = 1.0, factorial(5) = 120
|
| 559 |
+
📊 Details: [Mathematical context]
|
| 560 |
+
⚡ Steps: [Calculation steps]
|
| 561 |
+
💡 Note: [Additional insights]
|
| 562 |
+
```
|
| 563 |
+
|
| 564 |
+
### Example 3: Algorithms
|
| 565 |
+
When you ask: *"Calculate fibonacci(10) and npr(5, 3)"*
|
| 566 |
+
|
| 567 |
+
meeTARA should:
|
| 568 |
+
1. ✅ Detect calculator need (matches "fibonacci" and "npr")
|
| 569 |
+
2. ✅ Execute calculator: `fibonacci(10) = 55` and `npr(5, 3) = 60`
|
| 570 |
+
3. ✅ Feed results to AI model
|
| 571 |
+
4. ✅ Generate structured response:
|
| 572 |
+
```
|
| 573 |
+
🎯 Answer: fibonacci(10) = 55, npr(5, 3) = 60
|
| 574 |
+
📊 Details: [Algorithm context]
|
| 575 |
+
⚡ Steps: [Calculation steps]
|
| 576 |
+
💡 Note: [Additional insights]
|
| 577 |
+
```
|
| 578 |
+
|
| 579 |
+
### Example 4: Base Conversion
|
| 580 |
+
When you ask: *"Convert 255 to binary and hexadecimal"*
|
| 581 |
+
|
| 582 |
+
meeTARA should:
|
| 583 |
+
1. ✅ Detect calculator need (matches "convert" and "binary"/"hexadecimal")
|
| 584 |
+
2. ✅ Execute calculator: `bin(255) = 0b11111111` and `hex(255) = 0xff`
|
| 585 |
+
3. ✅ Feed results to AI model
|
| 586 |
+
4. ✅ Generate structured response:
|
| 587 |
+
```
|
| 588 |
+
🎯 Answer: 255 in binary = 0b11111111, in hexadecimal = 0xff
|
| 589 |
+
📊 Details: [Base conversion context]
|
| 590 |
+
⚡ Steps: [Conversion steps]
|
| 591 |
+
💡 Note: [Additional insights]
|
| 592 |
+
```
|
| 593 |
+
|
| 594 |
+
### Example 5: Complex Combined Query
|
| 595 |
+
When you ask: *"Calculate fibonacci(15), factorial(7), and search for latest algorithm research"*
|
| 596 |
+
|
| 597 |
+
meeTARA should:
|
| 598 |
+
1. ✅ Detect calculator need (matches "fibonacci" and "factorial")
|
| 599 |
+
2. ✅ Detect web search need (matches "latest" + "research")
|
| 600 |
+
3. ✅ Execute calculator: `fibonacci(15) = 610` and `factorial(7) = 5040`
|
| 601 |
+
4. ✅ Execute web search: Get algorithm research from Google/DuckDuckGo
|
| 602 |
+
5. ✅ Feed all results to AI model
|
| 603 |
+
6. ✅ Generate structured response with all calculations and search results
|
| 604 |
+
|
| 605 |
+
---
|
| 606 |
+
|
| 607 |
+
## 📝 Notes for Testing
|
| 608 |
+
|
| 609 |
+
### Calculator Testing
|
| 610 |
+
- ✅ **Basic math queries** should return accurate results
|
| 611 |
+
- ✅ **Percentage queries** should convert correctly (e.g., "15% of 340" → 51)
|
| 612 |
+
- ✅ **Division text** should convert correctly (e.g., "999 divided by 3" → 333)
|
| 613 |
+
- ✅ **Scientific functions** should handle radians, degrees, logarithms correctly
|
| 614 |
+
- ✅ **Algorithm functions** should calculate Fibonacci, Permutations, Combinations accurately
|
| 615 |
+
- ✅ **Base conversions** should return properly formatted results (0b, 0x, 0o prefixes)
|
| 616 |
+
- ✅ **Geometry queries** should detect and provide context (model calculates formulas)
|
| 617 |
+
- ✅ **Complex expressions** should respect order of operations (PEMDAS/BODMAS)
|
| 618 |
+
|
| 619 |
+
### Web Search Testing
|
| 620 |
+
- ✅ **Web search queries** should fetch current/recent information
|
| 621 |
+
- ✅ **Time-sensitive queries** should trigger search (today, latest, current, present day)
|
| 622 |
+
- ✅ **Stock market queries** should detect and search for market data
|
| 623 |
+
- ✅ **News queries** should detect and search for current events
|
| 624 |
+
- ✅ **Fallback behavior** should work if Google API is unavailable (DuckDuckGo)
|
| 625 |
+
- ✅ **Error handling** should be graceful if search returns no results
|
| 626 |
+
|
| 627 |
+
### Combined Queries Testing
|
| 628 |
+
- ✅ **Combined queries** should handle both calculator and web search correctly
|
| 629 |
+
- ✅ **Multiple calculator operations** should execute sequentially
|
| 630 |
+
- ✅ **Calculator + Search** should combine results properly
|
| 631 |
+
- ✅ **Response format** should follow meeTARA's structured format (🎯📊⚡💡)
|
| 632 |
+
|
| 633 |
+
### Detection Testing
|
| 634 |
+
- ✅ **Calculator detection** should catch: basic math, percentage, division, scientific, algorithms
|
| 635 |
+
- ✅ **Web search detection** should catch: today, latest, current, trends, news, stock market
|
| 636 |
+
- ✅ **Natural language** should be converted correctly (e.g., "sine of 90" → sin(90))
|
| 637 |
+
- ✅ **Pattern matching** should work for variations (e.g., "5P3", "5C3", "npr(5,3)")
|
| 638 |
+
|
| 639 |
+
### Error Handling
|
| 640 |
+
- ✅ **Invalid expressions** should return error messages gracefully
|
| 641 |
+
- ✅ **Division by zero** should be handled safely
|
| 642 |
+
- ✅ **Out of range** (e.g., factorial(1000)) should be handled
|
| 643 |
+
- ✅ **Search failures** should fallback to DuckDuckGo automatically
|
| 644 |
+
- ✅ **No search results** should still provide model response
|
| 645 |
+
|
| 646 |
+
---
|
| 647 |
+
|
| 648 |
+
## 🎯 Testing Checklist
|
| 649 |
+
|
| 650 |
+
### Basic Calculator ✅
|
| 651 |
+
- [ ] Basic arithmetic (+, -, *, /)
|
| 652 |
+
- [ ] Percentage calculations
|
| 653 |
+
- [ ] Division text conversion
|
| 654 |
+
- [ ] Order of operations
|
| 655 |
+
|
| 656 |
+
### Scientific Calculator ✅
|
| 657 |
+
- [ ] Trigonometry (sin, cos, tan, arcsin, arccos, arctan)
|
| 658 |
+
- [ ] Hyperbolic functions (sinh, cosh, tanh)
|
| 659 |
+
- [ ] Logarithms (log, log10, log2, ln, exp)
|
| 660 |
+
- [ ] Powers and roots (sqrt, cbrt, pow)
|
| 661 |
+
- [ ] Advanced (factorial, gcd, lcm, floor, ceil)
|
| 662 |
+
- [ ] Degree/radian conversion
|
| 663 |
+
|
| 664 |
+
### Algorithms & Data Structures ✅
|
| 665 |
+
- [ ] Fibonacci sequence
|
| 666 |
+
- [ ] Permutations (nPr)
|
| 667 |
+
- [ ] Combinations (nCr)
|
| 668 |
+
- [ ] Base conversions (binary, hex, octal)
|
| 669 |
+
- [ ] Complexity keywords (detection)
|
| 670 |
+
- [ ] Data structure keywords (detection)
|
| 671 |
+
|
| 672 |
+
### Geometry ✅
|
| 673 |
+
- [ ] Surface area
|
| 674 |
+
- [ ] Area of circle
|
| 675 |
+
- [ ] Volume calculations
|
| 676 |
+
- [ ] Perimeter calculations
|
| 677 |
+
|
| 678 |
+
### Web Search ✅
|
| 679 |
+
- [ ] Today's news
|
| 680 |
+
- [ ] Current trends
|
| 681 |
+
- [ ] Stock market data
|
| 682 |
+
- [ ] Latest developments
|
| 683 |
+
- [ ] Time-sensitive queries
|
| 684 |
+
|
| 685 |
+
### Combined Queries ✅
|
| 686 |
+
- [ ] Calculator + Search
|
| 687 |
+
- [ ] Multiple calculations + Search
|
| 688 |
+
- [ ] Scientific + Search
|
| 689 |
+
- [ ] Algorithms + Search
|
| 690 |
+
|
| 691 |
+
---
|
| 692 |
+
|
| 693 |
+
**Happy Testing! 🚀**
|
| 694 |
+
|
| 695 |
+
The meeTARA Agent now supports comprehensive mathematical calculations, scientific functions, algorithms, data structures, and intelligent web search!
|
| 696 |
+
|
config/agent_config.json
CHANGED
|
@@ -11,6 +11,15 @@
|
|
| 11 |
"trend",
|
| 12 |
"trends",
|
| 13 |
"news",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
"2024",
|
| 15 |
"2025",
|
| 16 |
"2026",
|
|
@@ -49,6 +58,50 @@
|
|
| 49 |
"breaking news",
|
| 50 |
"latest developments"
|
| 51 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
"search_patterns": [
|
| 53 |
{
|
| 54 |
"pattern": "(?:search|find)\\s+(?:for\\s+)?(.+?)(?:\\s+and|\\s+also|$)",
|
|
@@ -96,7 +149,86 @@
|
|
| 96 |
"provider": "duckduckgo",
|
| 97 |
"google_custom_search": {
|
| 98 |
"enabled": false,
|
| 99 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
}
|
| 101 |
},
|
| 102 |
|
|
@@ -123,20 +255,241 @@
|
|
| 123 |
"sum",
|
| 124 |
"difference",
|
| 125 |
"product",
|
| 126 |
-
"quotient"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
],
|
| 128 |
"math_patterns": [
|
| 129 |
{
|
| 130 |
-
"pattern": "\\b(calculate|compute|what is|what's|solve|evaluate|multiply|divide|add|subtract)\\s+([0-9+\\-*/().\\s]+?)(?:\\s+and|\\s+also|$)",
|
| 131 |
-
"description": "calculate 25 * 48, what is 25 * 48, compute X"
|
| 132 |
},
|
| 133 |
{
|
| 134 |
-
"pattern": "\\b([0-9]+\\s*[+\\-*/×÷]\\s*[0-9]+)",
|
| 135 |
-
"description": "25 * 48 or 25 × 48"
|
| 136 |
},
|
| 137 |
{
|
| 138 |
"pattern": "\\b(sqrt|square root|power|exponent)\\s*\\(?\\s*([0-9]+)\\s*\\)?",
|
| 139 |
"description": "sqrt(16) or square root 16"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
}
|
| 141 |
],
|
| 142 |
"enabled": true
|
|
|
|
| 11 |
"trend",
|
| 12 |
"trends",
|
| 13 |
"news",
|
| 14 |
+
"headlines",
|
| 15 |
+
"headline",
|
| 16 |
+
"breaking news",
|
| 17 |
+
"latest news",
|
| 18 |
+
"today's news",
|
| 19 |
+
"top news",
|
| 20 |
+
"current news",
|
| 21 |
+
"what happened",
|
| 22 |
+
"happening",
|
| 23 |
"2024",
|
| 24 |
"2025",
|
| 25 |
"2026",
|
|
|
|
| 58 |
"breaking news",
|
| 59 |
"latest developments"
|
| 60 |
],
|
| 61 |
+
"news_query_keywords": [
|
| 62 |
+
"news",
|
| 63 |
+
"headlines",
|
| 64 |
+
"headline",
|
| 65 |
+
"breaking news",
|
| 66 |
+
"latest news",
|
| 67 |
+
"today's news",
|
| 68 |
+
"top news",
|
| 69 |
+
"current news",
|
| 70 |
+
"what happened",
|
| 71 |
+
"happening",
|
| 72 |
+
"breaking",
|
| 73 |
+
"developing"
|
| 74 |
+
],
|
| 75 |
+
"meta_page_filter_phrases": [
|
| 76 |
+
"provides",
|
| 77 |
+
"offers",
|
| 78 |
+
"visit",
|
| 79 |
+
"check",
|
| 80 |
+
"read",
|
| 81 |
+
"explore",
|
| 82 |
+
"go to",
|
| 83 |
+
"subscribe",
|
| 84 |
+
"newsletter",
|
| 85 |
+
"website",
|
| 86 |
+
"at cnn",
|
| 87 |
+
"at fox",
|
| 88 |
+
"at bbc",
|
| 89 |
+
"you can find",
|
| 90 |
+
"available across",
|
| 91 |
+
"including cnn",
|
| 92 |
+
"including fox",
|
| 93 |
+
"visit cnn",
|
| 94 |
+
"check fox",
|
| 95 |
+
"view",
|
| 96 |
+
"on cnn.com",
|
| 97 |
+
"on foxnews.com",
|
| 98 |
+
"on bbc.com"
|
| 99 |
+
],
|
| 100 |
+
"news_enhancement_keywords": [
|
| 101 |
+
"headlines",
|
| 102 |
+
"breaking",
|
| 103 |
+
"latest"
|
| 104 |
+
],
|
| 105 |
"search_patterns": [
|
| 106 |
{
|
| 107 |
"pattern": "(?:search|find)\\s+(?:for\\s+)?(.+?)(?:\\s+and|\\s+also|$)",
|
|
|
|
| 149 |
"provider": "duckduckgo",
|
| 150 |
"google_custom_search": {
|
| 151 |
"enabled": false,
|
| 152 |
+
"auto_fallback_on_quota": true,
|
| 153 |
+
"note": "Set GOOGLE_CUSTOM_SEARCH_API_KEY and GOOGLE_CUSTOM_SEARCH_ENGINE_ID environment variables to enable. Free tier: 100 queries/day. When quota exceeded, automatically falls back to DuckDuckGo (free, unlimited). Paid tier: $5 per 1,000 queries after free tier. See README for setup instructions.",
|
| 154 |
+
"quota_info": {
|
| 155 |
+
"free_tier_quota": 100,
|
| 156 |
+
"free_tier_period": "per day",
|
| 157 |
+
"paid_tier_cost": "$5 per 1,000 queries",
|
| 158 |
+
"auto_fallback": "DuckDuckGo (free, unlimited)"
|
| 159 |
+
}
|
| 160 |
+
},
|
| 161 |
+
"news_query_instructions": {
|
| 162 |
+
"enabled": true,
|
| 163 |
+
"instruction_template": "CRITICAL INSTRUCTIONS FOR NEWS/HEADLINES QUERY:\n1. Extract and list the ACTUAL NEWS HEADLINES and STORIES from the search results above.\n2. Do NOT just describe news sources (e.g., 'CNN provides...' or 'Fox News offers...').\n3. Extract the REAL HEADLINES and NEWS CONTENT (e.g., 'President announces...', 'Stock market rises...', 'New study finds...').\n4. Focus on actual events, developments, and stories mentioned in the search results.\n5. You may mention source names briefly for attribution (e.g., 'According to CNN...'), but the primary content should be the actual news headlines and stories.\n6. List specific headlines and news items, not generic descriptions of news websites.\n\nExample of what to extract: 'Breaking: Stock market surges 2% today' (actual news)\nNOT: 'CNN provides breaking news updates' (source description)\n\nNow extract the actual news headlines and content from the search results above.",
|
| 164 |
+
"regular_instruction": "Use the tool results above to provide your response."
|
| 165 |
+
},
|
| 166 |
+
"safety_filter": {
|
| 167 |
+
"enabled": true,
|
| 168 |
+
"blocked_keywords": [
|
| 169 |
+
"how to hack",
|
| 170 |
+
"how to crack",
|
| 171 |
+
"how to break into",
|
| 172 |
+
"how to bypass",
|
| 173 |
+
"how to exploit",
|
| 174 |
+
"how to harm",
|
| 175 |
+
"how to hurt",
|
| 176 |
+
"how to kill",
|
| 177 |
+
"how to attack",
|
| 178 |
+
"how to destroy",
|
| 179 |
+
"how to steal",
|
| 180 |
+
"how to scam",
|
| 181 |
+
"how to cheat",
|
| 182 |
+
"how to manipulate",
|
| 183 |
+
"illegal activities",
|
| 184 |
+
"illegal content",
|
| 185 |
+
"piracy",
|
| 186 |
+
"warez",
|
| 187 |
+
"crack software",
|
| 188 |
+
"hack account",
|
| 189 |
+
"ddos attack",
|
| 190 |
+
"phishing",
|
| 191 |
+
"malware",
|
| 192 |
+
"virus download",
|
| 193 |
+
"trojan",
|
| 194 |
+
"keylogger",
|
| 195 |
+
"spyware",
|
| 196 |
+
"ransomware",
|
| 197 |
+
"drugs buy",
|
| 198 |
+
"drugs online",
|
| 199 |
+
"weapons buy",
|
| 200 |
+
"weapons online",
|
| 201 |
+
"violence instructions",
|
| 202 |
+
"terrorism",
|
| 203 |
+
"extremist content",
|
| 204 |
+
"hate speech",
|
| 205 |
+
"discriminatory content",
|
| 206 |
+
"explicit adult content",
|
| 207 |
+
"adult websites",
|
| 208 |
+
"nsfw content",
|
| 209 |
+
"inappropriate content"
|
| 210 |
+
],
|
| 211 |
+
"blocked_patterns": [
|
| 212 |
+
{
|
| 213 |
+
"pattern": "how\\s+to\\s+(?:hack|crack|break|bypass|exploit|harm|hurt|attack|destroy|steal|scam|cheat|manipulate)",
|
| 214 |
+
"description": "How-to queries for harmful activities"
|
| 215 |
+
},
|
| 216 |
+
{
|
| 217 |
+
"pattern": "(?:download|get|buy)\\s+(?:malware|virus|trojan|keylogger|spyware|ransomware|warez|cracked)",
|
| 218 |
+
"description": "Downloads of malicious software or pirated content"
|
| 219 |
+
},
|
| 220 |
+
{
|
| 221 |
+
"pattern": "(?:buy|purchase|get)\\s+(?:drugs|weapons|illegal)",
|
| 222 |
+
"description": "Illegal goods purchase queries"
|
| 223 |
+
},
|
| 224 |
+
{
|
| 225 |
+
"pattern": "(?:instructions|guide|tutorial)\\s+(?:for|on)\\s+(?:violence|attack|harm|illegal)",
|
| 226 |
+
"description": "Instructions for harmful activities"
|
| 227 |
+
}
|
| 228 |
+
],
|
| 229 |
+
"safe_search_enabled": true,
|
| 230 |
+
"safe_search_param": "safe=active",
|
| 231 |
+
"blocked_response_message": "I cannot search for content that may involve harmful, illegal, or inappropriate material. Please try a different query related to news, current events, technology, education, or general information."
|
| 232 |
}
|
| 233 |
},
|
| 234 |
|
|
|
|
| 255 |
"sum",
|
| 256 |
"difference",
|
| 257 |
"product",
|
| 258 |
+
"quotient",
|
| 259 |
+
"percentage",
|
| 260 |
+
"percent",
|
| 261 |
+
"%",
|
| 262 |
+
"of",
|
| 263 |
+
"surface area",
|
| 264 |
+
"area",
|
| 265 |
+
"volume",
|
| 266 |
+
"perimeter",
|
| 267 |
+
"circumference",
|
| 268 |
+
"radius",
|
| 269 |
+
"diameter",
|
| 270 |
+
"find the",
|
| 271 |
+
"find",
|
| 272 |
+
"rectangular prism",
|
| 273 |
+
"circle",
|
| 274 |
+
"rectangle",
|
| 275 |
+
"triangle",
|
| 276 |
+
"cylinder",
|
| 277 |
+
"sphere",
|
| 278 |
+
"sine",
|
| 279 |
+
"cosine",
|
| 280 |
+
"tangent",
|
| 281 |
+
"sin",
|
| 282 |
+
"cos",
|
| 283 |
+
"tan",
|
| 284 |
+
"arcsin",
|
| 285 |
+
"arccos",
|
| 286 |
+
"arctan",
|
| 287 |
+
"logarithm",
|
| 288 |
+
"log",
|
| 289 |
+
"ln",
|
| 290 |
+
"natural log",
|
| 291 |
+
"exponential",
|
| 292 |
+
"exp",
|
| 293 |
+
"factorial",
|
| 294 |
+
"gcd",
|
| 295 |
+
"lcm",
|
| 296 |
+
"degrees",
|
| 297 |
+
"radians",
|
| 298 |
+
"square root",
|
| 299 |
+
"cube root",
|
| 300 |
+
"sqrt",
|
| 301 |
+
"power",
|
| 302 |
+
"exponent",
|
| 303 |
+
"pow",
|
| 304 |
+
"algorithm",
|
| 305 |
+
"algorithms",
|
| 306 |
+
"data structure",
|
| 307 |
+
"data structures",
|
| 308 |
+
"big o",
|
| 309 |
+
"complexity",
|
| 310 |
+
"time complexity",
|
| 311 |
+
"space complexity",
|
| 312 |
+
"fibonacci",
|
| 313 |
+
"fibonacci sequence",
|
| 314 |
+
"permutation",
|
| 315 |
+
"permutations",
|
| 316 |
+
"combination",
|
| 317 |
+
"combinations",
|
| 318 |
+
"ncr",
|
| 319 |
+
"npr",
|
| 320 |
+
"factorial",
|
| 321 |
+
"fact",
|
| 322 |
+
"binary search",
|
| 323 |
+
"linear search",
|
| 324 |
+
"sorting",
|
| 325 |
+
"quick sort",
|
| 326 |
+
"merge sort",
|
| 327 |
+
"bubble sort",
|
| 328 |
+
"graph",
|
| 329 |
+
"tree",
|
| 330 |
+
"binary tree",
|
| 331 |
+
"array",
|
| 332 |
+
"linked list",
|
| 333 |
+
"stack",
|
| 334 |
+
"queue",
|
| 335 |
+
"hash",
|
| 336 |
+
"hash table",
|
| 337 |
+
"heap",
|
| 338 |
+
"binary heap",
|
| 339 |
+
"trie",
|
| 340 |
+
"recursion",
|
| 341 |
+
"recursive",
|
| 342 |
+
"dynamic programming",
|
| 343 |
+
"greedy",
|
| 344 |
+
"backtracking",
|
| 345 |
+
"divide and conquer",
|
| 346 |
+
"binary",
|
| 347 |
+
"hexadecimal",
|
| 348 |
+
"hex",
|
| 349 |
+
"decimal",
|
| 350 |
+
"octal",
|
| 351 |
+
"base conversion"
|
| 352 |
],
|
| 353 |
"math_patterns": [
|
| 354 |
{
|
| 355 |
+
"pattern": "\\b(calculate|compute|what is|what's|solve|evaluate|multiply|divide|add|subtract|find|find the)\\s+([0-9+\\-*/().\\s]+?)(?:\\s+and|\\s+also|$)",
|
| 356 |
+
"description": "calculate 25 * 48, what is 25 * 48, compute X, find the area"
|
| 357 |
},
|
| 358 |
{
|
| 359 |
+
"pattern": "\\b([0-9]+\\s*[+\\-*/×÷]\\s*[0-9]+(?:\\s*[+\\-*/×÷]\\s*[0-9]+)*)",
|
| 360 |
+
"description": "25 * 48 or 25 × 48 or 1000 - 456 + 234 * 3"
|
| 361 |
},
|
| 362 |
{
|
| 363 |
"pattern": "\\b(sqrt|square root|power|exponent)\\s*\\(?\\s*([0-9]+)\\s*\\)?",
|
| 364 |
"description": "sqrt(16) or square root 16"
|
| 365 |
+
},
|
| 366 |
+
{
|
| 367 |
+
"pattern": "\\b([0-9]+(?:\\.[0-9]+)?)\\s*%\\s*(?:of|times|×)\\s*([0-9]+)",
|
| 368 |
+
"description": "15% of 340, 25% times 100"
|
| 369 |
+
},
|
| 370 |
+
{
|
| 371 |
+
"pattern": "(?:what is|what's|calculate|compute|find|find the)\\s+([0-9]+(?:\\.[0-9]+)?)\\s*%\\s*(?:of|times|×)?\\s*([0-9]+)",
|
| 372 |
+
"description": "what's 15% of 340"
|
| 373 |
+
},
|
| 374 |
+
{
|
| 375 |
+
"pattern": "\\b([0-9]+)\\s+(?:divided by|divided|÷|/)\\s+([0-9]+)",
|
| 376 |
+
"description": "999 divided by 3, 100 / 4, 50 ÷ 2"
|
| 377 |
+
},
|
| 378 |
+
{
|
| 379 |
+
"pattern": "(?:find|calculate|compute|what is|what's|the)\\s+(?:surface area|area|volume|perimeter|circumference)\\s+(?:of|for)?",
|
| 380 |
+
"description": "find the surface area of, calculate the area of a circle, volume of a cylinder"
|
| 381 |
+
},
|
| 382 |
+
{
|
| 383 |
+
"pattern": "(?:surface area|area|volume|perimeter|circumference)\\s+(?:of|for|with)\\s+.*?(?:radius|diameter|length|width|height|dimensions)\\s*=",
|
| 384 |
+
"description": "area of a circle with radius 7 cm, surface area with dimensions length = 6"
|
| 385 |
+
},
|
| 386 |
+
{
|
| 387 |
+
"pattern": "\\b(sin|cos|tan|asin|acos|atan|arcsin|arccos|arctan|sine|cosine|tangent)\\s*\\(\\s*([0-9]+(?:\\.[0-9]+)?|pi|e|pi/[0-9]+)\\s*\\)",
|
| 388 |
+
"description": "sin(90), cos(pi/2), tan(45), sine(90), arcsin(1)"
|
| 389 |
+
},
|
| 390 |
+
{
|
| 391 |
+
"pattern": "(?:calculate|compute|what is|what's|find|find the)\\s+(?:the\\s+)?(sin|cos|tan|sine|cosine|tangent|arcsin|arccos|arctan)\\s+(?:of|at)?\\s*([0-9]+(?:\\.[0-9]+)?|pi|e|pi/[0-9]+)",
|
| 392 |
+
"description": "calculate sine of 90, what is cos of pi/2, find tangent of 45"
|
| 393 |
+
},
|
| 394 |
+
{
|
| 395 |
+
"pattern": "\\b(sinh|cosh|tanh|asinh|acosh|atanh)\\s*\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\s*\\)",
|
| 396 |
+
"description": "sinh(2), cosh(3), tanh(1)"
|
| 397 |
+
},
|
| 398 |
+
{
|
| 399 |
+
"pattern": "\\b(log|ln|log10|log2|natural log|logarithm)\\s*\\(\\s*([0-9]+(?:\\.[0-9]+)?|e|10|2)\\s*\\)",
|
| 400 |
+
"description": "log(10), ln(e), log10(100), log2(8), natural log of e"
|
| 401 |
+
},
|
| 402 |
+
{
|
| 403 |
+
"pattern": "(?:calculate|compute|what is|what's|find)\\s+(?:the\\s+)?(log|ln|natural log|logarithm|log base 10|log base 2)\\s+(?:of|of the number)?\\s*([0-9]+(?:\\.[0-9]+)?|e|10|2)",
|
| 404 |
+
"description": "calculate log of 10, what is natural log of e, find log base 10 of 100"
|
| 405 |
+
},
|
| 406 |
+
{
|
| 407 |
+
"pattern": "\\bexp\\s*\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\s*\\)|exponential\\s+of\\s+([0-9]+(?:\\.[0-9]+)?)|e\\^([0-9]+(?:\\.[0-9]+)?)",
|
| 408 |
+
"description": "exp(2), exponential of 3, e^2"
|
| 409 |
+
},
|
| 410 |
+
{
|
| 411 |
+
"pattern": "\\bfactorial\\s*\\(\\s*([0-9]+)\\s*\\)|([0-9]+)!",
|
| 412 |
+
"description": "factorial(5), 5!"
|
| 413 |
+
},
|
| 414 |
+
{
|
| 415 |
+
"pattern": "(?:calculate|compute|what is|what's|find)\\s+(?:the\\s+)?factorial\\s+of\\s+([0-9]+)|([0-9]+)\\s*factorial",
|
| 416 |
+
"description": "calculate factorial of 5, what is 5 factorial"
|
| 417 |
+
},
|
| 418 |
+
{
|
| 419 |
+
"pattern": "\\bgcd\\s*\\(\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*\\)|greatest common divisor\\s+of\\s+([0-9]+)\\s+and\\s+([0-9]+)",
|
| 420 |
+
"description": "gcd(48, 18), greatest common divisor of 48 and 18"
|
| 421 |
+
},
|
| 422 |
+
{
|
| 423 |
+
"pattern": "\\blcm\\s*\\(\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*\\)|least common multiple\\s+of\\s+([0-9]+)\\s+and\\s+([0-9]+)",
|
| 424 |
+
"description": "lcm(12, 18), least common multiple of 12 and 18"
|
| 425 |
+
},
|
| 426 |
+
{
|
| 427 |
+
"pattern": "\\b(pow|power|\\^)\\s*\\(\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*\\)|([0-9]+)\\s*\\^\\s*([0-9]+)|([0-9]+)\\s+to\\s+the\\s+power\\s+of\\s+([0-9]+)",
|
| 428 |
+
"description": "pow(2, 8), 2^8, 2 to the power of 8"
|
| 429 |
+
},
|
| 430 |
+
{
|
| 431 |
+
"pattern": "\\b(sqrt|square root|√)\\s*\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\s*\\)|square root of\\s+([0-9]+(?:\\.[0-9]+)?)|√([0-9]+(?:\\.[0-9]+)?)",
|
| 432 |
+
"description": "sqrt(144), square root(16), square root of 144, √16"
|
| 433 |
+
},
|
| 434 |
+
{
|
| 435 |
+
"pattern": "\\b(cbrt|cube root)\\s*\\(\\s*([0-9]+)\\s*\\)|cube root of\\s+([0-9]+)",
|
| 436 |
+
"description": "cbrt(27), cube root(8), cube root of 27"
|
| 437 |
+
},
|
| 438 |
+
{
|
| 439 |
+
"pattern": "(?:convert|what is|calculate|compute)\\s+([0-9]+(?:\\.[0-9]+)?)\\s*(?:degrees?|°)\\s+(?:to|in)\\s+radians?",
|
| 440 |
+
"description": "convert 180 degrees to radians, what is 90° in radians"
|
| 441 |
+
},
|
| 442 |
+
{
|
| 443 |
+
"pattern": "(?:convert|what is|calculate|compute)\\s+([0-9]+(?:\\.[0-9]+)?|pi|pi/[0-9]+)\\s+radians?\\s+(?:to|in)\\s+degrees?",
|
| 444 |
+
"description": "convert pi radians to degrees, what is pi/2 in degrees"
|
| 445 |
+
},
|
| 446 |
+
{
|
| 447 |
+
"pattern": "\\b(degrees|radians)\\s*\\(\\s*([0-9]+(?:\\.[0-9]+)?|pi|pi/[0-9]+)\\s*\\)",
|
| 448 |
+
"description": "degrees(pi), radians(180)"
|
| 449 |
+
},
|
| 450 |
+
{
|
| 451 |
+
"pattern": "\\b(floor|ceil|trunc|round)\\s*\\(\\s*([0-9]+\\.[0-9]+)\\s*\\)",
|
| 452 |
+
"description": "floor(3.7), ceil(3.2), trunc(3.9), round(3.5)"
|
| 453 |
+
},
|
| 454 |
+
{
|
| 455 |
+
"pattern": "(?:calculate|compute|what is|what's|find|find the|nth term of)\\s+(?:the\\s+)?fibonacci\\s+(?:number|sequence|of|at)?\\s*([0-9]+)|fibonacci\\s*\\(\\s*([0-9]+)\\s*\\)",
|
| 456 |
+
"description": "calculate fibonacci of 10, what is the 10th fibonacci number, fibonacci(10)"
|
| 457 |
+
},
|
| 458 |
+
{
|
| 459 |
+
"pattern": "(?:calculate|compute|what is|what's|find)\\s+(?:the\\s+)?(?:number of\\s+)?permutations?\\s+(?:of|for|with)?\\s*([0-9]+)\\s+(?:taken|choose|selected|at a time|per group)?\\s*([0-9]+)?|npr\\s*\\(\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*\\)|([0-9]+)p([0-9]+)",
|
| 460 |
+
"description": "permutations of 5 taken 3, npr(5,3), 5P3, number of permutations for 5 items"
|
| 461 |
+
},
|
| 462 |
+
{
|
| 463 |
+
"pattern": "(?:calculate|compute|what is|what's|find)\\s+(?:the\\s+)?(?:number of\\s+)?combinations?\\s+(?:of|for|with)?\\s*([0-9]+)\\s+(?:taken|choose|selected|at a time|per group)?\\s*([0-9]+)?|ncr\\s*\\(\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*\\)|([0-9]+)c([0-9]+)",
|
| 464 |
+
"description": "combinations of 5 choose 3, ncr(5,3), 5C3, number of combinations for 5 items"
|
| 465 |
+
},
|
| 466 |
+
{
|
| 467 |
+
"pattern": "(?:what is|what's|calculate|compute|find|analyze|explain)\\s+(?:the\\s+)?(?:time|space)?\\s*complexity\\s+(?:of|for)?|big\\s*o\\s+(?:of|for|notation)?|o\\s*\\(|complexity\\s+analysis",
|
| 468 |
+
"description": "what is the time complexity of, big o of, o(n), complexity analysis"
|
| 469 |
+
},
|
| 470 |
+
{
|
| 471 |
+
"pattern": "(?:calculate|compute|what is|what's|find|explain)\\s+(?:binary|linear|quick|merge|bubble|heap|selection|insertion)\\s+search\\s+(?:complexity|time|space|algorithm)?",
|
| 472 |
+
"description": "binary search complexity, time complexity of merge sort, quick sort big o"
|
| 473 |
+
},
|
| 474 |
+
{
|
| 475 |
+
"pattern": "(?:calculate|compute|what is|what's|find|explain)\\s+(?:binary|linear|quick|merge|bubble|heap|selection|insertion)\\s+sort\\s+(?:complexity|time|space|algorithm)?",
|
| 476 |
+
"description": "merge sort time complexity, big o of quick sort, bubble sort space complexity"
|
| 477 |
+
},
|
| 478 |
+
{
|
| 479 |
+
"pattern": "(?:calculate|compute|what is|what's|find|explain|analyze)\\s+(?:binary\\s+)?tree\\s+(?:height|depth|nodes|leaves|complexity|traversal|algorithm)?|tree\\s+(?:height|depth|nodes|leaves)\\s+(?:of|for)?",
|
| 480 |
+
"description": "binary tree height, tree depth calculation, tree nodes count, tree complexity"
|
| 481 |
+
},
|
| 482 |
+
{
|
| 483 |
+
"pattern": "(?:calculate|compute|what is|what's|find|explain|analyze)\\s+(?:graph|hash|heap|trie|array|linked list|stack|queue)\\s+(?:complexity|operations|algorithm|time|space)?",
|
| 484 |
+
"description": "graph complexity, hash table operations, heap insert complexity, trie search time"
|
| 485 |
+
},
|
| 486 |
+
{
|
| 487 |
+
"pattern": "(?:convert|what is|calculate|compute)\\s+([0-9]+|binary|hex|hexadecimal|decimal|octal)\\s+(?:to|in|as)\\s+(binary|hex|hexadecimal|decimal|octal|base\\s+[0-9]+)",
|
| 488 |
+
"description": "convert 255 to binary, what is 10 in hex, 1010 to decimal, base conversion"
|
| 489 |
+
},
|
| 490 |
+
{
|
| 491 |
+
"pattern": "(?:calculate|compute|what is|what's|find)\\s+(?:recursive|recursion)\\s+(?:complexity|time|space|depth|calls)?|recursion\\s+(?:depth|complexity|for)?",
|
| 492 |
+
"description": "recursive complexity, recursion depth, recursive fibonacci complexity"
|
| 493 |
}
|
| 494 |
],
|
| 495 |
"enabled": true
|
core/meetara_agent.py
CHANGED
|
@@ -54,27 +54,242 @@ def calculator(expression: str) -> str:
|
|
| 54 |
Evaluates a mathematical expression and returns the result.
|
| 55 |
Use this for any calculations to ensure accuracy.
|
| 56 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
Args:
|
| 58 |
-
expression: A mathematical expression
|
| 59 |
|
| 60 |
Returns:
|
| 61 |
The calculated result as a string
|
| 62 |
"""
|
| 63 |
import math
|
|
|
|
|
|
|
| 64 |
try:
|
| 65 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
allowed_names = {
|
| 67 |
-
|
| 68 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
"sin": math.sin, "cos": math.cos, "tan": math.tan,
|
| 70 |
-
"
|
| 71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
logger.info(f"[AGENT] 🧮 Calculator API call: expression='{expression}'")
|
| 74 |
-
|
| 75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
logger.info(f"[AGENT] 📥 Calculator result: {result_str}")
|
| 77 |
return result_str
|
|
|
|
| 78 |
except Exception as e:
|
| 79 |
error_msg = f"Error calculating '{expression}': {str(e)}"
|
| 80 |
logger.error(f"[AGENT] ❌ Calculator error: {error_msg}")
|
|
@@ -98,18 +313,113 @@ if USE_GOOGLE_SEARCH:
|
|
| 98 |
else:
|
| 99 |
logger.debug("[AGENT] ℹ️ Google Custom Search API not configured - using DuckDuckGo (free)")
|
| 100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
# Define Google Search function first (doesn't require DDGS imports)
|
| 102 |
-
def web_search_google(query: str, max_results: int = 5) -> str:
|
| 103 |
"""
|
| 104 |
Search using Google Custom Search API (requires API key - free tier: 100 queries/day)
|
| 105 |
Returns better, more relevant results than DuckDuckGo
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 106 |
"""
|
| 107 |
if not USE_GOOGLE_SEARCH:
|
| 108 |
return None
|
| 109 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
try:
|
| 111 |
import requests
|
| 112 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
# Google Custom Search API endpoint
|
| 114 |
url = "https://www.googleapis.com/customsearch/v1"
|
| 115 |
params = {
|
|
@@ -119,34 +429,136 @@ def web_search_google(query: str, max_results: int = 5) -> str:
|
|
| 119 |
"num": min(max_results, 10) # Google allows max 10 per request
|
| 120 |
}
|
| 121 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
logger.info(f"[AGENT] 🔍 Google Custom Search API call: query='{query}', max_results={max_results}")
|
| 123 |
response = requests.get(url, params=params, timeout=10)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
response.raise_for_status()
|
| 125 |
|
|
|
|
| 126 |
data = response.json()
|
| 127 |
items = data.get("items", [])
|
| 128 |
|
| 129 |
logger.info(f"[AGENT] 📥 Google Search API returned {len(items)} results")
|
| 130 |
|
| 131 |
if not items:
|
|
|
|
| 132 |
return None
|
| 133 |
|
| 134 |
-
# Format results for model
|
| 135 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
for i, item in enumerate(items[:max_results], 1):
|
| 137 |
title = item.get("title", "No title")
|
| 138 |
snippet = item.get("snippet", "No description")
|
| 139 |
link = item.get("link", "")
|
| 140 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
|
| 142 |
formatted_response = formatted.strip()
|
| 143 |
logger.info(f"[AGENT] ✅ Google search formatted response: {len(formatted_response)} chars")
|
|
|
|
|
|
|
| 144 |
return formatted_response
|
| 145 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
except Exception as e:
|
| 147 |
-
|
|
|
|
|
|
|
|
|
|
| 148 |
import traceback
|
| 149 |
-
logger.
|
| 150 |
return None
|
| 151 |
|
| 152 |
# Initialize DDGS availability flag
|
|
@@ -168,7 +580,7 @@ try:
|
|
| 168 |
DDGS_AVAILABLE = False
|
| 169 |
logger.warning("[AGENT] ⚠️ Neither ddgs nor duckduckgo_search available")
|
| 170 |
|
| 171 |
-
def web_search(query: str, max_results: int = 5) -> str:
|
| 172 |
"""
|
| 173 |
Search the web for current information.
|
| 174 |
Uses Google Custom Search API if available (better results), otherwise DuckDuckGo (free).
|
|
@@ -177,17 +589,54 @@ try:
|
|
| 177 |
Args:
|
| 178 |
query: Search query string
|
| 179 |
max_results: Maximum number of results to return (default: 5)
|
|
|
|
| 180 |
|
| 181 |
Returns:
|
| 182 |
Formatted search results as a string (or None if no results)
|
| 183 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
# Try Google Custom Search first (if API key configured - better results)
|
| 185 |
if USE_GOOGLE_SEARCH:
|
| 186 |
logger.info("[AGENT] 🔍 Using Google Custom Search API (AI-enhanced results)")
|
| 187 |
-
google_results = web_search_google(query, max_results)
|
| 188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
return google_results
|
| 190 |
-
|
|
|
|
|
|
|
| 191 |
|
| 192 |
# Fallback to DuckDuckGo (free, no API key needed)
|
| 193 |
if not DDGS_AVAILABLE:
|
|
@@ -236,6 +685,13 @@ try:
|
|
| 236 |
if ' and ' in query.lower():
|
| 237 |
logger.info(f"[AGENT] 🔄 Trying simpler query (splitting on 'and')...")
|
| 238 |
simpler_query = query.split(' and ', 1)[0].strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 239 |
logger.info(f"[AGENT] 🔄 Retry with query: '{simpler_query}'")
|
| 240 |
time.sleep(0.5) # Add delay for retry
|
| 241 |
results = list(ddgs.text(simpler_query, max_results=max_results))
|
|
@@ -245,19 +701,67 @@ try:
|
|
| 245 |
logger.warning(f"[AGENT] ⚠️ No search results found after all attempts for: {query}")
|
| 246 |
return f"No results found for: {query}"
|
| 247 |
|
| 248 |
-
# Format results for model
|
| 249 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 250 |
for i, result in enumerate(results, 1):
|
| 251 |
title = result.get('title', 'No title')
|
| 252 |
snippet = result.get('body', 'No description')
|
| 253 |
url = result.get('href', result.get('url', ''))
|
| 254 |
-
|
| 255 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 256 |
else:
|
| 257 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 258 |
|
| 259 |
formatted_response = formatted.strip()
|
| 260 |
logger.info(f"[AGENT] ✅ Web search formatted response: {len(formatted_response)} chars")
|
|
|
|
|
|
|
| 261 |
logger.debug(f"[AGENT] 📝 Formatted response preview (first 500 chars):\n{formatted_response[:500]}...")
|
| 262 |
|
| 263 |
return formatted_response
|
|
@@ -406,9 +910,15 @@ class MeeTARAAgent:
|
|
| 406 |
needs = {"calculator": False, "web_search": False, "calc_expression": None, "search_query": None}
|
| 407 |
|
| 408 |
# Check for math/calculation needs
|
| 409 |
-
#
|
| 410 |
query_lower = query.lower()
|
| 411 |
calculator_config = self.agent_config.get("calculator", {})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 412 |
math_patterns_config = calculator_config.get("math_patterns", [])
|
| 413 |
|
| 414 |
# Extract patterns from config (list of dicts with "pattern" key) or use defaults
|
|
@@ -422,6 +932,7 @@ class MeeTARAAgent:
|
|
| 422 |
r'\b(sqrt|square root|power|exponent)\s*\(?\s*([0-9]+)\s*\)?',
|
| 423 |
]
|
| 424 |
|
|
|
|
| 425 |
for pattern in math_patterns:
|
| 426 |
match = re.search(pattern, query, re.IGNORECASE)
|
| 427 |
if match:
|
|
@@ -429,7 +940,7 @@ class MeeTARAAgent:
|
|
| 429 |
# Extract the expression - try all groups
|
| 430 |
expr = None
|
| 431 |
for i in range(1, len(match.groups()) + 1):
|
| 432 |
-
if match.group(i) and re.search(r'[0-9+\-*/().×÷]', match.group(i)):
|
| 433 |
expr = match.group(i).strip()
|
| 434 |
break
|
| 435 |
|
|
@@ -438,12 +949,42 @@ class MeeTARAAgent:
|
|
| 438 |
expr = expr.replace('×', '*').replace('÷', '/')
|
| 439 |
needs["calc_expression"] = expr
|
| 440 |
else:
|
| 441 |
-
#
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 445 |
break
|
| 446 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 447 |
# Check for web search needs
|
| 448 |
# Load keywords and patterns from config
|
| 449 |
web_search_config = self.agent_config.get("web_search", {})
|
|
@@ -609,6 +1150,36 @@ class MeeTARAAgent:
|
|
| 609 |
search_q = tool_needs["search_query"] or query
|
| 610 |
logger.info(f"[AGENT] 🔍 Extracted search query: '{search_q}' (original: '{query[:100]}')")
|
| 611 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 612 |
# Validate search query before calling API
|
| 613 |
search_q_lower = search_q.lower().strip()
|
| 614 |
if (search_q_lower.startswith('and ') or
|
|
@@ -623,7 +1194,8 @@ class MeeTARAAgent:
|
|
| 623 |
if search_q and 'custom_web_search' in globals() and custom_web_search is not None:
|
| 624 |
max_results = self.agent_config.get("web_search", {}).get("max_results", 5)
|
| 625 |
logger.info(f"[AGENT] 🌐 Web search API call: query='{search_q}', max_results={max_results}")
|
| 626 |
-
|
|
|
|
| 627 |
|
| 628 |
# Check if search actually returned valid results (not "No results found" or error)
|
| 629 |
has_results = (search_result and
|
|
@@ -656,13 +1228,34 @@ class MeeTARAAgent:
|
|
| 656 |
# The model already has structured format (🎯, 📊, ⚡, 💡) built-in via meetara_lab_core.py
|
| 657 |
# Just feed tool results - model will automatically structure the response
|
| 658 |
if tool_results:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 659 |
enhanced_prompt = (
|
| 660 |
f"{query}\n\n"
|
| 661 |
f"=== Tool Results ===\n"
|
| 662 |
+ "\n\n".join(tool_results) +
|
| 663 |
-
f"\n\
|
| 664 |
)
|
| 665 |
logger.info(f"[AGENT] 📝 Feeding {len(tool_results)} tool results to model (model will auto-format)")
|
|
|
|
|
|
|
| 666 |
logger.debug(f"[AGENT] 📤 Enhanced prompt to model (first 1000 chars):\n{enhanced_prompt[:1000]}...")
|
| 667 |
|
| 668 |
# Log full tool results being fed to model
|
|
|
|
| 54 |
Evaluates a mathematical expression and returns the result.
|
| 55 |
Use this for any calculations to ensure accuracy.
|
| 56 |
|
| 57 |
+
Supports:
|
| 58 |
+
- Basic math: "25 * 48", "1000 - 456 + 234 * 3"
|
| 59 |
+
- Percentage: "15% of 340" (converts to "0.15 * 340")
|
| 60 |
+
- Division text: "999 divided by 3" (converts to "999 / 3")
|
| 61 |
+
- Scientific functions:
|
| 62 |
+
* Powers/roots: "sqrt(144)", "pow(2, 8)", "cbrt(27)"
|
| 63 |
+
* Trigonometry: "sin(pi/2)", "cos(0)", "tan(pi/4)", "asin(1)", "acos(0)", "atan(1)"
|
| 64 |
+
* Hyperbolic: "sinh(2)", "cosh(2)", "tanh(1)"
|
| 65 |
+
* Logarithms: "log(10)", "log10(100)", "log2(8)", "ln(e)", "exp(2)"
|
| 66 |
+
* Advanced: "factorial(5)", "gcd(48, 18)", "lcm(12, 18)", "degrees(pi)", "radians(180)"
|
| 67 |
+
- Natural language: "sine of pi/2", "natural log of e", "square root of 144"
|
| 68 |
+
- Algorithms & Data Structures:
|
| 69 |
+
* Fibonacci: "fibonacci(10)", "fibonacci of 10", "10th fibonacci"
|
| 70 |
+
* Permutations: "npr(5, 3)", "permutations of 5 taken 3", "5P3"
|
| 71 |
+
* Combinations: "ncr(5, 3)", "combinations of 5 choose 3", "5C3"
|
| 72 |
+
* Base conversion: "bin(255)", "hex(255)", "oct(255)", "convert 255 to binary"
|
| 73 |
+
|
| 74 |
Args:
|
| 75 |
+
expression: A mathematical expression or natural language math query
|
| 76 |
|
| 77 |
Returns:
|
| 78 |
The calculated result as a string
|
| 79 |
"""
|
| 80 |
import math
|
| 81 |
+
import re
|
| 82 |
+
|
| 83 |
try:
|
| 84 |
+
expr_lower = expression.lower()
|
| 85 |
+
original_expr = expression
|
| 86 |
+
|
| 87 |
+
# Handle percentage: "15% of 340" or "15% times 340" or "what's 15% of 340"
|
| 88 |
+
percentage_match = re.search(r'([0-9]+(?:\.[0-9]+)?)\s*%\s*(?:of|times|×)\s*([0-9]+)', expr_lower)
|
| 89 |
+
if percentage_match:
|
| 90 |
+
percent = float(percentage_match.group(1)) / 100
|
| 91 |
+
value = float(percentage_match.group(2))
|
| 92 |
+
expression = f"{percent} * {value}"
|
| 93 |
+
logger.info(f"[AGENT] 🧮 Converted percentage: '{original_expr}' → '{expression}'")
|
| 94 |
+
|
| 95 |
+
# Handle division text: "999 divided by 3" or "999 ÷ 3"
|
| 96 |
+
if not percentage_match:
|
| 97 |
+
division_match = re.search(r'([0-9]+(?:\.[0-9]+)?)\s+(?:divided by|divided|÷)\s+([0-9]+(?:\.[0-9]+)?)', expr_lower)
|
| 98 |
+
if division_match:
|
| 99 |
+
dividend = division_match.group(1)
|
| 100 |
+
divisor = division_match.group(2)
|
| 101 |
+
expression = f"{dividend} / {divisor}"
|
| 102 |
+
logger.info(f"[AGENT] 🧮 Converted division text: '{original_expr}' → '{expression}'")
|
| 103 |
+
|
| 104 |
+
# Handle geometry queries (model will calculate, calculator just provides context)
|
| 105 |
+
geometry_keywords = ["surface area", "area of", "volume of", "perimeter", "circumference", "radius", "diameter"]
|
| 106 |
+
if any(geo in expr_lower for geo in geometry_keywords):
|
| 107 |
+
# Extract numbers for context (model will do the actual geometry calculation)
|
| 108 |
+
numbers = re.findall(r'[0-9]+(?:\.[0-9]+)?', expression)
|
| 109 |
+
if len(numbers) >= 2:
|
| 110 |
+
# Try to extract a simple expression if possible
|
| 111 |
+
logger.info(f"[AGENT] 🧮 Geometry query detected: '{expression}' - model will calculate")
|
| 112 |
+
# Return context - model will handle geometry formulas
|
| 113 |
+
return f"Geometry calculation requested: {expression}. Numbers found: {', '.join(numbers)}. Please calculate using appropriate formulas."
|
| 114 |
+
|
| 115 |
+
# Clean expression: remove extra spaces, normalize operators
|
| 116 |
+
expression = re.sub(r'\s+', ' ', expression.strip())
|
| 117 |
+
expression = expression.replace('×', '*').replace('÷', '/')
|
| 118 |
+
|
| 119 |
+
# Safe evaluation with comprehensive scientific math functions
|
| 120 |
allowed_names = {
|
| 121 |
+
# Basic functions
|
| 122 |
+
"abs": abs, "round": round, "min": min, "max": max, "sum": sum,
|
| 123 |
+
|
| 124 |
+
# Powers and roots
|
| 125 |
+
"pow": pow, "sqrt": math.sqrt, "cbrt": lambda x: x ** (1/3), # Cube root
|
| 126 |
+
|
| 127 |
+
# Trigonometric functions (radians)
|
| 128 |
"sin": math.sin, "cos": math.cos, "tan": math.tan,
|
| 129 |
+
"asin": math.asin, "acos": math.acos, "atan": math.atan, "atan2": math.atan2,
|
| 130 |
+
|
| 131 |
+
# Hyperbolic functions
|
| 132 |
+
"sinh": math.sinh, "cosh": math.cosh, "tanh": math.tanh,
|
| 133 |
+
"asinh": math.asinh, "acosh": math.acosh, "atanh": math.atanh,
|
| 134 |
+
|
| 135 |
+
# Logarithmic functions
|
| 136 |
+
"log": math.log, "log10": math.log10, "log2": math.log2, "exp": math.exp,
|
| 137 |
+
"ln": math.log, # Natural logarithm (alias)
|
| 138 |
+
|
| 139 |
+
# Additional functions
|
| 140 |
+
"factorial": math.factorial, "gcd": math.gcd, "lcm": lambda a, b: abs(a * b) // math.gcd(a, b) if a and b else 0,
|
| 141 |
+
"degrees": math.degrees, "radians": math.radians,
|
| 142 |
+
"floor": math.floor, "ceil": math.ceil, "trunc": math.trunc,
|
| 143 |
+
|
| 144 |
+
# Algorithm & Data Structure functions
|
| 145 |
+
"perm": lambda n, r: math.factorial(n) // math.factorial(n - r) if n >= r >= 0 else 0, # Permutations nPr
|
| 146 |
+
"permutations": lambda n, r: math.factorial(n) // math.factorial(n - r) if n >= r >= 0 else 0,
|
| 147 |
+
"npr": lambda n, r: math.factorial(n) // math.factorial(n - r) if n >= r >= 0 else 0,
|
| 148 |
+
"comb": lambda n, r: math.factorial(n) // (math.factorial(r) * math.factorial(n - r)) if n >= r >= 0 else 0, # Combinations nCr
|
| 149 |
+
"combinations": lambda n, r: math.factorial(n) // (math.factorial(r) * math.factorial(n - r)) if n >= r >= 0 else 0,
|
| 150 |
+
"ncr": lambda n, r: math.factorial(n) // (math.factorial(r) * math.factorial(n - r)) if n >= r >= 0 else 0,
|
| 151 |
+
"choose": lambda n, r: math.factorial(n) // (math.factorial(r) * math.factorial(n - r)) if n >= r >= 0 else 0,
|
| 152 |
+
|
| 153 |
+
# Fibonacci function (iterative for efficiency)
|
| 154 |
+
"fibonacci": lambda n: int((((1 + math.sqrt(5)) / 2) ** n - ((1 - math.sqrt(5)) / 2) ** n) / math.sqrt(5)) if n >= 0 else 0,
|
| 155 |
+
"fib": lambda n: int((((1 + math.sqrt(5)) / 2) ** n - ((1 - math.sqrt(5)) / 2) ** n) / math.sqrt(5)) if n >= 0 else 0,
|
| 156 |
+
|
| 157 |
+
# Base conversion helpers (to be used in expressions like "int('1010', 2)")
|
| 158 |
+
"bin_to_dec": lambda b: int(str(b), 2),
|
| 159 |
+
"hex_to_dec": lambda h: int(str(h), 16),
|
| 160 |
+
"oct_to_dec": lambda o: int(str(o), 8),
|
| 161 |
+
"dec_to_bin": lambda n: bin(int(n)),
|
| 162 |
+
"dec_to_hex": lambda n: hex(int(n)),
|
| 163 |
+
"dec_to_oct": lambda n: oct(int(n)),
|
| 164 |
+
|
| 165 |
+
# Constants
|
| 166 |
+
"pi": math.pi, "e": math.e, "tau": math.tau,
|
| 167 |
+
"inf": float('inf'), "nan": float('nan')
|
| 168 |
}
|
| 169 |
+
|
| 170 |
+
# Handle base conversion expressions separately (they return strings)
|
| 171 |
+
# Check for direct function calls like bin(255), hex(255), oct(255)
|
| 172 |
+
base_conv_pattern = re.search(r'\b(bin|hex|oct|dec_to_bin|dec_to_hex|dec_to_oct)\s*\(\s*([0-9]+)\s*\)', expression, re.IGNORECASE)
|
| 173 |
+
base_conv_result = None
|
| 174 |
+
if base_conv_pattern:
|
| 175 |
+
func_name = base_conv_pattern.group(1).lower()
|
| 176 |
+
num = int(base_conv_pattern.group(2))
|
| 177 |
+
if 'bin' in func_name:
|
| 178 |
+
base_conv_result = bin(num)
|
| 179 |
+
elif 'hex' in func_name:
|
| 180 |
+
base_conv_result = hex(num)
|
| 181 |
+
elif 'oct' in func_name:
|
| 182 |
+
base_conv_result = oct(num)
|
| 183 |
+
|
| 184 |
+
if base_conv_result:
|
| 185 |
+
result_str = f"{original_expr} = {base_conv_result}"
|
| 186 |
+
logger.info(f"[AGENT] 📥 Calculator result (base conversion): {result_str}")
|
| 187 |
+
return result_str
|
| 188 |
+
|
| 189 |
+
# Handle natural language scientific function names (before cleaning)
|
| 190 |
+
scientific_aliases = {
|
| 191 |
+
"sine of": "sin", "cosine of": "cos", "tangent of": "tan",
|
| 192 |
+
"sine": "sin", "cosine": "cos", "tangent": "tan",
|
| 193 |
+
"arcsin of": "asin", "arccos of": "acos", "arctan of": "atan",
|
| 194 |
+
"square root of": "sqrt", "cube root of": "cbrt",
|
| 195 |
+
"natural log of": "ln", "log base 10 of": "log10", "log base 2 of": "log2"
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
# Replace natural language patterns like "sine of 90" -> "sin(90)" or "sine(90)"
|
| 199 |
+
for alias, func_name in scientific_aliases.items():
|
| 200 |
+
if alias in expr_lower:
|
| 201 |
+
# Pattern: "sine of 90" -> "sin(90)"
|
| 202 |
+
pattern1 = re.compile(r'\b' + re.escape(alias) + r'\s+([0-9]+(?:\.[0-9]+)?|pi|e)' , re.IGNORECASE)
|
| 203 |
+
expression = pattern1.sub(func_name + r'(\1)', expression)
|
| 204 |
+
# Pattern: "sine(90)" -> "sin(90)" (already in correct format)
|
| 205 |
+
pattern2 = re.compile(r'\b' + re.escape(alias.split()[0]) + r'\s*\(' , re.IGNORECASE)
|
| 206 |
+
expression = pattern2.sub(func_name + '(', expression)
|
| 207 |
+
|
| 208 |
+
# Handle algorithm & data structure natural language queries
|
| 209 |
+
# Fibonacci: "fibonacci of 10" or "fibonacci(10)" or "10th fibonacci"
|
| 210 |
+
fib_match = re.search(r'(?:fibonacci|fib)\s+(?:of|at|number)?\s*([0-9]+)|([0-9]+)(?:th|st|nd|rd)?\s+fibonacci', expr_lower)
|
| 211 |
+
if fib_match:
|
| 212 |
+
n = int(fib_match.group(1) or fib_match.group(2))
|
| 213 |
+
expression = f"fibonacci({n})"
|
| 214 |
+
logger.info(f"[AGENT] 🧮 Converted fibonacci query: '{original_expr}' → '{expression}'")
|
| 215 |
+
|
| 216 |
+
# Permutations: "permutations of 5 taken 3" or "5P3" or "npr(5, 3)"
|
| 217 |
+
perm_match = re.search(r'(?:permutations?|perm|npr)\s+(?:of|for)?\s*([0-9]+)\s+(?:taken|choose|selected|at a time)?\s*([0-9]+)|([0-9]+)p([0-9]+)', expr_lower)
|
| 218 |
+
if perm_match:
|
| 219 |
+
n = int(perm_match.group(1) or perm_match.group(3))
|
| 220 |
+
r = int(perm_match.group(2) or perm_match.group(4))
|
| 221 |
+
expression = f"npr({n}, {r})"
|
| 222 |
+
logger.info(f"[AGENT] 🧮 Converted permutations query: '{original_expr}' → '{expression}'")
|
| 223 |
+
|
| 224 |
+
# Combinations: "combinations of 5 choose 3" or "5C3" or "ncr(5, 3)"
|
| 225 |
+
comb_match = re.search(r'(?:combinations?|comb|ncr|choose)\s+(?:of|for)?\s*([0-9]+)\s+(?:choose|taken|selected|at a time)?\s*([0-9]+)|([0-9]+)c([0-9]+)', expr_lower)
|
| 226 |
+
if comb_match:
|
| 227 |
+
n = int(comb_match.group(1) or comb_match.group(3))
|
| 228 |
+
r = int(comb_match.group(2) or comb_match.group(4))
|
| 229 |
+
expression = f"ncr({n}, {r})"
|
| 230 |
+
logger.info(f"[AGENT] 🧮 Converted combinations query: '{original_expr}' → '{expression}'")
|
| 231 |
+
|
| 232 |
+
# Base conversion: "convert 255 to binary" or "binary of 255"
|
| 233 |
+
base_conv_match = re.search(r'(?:convert|what is|calculate|compute)\s+([0-9]+)\s+(?:to|in|as)\s+(binary|hex|hexadecimal|decimal|octal|base\s+([0-9]+))|(?:binary|hex|hexadecimal|decimal|octal)\s+(?:of|for)?\s*([0-9]+)', expr_lower)
|
| 234 |
+
if base_conv_match and not percentage_match and not division_match:
|
| 235 |
+
if base_conv_match.group(1): # "convert 255 to binary" pattern
|
| 236 |
+
num = int(base_conv_match.group(1))
|
| 237 |
+
target_base = base_conv_match.group(2).lower() if base_conv_match.group(2) else ""
|
| 238 |
+
if 'binary' in target_base or 'base 2' in target_base or (not target_base and 'binary' in expr_lower):
|
| 239 |
+
expression = f"bin({num})"
|
| 240 |
+
elif 'hex' in target_base or 'base 16' in target_base or (not target_base and ('hex' in expr_lower or 'hexadecimal' in expr_lower)):
|
| 241 |
+
expression = f"hex({num})"
|
| 242 |
+
elif 'octal' in target_base or 'base 8' in target_base or (not target_base and 'octal' in expr_lower):
|
| 243 |
+
expression = f"oct({num})"
|
| 244 |
+
logger.info(f"[AGENT] 🧮 Converted base conversion query: '{original_expr}' → '{expression}'")
|
| 245 |
+
elif base_conv_match.group(4): # "binary of 255" pattern
|
| 246 |
+
num = int(base_conv_match.group(4))
|
| 247 |
+
if 'binary' in expr_lower:
|
| 248 |
+
expression = f"bin({num})"
|
| 249 |
+
elif 'hex' in expr_lower or 'hexadecimal' in expr_lower:
|
| 250 |
+
expression = f"hex({num})"
|
| 251 |
+
elif 'octal' in expr_lower:
|
| 252 |
+
expression = f"oct({num})"
|
| 253 |
+
logger.info(f"[AGENT] 🧮 Converted base conversion query: '{original_expr}' → '{expression}'")
|
| 254 |
+
|
| 255 |
logger.info(f"[AGENT] 🧮 Calculator API call: expression='{expression}'")
|
| 256 |
+
|
| 257 |
+
# Check again for base conversion after natural language processing
|
| 258 |
+
base_conv_after = re.search(r'\b(bin|hex|oct)\s*\(\s*([0-9]+)\s*\)', expression, re.IGNORECASE)
|
| 259 |
+
if base_conv_after and not base_conv_result:
|
| 260 |
+
func_name = base_conv_after.group(1).lower()
|
| 261 |
+
num = int(base_conv_after.group(2))
|
| 262 |
+
if func_name == 'bin':
|
| 263 |
+
base_conv_result = bin(num)
|
| 264 |
+
elif func_name == 'hex':
|
| 265 |
+
base_conv_result = hex(num)
|
| 266 |
+
elif func_name == 'oct':
|
| 267 |
+
base_conv_result = oct(num)
|
| 268 |
+
|
| 269 |
+
# Evaluate expression
|
| 270 |
+
if base_conv_result:
|
| 271 |
+
result = base_conv_result
|
| 272 |
+
else:
|
| 273 |
+
# Add bin, hex, oct to allowed built-ins for eval
|
| 274 |
+
safe_builtins = {"__builtins__": {}, "bin": bin, "hex": hex, "oct": oct}
|
| 275 |
+
result = eval(expression, safe_builtins, allowed_names)
|
| 276 |
+
|
| 277 |
+
# Format result nicely
|
| 278 |
+
if isinstance(result, str) and (result.startswith('0b') or result.startswith('0x') or result.startswith('0o')):
|
| 279 |
+
# Base conversion result (already formatted)
|
| 280 |
+
result_str = f"{original_expr if original_expr != expression else expression} = {result}"
|
| 281 |
+
elif isinstance(result, float):
|
| 282 |
+
if result.is_integer():
|
| 283 |
+
result = int(result)
|
| 284 |
+
else:
|
| 285 |
+
result = round(result, 10) # Round to 10 decimal places
|
| 286 |
+
result_str = f"{original_expr if original_expr != expression else expression} = {result}"
|
| 287 |
+
else:
|
| 288 |
+
result_str = f"{original_expr if original_expr != expression else expression} = {result}"
|
| 289 |
+
|
| 290 |
logger.info(f"[AGENT] 📥 Calculator result: {result_str}")
|
| 291 |
return result_str
|
| 292 |
+
|
| 293 |
except Exception as e:
|
| 294 |
error_msg = f"Error calculating '{expression}': {str(e)}"
|
| 295 |
logger.error(f"[AGENT] ❌ Calculator error: {error_msg}")
|
|
|
|
| 313 |
else:
|
| 314 |
logger.debug("[AGENT] ℹ️ Google Custom Search API not configured - using DuckDuckGo (free)")
|
| 315 |
|
| 316 |
+
def is_safe_search_query(query: str, agent_config: dict = None) -> tuple[bool, str]:
|
| 317 |
+
"""
|
| 318 |
+
Check if a search query is safe to execute.
|
| 319 |
+
|
| 320 |
+
Args:
|
| 321 |
+
query: Search query string to validate
|
| 322 |
+
agent_config: Optional agent configuration dict (if None, uses defaults)
|
| 323 |
+
|
| 324 |
+
Returns:
|
| 325 |
+
Tuple of (is_safe: bool, reason: str)
|
| 326 |
+
"""
|
| 327 |
+
# Load safety filter config
|
| 328 |
+
if agent_config is None:
|
| 329 |
+
try:
|
| 330 |
+
if CONFIG_AVAILABLE:
|
| 331 |
+
agent_config = get_agent_config()
|
| 332 |
+
else:
|
| 333 |
+
agent_config = {}
|
| 334 |
+
except:
|
| 335 |
+
agent_config = {}
|
| 336 |
+
|
| 337 |
+
web_search_config = agent_config.get("web_search", {})
|
| 338 |
+
safety_config = web_search_config.get("safety_filter", {})
|
| 339 |
+
|
| 340 |
+
# Check if safety filter is enabled (default: True)
|
| 341 |
+
if not safety_config.get("enabled", True):
|
| 342 |
+
return True, "Safety filter disabled"
|
| 343 |
+
|
| 344 |
+
# Load blocked keywords and patterns
|
| 345 |
+
blocked_keywords = safety_config.get("blocked_keywords", [])
|
| 346 |
+
blocked_patterns = safety_config.get("blocked_patterns", [])
|
| 347 |
+
|
| 348 |
+
# Normalize query for checking
|
| 349 |
+
query_lower = query.lower().strip()
|
| 350 |
+
|
| 351 |
+
# Check blocked keywords
|
| 352 |
+
for keyword in blocked_keywords:
|
| 353 |
+
if keyword.lower() in query_lower:
|
| 354 |
+
logger.warning(f"[AGENT] 🚫 Safety filter blocked query: contains blocked keyword '{keyword}'")
|
| 355 |
+
return False, f"Query contains blocked keyword: {keyword}"
|
| 356 |
+
|
| 357 |
+
# Check blocked patterns (regex)
|
| 358 |
+
import re
|
| 359 |
+
for pattern_obj in blocked_patterns:
|
| 360 |
+
pattern = pattern_obj.get("pattern", "") if isinstance(pattern_obj, dict) else pattern_obj
|
| 361 |
+
if not pattern:
|
| 362 |
+
continue
|
| 363 |
+
|
| 364 |
+
try:
|
| 365 |
+
if re.search(pattern, query_lower, re.IGNORECASE):
|
| 366 |
+
desc = pattern_obj.get("description", "harmful pattern") if isinstance(pattern_obj, dict) else "harmful pattern"
|
| 367 |
+
logger.warning(f"[AGENT] 🚫 Safety filter blocked query: matches blocked pattern '{desc}'")
|
| 368 |
+
return False, f"Query matches blocked pattern: {desc}"
|
| 369 |
+
except re.error as e:
|
| 370 |
+
logger.warning(f"[AGENT] ⚠️ Invalid regex pattern in safety config: {pattern}, error: {e}")
|
| 371 |
+
continue
|
| 372 |
+
|
| 373 |
+
# Query passed all safety checks
|
| 374 |
+
return True, "Query is safe"
|
| 375 |
+
|
| 376 |
+
|
| 377 |
# Define Google Search function first (doesn't require DDGS imports)
|
| 378 |
+
def web_search_google(query: str, max_results: int = 5, agent_config: dict = None) -> str:
|
| 379 |
"""
|
| 380 |
Search using Google Custom Search API (requires API key - free tier: 100 queries/day)
|
| 381 |
Returns better, more relevant results than DuckDuckGo
|
| 382 |
+
|
| 383 |
+
Args:
|
| 384 |
+
query: Search query string
|
| 385 |
+
max_results: Maximum number of results (default: 5)
|
| 386 |
+
agent_config: Optional agent configuration dict (if None, uses defaults)
|
| 387 |
"""
|
| 388 |
if not USE_GOOGLE_SEARCH:
|
| 389 |
return None
|
| 390 |
|
| 391 |
+
# Load config for safety check and news detection
|
| 392 |
+
if agent_config is None:
|
| 393 |
+
try:
|
| 394 |
+
if CONFIG_AVAILABLE:
|
| 395 |
+
agent_config = get_agent_config()
|
| 396 |
+
else:
|
| 397 |
+
agent_config = {}
|
| 398 |
+
except:
|
| 399 |
+
agent_config = {}
|
| 400 |
+
|
| 401 |
+
# Safety check - block harmful queries before searching
|
| 402 |
+
is_safe, safety_reason = is_safe_search_query(query, agent_config)
|
| 403 |
+
if not is_safe:
|
| 404 |
+
web_search_config = agent_config.get("web_search", {})
|
| 405 |
+
safety_config = web_search_config.get("safety_filter", {})
|
| 406 |
+
blocked_message = safety_config.get("blocked_response_message",
|
| 407 |
+
"I cannot search for content that may involve harmful, illegal, or inappropriate material. Please try a different query.")
|
| 408 |
+
logger.warning(f"[AGENT] 🚫 Safety filter blocked Google search: {safety_reason}")
|
| 409 |
+
return f"⚠️ {blocked_message}"
|
| 410 |
+
|
| 411 |
try:
|
| 412 |
import requests
|
| 413 |
|
| 414 |
+
web_search_config = agent_config.get("web_search", {})
|
| 415 |
+
news_keywords = web_search_config.get("news_query_keywords", ["news", "headlines", "headline", "breaking"])
|
| 416 |
+
meta_filter_phrases = web_search_config.get("meta_page_filter_phrases", [
|
| 417 |
+
"provides", "offers", "visit", "check", "read", "explore", "go to",
|
| 418 |
+
"subscribe", "newsletter", "website", "at cnn", "at fox", "at bbc"
|
| 419 |
+
])
|
| 420 |
+
safety_config = web_search_config.get("safety_filter", {})
|
| 421 |
+
safe_search_enabled = safety_config.get("safe_search_enabled", True)
|
| 422 |
+
|
| 423 |
# Google Custom Search API endpoint
|
| 424 |
url = "https://www.googleapis.com/customsearch/v1"
|
| 425 |
params = {
|
|
|
|
| 429 |
"num": min(max_results, 10) # Google allows max 10 per request
|
| 430 |
}
|
| 431 |
|
| 432 |
+
# Enable safe search (filters explicit content)
|
| 433 |
+
if safe_search_enabled:
|
| 434 |
+
safe_search_param = safety_config.get("safe_search_param", "safe=active")
|
| 435 |
+
# Google API uses "safe" parameter with values: "active", "off", "high"
|
| 436 |
+
params["safe"] = "active"
|
| 437 |
+
|
| 438 |
logger.info(f"[AGENT] 🔍 Google Custom Search API call: query='{query}', max_results={max_results}")
|
| 439 |
response = requests.get(url, params=params, timeout=10)
|
| 440 |
+
|
| 441 |
+
# Handle HTTP errors with detailed diagnostics
|
| 442 |
+
if response.status_code == 429:
|
| 443 |
+
# Quota exceeded (100 queries/day free tier limit reached)
|
| 444 |
+
error_data = response.json() if response.content else {}
|
| 445 |
+
error_message = error_data.get("error", {}).get("message", "Quota exceeded")
|
| 446 |
+
logger.warning(f"[AGENT] ⚠️ Google Search API 429 - Daily quota exceeded (free tier: 100 queries/day)")
|
| 447 |
+
logger.warning(f"[AGENT] Error: {error_message}")
|
| 448 |
+
logger.info(f"[AGENT] → Auto-fallback to DuckDuckGo (free, unlimited)")
|
| 449 |
+
# Return special marker to trigger fallback
|
| 450 |
+
return "QUOTA_EXCEEDED"
|
| 451 |
+
|
| 452 |
+
elif response.status_code == 403:
|
| 453 |
+
# Forbidden - could be quota, API not enabled, or billing issue
|
| 454 |
+
error_data = response.json() if response.content else {}
|
| 455 |
+
error_message = error_data.get("error", {}).get("message", "Forbidden")
|
| 456 |
+
error_code = error_data.get("error", {}).get("code", 0)
|
| 457 |
+
|
| 458 |
+
# Check if it's a quota issue (sometimes 403 is used for quota)
|
| 459 |
+
if "quota" in error_message.lower() or "quotaExceeded" in str(error_data):
|
| 460 |
+
logger.warning(f"[AGENT] ⚠️ Google Search API 403 - Quota exceeded (free tier: 100 queries/day)")
|
| 461 |
+
logger.info(f"[AGENT] → Auto-fallback to DuckDuckGo (free, unlimited)")
|
| 462 |
+
return "QUOTA_EXCEEDED"
|
| 463 |
+
else:
|
| 464 |
+
logger.error(f"[AGENT] ❌ Google Search API 403 Forbidden - Possible causes:")
|
| 465 |
+
logger.error(f"[AGENT] 1. API not enabled in Google Cloud Console")
|
| 466 |
+
logger.error(f"[AGENT] 2. Billing account required (even for free tier)")
|
| 467 |
+
logger.error(f"[AGENT] 3. API key restricted to wrong HTTP referrers (should be unrestricted for server-side)")
|
| 468 |
+
logger.error(f"[AGENT] 4. Daily quota exceeded (free tier: 100 queries/day)")
|
| 469 |
+
logger.error(f"[AGENT] Error: {error_message}")
|
| 470 |
+
logger.info(f"[AGENT] → Falling back to DuckDuckGo (free, unlimited)")
|
| 471 |
+
# Fallback to DuckDuckGo even for other 403 errors
|
| 472 |
+
return None
|
| 473 |
+
|
| 474 |
+
elif response.status_code == 401:
|
| 475 |
+
# Unauthorized - invalid API key
|
| 476 |
+
error_data = response.json() if response.content else {}
|
| 477 |
+
error_message = error_data.get("error", {}).get("message", "Unauthorized")
|
| 478 |
+
logger.error(f"[AGENT] ❌ Google Search API 401 Unauthorized - Invalid API key")
|
| 479 |
+
logger.error(f"[AGENT] Error: {error_message}")
|
| 480 |
+
logger.error(f"[AGENT] → Check GOOGLE_CUSTOM_SEARCH_API_KEY in environment variables")
|
| 481 |
+
logger.info(f"[AGENT] → Falling back to DuckDuckGo")
|
| 482 |
+
return None
|
| 483 |
+
|
| 484 |
+
elif response.status_code == 400:
|
| 485 |
+
# Bad request - invalid parameters
|
| 486 |
+
error_data = response.json() if response.content else {}
|
| 487 |
+
error_message = error_data.get("error", {}).get("message", "Bad request")
|
| 488 |
+
logger.error(f"[AGENT] ❌ Google Search API 400 Bad Request")
|
| 489 |
+
logger.error(f"[AGENT] Error: {error_message}")
|
| 490 |
+
logger.error(f"[AGENT] → Check query parameters and Search Engine ID")
|
| 491 |
+
logger.info(f"[AGENT] → Falling back to DuckDuckGo")
|
| 492 |
+
return None
|
| 493 |
+
|
| 494 |
+
# Raise for other HTTP errors
|
| 495 |
response.raise_for_status()
|
| 496 |
|
| 497 |
+
# Parse successful response
|
| 498 |
data = response.json()
|
| 499 |
items = data.get("items", [])
|
| 500 |
|
| 501 |
logger.info(f"[AGENT] 📥 Google Search API returned {len(items)} results")
|
| 502 |
|
| 503 |
if not items:
|
| 504 |
+
logger.info(f"[AGENT] ℹ️ Google Search returned no results - falling back to DuckDuckGo")
|
| 505 |
return None
|
| 506 |
|
| 507 |
+
# Format results for model - prioritize headlines for news queries
|
| 508 |
+
query_lower = query.lower()
|
| 509 |
+
is_news_query = any(kw in query_lower for kw in news_keywords)
|
| 510 |
+
|
| 511 |
+
if is_news_query:
|
| 512 |
+
formatted = f"Today's News Headlines:\n\n"
|
| 513 |
+
else:
|
| 514 |
+
formatted = f"Web search results for '{query}':\n\n"
|
| 515 |
+
|
| 516 |
for i, item in enumerate(items[:max_results], 1):
|
| 517 |
title = item.get("title", "No title")
|
| 518 |
snippet = item.get("snippet", "No description")
|
| 519 |
link = item.get("link", "")
|
| 520 |
+
|
| 521 |
+
# For news queries, prioritize title (often contains the headline) and filter out meta descriptions
|
| 522 |
+
if is_news_query:
|
| 523 |
+
# Filter out results that are just about news sources (meta pages)
|
| 524 |
+
title_lower = title.lower()
|
| 525 |
+
snippet_lower = snippet.lower()
|
| 526 |
+
is_meta_page = any(phrase in title_lower or phrase in snippet_lower for phrase in meta_filter_phrases)
|
| 527 |
+
|
| 528 |
+
# If it's not a meta page, include it as a headline
|
| 529 |
+
if not is_meta_page and title and title != "No title":
|
| 530 |
+
# Use title as headline, snippet as content if it contains actual news
|
| 531 |
+
if snippet and len(snippet) > 50 and not snippet_lower.startswith("view") and not snippet_lower.startswith("visit"):
|
| 532 |
+
formatted += f"{i}. {title}\n {snippet[:300]}\n Source: {link}\n\n"
|
| 533 |
+
else:
|
| 534 |
+
formatted += f"{i}. {title}\n Source: {link}\n\n"
|
| 535 |
+
elif snippet and len(snippet) > 100 and any(word in snippet_lower for word in ["announced", "reported", "said", "according", "breaking", "developing"]):
|
| 536 |
+
# Snippet contains actual news content - use it
|
| 537 |
+
formatted += f"{i}. {snippet[:300]}\n Source: {link}\n\n"
|
| 538 |
+
else:
|
| 539 |
+
# Regular search results formatting
|
| 540 |
+
formatted += f"{i}. {title}\n {snippet[:200]}...\n Source: {link}\n\n"
|
| 541 |
|
| 542 |
formatted_response = formatted.strip()
|
| 543 |
logger.info(f"[AGENT] ✅ Google search formatted response: {len(formatted_response)} chars")
|
| 544 |
+
if is_news_query:
|
| 545 |
+
logger.debug(f"[AGENT] 📰 News query - formatted for headline extraction")
|
| 546 |
return formatted_response
|
| 547 |
|
| 548 |
+
except requests.exceptions.RequestException as e:
|
| 549 |
+
# Network/connection errors
|
| 550 |
+
logger.error(f"[AGENT] ❌ Google Search API network error: {e}")
|
| 551 |
+
logger.info(f"[AGENT] → Falling back to DuckDuckGo")
|
| 552 |
+
import traceback
|
| 553 |
+
logger.debug(f"[AGENT] Google search traceback: {traceback.format_exc()}")
|
| 554 |
+
return None
|
| 555 |
except Exception as e:
|
| 556 |
+
# Other unexpected errors
|
| 557 |
+
error_msg = str(e)
|
| 558 |
+
logger.error(f"[AGENT] ❌ Google Search API unexpected error: {e}")
|
| 559 |
+
logger.info(f"[AGENT] → Falling back to DuckDuckGo")
|
| 560 |
import traceback
|
| 561 |
+
logger.debug(f"[AGENT] Google search traceback: {traceback.format_exc()}")
|
| 562 |
return None
|
| 563 |
|
| 564 |
# Initialize DDGS availability flag
|
|
|
|
| 580 |
DDGS_AVAILABLE = False
|
| 581 |
logger.warning("[AGENT] ⚠️ Neither ddgs nor duckduckgo_search available")
|
| 582 |
|
| 583 |
+
def web_search(query: str, max_results: int = 5, agent_config: dict = None) -> str:
|
| 584 |
"""
|
| 585 |
Search the web for current information.
|
| 586 |
Uses Google Custom Search API if available (better results), otherwise DuckDuckGo (free).
|
|
|
|
| 589 |
Args:
|
| 590 |
query: Search query string
|
| 591 |
max_results: Maximum number of results to return (default: 5)
|
| 592 |
+
agent_config: Optional agent configuration dict (for news detection and filtering)
|
| 593 |
|
| 594 |
Returns:
|
| 595 |
Formatted search results as a string (or None if no results)
|
| 596 |
"""
|
| 597 |
+
# Load config for safety check and news detection
|
| 598 |
+
if agent_config is None:
|
| 599 |
+
try:
|
| 600 |
+
if CONFIG_AVAILABLE:
|
| 601 |
+
agent_config = get_agent_config()
|
| 602 |
+
else:
|
| 603 |
+
agent_config = {}
|
| 604 |
+
except:
|
| 605 |
+
agent_config = {}
|
| 606 |
+
|
| 607 |
+
# Safety check - block harmful queries before searching
|
| 608 |
+
is_safe, safety_reason = is_safe_search_query(query, agent_config)
|
| 609 |
+
if not is_safe:
|
| 610 |
+
web_search_config = agent_config.get("web_search", {})
|
| 611 |
+
safety_config = web_search_config.get("safety_filter", {})
|
| 612 |
+
blocked_message = safety_config.get("blocked_response_message",
|
| 613 |
+
"I cannot search for content that may involve harmful, illegal, or inappropriate material. Please try a different query.")
|
| 614 |
+
logger.warning(f"[AGENT] 🚫 Safety filter blocked web search: {safety_reason}")
|
| 615 |
+
return f"⚠️ {blocked_message}"
|
| 616 |
+
|
| 617 |
+
web_search_config = agent_config.get("web_search", {})
|
| 618 |
+
news_keywords = web_search_config.get("news_query_keywords", ["news", "headlines", "headline", "breaking"])
|
| 619 |
+
meta_filter_phrases = web_search_config.get("meta_page_filter_phrases", [
|
| 620 |
+
"provides", "offers", "visit", "check", "read", "explore", "go to",
|
| 621 |
+
"subscribe", "newsletter", "website", "at cnn", "at fox", "at bbc"
|
| 622 |
+
])
|
| 623 |
+
|
| 624 |
# Try Google Custom Search first (if API key configured - better results)
|
| 625 |
if USE_GOOGLE_SEARCH:
|
| 626 |
logger.info("[AGENT] 🔍 Using Google Custom Search API (AI-enhanced results)")
|
| 627 |
+
google_results = web_search_google(query, max_results, agent_config)
|
| 628 |
+
|
| 629 |
+
# Check if quota exceeded (special marker)
|
| 630 |
+
if google_results == "QUOTA_EXCEEDED":
|
| 631 |
+
logger.warning("[AGENT] ⚠️ Google Search quota exceeded (100 queries/day free tier limit)")
|
| 632 |
+
logger.info("[AGENT] → Automatically falling back to DuckDuckGo (free, unlimited)")
|
| 633 |
+
# Continue to DuckDuckGo fallback below
|
| 634 |
+
elif google_results:
|
| 635 |
+
# Success - return Google results
|
| 636 |
return google_results
|
| 637 |
+
else:
|
| 638 |
+
# No results or error - fallback to DuckDuckGo
|
| 639 |
+
logger.info("[AGENT] ℹ️ Google Search returned no results or error, falling back to DuckDuckGo")
|
| 640 |
|
| 641 |
# Fallback to DuckDuckGo (free, no API key needed)
|
| 642 |
if not DDGS_AVAILABLE:
|
|
|
|
| 685 |
if ' and ' in query.lower():
|
| 686 |
logger.info(f"[AGENT] 🔄 Trying simpler query (splitting on 'and')...")
|
| 687 |
simpler_query = query.split(' and ', 1)[0].strip()
|
| 688 |
+
|
| 689 |
+
# Safety check for retry query as well
|
| 690 |
+
is_safe_retry, safety_reason_retry = is_safe_search_query(simpler_query, agent_config)
|
| 691 |
+
if not is_safe_retry:
|
| 692 |
+
logger.warning(f"[AGENT] 🚫 Safety filter blocked retry query: {safety_reason_retry}")
|
| 693 |
+
return f"⚠️ {blocked_message}"
|
| 694 |
+
|
| 695 |
logger.info(f"[AGENT] 🔄 Retry with query: '{simpler_query}'")
|
| 696 |
time.sleep(0.5) # Add delay for retry
|
| 697 |
results = list(ddgs.text(simpler_query, max_results=max_results))
|
|
|
|
| 701 |
logger.warning(f"[AGENT] ⚠️ No search results found after all attempts for: {query}")
|
| 702 |
return f"No results found for: {query}"
|
| 703 |
|
| 704 |
+
# Format results for model - prioritize headlines for news queries (using config values)
|
| 705 |
+
query_lower = query.lower()
|
| 706 |
+
is_news_query = any(kw in query_lower for kw in news_keywords)
|
| 707 |
+
|
| 708 |
+
if is_news_query:
|
| 709 |
+
formatted = f"Today's News Headlines:\n\n"
|
| 710 |
+
else:
|
| 711 |
+
formatted = f"Web search results for '{query}':\n\n"
|
| 712 |
+
|
| 713 |
for i, result in enumerate(results, 1):
|
| 714 |
title = result.get('title', 'No title')
|
| 715 |
snippet = result.get('body', 'No description')
|
| 716 |
url = result.get('href', result.get('url', ''))
|
| 717 |
+
|
| 718 |
+
# For news queries, prioritize actual headlines over source descriptions (using config filter phrases)
|
| 719 |
+
if is_news_query:
|
| 720 |
+
title_lower = title.lower()
|
| 721 |
+
snippet_lower = snippet.lower() if snippet else ""
|
| 722 |
+
|
| 723 |
+
# Filter out meta pages about news sources (using config values)
|
| 724 |
+
is_meta_page = any(phrase in title_lower or phrase in snippet_lower for phrase in meta_filter_phrases)
|
| 725 |
+
|
| 726 |
+
# Skip meta pages, focus on actual news content
|
| 727 |
+
if is_meta_page:
|
| 728 |
+
continue # Skip this result
|
| 729 |
+
|
| 730 |
+
# Use title as headline if it contains actual news
|
| 731 |
+
if title and title != "No title" and len(title) > 10:
|
| 732 |
+
if snippet and len(snippet) > 50:
|
| 733 |
+
# Check if snippet contains actual news content (not just "visit website")
|
| 734 |
+
if not snippet_lower.startswith(("visit", "check", "read", "go to", "explore", "view", "subscribe")):
|
| 735 |
+
formatted += f"{i}. {title}\n {snippet[:300]}\n"
|
| 736 |
+
if url:
|
| 737 |
+
formatted += f" Source: {url}\n\n"
|
| 738 |
+
else:
|
| 739 |
+
formatted += "\n"
|
| 740 |
+
else:
|
| 741 |
+
# Title is good, snippet is meta - use just title
|
| 742 |
+
formatted += f"{i}. {title}\n"
|
| 743 |
+
if url:
|
| 744 |
+
formatted += f" Source: {url}\n\n"
|
| 745 |
+
else:
|
| 746 |
+
formatted += "\n"
|
| 747 |
+
else:
|
| 748 |
+
# Only title available
|
| 749 |
+
formatted += f"{i}. {title}\n"
|
| 750 |
+
if url:
|
| 751 |
+
formatted += f" Source: {url}\n\n"
|
| 752 |
+
else:
|
| 753 |
+
formatted += "\n"
|
| 754 |
else:
|
| 755 |
+
# Regular search results formatting
|
| 756 |
+
if url:
|
| 757 |
+
formatted += f"{i}. {title}\n {snippet[:200] if snippet else 'No description'}...\n Source: {url}\n\n"
|
| 758 |
+
else:
|
| 759 |
+
formatted += f"{i}. {title}\n {snippet[:200] if snippet else 'No description'}...\n\n"
|
| 760 |
|
| 761 |
formatted_response = formatted.strip()
|
| 762 |
logger.info(f"[AGENT] ✅ Web search formatted response: {len(formatted_response)} chars")
|
| 763 |
+
if is_news_query:
|
| 764 |
+
logger.debug(f"[AGENT] 📰 News query - formatted for headline extraction (filtered meta pages)")
|
| 765 |
logger.debug(f"[AGENT] 📝 Formatted response preview (first 500 chars):\n{formatted_response[:500]}...")
|
| 766 |
|
| 767 |
return formatted_response
|
|
|
|
| 910 |
needs = {"calculator": False, "web_search": False, "calc_expression": None, "search_query": None}
|
| 911 |
|
| 912 |
# Check for math/calculation needs
|
| 913 |
+
# First check keywords (faster), then patterns (more specific)
|
| 914 |
query_lower = query.lower()
|
| 915 |
calculator_config = self.agent_config.get("calculator", {})
|
| 916 |
+
calculator_keywords_config = calculator_config.get("keywords", [])
|
| 917 |
+
|
| 918 |
+
# Check for calculator keywords first
|
| 919 |
+
matched_calc_keywords = [kw for kw in calculator_keywords_config if kw in query_lower]
|
| 920 |
+
|
| 921 |
+
# Load patterns from config
|
| 922 |
math_patterns_config = calculator_config.get("math_patterns", [])
|
| 923 |
|
| 924 |
# Extract patterns from config (list of dicts with "pattern" key) or use defaults
|
|
|
|
| 932 |
r'\b(sqrt|square root|power|exponent)\s*\(?\s*([0-9]+)\s*\)?',
|
| 933 |
]
|
| 934 |
|
| 935 |
+
# Try pattern matching first (more specific)
|
| 936 |
for pattern in math_patterns:
|
| 937 |
match = re.search(pattern, query, re.IGNORECASE)
|
| 938 |
if match:
|
|
|
|
| 940 |
# Extract the expression - try all groups
|
| 941 |
expr = None
|
| 942 |
for i in range(1, len(match.groups()) + 1):
|
| 943 |
+
if match.group(i) and re.search(r'[0-9+\-*/().×÷%]', match.group(i)):
|
| 944 |
expr = match.group(i).strip()
|
| 945 |
break
|
| 946 |
|
|
|
|
| 949 |
expr = expr.replace('×', '*').replace('÷', '/')
|
| 950 |
needs["calc_expression"] = expr
|
| 951 |
else:
|
| 952 |
+
# For geometry/percentage queries without explicit expression, extract full query as context
|
| 953 |
+
if any(geo in query_lower for geo in ["surface area", "area of", "volume of", "perimeter", "circumference", "% of"]):
|
| 954 |
+
# Geometry or percentage query - extract numbers from query for context
|
| 955 |
+
numbers = re.findall(r'[0-9]+(?:\.[0-9]+)?', query)
|
| 956 |
+
if numbers:
|
| 957 |
+
needs["calc_expression"] = " ".join(numbers) # Pass numbers as context
|
| 958 |
+
else:
|
| 959 |
+
needs["calc_expression"] = query # Pass full query as context
|
| 960 |
+
else:
|
| 961 |
+
# Fallback: extract numbers with operators from the match
|
| 962 |
+
numbers_ops = re.search(r'([0-9+\-*/().\s]+)', match.group(0))
|
| 963 |
+
if numbers_ops:
|
| 964 |
+
needs["calc_expression"] = numbers_ops.group(1).strip().replace('×', '*').replace('÷', '/')
|
| 965 |
break
|
| 966 |
|
| 967 |
+
# If no pattern match but keywords found and numbers present, still flag as calculator
|
| 968 |
+
if not needs["calculator"] and matched_calc_keywords:
|
| 969 |
+
# Check if query contains numbers (likely a math query)
|
| 970 |
+
has_numbers = bool(re.search(r'[0-9]+', query))
|
| 971 |
+
# Check for geometry keywords
|
| 972 |
+
has_geometry = any(geo in query_lower for geo in ["surface area", "area of", "volume of", "perimeter", "circumference"])
|
| 973 |
+
# Check for percentage keywords
|
| 974 |
+
has_percentage = "%" in query or "percent" in query_lower or "percentage" in query_lower
|
| 975 |
+
# Check for division keywords
|
| 976 |
+
has_division = any(div in query_lower for div in ["divided by", "divided", "divide"])
|
| 977 |
+
|
| 978 |
+
if has_numbers and (has_geometry or has_percentage or has_division or any(kw in ["calculate", "compute", "what is", "what's", "find", "find the"] for kw in matched_calc_keywords)):
|
| 979 |
+
needs["calculator"] = True
|
| 980 |
+
logger.info(f"[AGENT] 🔍 Calculator detected via keywords: {matched_calc_keywords}")
|
| 981 |
+
# Extract numbers for context
|
| 982 |
+
numbers = re.findall(r'[0-9]+(?:\.[0-9]+)?', query)
|
| 983 |
+
if numbers:
|
| 984 |
+
needs["calc_expression"] = " ".join(numbers) if len(numbers) <= 3 else query[:100]
|
| 985 |
+
else:
|
| 986 |
+
needs["calc_expression"] = query[:100] # Pass query as context
|
| 987 |
+
|
| 988 |
# Check for web search needs
|
| 989 |
# Load keywords and patterns from config
|
| 990 |
web_search_config = self.agent_config.get("web_search", {})
|
|
|
|
| 1150 |
search_q = tool_needs["search_query"] or query
|
| 1151 |
logger.info(f"[AGENT] 🔍 Extracted search query: '{search_q}' (original: '{query[:100]}')")
|
| 1152 |
|
| 1153 |
+
# Load news detection keywords from config
|
| 1154 |
+
web_search_config = self.agent_config.get("web_search", {})
|
| 1155 |
+
news_keywords = web_search_config.get("news_query_keywords", ["news", "headlines", "headline", "breaking"])
|
| 1156 |
+
news_enhancement_keywords = web_search_config.get("news_enhancement_keywords", ["headlines", "breaking", "latest"])
|
| 1157 |
+
|
| 1158 |
+
# Detect news/headlines queries using config keywords
|
| 1159 |
+
query_lower = query.lower()
|
| 1160 |
+
search_q_lower = search_q.lower()
|
| 1161 |
+
is_news_query = any(keyword in query_lower for keyword in news_keywords)
|
| 1162 |
+
|
| 1163 |
+
# Enhance news queries to get actual headlines, not just source pages
|
| 1164 |
+
if is_news_query:
|
| 1165 |
+
# Remove question marks and question words that might reduce relevance
|
| 1166 |
+
enhanced_search = re.sub(r'[?]', '', search_q)
|
| 1167 |
+
enhanced_search = re.sub(r'^(what are|what is|what\'s|tell me|show me|find me)\s+', '', enhanced_search, flags=re.IGNORECASE)
|
| 1168 |
+
enhanced_search = enhanced_search.strip()
|
| 1169 |
+
|
| 1170 |
+
# For generic news queries, add specific keywords to get actual headlines (using config)
|
| 1171 |
+
if any(gen in search_q_lower for gen in ["today's", "today", "top news", "breaking news", "latest news", "news headlines", "headlines"]):
|
| 1172 |
+
# Already contains news keywords - keep as is but enhance using config
|
| 1173 |
+
if "headlines" not in search_q_lower and "headline" not in search_q_lower:
|
| 1174 |
+
if any(kw in news_enhancement_keywords for kw in ["headlines", "headline"]):
|
| 1175 |
+
enhanced_search = f"{enhanced_search} headlines"
|
| 1176 |
+
if "breaking" not in search_q_lower and "latest" not in search_q_lower:
|
| 1177 |
+
if "latest" in news_enhancement_keywords:
|
| 1178 |
+
enhanced_search = f"latest {enhanced_search}"
|
| 1179 |
+
|
| 1180 |
+
search_q = enhanced_search
|
| 1181 |
+
logger.info(f"[AGENT] 📰 Enhanced news query: '{search_q}' (for better headline results)")
|
| 1182 |
+
|
| 1183 |
# Validate search query before calling API
|
| 1184 |
search_q_lower = search_q.lower().strip()
|
| 1185 |
if (search_q_lower.startswith('and ') or
|
|
|
|
| 1194 |
if search_q and 'custom_web_search' in globals() and custom_web_search is not None:
|
| 1195 |
max_results = self.agent_config.get("web_search", {}).get("max_results", 5)
|
| 1196 |
logger.info(f"[AGENT] 🌐 Web search API call: query='{search_q}', max_results={max_results}")
|
| 1197 |
+
# Pass agent_config to web_search for news detection and filtering
|
| 1198 |
+
search_result = custom_web_search(search_q, max_results=max_results, agent_config=self.agent_config)
|
| 1199 |
|
| 1200 |
# Check if search actually returned valid results (not "No results found" or error)
|
| 1201 |
has_results = (search_result and
|
|
|
|
| 1228 |
# The model already has structured format (🎯, 📊, ⚡, 💡) built-in via meetara_lab_core.py
|
| 1229 |
# Just feed tool results - model will automatically structure the response
|
| 1230 |
if tool_results:
|
| 1231 |
+
# Load news query keywords and instruction templates from config
|
| 1232 |
+
web_search_config = self.agent_config.get("web_search", {})
|
| 1233 |
+
news_query_config = web_search_config.get("news_query_instructions", {})
|
| 1234 |
+
news_keywords = web_search_config.get("news_query_keywords", ["news", "headlines", "headline", "breaking"])
|
| 1235 |
+
|
| 1236 |
+
# Detect if this is a news/headlines query using config keywords
|
| 1237 |
+
query_lower = query.lower()
|
| 1238 |
+
is_news_query = any(keyword in query_lower for keyword in news_keywords)
|
| 1239 |
+
|
| 1240 |
+
# Build context-aware instructions from config
|
| 1241 |
+
if is_news_query and news_query_config.get("enabled", True):
|
| 1242 |
+
instruction_text = news_query_config.get("instruction_template",
|
| 1243 |
+
"CRITICAL: Extract and list the ACTUAL NEWS HEADLINES and STORIES from the search results above. "
|
| 1244 |
+
"Do NOT just describe what news sources offer - provide the REAL NEWS HEADLINES and CONTENT."
|
| 1245 |
+
)
|
| 1246 |
+
logger.info(f"[AGENT] 📰 News query detected - using config-based instructions for headline extraction")
|
| 1247 |
+
else:
|
| 1248 |
+
instruction_text = news_query_config.get("regular_instruction", "Use the tool results above to provide your response.")
|
| 1249 |
+
|
| 1250 |
enhanced_prompt = (
|
| 1251 |
f"{query}\n\n"
|
| 1252 |
f"=== Tool Results ===\n"
|
| 1253 |
+ "\n\n".join(tool_results) +
|
| 1254 |
+
f"\n\n{instruction_text}"
|
| 1255 |
)
|
| 1256 |
logger.info(f"[AGENT] 📝 Feeding {len(tool_results)} tool results to model (model will auto-format)")
|
| 1257 |
+
if is_news_query:
|
| 1258 |
+
logger.info(f"[AGENT] 📰 News query detected - instructing model to extract actual headlines")
|
| 1259 |
logger.debug(f"[AGENT] 📤 Enhanced prompt to model (first 1000 chars):\n{enhanced_prompt[:1000]}...")
|
| 1260 |
|
| 1261 |
# Log full tool results being fed to model
|