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.
- intentkit/__init__.py +1 -1
- intentkit/abstracts/graph.py +4 -0
- intentkit/abstracts/skill.py +2 -140
- intentkit/clients/twitter.py +35 -28
- intentkit/core/agent.py +2 -374
- intentkit/core/asset.py +63 -16
- intentkit/core/engine.py +16 -7
- intentkit/core/scheduler.py +8 -8
- intentkit/models/agent.py +109 -94
- intentkit/models/agent_schema.json +6 -9
- intentkit/models/llm.csv +15 -12
- intentkit/models/skill.py +38 -40
- intentkit/skills/acolyt/__init__.py +2 -9
- intentkit/skills/acolyt/base.py +2 -5
- intentkit/skills/aixbt/__init__.py +2 -13
- intentkit/skills/aixbt/base.py +0 -4
- intentkit/skills/aixbt/projects.py +1 -2
- intentkit/skills/allora/__init__.py +2 -9
- intentkit/skills/allora/base.py +2 -5
- intentkit/skills/base.py +168 -27
- intentkit/skills/basename/__init__.py +1 -3
- intentkit/skills/carv/__init__.py +116 -121
- intentkit/skills/carv/base.py +184 -185
- intentkit/skills/casino/__init__.py +4 -15
- intentkit/skills/casino/base.py +0 -4
- intentkit/skills/casino/deck_draw.py +4 -6
- intentkit/skills/casino/deck_shuffle.py +5 -4
- intentkit/skills/casino/dice_roll.py +1 -2
- intentkit/skills/cdp/__init__.py +0 -5
- intentkit/skills/cdp/base.py +0 -4
- intentkit/skills/cdp/schema.json +1 -17
- intentkit/skills/chainlist/__init__.py +2 -7
- intentkit/skills/chainlist/base.py +0 -4
- intentkit/skills/common/__init__.py +2 -9
- intentkit/skills/common/base.py +0 -4
- intentkit/skills/cookiefun/__init__.py +6 -9
- intentkit/skills/cookiefun/base.py +0 -4
- intentkit/skills/cryptocompare/__init__.py +7 -24
- intentkit/skills/cryptocompare/base.py +4 -18
- intentkit/skills/cryptocompare/fetch_news.py +1 -1
- intentkit/skills/cryptocompare/fetch_price.py +1 -1
- intentkit/skills/cryptocompare/fetch_top_exchanges.py +1 -1
- intentkit/skills/cryptocompare/fetch_top_market_cap.py +1 -1
- intentkit/skills/cryptocompare/fetch_top_volume.py +1 -1
- intentkit/skills/cryptocompare/fetch_trading_signals.py +1 -1
- intentkit/skills/cryptopanic/__init__.py +3 -6
- intentkit/skills/cryptopanic/base.py +53 -55
- intentkit/skills/cryptopanic/fetch_crypto_news.py +0 -2
- intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +1 -3
- intentkit/skills/dapplooker/__init__.py +2 -9
- intentkit/skills/dapplooker/base.py +2 -5
- intentkit/skills/defillama/__init__.py +24 -74
- intentkit/skills/defillama/base.py +3 -13
- intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +2 -2
- intentkit/skills/defillama/coins/fetch_block.py +2 -2
- intentkit/skills/defillama/coins/fetch_current_prices.py +2 -2
- intentkit/skills/defillama/coins/fetch_first_price.py +2 -2
- intentkit/skills/defillama/coins/fetch_historical_prices.py +2 -2
- intentkit/skills/defillama/coins/fetch_price_chart.py +2 -2
- intentkit/skills/defillama/coins/fetch_price_percentage.py +2 -2
- intentkit/skills/defillama/fees/fetch_fees_overview.py +2 -2
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +2 -2
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +2 -2
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +2 -2
- intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +2 -2
- intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +2 -2
- intentkit/skills/defillama/tvl/fetch_chains.py +2 -2
- intentkit/skills/defillama/tvl/fetch_historical_tvl.py +2 -2
- intentkit/skills/defillama/tvl/fetch_protocol.py +2 -2
- intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +2 -2
- intentkit/skills/defillama/tvl/fetch_protocols.py +2 -2
- intentkit/skills/defillama/volumes/fetch_dex_overview.py +2 -2
- intentkit/skills/defillama/volumes/fetch_dex_summary.py +2 -2
- intentkit/skills/defillama/volumes/fetch_options_overview.py +2 -2
- intentkit/skills/defillama/yields/fetch_pool_chart.py +2 -2
- intentkit/skills/defillama/yields/fetch_pools.py +2 -2
- intentkit/skills/dexscreener/__init__.py +97 -102
- intentkit/skills/dexscreener/base.py +125 -130
- intentkit/skills/dexscreener/get_pair_info.py +2 -3
- intentkit/skills/dexscreener/get_token_pairs.py +2 -3
- intentkit/skills/dexscreener/get_tokens_info.py +2 -3
- intentkit/skills/dexscreener/search_token.py +2 -4
- intentkit/skills/dune_analytics/__init__.py +4 -6
- intentkit/skills/dune_analytics/base.py +50 -52
- intentkit/skills/dune_analytics/fetch_kol_buys.py +0 -2
- intentkit/skills/dune_analytics/fetch_nation_metrics.py +0 -2
- intentkit/skills/elfa/__init__.py +5 -18
- intentkit/skills/elfa/base.py +8 -10
- intentkit/skills/enso/__init__.py +9 -29
- intentkit/skills/enso/base.py +3 -6
- intentkit/skills/enso/networks.py +1 -6
- intentkit/skills/enso/route.py +4 -8
- intentkit/skills/enso/tokens.py +2 -12
- intentkit/skills/erc20/__init__.py +1 -5
- intentkit/skills/erc721/__init__.py +1 -3
- intentkit/skills/firecrawl/__init__.py +5 -18
- intentkit/skills/firecrawl/base.py +2 -5
- intentkit/skills/firecrawl/clear.py +3 -6
- intentkit/skills/firecrawl/crawl.py +10 -9
- intentkit/skills/firecrawl/query.py +3 -1
- intentkit/skills/firecrawl/scrape.py +10 -14
- intentkit/skills/firecrawl/utils.py +39 -31
- intentkit/skills/github/__init__.py +2 -7
- intentkit/skills/github/base.py +0 -4
- intentkit/skills/heurist/__init__.py +8 -27
- intentkit/skills/heurist/base.py +2 -5
- intentkit/skills/heurist/image_generation_animagine_xl.py +5 -5
- intentkit/skills/heurist/image_generation_arthemy_comics.py +5 -5
- intentkit/skills/heurist/image_generation_arthemy_real.py +5 -5
- intentkit/skills/heurist/image_generation_braindance.py +5 -5
- intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +5 -5
- intentkit/skills/heurist/image_generation_flux_1_dev.py +5 -5
- intentkit/skills/heurist/image_generation_sdxl.py +5 -5
- intentkit/skills/http/__init__.py +4 -15
- intentkit/skills/http/base.py +0 -4
- intentkit/skills/lifi/__init__.py +1 -6
- intentkit/skills/lifi/base.py +0 -4
- intentkit/skills/lifi/token_execute.py +1 -4
- intentkit/skills/lifi/token_quote.py +1 -3
- intentkit/skills/moralis/__init__.py +3 -7
- intentkit/skills/moralis/base.py +2 -5
- intentkit/skills/morpho/__init__.py +1 -3
- intentkit/skills/nation/__init__.py +2 -7
- intentkit/skills/nation/base.py +4 -7
- intentkit/skills/openai/__init__.py +5 -18
- intentkit/skills/openai/base.py +8 -10
- intentkit/skills/openai/dalle_image_generation.py +2 -5
- intentkit/skills/openai/gpt_image_generation.py +2 -5
- intentkit/skills/openai/gpt_image_to_image.py +2 -5
- intentkit/skills/openai/image_to_text.py +2 -5
- intentkit/skills/portfolio/__init__.py +11 -35
- intentkit/skills/portfolio/base.py +2 -5
- intentkit/skills/pyth/__init__.py +1 -5
- intentkit/skills/slack/__init__.py +5 -17
- intentkit/skills/slack/base.py +0 -4
- intentkit/skills/supabase/__init__.py +7 -23
- intentkit/skills/supabase/base.py +0 -4
- intentkit/skills/superfluid/__init__.py +1 -3
- intentkit/skills/system/__init__.py +7 -24
- intentkit/skills/system/add_autonomous_task.py +2 -2
- intentkit/skills/system/delete_autonomous_task.py +2 -2
- intentkit/skills/system/edit_autonomous_task.py +2 -4
- intentkit/skills/system/list_autonomous_tasks.py +2 -2
- intentkit/skills/system/read_agent_api_key.py +6 -4
- intentkit/skills/system/regenerate_agent_api_key.py +6 -4
- intentkit/skills/tavily/__init__.py +3 -12
- intentkit/skills/tavily/base.py +2 -5
- intentkit/skills/tavily/tavily_extract.py +1 -2
- intentkit/skills/tavily/tavily_search.py +3 -3
- intentkit/skills/token/__init__.py +5 -10
- intentkit/skills/token/base.py +2 -6
- intentkit/skills/twitter/__init__.py +11 -35
- intentkit/skills/twitter/base.py +18 -29
- intentkit/skills/twitter/follow_user.py +1 -4
- intentkit/skills/twitter/get_mentions.py +2 -8
- intentkit/skills/twitter/get_timeline.py +3 -10
- intentkit/skills/twitter/get_user_by_username.py +1 -4
- intentkit/skills/twitter/get_user_tweets.py +3 -10
- intentkit/skills/twitter/like_tweet.py +1 -4
- intentkit/skills/twitter/post_tweet.py +3 -5
- intentkit/skills/twitter/reply_tweet.py +3 -5
- intentkit/skills/twitter/retweet.py +1 -4
- intentkit/skills/twitter/search_tweets.py +3 -10
- intentkit/skills/unrealspeech/__init__.py +2 -7
- intentkit/skills/unrealspeech/base.py +0 -4
- intentkit/skills/venice_audio/__init__.py +99 -106
- intentkit/skills/venice_audio/base.py +118 -121
- intentkit/skills/venice_audio/venice_audio.py +1 -5
- intentkit/skills/venice_image/__init__.py +147 -154
- intentkit/skills/venice_image/base.py +185 -192
- intentkit/skills/web_scraper/__init__.py +5 -18
- intentkit/skills/web_scraper/base.py +20 -4
- intentkit/skills/web_scraper/document_indexer.py +6 -4
- intentkit/skills/web_scraper/scrape_and_index.py +11 -10
- intentkit/skills/web_scraper/utils.py +38 -38
- intentkit/skills/web_scraper/website_indexer.py +7 -8
- intentkit/skills/weth/__init__.py +1 -5
- intentkit/skills/wow/__init__.py +1 -5
- intentkit/skills/xmtp/__init__.py +4 -15
- {intentkit-0.8.11.dist-info → intentkit-0.8.12.dist-info}/METADATA +1 -1
- {intentkit-0.8.11.dist-info → intentkit-0.8.12.dist-info}/RECORD +183 -183
- {intentkit-0.8.11.dist-info → intentkit-0.8.12.dist-info}/WHEEL +0 -0
- {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
|
|
47
|
-
agent_data = await
|
|
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 =
|
|
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
|
|
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
|
|
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}")
|
intentkit/skills/tavily/base.py
CHANGED
|
@@ -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.
|
|
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
|
|
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 =
|
|
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
|
|
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(
|
|
88
|
+
skill = TokenPrice()
|
|
94
89
|
elif name == "token_erc20_transfers":
|
|
95
|
-
skill = ERC20Transfers(
|
|
90
|
+
skill = ERC20Transfers()
|
|
96
91
|
elif name == "token_search":
|
|
97
|
-
skill = TokenSearch(
|
|
92
|
+
skill = TokenSearch()
|
|
98
93
|
elif name == "token_analytics":
|
|
99
|
-
skill = TokenAnalytics(
|
|
94
|
+
skill = TokenAnalytics()
|
|
100
95
|
else:
|
|
101
96
|
logger.warning(f"Unknown Token skill: {name}")
|
|
102
97
|
return None
|
intentkit/skills/token/base.py
CHANGED
|
@@ -5,7 +5,7 @@ from typing import Any, Dict
|
|
|
5
5
|
|
|
6
6
|
import aiohttp
|
|
7
7
|
|
|
8
|
-
from intentkit.
|
|
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
|
|
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
|
|
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}")
|
intentkit/skills/twitter/base.py
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
29
|
-
"consumer_key":
|
|
30
|
-
|
|
31
|
-
),
|
|
32
|
-
"
|
|
33
|
-
"
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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 =
|
|
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)
|