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
@@ -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_reply_tweet"
@@ -56,16 +57,13 @@ class TwitterReplyTweet(TwitterBaseTool):
56
57
  skill_config = context.agent.skill_config(self.category)
57
58
  twitter = get_twitter_client(
58
59
  agent_id=context.agent_id,
59
- skill_store=self.skill_store,
60
60
  config=skill_config,
61
61
  )
62
62
  client = await twitter.get_client()
63
63
 
64
64
  # Check rate limit only when not using OAuth
65
65
  if not twitter.use_key:
66
- await self.check_rate_limit(
67
- context.agent_id, max_requests=48, interval=1440
68
- )
66
+ await self.check_rate_limit(max_requests=48, interval=1440)
69
67
 
70
68
  media_ids = []
71
69
  image_warning = ""
@@ -73,7 +71,7 @@ class TwitterReplyTweet(TwitterBaseTool):
73
71
  # Handle image upload if provided
74
72
  if image:
75
73
  # Validate image URL - must be from system's S3 CDN
76
- aws_s3_cdn_url = self.skill_store.get_system_config("aws_s3_cdn_url")
74
+ aws_s3_cdn_url = config.aws_s3_cdn_url
77
75
  if aws_s3_cdn_url and image.startswith(aws_s3_cdn_url):
78
76
  # Use the TwitterClient method to upload the image
79
77
  media_ids = await twitter.upload_media(context.agent_id, image)
@@ -40,16 +40,13 @@ class TwitterRetweet(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=5, interval=15
52
- )
49
+ await self.check_rate_limit(max_requests=5, interval=15)
53
50
 
54
51
  # Get authenticated user's ID
55
52
  user_id = twitter.self_id
@@ -42,21 +42,16 @@ class TwitterSearchTweets(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=1, interval=15
54
- )
51
+ await self.check_rate_limit(max_requests=1, interval=15)
55
52
 
56
53
  # Get since_id from store to avoid duplicate results
57
- last = await self.skill_store.get_agent_skill_data(
58
- context.agent_id, self.name, query
59
- )
54
+ last = await self.get_agent_skill_data(query)
60
55
  last = last or {}
61
56
  since_id = last.get("since_id")
62
57
 
@@ -104,9 +99,7 @@ class TwitterSearchTweets(TwitterBaseTool):
104
99
  if tweets.get("meta") and tweets.get("meta").get("newest_id"):
105
100
  last["since_id"] = tweets["meta"]["newest_id"]
106
101
  last["timestamp"] = datetime.datetime.now().isoformat()
107
- await self.skill_store.save_agent_skill_data(
108
- context.agent_id, self.name, query, last
109
- )
102
+ await self.save_agent_skill_data(query, last)
110
103
 
111
104
  return tweets
112
105
 
@@ -1,6 +1,5 @@
1
1
  from typing import TypedDict
2
2
 
3
- from intentkit.abstracts.skill import SkillStoreABC
4
3
  from intentkit.skills.base import SkillConfig, SkillState
5
4
  from intentkit.skills.unrealspeech.base import UnrealSpeechBaseTool
6
5
  from intentkit.skills.unrealspeech.text_to_speech import TextToSpeech
@@ -23,7 +22,6 @@ class Config(SkillConfig):
23
22
  async def get_skills(
24
23
  config: "Config",
25
24
  is_private: bool,
26
- store: SkillStoreABC,
27
25
  **_,
28
26
  ) -> list[UnrealSpeechBaseTool]:
29
27
  """Get all UnrealSpeech tools."""
@@ -37,19 +35,16 @@ async def get_skills(
37
35
  available_skills.append(skill_name)
38
36
 
39
37
  # Get each skill using the cached getter
40
- return [get_unrealspeech_skill(name, store) for name in available_skills]
38
+ return [get_unrealspeech_skill(name) for name in available_skills]
41
39
 
42
40
 
43
41
  def get_unrealspeech_skill(
44
42
  name: str,
45
- store: SkillStoreABC,
46
43
  ) -> UnrealSpeechBaseTool:
47
44
  """Get an UnrealSpeech skill by name."""
48
45
  if name == "text_to_speech":
49
46
  if name not in _cache:
50
- _cache[name] = TextToSpeech(
51
- skill_store=store,
52
- )
47
+ _cache[name] = TextToSpeech()
53
48
  return _cache[name]
54
49
  else:
55
50
  raise ValueError(f"Unknown UnrealSpeech skill: {name}")
@@ -3,7 +3,6 @@ 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
7
6
  from intentkit.skills.base import IntentKitSkill
8
7
 
9
8
 
@@ -13,9 +12,6 @@ class UnrealSpeechBaseTool(IntentKitSkill):
13
12
  name: str = Field(description="The name of the tool")
14
13
  description: str = Field(description="A description of what the tool does")
15
14
  args_schema: Type[BaseModel]
16
- skill_store: SkillStoreABC = Field(
17
- description="The skill store for persisting data"
18
- )
19
15
 
20
16
  def get_api_key(self) -> str:
21
17
  context = self.get_context()
@@ -1,106 +1,99 @@
1
- import logging
2
- from typing import List, Literal, Optional, TypedDict
3
-
4
- from intentkit.abstracts.skill import SkillStoreABC
5
- from intentkit.skills.base import SkillConfig, SkillState
6
- from intentkit.skills.venice_audio.base import VeniceAudioBaseTool
7
- from intentkit.skills.venice_audio.venice_audio import VeniceAudioTool
8
-
9
- logger = logging.getLogger(__name__)
10
-
11
-
12
- _cache: dict[str, VeniceAudioBaseTool] = {}
13
-
14
- _SKILL_NAME_TO_CLASS_MAP = {
15
- "text_to_speech": VeniceAudioTool,
16
- # Add new mappings here: "skill_name": SkillClassName
17
- }
18
-
19
-
20
- class SkillStates(TypedDict):
21
- text_to_speech: SkillState
22
-
23
-
24
- class Config(SkillConfig):
25
- enabled: bool
26
- voice_model: Literal["af_heart", "bm_lewis", "custom"]
27
- states: SkillStates # type: ignore
28
- api_key_provider: Optional[Literal["agent_owner"]]
29
-
30
- # conditionally required
31
- api_key: Optional[str]
32
- voice_model_custom: Optional[list[str]]
33
-
34
- # optional
35
- rate_limit_number: Optional[int]
36
- rate_limit_minutes: Optional[int]
37
-
38
-
39
- async def get_skills(
40
- config: "Config",
41
- is_private: bool,
42
- store: SkillStoreABC,
43
- **_, # Allow for extra arguments if the loader passes them
44
- ) -> list[VeniceAudioBaseTool]:
45
- """
46
- Factory function to create and return Venice Audio skill tools.
47
-
48
- Args:
49
- config: The configuration dictionary for the Venice Audio skill.
50
- skill_store: The skill store instance.
51
- agent_id: The ID of the agent requesting the skills.
52
-
53
- Returns:
54
- A list of VeniceAudioBaseTool instances for the Venice Audio skill.
55
- """
56
- # Check if the entire category is disabled first
57
- if not config.get("enabled", False):
58
- return []
59
-
60
- available_skills: List[VeniceAudioBaseTool] = []
61
- skill_states = config.get("states", {})
62
-
63
- # Iterate through all known skills defined in the map
64
- for skill_name in _SKILL_NAME_TO_CLASS_MAP:
65
- state = skill_states.get(
66
- skill_name, "disabled"
67
- ) # Default to disabled if not in config
68
-
69
- if state == "disabled":
70
- continue
71
- elif state == "public" or (state == "private" and is_private):
72
- # If enabled, get the skill instance using the factory function
73
- skill_instance = get_venice_audio_skill(skill_name, store)
74
- if skill_instance:
75
- available_skills.append(skill_instance)
76
- else:
77
- # This case should ideally not happen if the map is correct
78
- logger.warning(f"Could not instantiate known skill: {skill_name}")
79
-
80
- return available_skills
81
-
82
-
83
- def get_venice_audio_skill(
84
- name: str,
85
- store: SkillStoreABC,
86
- ) -> Optional[VeniceAudioBaseTool]:
87
- """
88
- Factory function to get a cached Venice Audio skill instance by name.
89
-
90
- Args:
91
- name: The name of voice model.
92
- store: The skill store, passed to the skill constructor.
93
-
94
- Returns:
95
- The requested Venice Audio skill instance, or None if the name is unknown.
96
- """
97
-
98
- # Return from cache immediately if already exists
99
- if name in _cache:
100
- return _cache[name]
101
-
102
- # Cache and return the newly created instance
103
- _cache[name] = VeniceAudioTool(
104
- skill_store=store,
105
- )
106
- return _cache[name]
1
+ import logging
2
+ from typing import List, Literal, Optional, TypedDict
3
+
4
+ from intentkit.skills.base import SkillConfig, SkillState
5
+ from intentkit.skills.venice_audio.base import VeniceAudioBaseTool
6
+ from intentkit.skills.venice_audio.venice_audio import VeniceAudioTool
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ _cache: dict[str, VeniceAudioBaseTool] = {}
12
+
13
+ _SKILL_NAME_TO_CLASS_MAP = {
14
+ "text_to_speech": VeniceAudioTool,
15
+ # Add new mappings here: "skill_name": SkillClassName
16
+ }
17
+
18
+
19
+ class SkillStates(TypedDict):
20
+ text_to_speech: SkillState
21
+
22
+
23
+ class Config(SkillConfig):
24
+ enabled: bool
25
+ voice_model: Literal["af_heart", "bm_lewis", "custom"]
26
+ states: SkillStates # type: ignore
27
+ api_key_provider: Optional[Literal["agent_owner"]]
28
+
29
+ # conditionally required
30
+ api_key: Optional[str]
31
+ voice_model_custom: Optional[list[str]]
32
+
33
+ # optional
34
+ rate_limit_number: Optional[int]
35
+ rate_limit_minutes: Optional[int]
36
+
37
+
38
+ async def get_skills(
39
+ config: "Config",
40
+ is_private: bool,
41
+ **_, # Allow for extra arguments if the loader passes them
42
+ ) -> list[VeniceAudioBaseTool]:
43
+ """
44
+ Factory function to create and return Venice Audio skill tools.
45
+
46
+ Args:
47
+ config: The configuration dictionary for the Venice Audio skill.
48
+ agent_id: The ID of the agent requesting the skills.
49
+
50
+ Returns:
51
+ A list of VeniceAudioBaseTool instances for the Venice Audio skill.
52
+ """
53
+ # Check if the entire category is disabled first
54
+ if not config.get("enabled", False):
55
+ return []
56
+
57
+ available_skills: List[VeniceAudioBaseTool] = []
58
+ skill_states = config.get("states", {})
59
+
60
+ # Iterate through all known skills defined in the map
61
+ for skill_name in _SKILL_NAME_TO_CLASS_MAP:
62
+ state = skill_states.get(
63
+ skill_name, "disabled"
64
+ ) # Default to disabled if not in config
65
+
66
+ if state == "disabled":
67
+ continue
68
+ elif state == "public" or (state == "private" and is_private):
69
+ # If enabled, get the skill instance using the factory function
70
+ skill_instance = get_venice_audio_skill(skill_name)
71
+ if skill_instance:
72
+ available_skills.append(skill_instance)
73
+ else:
74
+ # This case should ideally not happen if the map is correct
75
+ logger.warning(f"Could not instantiate known skill: {skill_name}")
76
+
77
+ return available_skills
78
+
79
+
80
+ def get_venice_audio_skill(
81
+ name: str,
82
+ ) -> Optional[VeniceAudioBaseTool]:
83
+ """
84
+ Factory function to get a cached Venice Audio skill instance by name.
85
+
86
+ Args:
87
+ name: The name of voice model.
88
+
89
+ Returns:
90
+ The requested Venice Audio skill instance, or None if the name is unknown.
91
+ """
92
+
93
+ # Return from cache immediately if already exists
94
+ if name in _cache:
95
+ return _cache[name]
96
+
97
+ # Cache and return the newly created instance
98
+ _cache[name] = VeniceAudioTool()
99
+ return _cache[name]
@@ -1,121 +1,118 @@
1
- import logging
2
- from typing import Dict, List, Optional, Tuple, Type
3
-
4
- from langchain_core.tools.base import ToolException
5
- from pydantic import BaseModel, Field
6
-
7
- from intentkit.abstracts.skill import SkillStoreABC
8
- from intentkit.skills.base import IntentKitSkill
9
-
10
- logger = logging.getLogger(__name__)
11
-
12
-
13
- class VeniceAudioBaseTool(IntentKitSkill):
14
- """Base class for Venice Audio tools."""
15
-
16
- name: str = Field(default="venice_base_tool", description="The name of the tool")
17
- description: str = Field(description="A description of what the tool does")
18
- args_schema: Type[BaseModel] # type: ignore
19
- skill_store: SkillStoreABC = Field(
20
- description="The skill store for persisting data"
21
- )
22
-
23
- @property
24
- def category(self) -> str:
25
- return "venice_audio"
26
-
27
- def validate_voice_model(
28
- self, context, voice_model: str
29
- ) -> Tuple[bool, Optional[Dict[str, object]]]:
30
- config = context.config
31
-
32
- selected_model = config.get("voice_model")
33
- custom_models = config.get("voice_model_custom", [])
34
-
35
- allowed_voice_models: List[str] = []
36
-
37
- if selected_model == "custom":
38
- allowed_voice_models = custom_models or []
39
- else:
40
- allowed_voice_models = [selected_model] if selected_model else []
41
-
42
- if voice_model not in allowed_voice_models:
43
- return False, {
44
- "error": f'"{voice_model}" is not allowed',
45
- "allowed": allowed_voice_models,
46
- "suggestion": "please try again with allowed voice model",
47
- }
48
-
49
- return True, None
50
-
51
- def get_api_key(self) -> str:
52
- """
53
- Retrieves the Venice AI API key based on the api_key_provider setting.
54
-
55
- Returns:
56
- The API key if found.
57
-
58
- Raises:
59
- ToolException: If the API key is not found or provider is invalid.
60
- """
61
- try:
62
- context = self.get_context()
63
- skill_config = context.agent.skill_config(self.category)
64
- api_key_provider = skill_config.get("api_key_provider")
65
- if api_key_provider == "agent_owner":
66
- agent_api_key = skill_config.get("api_key")
67
- if agent_api_key:
68
- logger.debug(
69
- f"Using agent-specific Venice API key for skill {self.name} in category {self.category}"
70
- )
71
- return agent_api_key
72
- raise ToolException(
73
- f"No agent-owned Venice API key found for skill '{self.name}' in category '{self.category}'."
74
- )
75
-
76
- elif api_key_provider == "platform":
77
- system_api_key = self.skill_store.get_system_config("venice_api_key")
78
- if system_api_key:
79
- logger.debug(
80
- f"Using system Venice API key for skill {self.name} in category {self.category}"
81
- )
82
- return system_api_key
83
- raise ToolException(
84
- f"No platform-hosted Venice API key found for skill '{self.name}' in category '{self.category}'."
85
- )
86
-
87
- else:
88
- raise ToolException(
89
- f"Invalid API key provider '{api_key_provider}' for skill '{self.name}'"
90
- )
91
-
92
- except Exception as e:
93
- raise ToolException(f"Failed to retrieve Venice API key: {str(e)}") from e
94
-
95
- async def apply_rate_limit(self, context) -> None:
96
- """
97
- Applies rate limiting ONLY if specified in the agent's config ('skill_config').
98
- Checks for 'rate_limit_number' and 'rate_limit_minutes'.
99
- If not configured, NO rate limiting is applied.
100
- Raises ConnectionAbortedError if the configured limit is exceeded.
101
- """
102
- skill_config = context.agent.skill_config(self.category)
103
- user_id = context.agent.id
104
-
105
- # Get agent-specific limits safely
106
- limit_num = skill_config.get("rate_limit_number")
107
- limit_min = skill_config.get("rate_limit_minutes")
108
-
109
- # Apply limit ONLY if both values are present and valid (truthy check handles None and 0)
110
- if limit_num and limit_min:
111
- limit_source = "Agent"
112
- logger.debug(
113
- f"Applying {limit_source} rate limit ({limit_num}/{limit_min} min) for user {user_id} on {self.name}"
114
- )
115
- if user_id:
116
- await self.user_rate_limit_by_category(user_id, limit_num, limit_min)
117
- else:
118
- # No valid agent configuration found, so do nothing.
119
- logger.debug(
120
- f"No agent rate limits configured for category '{self.category}'. Skipping rate limit for user {user_id}."
121
- )
1
+ import logging
2
+ from typing import Dict, List, Optional, Tuple, Type
3
+
4
+ from langchain_core.tools.base import ToolException
5
+ from pydantic import BaseModel, Field
6
+
7
+ from intentkit.config.config import config
8
+ from intentkit.skills.base import IntentKitSkill
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class VeniceAudioBaseTool(IntentKitSkill):
14
+ """Base class for Venice Audio tools."""
15
+
16
+ name: str = Field(default="venice_base_tool", description="The name of the tool")
17
+ description: str = Field(description="A description of what the tool does")
18
+ args_schema: Type[BaseModel] # type: ignore
19
+
20
+ @property
21
+ def category(self) -> str:
22
+ return "venice_audio"
23
+
24
+ def validate_voice_model(
25
+ self, context, voice_model: str
26
+ ) -> Tuple[bool, Optional[Dict[str, object]]]:
27
+ config = context.config
28
+
29
+ selected_model = config.get("voice_model")
30
+ custom_models = config.get("voice_model_custom", [])
31
+
32
+ allowed_voice_models: List[str] = []
33
+
34
+ if selected_model == "custom":
35
+ allowed_voice_models = custom_models or []
36
+ else:
37
+ allowed_voice_models = [selected_model] if selected_model else []
38
+
39
+ if voice_model not in allowed_voice_models:
40
+ return False, {
41
+ "error": f'"{voice_model}" is not allowed',
42
+ "allowed": allowed_voice_models,
43
+ "suggestion": "please try again with allowed voice model",
44
+ }
45
+
46
+ return True, None
47
+
48
+ def get_api_key(self) -> str:
49
+ """
50
+ Retrieves the Venice AI API key based on the api_key_provider setting.
51
+
52
+ Returns:
53
+ The API key if found.
54
+
55
+ Raises:
56
+ ToolException: If the API key is not found or provider is invalid.
57
+ """
58
+ try:
59
+ context = self.get_context()
60
+ skill_config = context.agent.skill_config(self.category)
61
+ api_key_provider = skill_config.get("api_key_provider")
62
+ if api_key_provider == "agent_owner":
63
+ agent_api_key = skill_config.get("api_key")
64
+ if agent_api_key:
65
+ logger.debug(
66
+ f"Using agent-specific Venice API key for skill {self.name} in category {self.category}"
67
+ )
68
+ return agent_api_key
69
+ raise ToolException(
70
+ f"No agent-owned Venice API key found for skill '{self.name}' in category '{self.category}'."
71
+ )
72
+
73
+ elif api_key_provider == "platform":
74
+ system_api_key = config.venice_api_key
75
+ if system_api_key:
76
+ logger.debug(
77
+ f"Using system Venice API key for skill {self.name} in category {self.category}"
78
+ )
79
+ return system_api_key
80
+ raise ToolException(
81
+ f"No platform-hosted Venice API key found for skill '{self.name}' in category '{self.category}'."
82
+ )
83
+
84
+ else:
85
+ raise ToolException(
86
+ f"Invalid API key provider '{api_key_provider}' for skill '{self.name}'"
87
+ )
88
+
89
+ except Exception as e:
90
+ raise ToolException(f"Failed to retrieve Venice API key: {str(e)}") from e
91
+
92
+ async def apply_rate_limit(self, context) -> None:
93
+ """
94
+ Applies rate limiting ONLY if specified in the agent's config ('skill_config').
95
+ Checks for 'rate_limit_number' and 'rate_limit_minutes'.
96
+ If not configured, NO rate limiting is applied.
97
+ Raises ConnectionAbortedError if the configured limit is exceeded.
98
+ """
99
+ skill_config = context.agent.skill_config(self.category)
100
+ user_id = context.agent.id
101
+
102
+ # Get agent-specific limits safely
103
+ limit_num = skill_config.get("rate_limit_number")
104
+ limit_min = skill_config.get("rate_limit_minutes")
105
+
106
+ # Apply limit ONLY if both values are present and valid (truthy check handles None and 0)
107
+ if limit_num and limit_min:
108
+ limit_source = "Agent"
109
+ logger.debug(
110
+ f"Applying {limit_source} rate limit ({limit_num}/{limit_min} min) for user {user_id} on {self.name}"
111
+ )
112
+ if user_id:
113
+ await self.user_rate_limit_by_category(limit_num, limit_min * 60)
114
+ else:
115
+ # No valid agent configuration found, so do nothing.
116
+ logger.debug(
117
+ f"No agent rate limits configured for category '{self.category}'. Skipping rate limit for user {user_id}."
118
+ )
@@ -4,9 +4,8 @@ import logging
4
4
  from typing import Any, Dict, Optional, Type
5
5
 
6
6
  import httpx
7
- from pydantic import BaseModel, Field
7
+ from pydantic import BaseModel
8
8
 
9
- from intentkit.abstracts.skill import SkillStoreABC
10
9
  from intentkit.skills.venice_audio.base import VeniceAudioBaseTool
11
10
  from intentkit.skills.venice_audio.input import AllowedAudioFormat, VeniceAudioInput
12
11
  from intentkit.utils.s3 import store_file
@@ -34,9 +33,6 @@ class VeniceAudioTool(VeniceAudioBaseTool):
34
33
  "and audio format (mp3, opus, aac, flac, wav, pcm, default mp3)."
35
34
  )
36
35
  args_schema: Type[BaseModel] = VeniceAudioInput
37
- skill_store: SkillStoreABC = Field(
38
- description="The skill store instance for accessing system/agent configurations and persisting data."
39
- )
40
36
 
41
37
  async def _arun(
42
38
  self,