intentkit 0.8.11__py3-none-any.whl → 0.8.12__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 (183) hide show
  1. intentkit/__init__.py +1 -1
  2. intentkit/abstracts/graph.py +4 -0
  3. intentkit/abstracts/skill.py +2 -140
  4. intentkit/clients/twitter.py +35 -28
  5. intentkit/core/agent.py +2 -374
  6. intentkit/core/asset.py +63 -16
  7. intentkit/core/engine.py +16 -7
  8. intentkit/core/scheduler.py +8 -8
  9. intentkit/models/agent.py +109 -94
  10. intentkit/models/agent_schema.json +6 -9
  11. intentkit/models/llm.csv +15 -12
  12. intentkit/models/skill.py +38 -40
  13. intentkit/skills/acolyt/__init__.py +2 -9
  14. intentkit/skills/acolyt/base.py +2 -5
  15. intentkit/skills/aixbt/__init__.py +2 -13
  16. intentkit/skills/aixbt/base.py +0 -4
  17. intentkit/skills/aixbt/projects.py +1 -2
  18. intentkit/skills/allora/__init__.py +2 -9
  19. intentkit/skills/allora/base.py +2 -5
  20. intentkit/skills/base.py +168 -27
  21. intentkit/skills/basename/__init__.py +1 -3
  22. intentkit/skills/carv/__init__.py +116 -121
  23. intentkit/skills/carv/base.py +184 -185
  24. intentkit/skills/casino/__init__.py +4 -15
  25. intentkit/skills/casino/base.py +0 -4
  26. intentkit/skills/casino/deck_draw.py +4 -6
  27. intentkit/skills/casino/deck_shuffle.py +5 -4
  28. intentkit/skills/casino/dice_roll.py +1 -2
  29. intentkit/skills/cdp/__init__.py +0 -5
  30. intentkit/skills/cdp/base.py +0 -4
  31. intentkit/skills/cdp/schema.json +1 -17
  32. intentkit/skills/chainlist/__init__.py +2 -7
  33. intentkit/skills/chainlist/base.py +0 -4
  34. intentkit/skills/common/__init__.py +2 -9
  35. intentkit/skills/common/base.py +0 -4
  36. intentkit/skills/cookiefun/__init__.py +6 -9
  37. intentkit/skills/cookiefun/base.py +0 -4
  38. intentkit/skills/cryptocompare/__init__.py +7 -24
  39. intentkit/skills/cryptocompare/base.py +4 -18
  40. intentkit/skills/cryptocompare/fetch_news.py +1 -1
  41. intentkit/skills/cryptocompare/fetch_price.py +1 -1
  42. intentkit/skills/cryptocompare/fetch_top_exchanges.py +1 -1
  43. intentkit/skills/cryptocompare/fetch_top_market_cap.py +1 -1
  44. intentkit/skills/cryptocompare/fetch_top_volume.py +1 -1
  45. intentkit/skills/cryptocompare/fetch_trading_signals.py +1 -1
  46. intentkit/skills/cryptopanic/__init__.py +3 -6
  47. intentkit/skills/cryptopanic/base.py +53 -55
  48. intentkit/skills/cryptopanic/fetch_crypto_news.py +0 -2
  49. intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +1 -3
  50. intentkit/skills/dapplooker/__init__.py +2 -9
  51. intentkit/skills/dapplooker/base.py +2 -5
  52. intentkit/skills/defillama/__init__.py +24 -74
  53. intentkit/skills/defillama/base.py +3 -13
  54. intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +2 -2
  55. intentkit/skills/defillama/coins/fetch_block.py +2 -2
  56. intentkit/skills/defillama/coins/fetch_current_prices.py +2 -2
  57. intentkit/skills/defillama/coins/fetch_first_price.py +2 -2
  58. intentkit/skills/defillama/coins/fetch_historical_prices.py +2 -2
  59. intentkit/skills/defillama/coins/fetch_price_chart.py +2 -2
  60. intentkit/skills/defillama/coins/fetch_price_percentage.py +2 -2
  61. intentkit/skills/defillama/fees/fetch_fees_overview.py +2 -2
  62. intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +2 -2
  63. intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +2 -2
  64. intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +2 -2
  65. intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +2 -2
  66. intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +2 -2
  67. intentkit/skills/defillama/tvl/fetch_chains.py +2 -2
  68. intentkit/skills/defillama/tvl/fetch_historical_tvl.py +2 -2
  69. intentkit/skills/defillama/tvl/fetch_protocol.py +2 -2
  70. intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +2 -2
  71. intentkit/skills/defillama/tvl/fetch_protocols.py +2 -2
  72. intentkit/skills/defillama/volumes/fetch_dex_overview.py +2 -2
  73. intentkit/skills/defillama/volumes/fetch_dex_summary.py +2 -2
  74. intentkit/skills/defillama/volumes/fetch_options_overview.py +2 -2
  75. intentkit/skills/defillama/yields/fetch_pool_chart.py +2 -2
  76. intentkit/skills/defillama/yields/fetch_pools.py +2 -2
  77. intentkit/skills/dexscreener/__init__.py +97 -102
  78. intentkit/skills/dexscreener/base.py +125 -130
  79. intentkit/skills/dexscreener/get_pair_info.py +2 -3
  80. intentkit/skills/dexscreener/get_token_pairs.py +2 -3
  81. intentkit/skills/dexscreener/get_tokens_info.py +2 -3
  82. intentkit/skills/dexscreener/search_token.py +2 -4
  83. intentkit/skills/dune_analytics/__init__.py +4 -6
  84. intentkit/skills/dune_analytics/base.py +50 -52
  85. intentkit/skills/dune_analytics/fetch_kol_buys.py +0 -2
  86. intentkit/skills/dune_analytics/fetch_nation_metrics.py +0 -2
  87. intentkit/skills/elfa/__init__.py +5 -18
  88. intentkit/skills/elfa/base.py +8 -10
  89. intentkit/skills/enso/__init__.py +9 -29
  90. intentkit/skills/enso/base.py +3 -6
  91. intentkit/skills/enso/networks.py +1 -6
  92. intentkit/skills/enso/route.py +4 -8
  93. intentkit/skills/enso/tokens.py +2 -12
  94. intentkit/skills/erc20/__init__.py +1 -5
  95. intentkit/skills/erc721/__init__.py +1 -3
  96. intentkit/skills/firecrawl/__init__.py +5 -18
  97. intentkit/skills/firecrawl/base.py +2 -5
  98. intentkit/skills/firecrawl/clear.py +3 -6
  99. intentkit/skills/firecrawl/crawl.py +10 -9
  100. intentkit/skills/firecrawl/query.py +3 -1
  101. intentkit/skills/firecrawl/scrape.py +10 -14
  102. intentkit/skills/firecrawl/utils.py +39 -31
  103. intentkit/skills/github/__init__.py +2 -7
  104. intentkit/skills/github/base.py +0 -4
  105. intentkit/skills/heurist/__init__.py +8 -27
  106. intentkit/skills/heurist/base.py +2 -5
  107. intentkit/skills/heurist/image_generation_animagine_xl.py +5 -5
  108. intentkit/skills/heurist/image_generation_arthemy_comics.py +5 -5
  109. intentkit/skills/heurist/image_generation_arthemy_real.py +5 -5
  110. intentkit/skills/heurist/image_generation_braindance.py +5 -5
  111. intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +5 -5
  112. intentkit/skills/heurist/image_generation_flux_1_dev.py +5 -5
  113. intentkit/skills/heurist/image_generation_sdxl.py +5 -5
  114. intentkit/skills/http/__init__.py +4 -15
  115. intentkit/skills/http/base.py +0 -4
  116. intentkit/skills/lifi/__init__.py +1 -6
  117. intentkit/skills/lifi/base.py +0 -4
  118. intentkit/skills/lifi/token_execute.py +1 -4
  119. intentkit/skills/lifi/token_quote.py +1 -3
  120. intentkit/skills/moralis/__init__.py +3 -7
  121. intentkit/skills/moralis/base.py +2 -5
  122. intentkit/skills/morpho/__init__.py +1 -3
  123. intentkit/skills/nation/__init__.py +2 -7
  124. intentkit/skills/nation/base.py +4 -7
  125. intentkit/skills/openai/__init__.py +5 -18
  126. intentkit/skills/openai/base.py +8 -10
  127. intentkit/skills/openai/dalle_image_generation.py +2 -5
  128. intentkit/skills/openai/gpt_image_generation.py +2 -5
  129. intentkit/skills/openai/gpt_image_to_image.py +2 -5
  130. intentkit/skills/openai/image_to_text.py +2 -5
  131. intentkit/skills/portfolio/__init__.py +11 -35
  132. intentkit/skills/portfolio/base.py +2 -5
  133. intentkit/skills/pyth/__init__.py +1 -5
  134. intentkit/skills/slack/__init__.py +5 -17
  135. intentkit/skills/slack/base.py +0 -4
  136. intentkit/skills/supabase/__init__.py +7 -23
  137. intentkit/skills/supabase/base.py +0 -4
  138. intentkit/skills/superfluid/__init__.py +1 -3
  139. intentkit/skills/system/__init__.py +7 -24
  140. intentkit/skills/system/add_autonomous_task.py +2 -2
  141. intentkit/skills/system/delete_autonomous_task.py +2 -2
  142. intentkit/skills/system/edit_autonomous_task.py +2 -4
  143. intentkit/skills/system/list_autonomous_tasks.py +2 -2
  144. intentkit/skills/system/read_agent_api_key.py +6 -4
  145. intentkit/skills/system/regenerate_agent_api_key.py +6 -4
  146. intentkit/skills/tavily/__init__.py +3 -12
  147. intentkit/skills/tavily/base.py +2 -5
  148. intentkit/skills/tavily/tavily_extract.py +1 -2
  149. intentkit/skills/tavily/tavily_search.py +3 -3
  150. intentkit/skills/token/__init__.py +5 -10
  151. intentkit/skills/token/base.py +2 -6
  152. intentkit/skills/twitter/__init__.py +11 -35
  153. intentkit/skills/twitter/base.py +18 -29
  154. intentkit/skills/twitter/follow_user.py +1 -4
  155. intentkit/skills/twitter/get_mentions.py +2 -8
  156. intentkit/skills/twitter/get_timeline.py +3 -10
  157. intentkit/skills/twitter/get_user_by_username.py +1 -4
  158. intentkit/skills/twitter/get_user_tweets.py +3 -10
  159. intentkit/skills/twitter/like_tweet.py +1 -4
  160. intentkit/skills/twitter/post_tweet.py +3 -5
  161. intentkit/skills/twitter/reply_tweet.py +3 -5
  162. intentkit/skills/twitter/retweet.py +1 -4
  163. intentkit/skills/twitter/search_tweets.py +3 -10
  164. intentkit/skills/unrealspeech/__init__.py +2 -7
  165. intentkit/skills/unrealspeech/base.py +0 -4
  166. intentkit/skills/venice_audio/__init__.py +99 -106
  167. intentkit/skills/venice_audio/base.py +118 -121
  168. intentkit/skills/venice_audio/venice_audio.py +1 -5
  169. intentkit/skills/venice_image/__init__.py +147 -154
  170. intentkit/skills/venice_image/base.py +185 -192
  171. intentkit/skills/web_scraper/__init__.py +5 -18
  172. intentkit/skills/web_scraper/base.py +20 -4
  173. intentkit/skills/web_scraper/document_indexer.py +6 -4
  174. intentkit/skills/web_scraper/scrape_and_index.py +11 -10
  175. intentkit/skills/web_scraper/utils.py +38 -38
  176. intentkit/skills/web_scraper/website_indexer.py +7 -8
  177. intentkit/skills/weth/__init__.py +1 -5
  178. intentkit/skills/wow/__init__.py +1 -5
  179. intentkit/skills/xmtp/__init__.py +4 -15
  180. {intentkit-0.8.11.dist-info → intentkit-0.8.12.dist-info}/METADATA +1 -1
  181. {intentkit-0.8.11.dist-info → intentkit-0.8.12.dist-info}/RECORD +183 -183
  182. {intentkit-0.8.11.dist-info → intentkit-0.8.12.dist-info}/WHEEL +0 -0
  183. {intentkit-0.8.11.dist-info → intentkit-0.8.12.dist-info}/licenses/LICENSE +0 -0
@@ -1,5 +1,7 @@
1
1
  from pydantic import BaseModel, Field
2
2
 
3
+ from intentkit.config.config import config
4
+ from intentkit.models.agent_data import AgentData
3
5
  from intentkit.skills.system.base import SystemBaseTool
4
6
 
5
7
 
@@ -43,11 +45,11 @@ class RegenerateAgentApiKey(SystemBaseTool):
43
45
  context = self.get_context()
44
46
  agent_id = context.agent_id
45
47
 
46
- # Get agent data from skill store
47
- agent_data = await self.skill_store.get_agent_data(agent_id)
48
+ # Get agent data directly from the model
49
+ agent_data = await AgentData.get(agent_id)
48
50
 
49
51
  # Get API base URL from system config
50
- open_api_base_url = self.skill_store.get_system_config("open_api_base_url")
52
+ open_api_base_url = config.open_api_base_url
51
53
  api_endpoint = f"{open_api_base_url}/v1/chat/completions"
52
54
 
53
55
  # Check if previous API keys existed
@@ -58,7 +60,7 @@ class RegenerateAgentApiKey(SystemBaseTool):
58
60
  new_public_api_key = self._generate_public_api_key()
59
61
 
60
62
  # Save the new API keys to agent data (overwrites existing)
61
- await self.skill_store.set_agent_data(
63
+ await AgentData.patch(
62
64
  agent_id, {"api_key": new_api_key, "api_key_public": new_public_api_key}
63
65
  )
64
66
 
@@ -3,7 +3,6 @@
3
3
  import logging
4
4
  from typing import TypedDict
5
5
 
6
- from intentkit.abstracts.skill import SkillStoreABC
7
6
  from intentkit.skills.base import SkillConfig, SkillState
8
7
  from intentkit.skills.tavily.base import TavilyBaseTool
9
8
  from intentkit.skills.tavily.tavily_extract import TavilyExtract
@@ -30,7 +29,6 @@ class Config(SkillConfig):
30
29
  async def get_skills(
31
30
  config: "Config",
32
31
  is_private: bool,
33
- store: SkillStoreABC,
34
32
  **_,
35
33
  ) -> list[TavilyBaseTool]:
36
34
  """Get all Tavily search skills.
@@ -38,7 +36,6 @@ async def get_skills(
38
36
  Args:
39
37
  config: The configuration for Tavily search skills.
40
38
  is_private: Whether to include private skills.
41
- store: The skill store for persisting data.
42
39
 
43
40
  Returns:
44
41
  A list of Tavily search skills.
@@ -55,7 +52,7 @@ async def get_skills(
55
52
  # Get each skill using the cached getter
56
53
  result = []
57
54
  for name in available_skills:
58
- skill = get_tavily_skill(name, store)
55
+ skill = get_tavily_skill(name)
59
56
  if skill:
60
57
  result.append(skill)
61
58
  return result
@@ -63,28 +60,22 @@ async def get_skills(
63
60
 
64
61
  def get_tavily_skill(
65
62
  name: str,
66
- store: SkillStoreABC,
67
63
  ) -> TavilyBaseTool:
68
64
  """Get a Tavily search skill by name.
69
65
 
70
66
  Args:
71
67
  name: The name of the skill to get
72
- store: The skill store for persisting data
73
68
 
74
69
  Returns:
75
70
  The requested Tavily search skill
76
71
  """
77
72
  if name == "tavily_search":
78
73
  if name not in _cache:
79
- _cache[name] = TavilySearch(
80
- skill_store=store,
81
- )
74
+ _cache[name] = TavilySearch()
82
75
  return _cache[name]
83
76
  elif name == "tavily_extract":
84
77
  if name not in _cache:
85
- _cache[name] = TavilyExtract(
86
- skill_store=store,
87
- )
78
+ _cache[name] = TavilyExtract()
88
79
  return _cache[name]
89
80
  else:
90
81
  logger.warning(f"Unknown Tavily skill: {name}")
@@ -3,7 +3,7 @@ from typing import Type
3
3
  from langchain_core.tools.base import ToolException
4
4
  from pydantic import BaseModel, Field
5
5
 
6
- from intentkit.abstracts.skill import SkillStoreABC
6
+ from intentkit.config.config import config
7
7
  from intentkit.skills.base import IntentKitSkill
8
8
 
9
9
 
@@ -13,16 +13,13 @@ class TavilyBaseTool(IntentKitSkill):
13
13
  name: str = Field(description="The name of the tool")
14
14
  description: str = Field(description="A description of what the tool does")
15
15
  args_schema: Type[BaseModel]
16
- skill_store: SkillStoreABC = Field(
17
- description="The skill store for persisting data"
18
- )
19
16
 
20
17
  def get_api_key(self) -> str:
21
18
  context = self.get_context()
22
19
  skill_config = context.agent.skill_config(self.category)
23
20
  api_key_provider = skill_config.get("api_key_provider")
24
21
  if api_key_provider == "platform":
25
- return self.skill_store.get_system_config("tavily_api_key")
22
+ return config.tavily_api_key
26
23
  # for backward compatibility, may only have api_key in skill_config
27
24
  elif skill_config.get("api_key"):
28
25
  return skill_config.get("api_key")
@@ -73,9 +73,8 @@ class TavilyExtract(TavilyBaseTool):
73
73
  "rate_limit_minutes"
74
74
  ):
75
75
  await self.user_rate_limit_by_category(
76
- context.user_id,
77
76
  skill_config["rate_limit_number"],
78
- skill_config["rate_limit_minutes"],
77
+ skill_config["rate_limit_minutes"] * 60,
79
78
  )
80
79
 
81
80
  # Get the API key from the agent's configuration
@@ -4,6 +4,7 @@ from typing import Type
4
4
  import httpx
5
5
  from pydantic import BaseModel, Field
6
6
 
7
+ from intentkit.config.config import config
7
8
  from intentkit.skills.tavily.base import TavilyBaseTool
8
9
 
9
10
  logger = logging.getLogger(__name__)
@@ -80,16 +81,15 @@ class TavilySearch(TavilyBaseTool):
80
81
  "rate_limit_minutes"
81
82
  ):
82
83
  await self.user_rate_limit_by_category(
83
- context.user_id,
84
84
  skill_config["rate_limit_number"],
85
- skill_config["rate_limit_minutes"],
85
+ skill_config["rate_limit_minutes"] * 60,
86
86
  )
87
87
 
88
88
  # Get the API key from the agent's configuration
89
89
  if skill_config.get("api_key_provider") == "agent_owner":
90
90
  api_key = skill_config.get("api_key")
91
91
  else:
92
- api_key = self.skill_store.get_system_config("tavily_api_key")
92
+ api_key = config.tavily_api_key
93
93
  if not api_key:
94
94
  return "Error: No Tavily API key provided in the configuration."
95
95
 
@@ -3,7 +3,6 @@
3
3
  import logging
4
4
  from typing import TypedDict
5
5
 
6
- from intentkit.abstracts.skill import SkillStoreABC
7
6
  from intentkit.skills.base import SkillConfig, SkillState
8
7
  from intentkit.skills.token.base import TokenBaseTool
9
8
  from intentkit.skills.token.erc20_transfers import ERC20Transfers
@@ -36,7 +35,6 @@ class Config(SkillConfig):
36
35
  async def get_skills(
37
36
  config: "Config",
38
37
  is_private: bool,
39
- store: SkillStoreABC,
40
38
  **_,
41
39
  ) -> list[TokenBaseTool]:
42
40
  """Get all Token blockchain analysis skills.
@@ -44,7 +42,6 @@ async def get_skills(
44
42
  Args:
45
43
  config: The configuration for Token skills.
46
44
  is_private: Whether to include private skills.
47
- store: The skill store for persisting data.
48
45
 
49
46
  Returns:
50
47
  A list of Token blockchain analysis skills.
@@ -65,7 +62,7 @@ async def get_skills(
65
62
  # Get each skill using the cached getter
66
63
  result = []
67
64
  for name in available_skills:
68
- skill = get_token_skill(name, store)
65
+ skill = get_token_skill(name)
69
66
  if skill:
70
67
  result.append(skill)
71
68
 
@@ -74,13 +71,11 @@ async def get_skills(
74
71
 
75
72
  def get_token_skill(
76
73
  name: str,
77
- store: SkillStoreABC,
78
74
  ) -> TokenBaseTool:
79
75
  """Get a Token blockchain analysis skill by name.
80
76
 
81
77
  Args:
82
78
  name: The name of the skill to get
83
- store: The skill store for persisting data
84
79
 
85
80
  Returns:
86
81
  The requested Token blockchain analysis skill
@@ -90,13 +85,13 @@ def get_token_skill(
90
85
 
91
86
  skill = None
92
87
  if name == "token_price":
93
- skill = TokenPrice(skill_store=store)
88
+ skill = TokenPrice()
94
89
  elif name == "token_erc20_transfers":
95
- skill = ERC20Transfers(skill_store=store)
90
+ skill = ERC20Transfers()
96
91
  elif name == "token_search":
97
- skill = TokenSearch(skill_store=store)
92
+ skill = TokenSearch()
98
93
  elif name == "token_analytics":
99
- skill = TokenAnalytics(skill_store=store)
94
+ skill = TokenAnalytics()
100
95
  else:
101
96
  logger.warning(f"Unknown Token skill: {name}")
102
97
  return None
@@ -5,7 +5,7 @@ from typing import Any, Dict
5
5
 
6
6
  import aiohttp
7
7
 
8
- from intentkit.abstracts.skill import SkillStoreABC
8
+ from intentkit.config.config import config
9
9
  from intentkit.skills.base import IntentKitSkill
10
10
  from intentkit.skills.token.constants import MORALIS_API_BASE_URL
11
11
 
@@ -19,10 +19,6 @@ class TokenBaseTool(IntentKitSkill):
19
19
  including making HTTP requests to the Moralis API.
20
20
  """
21
21
 
22
- def __init__(self, skill_store: SkillStoreABC = None):
23
- """Initialize the token tool with a skill store."""
24
- super().__init__(skill_store=skill_store)
25
-
26
22
  @property
27
23
  def category(self) -> str:
28
24
  return "token"
@@ -37,7 +33,7 @@ class TokenBaseTool(IntentKitSkill):
37
33
  skill_config = context.agent.skill_config(self.category)
38
34
  if skill_config.get("api_key_provider") == "agent_owner":
39
35
  return skill_config.get("api_key")
40
- return self.skill_store.get_system_config("moralis_api_key")
36
+ return config.moralis_api_key
41
37
 
42
38
  def _prepare_params(self, params: Dict[str, Any]) -> Dict[str, Any]:
43
39
  """Convert boolean values to lowercase strings for API compatibility.
@@ -3,7 +3,6 @@
3
3
  import logging
4
4
  from typing import TypedDict
5
5
 
6
- from intentkit.abstracts.skill import SkillStoreABC
7
6
  from intentkit.clients import TwitterClientConfig
8
7
  from intentkit.skills.base import SkillConfig, SkillState
9
8
  from intentkit.skills.twitter.base import TwitterBaseTool
@@ -46,7 +45,6 @@ class Config(SkillConfig, TwitterClientConfig):
46
45
  async def get_skills(
47
46
  config: "Config",
48
47
  is_private: bool,
49
- store: SkillStoreABC,
50
48
  **_,
51
49
  ) -> list[TwitterBaseTool]:
52
50
  """Get all Twitter skills."""
@@ -62,7 +60,7 @@ async def get_skills(
62
60
  # Get each skill using the cached getter
63
61
  result = []
64
62
  for name in available_skills:
65
- skill = get_twitter_skill(name, store)
63
+ skill = get_twitter_skill(name)
66
64
  if skill:
67
65
  result.append(skill)
68
66
  return result
@@ -70,76 +68,54 @@ async def get_skills(
70
68
 
71
69
  def get_twitter_skill(
72
70
  name: str,
73
- store: SkillStoreABC,
74
71
  ) -> TwitterBaseTool:
75
72
  """Get a Twitter skill by name.
76
73
 
77
74
  Args:
78
75
  name: The name of the skill to get
79
- store: The skill store for persisting data
80
76
 
81
77
  Returns:
82
78
  The requested Twitter skill
83
79
  """
84
80
  if name == "get_mentions":
85
81
  if name not in _cache:
86
- _cache[name] = TwitterGetMentions(
87
- skill_store=store,
88
- )
82
+ _cache[name] = TwitterGetMentions()
89
83
  return _cache[name]
90
84
  elif name == "post_tweet":
91
85
  if name not in _cache:
92
- _cache[name] = TwitterPostTweet(
93
- skill_store=store,
94
- )
86
+ _cache[name] = TwitterPostTweet()
95
87
  return _cache[name]
96
88
  elif name == "reply_tweet":
97
89
  if name not in _cache:
98
- _cache[name] = TwitterReplyTweet(
99
- skill_store=store,
100
- )
90
+ _cache[name] = TwitterReplyTweet()
101
91
  return _cache[name]
102
92
  elif name == "get_timeline":
103
93
  if name not in _cache:
104
- _cache[name] = TwitterGetTimeline(
105
- skill_store=store,
106
- )
94
+ _cache[name] = TwitterGetTimeline()
107
95
  return _cache[name]
108
96
  elif name == "follow_user":
109
97
  if name not in _cache:
110
- _cache[name] = TwitterFollowUser(
111
- skill_store=store,
112
- )
98
+ _cache[name] = TwitterFollowUser()
113
99
  return _cache[name]
114
100
  elif name == "like_tweet":
115
101
  if name not in _cache:
116
- _cache[name] = TwitterLikeTweet(
117
- skill_store=store,
118
- )
102
+ _cache[name] = TwitterLikeTweet()
119
103
  return _cache[name]
120
104
  elif name == "retweet":
121
105
  if name not in _cache:
122
- _cache[name] = TwitterRetweet(
123
- skill_store=store,
124
- )
106
+ _cache[name] = TwitterRetweet()
125
107
  return _cache[name]
126
108
  elif name == "search_tweets":
127
109
  if name not in _cache:
128
- _cache[name] = TwitterSearchTweets(
129
- skill_store=store,
130
- )
110
+ _cache[name] = TwitterSearchTweets()
131
111
  return _cache[name]
132
112
  elif name == "get_user_by_username":
133
113
  if name not in _cache:
134
- _cache[name] = TwitterGetUserByUsername(
135
- skill_store=store,
136
- )
114
+ _cache[name] = TwitterGetUserByUsername()
137
115
  return _cache[name]
138
116
  elif name == "get_user_tweets":
139
117
  if name not in _cache:
140
- _cache[name] = TwitterGetUserTweets(
141
- skill_store=store,
142
- )
118
+ _cache[name] = TwitterGetUserTweets()
143
119
  return _cache[name]
144
120
  else:
145
121
  logger.warning(f"Unknown Twitter skill: {name}")
@@ -4,7 +4,7 @@ from typing import Type
4
4
  from langchain_core.tools.base import ToolException
5
5
  from pydantic import BaseModel, Field
6
6
 
7
- from intentkit.abstracts.skill import SkillStoreABC
7
+ from intentkit.config.config import config
8
8
  from intentkit.skills.base import IntentKitSkill
9
9
  from intentkit.utils.error import RateLimitExceeded
10
10
 
@@ -15,9 +15,6 @@ class TwitterBaseTool(IntentKitSkill):
15
15
  name: str = Field(description="The name of the tool")
16
16
  description: str = Field(description="A description of what the tool does")
17
17
  args_schema: Type[BaseModel]
18
- skill_store: SkillStoreABC = Field(
19
- description="The skill store for persisting data"
20
- )
21
18
 
22
19
  def get_api_key(self) -> dict:
23
20
  context = self.get_context()
@@ -25,20 +22,21 @@ class TwitterBaseTool(IntentKitSkill):
25
22
  api_key_provider = skill_config.get("api_key_provider")
26
23
  if api_key_provider == "platform":
27
24
  # Return platform keys (these need to be added to config.py)
28
- return {
29
- "consumer_key": self.skill_store.get_system_config(
30
- "twitter_consumer_key"
31
- ),
32
- "consumer_secret": self.skill_store.get_system_config(
33
- "twitter_consumer_secret"
34
- ),
35
- "access_token": self.skill_store.get_system_config(
36
- "twitter_access_token"
37
- ),
38
- "access_token_secret": self.skill_store.get_system_config(
39
- "twitter_access_token_secret"
25
+ platform_keys = {
26
+ "consumer_key": getattr(config, "twitter_consumer_key", None),
27
+ "consumer_secret": getattr(config, "twitter_consumer_secret", None),
28
+ "access_token": getattr(config, "twitter_access_token", None),
29
+ "access_token_secret": getattr(
30
+ config, "twitter_access_token_secret", None
40
31
  ),
41
32
  }
33
+ missing = [key for key, value in platform_keys.items() if not value]
34
+ if missing:
35
+ raise ToolException(
36
+ "Twitter platform API keys are not configured: "
37
+ + ", ".join(missing)
38
+ )
39
+ return platform_keys
42
40
  # for backward compatibility or agent_owner provider
43
41
  elif api_key_provider == "agent_owner":
44
42
  required_keys = [
@@ -63,22 +61,17 @@ class TwitterBaseTool(IntentKitSkill):
63
61
  def category(self) -> str:
64
62
  return "twitter"
65
63
 
66
- async def check_rate_limit(
67
- self, agent_id: str, max_requests: int = 1, interval: int = 15
68
- ) -> None:
64
+ async def check_rate_limit(self, max_requests: int = 1, interval: int = 15) -> None:
69
65
  """Check if the rate limit has been exceeded.
70
66
 
71
67
  Args:
72
- agent_id: The ID of the agent.
73
68
  max_requests: Maximum number of requests allowed within the rate limit window.
74
69
  interval: Time interval in minutes for the rate limit window.
75
70
 
76
71
  Raises:
77
72
  RateLimitExceeded: If the rate limit has been exceeded.
78
73
  """
79
- rate_limit = await self.skill_store.get_agent_skill_data(
80
- agent_id, self.name, "rate_limit"
81
- )
74
+ rate_limit = await self.get_agent_skill_data("rate_limit")
82
75
 
83
76
  current_time = datetime.now(tz=timezone.utc)
84
77
 
@@ -92,9 +85,7 @@ class TwitterBaseTool(IntentKitSkill):
92
85
  raise RateLimitExceeded("Rate limit exceeded")
93
86
 
94
87
  rate_limit["count"] += 1
95
- await self.skill_store.save_agent_skill_data(
96
- agent_id, self.name, "rate_limit", rate_limit
97
- )
88
+ await self.save_agent_skill_data("rate_limit", rate_limit)
98
89
 
99
90
  return
100
91
 
@@ -103,7 +94,5 @@ class TwitterBaseTool(IntentKitSkill):
103
94
  "count": 1,
104
95
  "reset_time": (current_time + timedelta(minutes=interval)).isoformat(),
105
96
  }
106
- await self.skill_store.save_agent_skill_data(
107
- agent_id, self.name, "rate_limit", new_rate_limit
108
- )
97
+ await self.save_agent_skill_data("rate_limit", new_rate_limit)
109
98
  return
@@ -42,16 +42,13 @@ class TwitterFollowUser(TwitterBaseTool):
42
42
  skill_config = context.agent.skill_config(self.category)
43
43
  twitter = get_twitter_client(
44
44
  agent_id=context.agent_id,
45
- skill_store=self.skill_store,
46
45
  config=skill_config,
47
46
  )
48
47
  client = await twitter.get_client()
49
48
 
50
49
  # Check rate limit only when not using OAuth
51
50
  if not twitter.use_key:
52
- await self.check_rate_limit(
53
- context.agent_id, max_requests=5, interval=15
54
- )
51
+ await self.check_rate_limit(max_requests=5, interval=15)
55
52
 
56
53
  # Follow the user using tweepy client
57
54
  response = await client.follow_user(
@@ -46,7 +46,6 @@ class TwitterGetMentions(TwitterBaseTool):
46
46
  skill_config = context.agent.skill_config(self.category)
47
47
  twitter = get_twitter_client(
48
48
  agent_id=context.agent_id,
49
- skill_store=self.skill_store,
50
49
  config=skill_config,
51
50
  )
52
51
  client = await twitter.get_client()
@@ -56,15 +55,12 @@ class TwitterGetMentions(TwitterBaseTool):
56
55
  # Check rate limit only when not using OAuth
57
56
  if not twitter.use_key:
58
57
  await self.check_rate_limit(
59
- context.agent_id,
60
58
  max_requests=1,
61
59
  interval=15,
62
60
  )
63
61
 
64
62
  # get since id from store
65
- last = await self.skill_store.get_agent_skill_data(
66
- context.agent_id, self.name, "last"
67
- )
63
+ last = await self.get_agent_skill_data("last")
68
64
  last = last or {}
69
65
  max_results = 10
70
66
  since_id = last.get("since_id")
@@ -113,9 +109,7 @@ class TwitterGetMentions(TwitterBaseTool):
113
109
  # Update since_id in store
114
110
  if mentions.get("meta") and mentions["meta"].get("newest_id"):
115
111
  last["since_id"] = mentions["meta"].get("newest_id")
116
- await self.skill_store.save_agent_skill_data(
117
- context.agent_id, self.name, "last", last
118
- )
112
+ await self.save_agent_skill_data("last", last)
119
113
 
120
114
  return mentions
121
115
 
@@ -45,21 +45,16 @@ class TwitterGetTimeline(TwitterBaseTool):
45
45
  skill_config = context.agent.skill_config(self.category)
46
46
  twitter = get_twitter_client(
47
47
  agent_id=context.agent_id,
48
- skill_store=self.skill_store,
49
48
  config=skill_config,
50
49
  )
51
50
  client = await twitter.get_client()
52
51
 
53
52
  # Check rate limit only when not using OAuth
54
53
  if not twitter.use_key:
55
- await self.check_rate_limit(
56
- context.agent_id, max_requests=1, interval=15
57
- )
54
+ await self.check_rate_limit(max_requests=1, interval=15)
58
55
 
59
56
  # get since id from store
60
- last = await self.skill_store.get_agent_skill_data(
61
- context.agent_id, self.name, "last"
62
- )
57
+ last = await self.get_agent_skill_data("last")
63
58
  last = last or {}
64
59
  since_id = last.get("since_id")
65
60
 
@@ -101,9 +96,7 @@ class TwitterGetTimeline(TwitterBaseTool):
101
96
  # Update the since_id in store for the next request
102
97
  if timeline.get("meta") and timeline["meta"].get("newest_id"):
103
98
  last["since_id"] = timeline["meta"]["newest_id"]
104
- await self.skill_store.save_agent_skill_data(
105
- context.agent_id, self.name, "last", last
106
- )
99
+ await self.save_agent_skill_data("last", last)
107
100
 
108
101
  return timeline
109
102
 
@@ -43,16 +43,13 @@ class TwitterGetUserByUsername(TwitterBaseTool):
43
43
  skill_config = context.agent.skill_config(self.category)
44
44
  twitter = get_twitter_client(
45
45
  agent_id=context.agent_id,
46
- skill_store=self.skill_store,
47
46
  config=skill_config,
48
47
  )
49
48
  client = await twitter.get_client()
50
49
 
51
50
  # Check rate limit only when not using OAuth
52
51
  if not twitter.use_key:
53
- await self.check_rate_limit(
54
- context.agent_id, max_requests=5, interval=60 * 24
55
- )
52
+ await self.check_rate_limit(max_requests=5, interval=60 * 24)
56
53
 
57
54
  user_data = await client.get_user(
58
55
  username=username,
@@ -59,21 +59,16 @@ class TwitterGetUserTweets(TwitterBaseTool):
59
59
  skill_config = context.agent.skill_config(self.category)
60
60
  twitter = get_twitter_client(
61
61
  agent_id=context.agent_id,
62
- skill_store=self.skill_store,
63
62
  config=skill_config,
64
63
  )
65
64
  client = await twitter.get_client()
66
65
 
67
66
  # Check rate limit only when not using OAuth
68
67
  if not twitter.use_key:
69
- await self.check_rate_limit(
70
- context.agent_id, max_requests=1, interval=15
71
- )
68
+ await self.check_rate_limit(max_requests=1, interval=15)
72
69
 
73
70
  # get since id from store
74
- last = await self.skill_store.get_agent_skill_data(
75
- context.agent_id, self.name, user_id
76
- )
71
+ last = await self.get_agent_skill_data(user_id)
77
72
  last = last or {}
78
73
  since_id = last.get("since_id")
79
74
 
@@ -112,9 +107,7 @@ class TwitterGetUserTweets(TwitterBaseTool):
112
107
  # Update the since_id in store for the next request
113
108
  if tweets.get("meta") and tweets["meta"].get("newest_id"):
114
109
  last["since_id"] = tweets["meta"]["newest_id"]
115
- await self.skill_store.save_agent_skill_data(
116
- context.agent_id, self.name, user_id, last
117
- )
110
+ await self.save_agent_skill_data(user_id, last)
118
111
 
119
112
  return tweets
120
113
 
@@ -40,16 +40,13 @@ class TwitterLikeTweet(TwitterBaseTool):
40
40
  skill_config = context.agent.skill_config(self.category)
41
41
  twitter = get_twitter_client(
42
42
  agent_id=context.agent_id,
43
- skill_store=self.skill_store,
44
43
  config=skill_config,
45
44
  )
46
45
  client = await twitter.get_client()
47
46
 
48
47
  # Check rate limit only when not using OAuth
49
48
  if not twitter.use_key:
50
- await self.check_rate_limit(
51
- context.agent_id, max_requests=100, interval=1440
52
- )
49
+ await self.check_rate_limit(max_requests=100, interval=1440)
53
50
 
54
51
  # Like the tweet using tweepy client
55
52
  response = await client.like(tweet_id=tweet_id, user_auth=twitter.use_key)
@@ -5,6 +5,7 @@ from langchain_core.tools import ToolException
5
5
  from pydantic import BaseModel, Field
6
6
 
7
7
  from intentkit.clients import get_twitter_client
8
+ from intentkit.config.config import config
8
9
  from intentkit.skills.twitter.base import TwitterBaseTool
9
10
 
10
11
  NAME = "twitter_post_tweet"
@@ -54,16 +55,13 @@ class TwitterPostTweet(TwitterBaseTool):
54
55
  skill_config = context.agent.skill_config(self.category)
55
56
  twitter = get_twitter_client(
56
57
  agent_id=context.agent_id,
57
- skill_store=self.skill_store,
58
58
  config=skill_config,
59
59
  )
60
60
  client = await twitter.get_client()
61
61
 
62
62
  # Check rate limit only when not using OAuth
63
63
  if not twitter.use_key:
64
- await self.check_rate_limit(
65
- context.agent_id, max_requests=24, interval=1440
66
- )
64
+ await self.check_rate_limit(max_requests=24, interval=1440)
67
65
 
68
66
  media_ids = []
69
67
  image_warning = ""
@@ -71,7 +69,7 @@ class TwitterPostTweet(TwitterBaseTool):
71
69
  # Handle image upload if provided
72
70
  if image:
73
71
  # Validate image URL - must be from system's S3 CDN
74
- aws_s3_cdn_url = self.skill_store.get_system_config("aws_s3_cdn_url")
72
+ aws_s3_cdn_url = config.aws_s3_cdn_url
75
73
  if aws_s3_cdn_url and image.startswith(aws_s3_cdn_url):
76
74
  # Use the TwitterClient method to upload the image
77
75
  media_ids = await twitter.upload_media(context.agent_id, image)