intentkit 0.6.9.dev2__py3-none-any.whl → 0.6.10.dev2__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.

Potentially problematic release.


This version of intentkit might be problematic. Click here for more details.

Files changed (168) hide show
  1. intentkit/__init__.py +1 -1
  2. intentkit/abstracts/graph.py +17 -2
  3. intentkit/core/engine.py +49 -30
  4. intentkit/core/node.py +10 -20
  5. intentkit/models/agent.py +3 -0
  6. intentkit/models/chat.py +9 -1
  7. intentkit/skills/acolyt/ask.py +2 -5
  8. intentkit/skills/acolyt/base.py +16 -6
  9. intentkit/skills/aixbt/__init__.py +3 -7
  10. intentkit/skills/aixbt/projects.py +12 -36
  11. intentkit/skills/allora/base.py +16 -6
  12. intentkit/skills/allora/price.py +2 -4
  13. intentkit/skills/base.py +8 -1
  14. intentkit/skills/carv/base.py +12 -10
  15. intentkit/skills/carv/fetch_news.py +90 -92
  16. intentkit/skills/carv/onchain_query.py +162 -164
  17. intentkit/skills/carv/token_info_and_price.py +108 -110
  18. intentkit/skills/chainlist/chain_lookup.py +1 -2
  19. intentkit/skills/common/current_time.py +1 -2
  20. intentkit/skills/cookiefun/base.py +20 -12
  21. intentkit/skills/cookiefun/get_account_details.py +1 -3
  22. intentkit/skills/cookiefun/get_account_feed.py +1 -3
  23. intentkit/skills/cookiefun/get_account_smart_followers.py +1 -3
  24. intentkit/skills/cookiefun/get_sectors.py +2 -3
  25. intentkit/skills/cookiefun/search_accounts.py +1 -3
  26. intentkit/skills/cryptocompare/fetch_news.py +3 -4
  27. intentkit/skills/cryptocompare/fetch_price.py +3 -4
  28. intentkit/skills/cryptocompare/fetch_top_exchanges.py +3 -4
  29. intentkit/skills/cryptocompare/fetch_top_market_cap.py +3 -4
  30. intentkit/skills/cryptocompare/fetch_top_volume.py +3 -4
  31. intentkit/skills/cryptocompare/fetch_trading_signals.py +3 -4
  32. intentkit/skills/cryptopanic/base.py +13 -9
  33. intentkit/skills/cryptopanic/fetch_crypto_news.py +150 -153
  34. intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +133 -136
  35. intentkit/skills/dapplooker/base.py +16 -6
  36. intentkit/skills/dapplooker/dapplooker_token_data.py +2 -4
  37. intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +2 -3
  38. intentkit/skills/defillama/coins/fetch_block.py +2 -3
  39. intentkit/skills/defillama/coins/fetch_current_prices.py +2 -5
  40. intentkit/skills/defillama/coins/fetch_first_price.py +2 -5
  41. intentkit/skills/defillama/coins/fetch_historical_prices.py +2 -3
  42. intentkit/skills/defillama/coins/fetch_price_chart.py +2 -5
  43. intentkit/skills/defillama/coins/fetch_price_percentage.py +2 -5
  44. intentkit/skills/defillama/fees/fetch_fees_overview.py +2 -3
  45. intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +2 -3
  46. intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +2 -3
  47. intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +2 -3
  48. intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +2 -3
  49. intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +2 -5
  50. intentkit/skills/defillama/tvl/fetch_chains.py +2 -3
  51. intentkit/skills/defillama/tvl/fetch_historical_tvl.py +2 -3
  52. intentkit/skills/defillama/tvl/fetch_protocol.py +2 -5
  53. intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +2 -5
  54. intentkit/skills/defillama/tvl/fetch_protocols.py +2 -3
  55. intentkit/skills/defillama/volumes/fetch_dex_overview.py +2 -3
  56. intentkit/skills/defillama/volumes/fetch_dex_summary.py +2 -5
  57. intentkit/skills/defillama/volumes/fetch_options_overview.py +2 -3
  58. intentkit/skills/defillama/yields/fetch_pool_chart.py +2 -5
  59. intentkit/skills/defillama/yields/fetch_pools.py +2 -3
  60. intentkit/skills/dune_analytics/base.py +15 -9
  61. intentkit/skills/dune_analytics/fetch_kol_buys.py +125 -128
  62. intentkit/skills/dune_analytics/fetch_nation_metrics.py +234 -237
  63. intentkit/skills/elfa/base.py +16 -6
  64. intentkit/skills/elfa/mention.py +2 -7
  65. intentkit/skills/elfa/stats.py +2 -6
  66. intentkit/skills/elfa/tokens.py +1 -4
  67. intentkit/skills/enso/base.py +25 -13
  68. intentkit/skills/enso/best_yield.py +1 -4
  69. intentkit/skills/enso/networks.py +2 -5
  70. intentkit/skills/enso/prices.py +1 -5
  71. intentkit/skills/enso/route.py +2 -5
  72. intentkit/skills/enso/tokens.py +1 -4
  73. intentkit/skills/enso/wallet.py +3 -9
  74. intentkit/skills/firecrawl/base.py +16 -6
  75. intentkit/skills/firecrawl/clear.py +1 -3
  76. intentkit/skills/firecrawl/crawl.py +7 -8
  77. intentkit/skills/firecrawl/query.py +7 -9
  78. intentkit/skills/firecrawl/scrape.py +7 -8
  79. intentkit/skills/github/github_search.py +1 -3
  80. intentkit/skills/heurist/base.py +15 -0
  81. intentkit/skills/heurist/image_generation_animagine_xl.py +3 -4
  82. intentkit/skills/heurist/image_generation_arthemy_comics.py +3 -4
  83. intentkit/skills/heurist/image_generation_arthemy_real.py +3 -4
  84. intentkit/skills/heurist/image_generation_braindance.py +3 -4
  85. intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +3 -4
  86. intentkit/skills/heurist/image_generation_flux_1_dev.py +3 -4
  87. intentkit/skills/heurist/image_generation_sdxl.py +3 -4
  88. intentkit/skills/http/get.py +0 -2
  89. intentkit/skills/http/post.py +0 -2
  90. intentkit/skills/http/put.py +0 -2
  91. intentkit/skills/lifi/token_execute.py +1 -3
  92. intentkit/skills/lifi/token_quote.py +0 -2
  93. intentkit/skills/moralis/base.py +15 -1
  94. intentkit/skills/nation/nft_check.py +2 -5
  95. intentkit/skills/openai/base.py +14 -5
  96. intentkit/skills/openai/dalle_image_generation.py +6 -5
  97. intentkit/skills/openai/gpt_image_generation.py +6 -5
  98. intentkit/skills/openai/gpt_image_to_image.py +6 -5
  99. intentkit/skills/openai/image_to_text.py +6 -6
  100. intentkit/skills/portfolio/base.py +4 -3
  101. intentkit/skills/portfolio/token_balances.py +2 -4
  102. intentkit/skills/portfolio/wallet_approvals.py +2 -4
  103. intentkit/skills/portfolio/wallet_defi_positions.py +3 -4
  104. intentkit/skills/portfolio/wallet_history.py +2 -4
  105. intentkit/skills/portfolio/wallet_net_worth.py +2 -4
  106. intentkit/skills/portfolio/wallet_nfts.py +2 -4
  107. intentkit/skills/portfolio/wallet_profitability.py +2 -4
  108. intentkit/skills/portfolio/wallet_profitability_summary.py +2 -4
  109. intentkit/skills/portfolio/wallet_stats.py +2 -4
  110. intentkit/skills/portfolio/wallet_swaps.py +2 -4
  111. intentkit/skills/slack/base.py +18 -0
  112. intentkit/skills/slack/get_channel.py +3 -4
  113. intentkit/skills/slack/get_message.py +3 -4
  114. intentkit/skills/slack/schedule_message.py +3 -4
  115. intentkit/skills/slack/send_message.py +3 -4
  116. intentkit/skills/supabase/delete_data.py +3 -6
  117. intentkit/skills/supabase/fetch_data.py +3 -6
  118. intentkit/skills/supabase/insert_data.py +3 -6
  119. intentkit/skills/supabase/invoke_function.py +3 -6
  120. intentkit/skills/supabase/update_data.py +3 -6
  121. intentkit/skills/supabase/upsert_data.py +3 -6
  122. intentkit/skills/system/add_autonomous_task.py +1 -3
  123. intentkit/skills/system/delete_autonomous_task.py +1 -3
  124. intentkit/skills/system/edit_autonomous_task.py +1 -3
  125. intentkit/skills/system/list_autonomous_tasks.py +1 -3
  126. intentkit/skills/system/read_agent_api_key.py +2 -3
  127. intentkit/skills/system/regenerate_agent_api_key.py +2 -5
  128. intentkit/skills/tavily/base.py +14 -5
  129. intentkit/skills/tavily/tavily_extract.py +7 -8
  130. intentkit/skills/tavily/tavily_search.py +11 -9
  131. intentkit/skills/token/base.py +4 -6
  132. intentkit/skills/token/erc20_transfers.py +2 -4
  133. intentkit/skills/token/token_analytics.py +2 -4
  134. intentkit/skills/token/token_price.py +2 -4
  135. intentkit/skills/token/token_search.py +2 -4
  136. intentkit/skills/twitter/base.py +41 -0
  137. intentkit/skills/twitter/follow_user.py +4 -4
  138. intentkit/skills/twitter/get_mentions.py +4 -4
  139. intentkit/skills/twitter/get_timeline.py +4 -4
  140. intentkit/skills/twitter/get_user_by_username.py +4 -4
  141. intentkit/skills/twitter/get_user_tweets.py +4 -4
  142. intentkit/skills/twitter/like_tweet.py +4 -4
  143. intentkit/skills/twitter/post_tweet.py +3 -4
  144. intentkit/skills/twitter/reply_tweet.py +3 -4
  145. intentkit/skills/twitter/retweet.py +4 -4
  146. intentkit/skills/twitter/search_tweets.py +4 -4
  147. intentkit/skills/unrealspeech/base.py +16 -0
  148. intentkit/skills/unrealspeech/text_to_speech.py +4 -4
  149. intentkit/skills/venice_audio/base.py +11 -9
  150. intentkit/skills/venice_audio/venice_audio.py +238 -240
  151. intentkit/skills/venice_image/base.py +23 -19
  152. intentkit/skills/venice_image/image_enhance/image_enhance.py +78 -80
  153. intentkit/skills/venice_image/image_generation/image_generation_base.py +115 -117
  154. intentkit/skills/venice_image/image_upscale/image_upscale.py +88 -90
  155. intentkit/skills/venice_image/image_vision/image_vision.py +98 -100
  156. intentkit/skills/web_scraper/document_indexer.py +3 -5
  157. intentkit/skills/web_scraper/scrape_and_index.py +14 -17
  158. intentkit/skills/web_scraper/website_indexer.py +8 -10
  159. intentkit/skills/xmtp/README.md +110 -0
  160. intentkit/skills/xmtp/__init__.py +82 -0
  161. intentkit/skills/xmtp/base.py +15 -0
  162. intentkit/skills/xmtp/schema.json +41 -0
  163. intentkit/skills/xmtp/transfer.py +155 -0
  164. intentkit/skills/xmtp/xmtp.svg +26 -0
  165. {intentkit-0.6.9.dev2.dist-info → intentkit-0.6.10.dev2.dist-info}/METADATA +3 -3
  166. {intentkit-0.6.9.dev2.dist-info → intentkit-0.6.10.dev2.dist-info}/RECORD +168 -162
  167. {intentkit-0.6.9.dev2.dist-info → intentkit-0.6.10.dev2.dist-info}/WHEEL +0 -0
  168. {intentkit-0.6.9.dev2.dist-info → intentkit-0.6.10.dev2.dist-info}/licenses/LICENSE +0 -0
@@ -2,7 +2,6 @@
2
2
 
3
3
  from typing import Optional
4
4
 
5
- from langchain.schema.runnable import RunnableConfig
6
5
  from pydantic import BaseModel, Field
7
6
 
8
7
  from intentkit.skills.defillama.api import fetch_pools
@@ -99,7 +98,7 @@ class DefiLlamaFetchPools(DefiLlamaBaseTool):
99
98
  description: str = FETCH_POOLS_PROMPT
100
99
  args_schema: None = None # No input parameters needed
101
100
 
102
- async def _arun(self, config: RunnableConfig) -> FetchPoolsResponse:
101
+ async def _arun(self, **kwargs) -> FetchPoolsResponse:
103
102
  """Fetch pool data.
104
103
 
105
104
  Returns:
@@ -107,7 +106,7 @@ class DefiLlamaFetchPools(DefiLlamaBaseTool):
107
106
  """
108
107
  try:
109
108
  # Check rate limiting
110
- context = self.context_from_config(config)
109
+ context = self.get_context()
111
110
  is_rate_limited, error_msg = await self.check_rate_limit(context)
112
111
  if is_rate_limited:
113
112
  return FetchPoolsResponse(error=error_msg)
@@ -9,7 +9,7 @@ from langchain.tools.base import ToolException
9
9
  from pydantic import BaseModel, Field
10
10
 
11
11
  from intentkit.abstracts.skill import SkillStoreABC
12
- from intentkit.skills.base import IntentKitSkill, SkillContext
12
+ from intentkit.skills.base import IntentKitSkill
13
13
 
14
14
 
15
15
  class DuneBaseTool(IntentKitSkill):
@@ -23,22 +23,28 @@ class DuneBaseTool(IntentKitSkill):
23
23
  args_schema: Type[BaseModel]
24
24
  skill_store: SkillStoreABC = Field(description="Skill store for data persistence")
25
25
 
26
- def get_api_key(self, context: SkillContext) -> str:
26
+ def get_api_key(self) -> str:
27
27
  """Retrieve the Dune Analytics API key from context.
28
28
 
29
- Args:
30
- context: Skill context containing configuration.
31
-
32
29
  Returns:
33
30
  API key string.
34
31
 
35
32
  Raises:
36
33
  ToolException: If the API key is not found.
37
34
  """
38
- api_key = context.config.get("api_key")
39
- if not api_key:
40
- raise ToolException("Dune API key not found in context.config['api_key']")
41
- return api_key
35
+ context = self.get_context()
36
+ skill_config = context.agent.skill_config(self.category)
37
+ api_key_provider = skill_config.get("api_key_provider")
38
+ if api_key_provider == "agent_owner":
39
+ api_key = skill_config.get("api_key")
40
+ if api_key:
41
+ return api_key
42
+ else:
43
+ raise ToolException("No api_key found in agent_owner configuration")
44
+ else:
45
+ raise ToolException(
46
+ f"Invalid API key provider: {api_key_provider}. Only 'agent_owner' is supported for Dune Analytics."
47
+ )
42
48
 
43
49
  @property
44
50
  def category(self) -> str:
@@ -1,128 +1,125 @@
1
- """Skill to fetch KOL memecoin buys on Solana from Dune Analytics API.
2
-
3
- Uses query ID 4832844 to retrieve a list of KOL buy transactions.
4
- """
5
-
6
- from typing import Any, Dict, Type
7
-
8
- import httpx
9
- from langchain_core.runnables import RunnableConfig
10
- from pydantic import BaseModel, Field
11
- from tenacity import retry, stop_after_attempt, wait_exponential
12
-
13
- from intentkit.abstracts.skill import SkillStoreABC
14
- from intentkit.skills.dune_analytics.base import DuneBaseTool
15
-
16
- BASE_URL = "https://api.dune.com/api/v1/query"
17
- KOL_BUYS_QUERY_ID = 4832844
18
-
19
-
20
- class KOLBuysInput(BaseModel):
21
- """Input schema for fetching KOL memecoin buys."""
22
-
23
- limit: int = Field(
24
- default=10,
25
- description="Maximum number of buy transactions to fetch (default 10).",
26
- ge=1,
27
- )
28
-
29
-
30
- class KOLBuyData(BaseModel):
31
- """Data model for KOL buy results."""
32
-
33
- data: Dict[str, Any] = Field(description="KOL buy data from Dune API")
34
- error: str = Field(default="", description="Error message if fetch failed")
35
-
36
-
37
- class KOLBuysOutput(BaseModel):
38
- """Output schema for KOL memecoin buys."""
39
-
40
- buys: KOLBuyData = Field(description="KOL buy transaction data")
41
- summary: str = Field(description="Summary of fetched data")
42
-
43
-
44
- class FetchKOLBuys(DuneBaseTool):
45
- """Skill to fetch KOL memecoin buys on Solana from Dune Analytics API."""
46
-
47
- name: str = "dune_fetch_kol_buys"
48
- description: str = (
49
- "Fetches a list of KOL memecoin buy transactions on Solana from Dune Analytics API using query ID 4832844. "
50
- "Supports a configurable limit for the number of results. Handles rate limits with retries."
51
- )
52
- args_schema: Type[BaseModel] = KOLBuysInput
53
- skill_store: SkillStoreABC = Field(description="Skill store for data persistence")
54
-
55
- @retry(
56
- stop=stop_after_attempt(3), wait=wait_exponential(multiplier=5, min=5, max=60)
57
- )
58
- async def fetch_data(
59
- self, query_id: int, api_key: str, limit: int = 10
60
- ) -> Dict[str, Any]:
61
- """Fetch data for a specific Dune query.
62
-
63
- Args:
64
- query_id: Dune query ID.
65
- api_key: Dune API key.
66
- limit: Maximum number of results (default 10).
67
-
68
- Returns:
69
- Dictionary of query results.
70
-
71
- Raises:
72
- ToolException: If the API request fails.
73
- """
74
- from langchain.tools.base import ToolException
75
-
76
- url = f"{BASE_URL}/{query_id}/results?limit={limit}"
77
- headers = {"X-Dune-API-Key": api_key}
78
-
79
- async with httpx.AsyncClient() as client:
80
- try:
81
- response = await client.get(url, headers=headers, timeout=10)
82
- response.raise_for_status()
83
- return response.json().get("result", {})
84
- except (httpx.RequestError, httpx.HTTPStatusError) as e:
85
- raise ToolException(f"Error fetching data from Dune API: {e}")
86
-
87
- async def _arun(
88
- self,
89
- limit: int = 10,
90
- config: RunnableConfig = None,
91
- **kwargs,
92
- ) -> str:
93
- """Fetch KOL memecoin buys asynchronously and return formatted output.
94
-
95
- Args:
96
- limit: Maximum number of buy transactions to fetch (default 10).
97
- config: Runnable configuration.
98
- **kwargs: Additional keyword arguments.
99
-
100
- Returns:
101
- Formatted string with KOL buy transactions or error message.
102
- """
103
- import logging
104
-
105
- logger = logging.getLogger(__name__)
106
- context = self.context_from_config(config)
107
- api_key = self.get_api_key(context)
108
-
109
- try:
110
- data = await self.fetch_data(KOL_BUYS_QUERY_ID, api_key, limit)
111
- rows = data.get("rows", [])
112
- if not rows:
113
- return "No KOL buy transactions found."
114
-
115
- output = f"Fetched {len(rows)} KOL memecoin buy transactions:\n"
116
- for row in rows:
117
- output += (
118
- f"- {row['kol_with_link']} bought {row['token_with_chart']} "
119
- f"(${row['amount_usd']:.2f}) at {row['buy_time']}\n"
120
- )
121
- return output.strip()
122
- except Exception as e:
123
- error_msg = f"Error fetching KOL memecoin buys: {str(e)}"
124
- logger.warning(error_msg)
125
- return error_msg
126
-
127
- def _run(self, question: str):
128
- raise NotImplementedError("Use _arun for async execution")
1
+ """Skill to fetch KOL memecoin buys on Solana from Dune Analytics API.
2
+
3
+ Uses query ID 4832844 to retrieve a list of KOL buy transactions.
4
+ """
5
+
6
+ from typing import Any, Dict, Type
7
+
8
+ import httpx
9
+ from pydantic import BaseModel, Field
10
+ from tenacity import retry, stop_after_attempt, wait_exponential
11
+
12
+ from intentkit.abstracts.skill import SkillStoreABC
13
+ from intentkit.skills.dune_analytics.base import DuneBaseTool
14
+
15
+ BASE_URL = "https://api.dune.com/api/v1/query"
16
+ KOL_BUYS_QUERY_ID = 4832844
17
+
18
+
19
+ class KOLBuysInput(BaseModel):
20
+ """Input schema for fetching KOL memecoin buys."""
21
+
22
+ limit: int = Field(
23
+ default=10,
24
+ description="Maximum number of buy transactions to fetch (default 10).",
25
+ ge=1,
26
+ )
27
+
28
+
29
+ class KOLBuyData(BaseModel):
30
+ """Data model for KOL buy results."""
31
+
32
+ data: Dict[str, Any] = Field(description="KOL buy data from Dune API")
33
+ error: str = Field(default="", description="Error message if fetch failed")
34
+
35
+
36
+ class KOLBuysOutput(BaseModel):
37
+ """Output schema for KOL memecoin buys."""
38
+
39
+ buys: KOLBuyData = Field(description="KOL buy transaction data")
40
+ summary: str = Field(description="Summary of fetched data")
41
+
42
+
43
+ class FetchKOLBuys(DuneBaseTool):
44
+ """Skill to fetch KOL memecoin buys on Solana from Dune Analytics API."""
45
+
46
+ name: str = "dune_fetch_kol_buys"
47
+ description: str = (
48
+ "Fetches a list of KOL memecoin buy transactions on Solana from Dune Analytics API using query ID 4832844. "
49
+ "Supports a configurable limit for the number of results. Handles rate limits with retries."
50
+ )
51
+ args_schema: Type[BaseModel] = KOLBuysInput
52
+ skill_store: SkillStoreABC = Field(description="Skill store for data persistence")
53
+
54
+ @retry(
55
+ stop=stop_after_attempt(3), wait=wait_exponential(multiplier=5, min=5, max=60)
56
+ )
57
+ async def fetch_data(
58
+ self, query_id: int, api_key: str, limit: int = 10
59
+ ) -> Dict[str, Any]:
60
+ """Fetch data for a specific Dune query.
61
+
62
+ Args:
63
+ query_id: Dune query ID.
64
+ api_key: Dune API key.
65
+ limit: Maximum number of results (default 10).
66
+
67
+ Returns:
68
+ Dictionary of query results.
69
+
70
+ Raises:
71
+ ToolException: If the API request fails.
72
+ """
73
+ from langchain.tools.base import ToolException
74
+
75
+ url = f"{BASE_URL}/{query_id}/results?limit={limit}"
76
+ headers = {"X-Dune-API-Key": api_key}
77
+
78
+ async with httpx.AsyncClient() as client:
79
+ try:
80
+ response = await client.get(url, headers=headers, timeout=10)
81
+ response.raise_for_status()
82
+ return response.json().get("result", {})
83
+ except (httpx.RequestError, httpx.HTTPStatusError) as e:
84
+ raise ToolException(f"Error fetching data from Dune API: {e}")
85
+
86
+ async def _arun(
87
+ self,
88
+ limit: int = 10,
89
+ **kwargs,
90
+ ) -> str:
91
+ """Fetch KOL memecoin buys asynchronously and return formatted output.
92
+
93
+ Args:
94
+ limit: Maximum number of buy transactions to fetch (default 10).
95
+ config: Runnable configuration.
96
+ **kwargs: Additional keyword arguments.
97
+
98
+ Returns:
99
+ Formatted string with KOL buy transactions or error message.
100
+ """
101
+ import logging
102
+
103
+ logger = logging.getLogger(__name__)
104
+ api_key = self.get_api_key()
105
+
106
+ try:
107
+ data = await self.fetch_data(KOL_BUYS_QUERY_ID, api_key, limit)
108
+ rows = data.get("rows", [])
109
+ if not rows:
110
+ return "No KOL buy transactions found."
111
+
112
+ output = f"Fetched {len(rows)} KOL memecoin buy transactions:\n"
113
+ for row in rows:
114
+ output += (
115
+ f"- {row['kol_with_link']} bought {row['token_with_chart']} "
116
+ f"(${row['amount_usd']:.2f}) at {row['buy_time']}\n"
117
+ )
118
+ return output.strip()
119
+ except Exception as e:
120
+ error_msg = f"Error fetching KOL memecoin buys: {str(e)}"
121
+ logger.warning(error_msg)
122
+ return error_msg
123
+
124
+ def _run(self, question: str):
125
+ raise NotImplementedError("Use _arun for async execution")