noesium 0.1.0__py3-none-any.whl → 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. noesium/agents/askura_agent/__init__.py +22 -0
  2. noesium/agents/askura_agent/askura_agent.py +480 -0
  3. noesium/agents/askura_agent/conversation.py +164 -0
  4. noesium/agents/askura_agent/extractor.py +175 -0
  5. noesium/agents/askura_agent/memory.py +14 -0
  6. noesium/agents/askura_agent/models.py +239 -0
  7. noesium/agents/askura_agent/prompts.py +202 -0
  8. noesium/agents/askura_agent/reflection.py +234 -0
  9. noesium/agents/askura_agent/summarizer.py +30 -0
  10. noesium/agents/askura_agent/utils.py +6 -0
  11. noesium/agents/deep_research/__init__.py +13 -0
  12. noesium/agents/deep_research/agent.py +398 -0
  13. noesium/agents/deep_research/prompts.py +84 -0
  14. noesium/agents/deep_research/schemas.py +42 -0
  15. noesium/agents/deep_research/state.py +54 -0
  16. noesium/agents/search/__init__.py +5 -0
  17. noesium/agents/search/agent.py +474 -0
  18. noesium/agents/search/state.py +28 -0
  19. noesium/core/__init__.py +1 -1
  20. noesium/core/agent/base.py +10 -2
  21. noesium/core/goalith/decomposer/llm_decomposer.py +1 -1
  22. noesium/core/llm/__init__.py +1 -1
  23. noesium/core/llm/base.py +2 -2
  24. noesium/core/llm/litellm.py +42 -21
  25. noesium/core/llm/llamacpp.py +25 -4
  26. noesium/core/llm/ollama.py +43 -22
  27. noesium/core/llm/openai.py +25 -5
  28. noesium/core/llm/openrouter.py +1 -1
  29. noesium/core/toolify/base.py +9 -2
  30. noesium/core/toolify/config.py +2 -2
  31. noesium/core/toolify/registry.py +21 -5
  32. noesium/core/tracing/opik_tracing.py +7 -7
  33. noesium/core/vector_store/__init__.py +2 -2
  34. noesium/core/vector_store/base.py +1 -1
  35. noesium/core/vector_store/pgvector.py +10 -13
  36. noesium/core/vector_store/weaviate.py +2 -1
  37. noesium/toolkits/__init__.py +1 -0
  38. noesium/toolkits/arxiv_toolkit.py +310 -0
  39. noesium/toolkits/audio_aliyun_toolkit.py +441 -0
  40. noesium/toolkits/audio_toolkit.py +370 -0
  41. noesium/toolkits/bash_toolkit.py +332 -0
  42. noesium/toolkits/document_toolkit.py +454 -0
  43. noesium/toolkits/file_edit_toolkit.py +552 -0
  44. noesium/toolkits/github_toolkit.py +395 -0
  45. noesium/toolkits/gmail_toolkit.py +575 -0
  46. noesium/toolkits/image_toolkit.py +425 -0
  47. noesium/toolkits/memory_toolkit.py +398 -0
  48. noesium/toolkits/python_executor_toolkit.py +334 -0
  49. noesium/toolkits/search_toolkit.py +451 -0
  50. noesium/toolkits/serper_toolkit.py +623 -0
  51. noesium/toolkits/tabular_data_toolkit.py +537 -0
  52. noesium/toolkits/user_interaction_toolkit.py +365 -0
  53. noesium/toolkits/video_toolkit.py +168 -0
  54. noesium/toolkits/wikipedia_toolkit.py +420 -0
  55. noesium-0.2.1.dist-info/METADATA +253 -0
  56. {noesium-0.1.0.dist-info → noesium-0.2.1.dist-info}/RECORD +59 -23
  57. {noesium-0.1.0.dist-info → noesium-0.2.1.dist-info}/licenses/LICENSE +1 -1
  58. noesium-0.1.0.dist-info/METADATA +0 -525
  59. {noesium-0.1.0.dist-info → noesium-0.2.1.dist-info}/WHEEL +0 -0
  60. {noesium-0.1.0.dist-info → noesium-0.2.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,623 @@
1
+ """
2
+ Serper toolkit for comprehensive Google search capabilities.
3
+
4
+ Provides tools for various Google search services including web search,
5
+ images, news, maps, scholar, and more through the Serper API.
6
+ """
7
+
8
+ import asyncio
9
+ import os
10
+ from typing import Any, Callable, Dict, Optional
11
+
12
+ import aiohttp
13
+
14
+ from noesium.core.toolify.base import AsyncBaseToolkit
15
+ from noesium.core.toolify.config import ToolkitConfig
16
+ from noesium.core.toolify.registry import register_toolkit
17
+ from noesium.core.utils.logging import get_logger
18
+
19
+ logger = get_logger(__name__)
20
+
21
+
22
+ @register_toolkit("serper")
23
+ class SerperToolkit(AsyncBaseToolkit):
24
+ """
25
+ Toolkit for comprehensive Google search using Serper API.
26
+
27
+ This toolkit provides access to various Google search services through
28
+ the Serper API (google.serper.dev), offering comprehensive search
29
+ capabilities across different Google services.
30
+
31
+ Features:
32
+ - Web search with customizable parameters
33
+ - Image search and visual content discovery
34
+ - News search with date filtering
35
+ - Google Maps and Places search
36
+ - Academic search via Google Scholar
37
+ - Video search capabilities
38
+ - Autocomplete suggestions
39
+ - Google Lens visual search
40
+ - Configurable location and language settings
41
+
42
+ Search Services:
43
+ - **Web Search**: General Google search results
44
+ - **Image Search**: Visual content and image discovery
45
+ - **News Search**: Current news and articles
46
+ - **Maps Search**: Location-based search and places
47
+ - **Scholar Search**: Academic papers and research
48
+ - **Video Search**: Video content discovery
49
+ - **Places Search**: Business and location information
50
+ - **Autocomplete**: Search suggestions and completions
51
+ - **Google Lens**: Visual search and image analysis
52
+
53
+ Required configuration:
54
+ - SERPER_API_KEY: API key from google.serper.dev
55
+
56
+ Optional configuration:
57
+ - default_location: Default search location
58
+ - default_language: Default interface language
59
+ - default_country: Default country code
60
+ """
61
+
62
+ def __init__(self, config: ToolkitConfig = None):
63
+ """
64
+ Initialize the Serper toolkit.
65
+
66
+ Args:
67
+ config: Toolkit configuration containing API key and settings
68
+
69
+ Raises:
70
+ ValueError: If SERPER_API_KEY is not provided
71
+ """
72
+ super().__init__(config)
73
+
74
+ # Get API key from config or environment
75
+ self.api_key = self.config.config.get("SERPER_API_KEY") or os.getenv("SERPER_API_KEY")
76
+
77
+ if not self.api_key:
78
+ raise ValueError(
79
+ "SERPER_API_KEY is required for SerperToolkit. " "Set it in config or environment variables."
80
+ )
81
+
82
+ # Configuration
83
+ self.base_url = "https://google.serper.dev"
84
+ self.default_location = self.config.config.get("default_location", "United States")
85
+ self.default_gl = self.config.config.get("default_gl", "us")
86
+ self.default_hl = self.config.config.get("default_hl", "en")
87
+ self.timeout = self.config.config.get("timeout", 30)
88
+
89
+ # Request headers
90
+ self.headers = {"X-API-KEY": self.api_key, "Content-Type": "application/json"}
91
+
92
+ self.logger.info("Serper toolkit initialized with Google search capabilities")
93
+
94
+ async def _make_search_request(self, endpoint: str, payload: Dict) -> Dict[str, Any]:
95
+ """
96
+ Make a request to the Serper API.
97
+
98
+ Args:
99
+ endpoint: API endpoint (search, images, news, etc.)
100
+ payload: Request payload
101
+
102
+ Returns:
103
+ API response as dictionary
104
+ """
105
+ url = f"{self.base_url}/{endpoint}"
106
+
107
+ try:
108
+ async with aiohttp.ClientSession() as session:
109
+ async with session.post(
110
+ url, headers=self.headers, json=payload, timeout=aiohttp.ClientTimeout(total=self.timeout)
111
+ ) as response:
112
+ if response.status == 200:
113
+ return await response.json()
114
+ elif response.status == 429:
115
+ return {"error": "Rate limit exceeded. Please try again later."}
116
+ elif response.status == 401:
117
+ return {"error": "Invalid API key or authentication failed."}
118
+ elif response.status == 400:
119
+ error_text = await response.text()
120
+ return {"error": f"Bad request: {error_text}"}
121
+ else:
122
+ error_text = await response.text()
123
+ return {"error": f"HTTP {response.status}: {error_text}"}
124
+
125
+ except asyncio.TimeoutError:
126
+ return {"error": f"Request timeout after {self.timeout} seconds"}
127
+ except aiohttp.ClientError as e:
128
+ return {"error": f"Connection error: {str(e)}"}
129
+ except Exception as e:
130
+ return {"error": f"Unexpected error: {str(e)}"}
131
+
132
+ async def google_search(
133
+ self,
134
+ query: str,
135
+ location: Optional[str] = None,
136
+ gl: Optional[str] = None,
137
+ hl: Optional[str] = None,
138
+ num: int = 10,
139
+ date_range: Optional[str] = None,
140
+ ) -> Dict[str, Any]:
141
+ """
142
+ Search the web using Google Search.
143
+
144
+ This tool performs comprehensive web searches using Google's search engine
145
+ through the Serper API. It provides access to organic search results with
146
+ customizable parameters for location, language, and filtering.
147
+
148
+ Args:
149
+ query: Search query string
150
+ location: Geographic location for search (default: "United States")
151
+ gl: Country code for search results (default: "us")
152
+ hl: Language code for search interface (default: "en")
153
+ num: Number of results to return (1-100, default: 10)
154
+ date_range: Time filter for search results
155
+ Options: "h" (past hour), "d" (past day), "w" (past week),
156
+ "m" (past month), "y" (past year)
157
+
158
+ Returns:
159
+ Dictionary containing:
160
+ - query: Original search query
161
+ - results: List of search results with title, link, snippet
162
+ - searchParameters: Search configuration used
163
+ - total_results: Number of results returned
164
+ - status: "success" or "error"
165
+
166
+ Examples:
167
+ - google_search("artificial intelligence trends 2024")
168
+ - google_search("python tutorials", num=20, date_range="m")
169
+ - google_search("restaurants", location="New York", gl="us")
170
+ """
171
+ self.logger.info(f"Performing Google search for: {query}")
172
+
173
+ # Use defaults if not specified
174
+ location = location or self.default_location
175
+ gl = gl or self.default_gl
176
+ hl = hl or self.default_hl
177
+
178
+ # Validate parameters
179
+ num = max(1, min(100, num)) # Clamp between 1 and 100
180
+
181
+ payload = {"q": query, "location": location, "gl": gl, "hl": hl, "num": num}
182
+
183
+ if date_range:
184
+ payload["tbs"] = f"qdr:{date_range}"
185
+
186
+ result = await self._make_search_request("search", payload)
187
+
188
+ if "error" in result:
189
+ return {"query": query, "error": result["error"], "status": "error"}
190
+
191
+ return {
192
+ "query": query,
193
+ "location": location,
194
+ "gl": gl,
195
+ "hl": hl,
196
+ "date_range": date_range,
197
+ "results": result.get("organic", []),
198
+ "searchParameters": result.get("searchParameters", {}),
199
+ "total_results": len(result.get("organic", [])),
200
+ "status": "success",
201
+ }
202
+
203
+ async def image_search(
204
+ self,
205
+ query: str,
206
+ location: Optional[str] = None,
207
+ gl: Optional[str] = None,
208
+ hl: Optional[str] = None,
209
+ num: int = 10,
210
+ date_range: Optional[str] = None,
211
+ ) -> Dict[str, Any]:
212
+ """
213
+ Search for images using Google Images.
214
+
215
+ This tool searches for visual content using Google Images, providing
216
+ access to a vast collection of images with metadata and source information.
217
+
218
+ Args:
219
+ query: Image search query
220
+ location: Geographic location for search
221
+ gl: Country code for search results
222
+ hl: Language code for search interface
223
+ num: Number of results to return (1-100)
224
+ date_range: Time filter for images
225
+
226
+ Returns:
227
+ Dictionary with image search results including URLs, titles, and sources
228
+ """
229
+ self.logger.info(f"Performing image search for: {query}")
230
+
231
+ location = location or self.default_location
232
+ gl = gl or self.default_gl
233
+ hl = hl or self.default_hl
234
+ num = max(1, min(100, num))
235
+
236
+ payload = {"q": query, "location": location, "gl": gl, "hl": hl, "num": num}
237
+
238
+ if date_range:
239
+ payload["tbs"] = f"qdr:{date_range}"
240
+
241
+ result = await self._make_search_request("images", payload)
242
+
243
+ if "error" in result:
244
+ return {"query": query, "error": result["error"], "status": "error"}
245
+
246
+ return {
247
+ "query": query,
248
+ "location": location,
249
+ "results": result.get("images", []),
250
+ "searchParameters": result.get("searchParameters", {}),
251
+ "total_results": len(result.get("images", [])),
252
+ "status": "success",
253
+ }
254
+
255
+ async def news_search(
256
+ self,
257
+ query: str,
258
+ location: Optional[str] = None,
259
+ gl: Optional[str] = None,
260
+ hl: Optional[str] = None,
261
+ num: int = 10,
262
+ date_range: Optional[str] = None,
263
+ ) -> Dict[str, Any]:
264
+ """
265
+ Search for news articles using Google News.
266
+
267
+ This tool searches current news and articles from various sources
268
+ worldwide, with options for location-based and time-filtered results.
269
+
270
+ Args:
271
+ query: News search query
272
+ location: Geographic location for news
273
+ gl: Country code for news sources
274
+ hl: Language code for news interface
275
+ num: Number of results to return
276
+ date_range: Time filter for news articles
277
+
278
+ Returns:
279
+ Dictionary with news search results including headlines, sources, and dates
280
+ """
281
+ self.logger.info(f"Performing news search for: {query}")
282
+
283
+ location = location or self.default_location
284
+ gl = gl or self.default_gl
285
+ hl = hl or self.default_hl
286
+ num = max(1, min(100, num))
287
+
288
+ payload = {"q": query, "location": location, "gl": gl, "hl": hl, "num": num}
289
+
290
+ if date_range:
291
+ payload["tbs"] = f"qdr:{date_range}"
292
+
293
+ result = await self._make_search_request("news", payload)
294
+
295
+ if "error" in result:
296
+ return {"query": query, "error": result["error"], "status": "error"}
297
+
298
+ return {
299
+ "query": query,
300
+ "location": location,
301
+ "gl": gl,
302
+ "hl": hl,
303
+ "date_range": date_range,
304
+ "results": result.get("news", []),
305
+ "searchParameters": result.get("searchParameters", {}),
306
+ "total_results": len(result.get("news", [])),
307
+ "status": "success",
308
+ }
309
+
310
+ async def scholar_search(
311
+ self,
312
+ query: str,
313
+ location: Optional[str] = None,
314
+ gl: Optional[str] = None,
315
+ hl: Optional[str] = None,
316
+ num: int = 10,
317
+ ) -> Dict[str, Any]:
318
+ """
319
+ Search for academic papers using Google Scholar.
320
+
321
+ This tool searches academic literature, including papers, theses,
322
+ books, conference papers, and other scholarly literature.
323
+
324
+ Args:
325
+ query: Academic search query
326
+ location: Geographic location
327
+ gl: Country code
328
+ hl: Language code
329
+ num: Number of results to return
330
+
331
+ Returns:
332
+ Dictionary with academic search results including citations and sources
333
+ """
334
+ self.logger.info(f"Performing scholar search for: {query}")
335
+
336
+ location = location or self.default_location
337
+ gl = gl or self.default_gl
338
+ hl = hl or self.default_hl
339
+ num = max(1, min(100, num))
340
+
341
+ payload = {
342
+ "q": query,
343
+ "location": location,
344
+ "gl": gl,
345
+ "hl": hl,
346
+ "num": num,
347
+ }
348
+
349
+ result = await self._make_search_request("scholar", payload)
350
+
351
+ if "error" in result:
352
+ return {"query": query, "error": result["error"], "status": "error"}
353
+
354
+ return {
355
+ "query": query,
356
+ "location": location,
357
+ "gl": gl,
358
+ "hl": hl,
359
+ "results": result.get("organic", []),
360
+ "searchParameters": result.get("searchParameters", {}),
361
+ "total_results": len(result.get("organic", [])),
362
+ "status": "success",
363
+ }
364
+
365
+ async def maps_search(
366
+ self,
367
+ query: str,
368
+ hl: Optional[str] = None,
369
+ latitude: Optional[float] = None,
370
+ longitude: Optional[float] = None,
371
+ zoom: Optional[int] = 18,
372
+ place_id: Optional[str] = None,
373
+ cid: Optional[str] = None,
374
+ num: int = 10,
375
+ ) -> Dict[str, Any]:
376
+ """
377
+ Search for locations using Google Maps.
378
+
379
+ This tool searches for places, businesses, and locations using Google Maps,
380
+ with support for GPS coordinates and place identifiers.
381
+
382
+ Args:
383
+ query: Location search query
384
+ hl: Language code
385
+ latitude: GPS latitude coordinate
386
+ longitude: GPS longitude coordinate
387
+ zoom: Map zoom level (1-21)
388
+ place_id: Google Place ID
389
+ cid: Google CID (Customer ID)
390
+ num: Number of results to return
391
+
392
+ Returns:
393
+ Dictionary with location search results including addresses and details
394
+ """
395
+ self.logger.info(f"Performing maps search for: {query}")
396
+
397
+ hl = hl or self.default_hl
398
+ num = max(1, min(100, num))
399
+
400
+ payload = {"q": query, "hl": hl, "num": num}
401
+
402
+ if latitude is not None and longitude is not None:
403
+ if zoom is not None:
404
+ payload["ll"] = f"@{latitude},{longitude},{zoom}z"
405
+ else:
406
+ payload["ll"] = f"@{latitude},{longitude}"
407
+ if place_id:
408
+ payload["placeId"] = place_id
409
+ if cid:
410
+ payload["cid"] = cid
411
+
412
+ result = await self._make_search_request("maps", payload)
413
+
414
+ if "error" in result:
415
+ return {"query": query, "error": result["error"], "status": "error"}
416
+
417
+ return {
418
+ "query": query,
419
+ "hl": hl,
420
+ "latitude": latitude,
421
+ "longitude": longitude,
422
+ "zoom": zoom,
423
+ "place_id": place_id,
424
+ "cid": cid,
425
+ "results": result.get("places", []),
426
+ "searchParameters": result.get("searchParameters", {}),
427
+ "total_results": len(result.get("places", [])),
428
+ "status": "success",
429
+ }
430
+
431
+ async def video_search(
432
+ self,
433
+ query: str,
434
+ location: Optional[str] = None,
435
+ gl: Optional[str] = None,
436
+ hl: Optional[str] = None,
437
+ num: int = 10,
438
+ date_range: Optional[str] = None,
439
+ ) -> Dict[str, Any]:
440
+ """
441
+ Search for videos using Google Videos.
442
+
443
+ Args:
444
+ query: Video search query
445
+ location: Geographic location
446
+ gl: Country code
447
+ hl: Language code
448
+ num: Number of results to return
449
+ date_range: Time filter for videos
450
+
451
+ Returns:
452
+ Dictionary with video search results
453
+ """
454
+ self.logger.info(f"Performing video search for: {query}")
455
+
456
+ location = location or self.default_location
457
+ gl = gl or self.default_gl
458
+ hl = hl or self.default_hl
459
+ num = max(1, min(100, num))
460
+
461
+ payload = {"q": query, "location": location, "gl": gl, "hl": hl, "num": num}
462
+
463
+ if date_range:
464
+ payload["tbs"] = f"qdr:{date_range}"
465
+
466
+ result = await self._make_search_request("videos", payload)
467
+
468
+ if "error" in result:
469
+ return {"query": query, "error": result["error"], "status": "error"}
470
+
471
+ return {
472
+ "query": query,
473
+ "location": location,
474
+ "results": result.get("videos", []),
475
+ "searchParameters": result.get("searchParameters", {}),
476
+ "total_results": len(result.get("videos", [])),
477
+ "status": "success",
478
+ }
479
+
480
+ async def autocomplete(
481
+ self, query: str, location: Optional[str] = None, gl: Optional[str] = None, hl: Optional[str] = None
482
+ ) -> Dict[str, Any]:
483
+ """
484
+ Get autocomplete suggestions for a search query.
485
+
486
+ Args:
487
+ query: Partial search query
488
+ location: Geographic location
489
+ gl: Country code
490
+ hl: Language code
491
+
492
+ Returns:
493
+ Dictionary with autocomplete suggestions
494
+ """
495
+ self.logger.info(f"Getting autocomplete for: {query}")
496
+
497
+ location = location or self.default_location
498
+ gl = gl or self.default_gl
499
+ hl = hl or self.default_hl
500
+
501
+ payload = {"q": query, "location": location, "gl": gl, "hl": hl}
502
+
503
+ result = await self._make_search_request("autocomplete", payload)
504
+
505
+ if "error" in result:
506
+ return {"query": query, "error": result["error"], "status": "error"}
507
+
508
+ return {
509
+ "query": query,
510
+ "location": location,
511
+ "gl": gl,
512
+ "hl": hl,
513
+ "suggestions": result.get("suggestions", []),
514
+ "searchParameters": result.get("searchParameters", {}),
515
+ "total_suggestions": len(result.get("suggestions", [])),
516
+ "status": "success",
517
+ }
518
+
519
+ async def google_lens(
520
+ self, url: str, gl: Optional[str] = None, hl: Optional[str] = None, num: int = 10
521
+ ) -> Dict[str, Any]:
522
+ """
523
+ Analyze an image using Google Lens.
524
+
525
+ Args:
526
+ url: URL of the image to analyze
527
+ gl: Country code
528
+ hl: Language code
529
+ num: Number of results to return
530
+
531
+ Returns:
532
+ Dictionary with visual search results
533
+ """
534
+ self.logger.info(f"Performing Google Lens analysis for: {url}")
535
+
536
+ gl = gl or self.default_gl
537
+ hl = hl or self.default_hl
538
+ num = max(1, min(100, num))
539
+
540
+ payload = {"url": url, "gl": gl, "hl": hl}
541
+
542
+ result = await self._make_search_request("lens", payload)
543
+
544
+ if "error" in result:
545
+ return {"url": url, "error": result["error"], "status": "error"}
546
+
547
+ return {
548
+ "url": url,
549
+ "gl": gl,
550
+ "hl": hl,
551
+ "results": result.get("organic", [])[:num],
552
+ "searchParameters": result.get("searchParameters", {}),
553
+ "total_results": min(len(result.get("organic", [])), num),
554
+ "status": "success",
555
+ }
556
+
557
+ async def places_search(
558
+ self,
559
+ query: str,
560
+ location: Optional[str] = None,
561
+ gl: Optional[str] = None,
562
+ hl: Optional[str] = None,
563
+ num: int = 10,
564
+ date_range: Optional[str] = None,
565
+ ) -> Dict[str, Any]:
566
+ """
567
+ Search for places using Google Places.
568
+
569
+ Args:
570
+ query: Places search query
571
+ location: Geographic location
572
+ gl: Country code
573
+ hl: Language code
574
+ num: Number of results to return
575
+ date_range: Time filter
576
+
577
+ Returns:
578
+ Dictionary with places search results
579
+ """
580
+ self.logger.info(f"Performing places search for: {query}")
581
+
582
+ location = location or self.default_location
583
+ gl = gl or self.default_gl
584
+ hl = hl or self.default_hl
585
+ num = max(1, min(100, num))
586
+
587
+ payload = {"q": query, "location": location, "gl": gl, "hl": hl, "num": num}
588
+
589
+ if date_range:
590
+ payload["tbs"] = f"qdr:{date_range}"
591
+
592
+ result = await self._make_search_request("places", payload)
593
+
594
+ if "error" in result:
595
+ return {"query": query, "error": result["error"], "status": "error"}
596
+
597
+ return {
598
+ "query": query,
599
+ "location": location,
600
+ "results": result.get("places", []),
601
+ "searchParameters": result.get("searchParameters", {}),
602
+ "total_results": len(result.get("places", [])),
603
+ "status": "success",
604
+ }
605
+
606
+ async def get_tools_map(self) -> Dict[str, Callable]:
607
+ """
608
+ Get the mapping of tool names to their implementation functions.
609
+
610
+ Returns:
611
+ Dictionary mapping tool names to callable functions
612
+ """
613
+ return {
614
+ "google_search": self.google_search,
615
+ "image_search": self.image_search,
616
+ "news_search": self.news_search,
617
+ "scholar_search": self.scholar_search,
618
+ "maps_search": self.maps_search,
619
+ "video_search": self.video_search,
620
+ "autocomplete": self.autocomplete,
621
+ "google_lens": self.google_lens,
622
+ "places_search": self.places_search,
623
+ }