intentkit 0.6.9.dev2__py3-none-any.whl → 0.6.10__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 +17 -2
- intentkit/core/engine.py +49 -30
- intentkit/core/node.py +10 -20
- intentkit/models/agent.py +215 -11
- intentkit/models/agent_schema.json +4 -0
- intentkit/models/chat.py +9 -1
- intentkit/models/llm.py +53 -0
- intentkit/skills/acolyt/ask.py +2 -5
- intentkit/skills/acolyt/base.py +16 -6
- intentkit/skills/aixbt/__init__.py +3 -7
- intentkit/skills/aixbt/projects.py +12 -36
- intentkit/skills/allora/base.py +16 -6
- intentkit/skills/allora/price.py +2 -4
- intentkit/skills/base.py +8 -1
- intentkit/skills/carv/base.py +12 -10
- intentkit/skills/carv/fetch_news.py +90 -92
- intentkit/skills/carv/onchain_query.py +162 -164
- intentkit/skills/carv/token_info_and_price.py +108 -110
- intentkit/skills/chainlist/chain_lookup.py +1 -2
- intentkit/skills/common/current_time.py +1 -2
- intentkit/skills/cookiefun/base.py +20 -12
- intentkit/skills/cookiefun/get_account_details.py +1 -3
- intentkit/skills/cookiefun/get_account_feed.py +1 -3
- intentkit/skills/cookiefun/get_account_smart_followers.py +1 -3
- intentkit/skills/cookiefun/get_sectors.py +2 -3
- intentkit/skills/cookiefun/search_accounts.py +1 -3
- intentkit/skills/cryptocompare/fetch_news.py +3 -4
- intentkit/skills/cryptocompare/fetch_price.py +3 -4
- intentkit/skills/cryptocompare/fetch_top_exchanges.py +3 -4
- intentkit/skills/cryptocompare/fetch_top_market_cap.py +3 -4
- intentkit/skills/cryptocompare/fetch_top_volume.py +3 -4
- intentkit/skills/cryptocompare/fetch_trading_signals.py +3 -4
- intentkit/skills/cryptopanic/base.py +13 -9
- intentkit/skills/cryptopanic/fetch_crypto_news.py +150 -153
- intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +133 -136
- intentkit/skills/dapplooker/base.py +16 -6
- intentkit/skills/dapplooker/dapplooker_token_data.py +2 -4
- intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +2 -3
- intentkit/skills/defillama/coins/fetch_block.py +2 -3
- intentkit/skills/defillama/coins/fetch_current_prices.py +2 -5
- intentkit/skills/defillama/coins/fetch_first_price.py +2 -5
- intentkit/skills/defillama/coins/fetch_historical_prices.py +2 -3
- intentkit/skills/defillama/coins/fetch_price_chart.py +2 -5
- intentkit/skills/defillama/coins/fetch_price_percentage.py +2 -5
- intentkit/skills/defillama/fees/fetch_fees_overview.py +2 -3
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +2 -3
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +2 -3
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +2 -3
- intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +2 -3
- intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +2 -5
- intentkit/skills/defillama/tvl/fetch_chains.py +2 -3
- intentkit/skills/defillama/tvl/fetch_historical_tvl.py +2 -3
- intentkit/skills/defillama/tvl/fetch_protocol.py +2 -5
- intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +2 -5
- intentkit/skills/defillama/tvl/fetch_protocols.py +2 -3
- intentkit/skills/defillama/volumes/fetch_dex_overview.py +2 -3
- intentkit/skills/defillama/volumes/fetch_dex_summary.py +2 -5
- intentkit/skills/defillama/volumes/fetch_options_overview.py +2 -3
- intentkit/skills/defillama/yields/fetch_pool_chart.py +2 -5
- intentkit/skills/defillama/yields/fetch_pools.py +2 -3
- intentkit/skills/dune_analytics/base.py +15 -9
- intentkit/skills/dune_analytics/fetch_kol_buys.py +125 -128
- intentkit/skills/dune_analytics/fetch_nation_metrics.py +234 -237
- intentkit/skills/elfa/base.py +16 -6
- intentkit/skills/elfa/mention.py +2 -7
- intentkit/skills/elfa/stats.py +2 -6
- intentkit/skills/elfa/tokens.py +1 -4
- intentkit/skills/enso/base.py +25 -13
- intentkit/skills/enso/best_yield.py +1 -4
- intentkit/skills/enso/networks.py +2 -5
- intentkit/skills/enso/prices.py +1 -5
- intentkit/skills/enso/route.py +2 -5
- intentkit/skills/enso/tokens.py +1 -4
- intentkit/skills/enso/wallet.py +3 -9
- intentkit/skills/firecrawl/base.py +16 -6
- intentkit/skills/firecrawl/clear.py +1 -3
- intentkit/skills/firecrawl/crawl.py +7 -8
- intentkit/skills/firecrawl/query.py +7 -9
- intentkit/skills/firecrawl/scrape.py +7 -8
- intentkit/skills/github/github_search.py +1 -3
- intentkit/skills/heurist/base.py +15 -0
- intentkit/skills/heurist/image_generation_animagine_xl.py +3 -4
- intentkit/skills/heurist/image_generation_arthemy_comics.py +3 -4
- intentkit/skills/heurist/image_generation_arthemy_real.py +3 -4
- intentkit/skills/heurist/image_generation_braindance.py +3 -4
- intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +3 -4
- intentkit/skills/heurist/image_generation_flux_1_dev.py +3 -4
- intentkit/skills/heurist/image_generation_sdxl.py +3 -4
- intentkit/skills/http/get.py +0 -2
- intentkit/skills/http/post.py +0 -2
- intentkit/skills/http/put.py +0 -2
- intentkit/skills/lifi/token_execute.py +1 -3
- intentkit/skills/lifi/token_quote.py +0 -2
- intentkit/skills/moralis/base.py +15 -1
- intentkit/skills/nation/nft_check.py +2 -5
- intentkit/skills/openai/base.py +14 -5
- intentkit/skills/openai/dalle_image_generation.py +6 -5
- intentkit/skills/openai/gpt_image_generation.py +6 -5
- intentkit/skills/openai/gpt_image_to_image.py +6 -5
- intentkit/skills/openai/image_to_text.py +6 -6
- intentkit/skills/portfolio/base.py +4 -3
- intentkit/skills/portfolio/token_balances.py +2 -4
- intentkit/skills/portfolio/wallet_approvals.py +2 -4
- intentkit/skills/portfolio/wallet_defi_positions.py +3 -4
- intentkit/skills/portfolio/wallet_history.py +2 -4
- intentkit/skills/portfolio/wallet_net_worth.py +2 -4
- intentkit/skills/portfolio/wallet_nfts.py +2 -4
- intentkit/skills/portfolio/wallet_profitability.py +2 -4
- intentkit/skills/portfolio/wallet_profitability_summary.py +2 -4
- intentkit/skills/portfolio/wallet_stats.py +2 -4
- intentkit/skills/portfolio/wallet_swaps.py +2 -4
- intentkit/skills/slack/base.py +18 -0
- intentkit/skills/slack/get_channel.py +3 -4
- intentkit/skills/slack/get_message.py +3 -4
- intentkit/skills/slack/schedule_message.py +3 -4
- intentkit/skills/slack/send_message.py +3 -4
- intentkit/skills/supabase/delete_data.py +3 -6
- intentkit/skills/supabase/fetch_data.py +3 -6
- intentkit/skills/supabase/insert_data.py +3 -6
- intentkit/skills/supabase/invoke_function.py +3 -6
- intentkit/skills/supabase/update_data.py +3 -6
- intentkit/skills/supabase/upsert_data.py +3 -6
- intentkit/skills/system/add_autonomous_task.py +1 -3
- intentkit/skills/system/delete_autonomous_task.py +1 -3
- intentkit/skills/system/edit_autonomous_task.py +1 -3
- intentkit/skills/system/list_autonomous_tasks.py +1 -3
- intentkit/skills/system/read_agent_api_key.py +2 -3
- intentkit/skills/system/regenerate_agent_api_key.py +2 -5
- intentkit/skills/tavily/base.py +14 -5
- intentkit/skills/tavily/tavily_extract.py +7 -8
- intentkit/skills/tavily/tavily_search.py +11 -9
- intentkit/skills/token/base.py +4 -6
- intentkit/skills/token/erc20_transfers.py +2 -4
- intentkit/skills/token/token_analytics.py +2 -4
- intentkit/skills/token/token_price.py +2 -4
- intentkit/skills/token/token_search.py +2 -4
- intentkit/skills/twitter/base.py +41 -0
- intentkit/skills/twitter/follow_user.py +4 -4
- intentkit/skills/twitter/get_mentions.py +4 -4
- intentkit/skills/twitter/get_timeline.py +4 -4
- intentkit/skills/twitter/get_user_by_username.py +4 -4
- intentkit/skills/twitter/get_user_tweets.py +4 -4
- intentkit/skills/twitter/like_tweet.py +4 -4
- intentkit/skills/twitter/post_tweet.py +3 -4
- intentkit/skills/twitter/reply_tweet.py +3 -4
- intentkit/skills/twitter/retweet.py +4 -4
- intentkit/skills/twitter/search_tweets.py +4 -4
- intentkit/skills/unrealspeech/base.py +16 -0
- intentkit/skills/unrealspeech/text_to_speech.py +4 -4
- intentkit/skills/venice_audio/base.py +11 -9
- intentkit/skills/venice_audio/venice_audio.py +238 -240
- intentkit/skills/venice_image/base.py +23 -19
- intentkit/skills/venice_image/image_enhance/image_enhance.py +78 -80
- intentkit/skills/venice_image/image_generation/image_generation_base.py +115 -117
- intentkit/skills/venice_image/image_upscale/image_upscale.py +88 -90
- intentkit/skills/venice_image/image_vision/image_vision.py +98 -100
- intentkit/skills/web_scraper/document_indexer.py +3 -5
- intentkit/skills/web_scraper/scrape_and_index.py +14 -17
- intentkit/skills/web_scraper/website_indexer.py +8 -10
- intentkit/skills/xmtp/README.md +110 -0
- intentkit/skills/xmtp/__init__.py +82 -0
- intentkit/skills/xmtp/base.py +15 -0
- intentkit/skills/xmtp/schema.json +43 -0
- intentkit/skills/xmtp/transfer.py +155 -0
- intentkit/skills/xmtp/xmtp.png +0 -0
- {intentkit-0.6.9.dev2.dist-info → intentkit-0.6.10.dist-info}/METADATA +4 -3
- {intentkit-0.6.9.dev2.dist-info → intentkit-0.6.10.dist-info}/RECORD +170 -164
- {intentkit-0.6.9.dev2.dist-info → intentkit-0.6.10.dist-info}/WHEEL +0 -0
- {intentkit-0.6.9.dev2.dist-info → intentkit-0.6.10.dist-info}/licenses/LICENSE +0 -0
intentkit/skills/acolyt/ask.py
CHANGED
|
@@ -2,7 +2,6 @@ import logging
|
|
|
2
2
|
from typing import Dict, Literal, Type
|
|
3
3
|
|
|
4
4
|
import httpx
|
|
5
|
-
from langchain_core.runnables import RunnableConfig
|
|
6
5
|
from pydantic import BaseModel, Field
|
|
7
6
|
|
|
8
7
|
from intentkit.skills.acolyt.base import AcolytBaseTool
|
|
@@ -67,12 +66,11 @@ class AcolytAskGpt(AcolytBaseTool):
|
|
|
67
66
|
"""
|
|
68
67
|
args_schema: Type[BaseModel] = AcolytAskGptInput
|
|
69
68
|
|
|
70
|
-
async def _arun(self, question: str,
|
|
69
|
+
async def _arun(self, question: str, **kwargs) -> Dict:
|
|
71
70
|
"""Run the tool to get answer from Acolyt GPT.
|
|
72
71
|
|
|
73
72
|
Args:
|
|
74
73
|
question (str): The question body from user.
|
|
75
|
-
config (RunnableConfig): The configuration for the runnable, containing agent context.
|
|
76
74
|
|
|
77
75
|
Returns:
|
|
78
76
|
Dict: The response from the API with message content.
|
|
@@ -80,8 +78,7 @@ class AcolytAskGpt(AcolytBaseTool):
|
|
|
80
78
|
Raises:
|
|
81
79
|
Exception: If there's an error accessing the Acolyt API.
|
|
82
80
|
"""
|
|
83
|
-
|
|
84
|
-
api_key = self.get_api_key(context)
|
|
81
|
+
api_key = self.get_api_key()
|
|
85
82
|
if not api_key:
|
|
86
83
|
raise ValueError("Acolyt API key not found")
|
|
87
84
|
|
intentkit/skills/acolyt/base.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Type
|
|
2
2
|
|
|
3
|
+
from langchain.tools.base import ToolException
|
|
3
4
|
from pydantic import BaseModel, Field
|
|
4
5
|
|
|
5
6
|
from intentkit.abstracts.skill import SkillStoreABC
|
|
6
|
-
from intentkit.skills.base import IntentKitSkill
|
|
7
|
+
from intentkit.skills.base import IntentKitSkill
|
|
7
8
|
|
|
8
9
|
base_url = "https://acolyt-oracle-poc.vercel.app"
|
|
9
10
|
|
|
@@ -18,10 +19,19 @@ class AcolytBaseTool(IntentKitSkill):
|
|
|
18
19
|
description="The skill store for persisting data"
|
|
19
20
|
)
|
|
20
21
|
|
|
21
|
-
def get_api_key(self
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
def get_api_key(self) -> str:
|
|
23
|
+
context = self.get_context()
|
|
24
|
+
skill_config = context.agent.skill_config(self.category)
|
|
25
|
+
api_key_provider = skill_config.get("api_key_provider")
|
|
26
|
+
if api_key_provider == "platform":
|
|
27
|
+
return self.skill_store.get_system_config("acolyt_api_key")
|
|
28
|
+
# for backward compatibility, may only have api_key in skill_config
|
|
29
|
+
elif skill_config.get("api_key"):
|
|
30
|
+
return skill_config.get("api_key")
|
|
31
|
+
else:
|
|
32
|
+
raise ToolException(
|
|
33
|
+
f"Invalid API key provider: {api_key_provider}, or no api_key in config"
|
|
34
|
+
)
|
|
25
35
|
|
|
26
36
|
@property
|
|
27
37
|
def category(self) -> str:
|
|
@@ -48,7 +48,6 @@ async def get_skills(
|
|
|
48
48
|
get_aixbt_skill(
|
|
49
49
|
name=name,
|
|
50
50
|
store=store,
|
|
51
|
-
api_key=config.get("api_key", ""),
|
|
52
51
|
)
|
|
53
52
|
for name in available_skills
|
|
54
53
|
]
|
|
@@ -57,17 +56,14 @@ async def get_skills(
|
|
|
57
56
|
def get_aixbt_skill(
|
|
58
57
|
name: str,
|
|
59
58
|
store: SkillStoreABC,
|
|
60
|
-
api_key: str = "",
|
|
61
59
|
) -> AIXBTBaseTool:
|
|
62
60
|
"""Get an AIXBT API skill by name."""
|
|
63
|
-
cache_key = f"{name}:{api_key}"
|
|
64
61
|
|
|
65
62
|
if name == "aixbt_projects":
|
|
66
|
-
if
|
|
67
|
-
_cache[
|
|
63
|
+
if name not in _cache:
|
|
64
|
+
_cache[name] = AIXBTProjects(
|
|
68
65
|
skill_store=store,
|
|
69
|
-
api_key=api_key,
|
|
70
66
|
)
|
|
71
|
-
return _cache[
|
|
67
|
+
return _cache[name]
|
|
72
68
|
else:
|
|
73
69
|
raise ValueError(f"Unknown AIXBT skill: {name}")
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
import os
|
|
3
2
|
from typing import Any, Dict, Optional, Type
|
|
4
3
|
|
|
5
4
|
import httpx
|
|
6
|
-
from langchain_core.
|
|
5
|
+
from langchain_core.tools import ToolException
|
|
7
6
|
from pydantic import BaseModel, Field
|
|
8
7
|
|
|
9
8
|
from intentkit.skills.aixbt.base import AIXBTBaseTool
|
|
@@ -55,11 +54,9 @@ class AIXBTProjects(AIXBTBaseTool):
|
|
|
55
54
|
"for accessing AIXBT's specific dataset for crypto research."
|
|
56
55
|
)
|
|
57
56
|
args_schema: Type[BaseModel] = ProjectsInput
|
|
58
|
-
api_key: str = ""
|
|
59
57
|
|
|
60
58
|
async def _arun(
|
|
61
59
|
self,
|
|
62
|
-
config: RunnableConfig,
|
|
63
60
|
limit: int = 10,
|
|
64
61
|
name: Optional[str] = None,
|
|
65
62
|
ticker: Optional[str] = None,
|
|
@@ -83,34 +80,27 @@ class AIXBTProjects(AIXBTBaseTool):
|
|
|
83
80
|
JSON response with project data
|
|
84
81
|
"""
|
|
85
82
|
# Get context from the config
|
|
86
|
-
context = self.
|
|
83
|
+
context = self.get_context()
|
|
84
|
+
skill_config = context.agent.skill_config(self.category)
|
|
87
85
|
logger.debug(f"aixbt_projects.py: Running search with context {context}")
|
|
88
86
|
|
|
89
87
|
# Check for rate limiting if configured
|
|
90
|
-
if
|
|
88
|
+
if skill_config.get("rate_limit_number") and skill_config.get(
|
|
91
89
|
"rate_limit_minutes"
|
|
92
90
|
):
|
|
93
91
|
await self.user_rate_limit_by_category(
|
|
94
92
|
context.user_id,
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
skill_config["rate_limit_number"],
|
|
94
|
+
skill_config["rate_limit_minutes"],
|
|
97
95
|
)
|
|
98
96
|
|
|
99
97
|
# Get the API key from the agent's configuration
|
|
100
|
-
api_key =
|
|
98
|
+
api_key = skill_config.get("api_key")
|
|
101
99
|
|
|
102
|
-
# If not available in config, try the instance attribute (for backward compatibility)
|
|
103
100
|
if not api_key:
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if not api_key:
|
|
108
|
-
api_key = os.environ.get("AIXBT_API_KEY")
|
|
109
|
-
|
|
110
|
-
if not api_key:
|
|
111
|
-
return {
|
|
112
|
-
"error": "AIXBT API key is not available. Please provide it in the agent configuration."
|
|
113
|
-
}
|
|
101
|
+
raise ToolException(
|
|
102
|
+
"AIXBT API key is not available. Please provide it in the agent configuration."
|
|
103
|
+
)
|
|
114
104
|
|
|
115
105
|
base_url = "https://api.aixbt.tech/v1/projects"
|
|
116
106
|
|
|
@@ -134,20 +124,6 @@ class AIXBTProjects(AIXBTBaseTool):
|
|
|
134
124
|
response = await client.get(base_url, params=params, headers=headers)
|
|
135
125
|
response.raise_for_status()
|
|
136
126
|
return response.json()
|
|
137
|
-
except httpx.HTTPStatusError as e:
|
|
138
|
-
logger.error(
|
|
139
|
-
f"aixbt_projects.py: HTTP error occurred: {e.response.status_code} - {e.response.text}"
|
|
140
|
-
)
|
|
141
|
-
return {
|
|
142
|
-
"error": f"HTTP error occurred: {e.response.status_code}",
|
|
143
|
-
"details": e.response.text,
|
|
144
|
-
}
|
|
145
|
-
except httpx.RequestError as e:
|
|
146
|
-
logger.error(f"aixbt_projects.py: Request error occurred: {str(e)}")
|
|
147
|
-
return {"error": f"Request error occurred: {str(e)}"}
|
|
148
127
|
except Exception as e:
|
|
149
|
-
logger.error(
|
|
150
|
-
|
|
151
|
-
exc_info=True,
|
|
152
|
-
)
|
|
153
|
-
return {"error": f"An unexpected error occurred: {str(e)}"}
|
|
128
|
+
logger.error(f"Error getting projects: {str(e)}")
|
|
129
|
+
raise type(e)(f"[agent:{context.agent_id}]: {e}") from e
|
intentkit/skills/allora/base.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Type
|
|
2
2
|
|
|
3
|
+
from langchain.tools.base import ToolException
|
|
3
4
|
from pydantic import BaseModel, Field
|
|
4
5
|
|
|
5
6
|
from intentkit.abstracts.skill import SkillStoreABC
|
|
6
|
-
from intentkit.skills.base import IntentKitSkill
|
|
7
|
+
from intentkit.skills.base import IntentKitSkill
|
|
7
8
|
|
|
8
9
|
base_url = "https://api.upshot.xyz/v2/allora"
|
|
9
10
|
|
|
@@ -18,10 +19,19 @@ class AlloraBaseTool(IntentKitSkill):
|
|
|
18
19
|
description="The skill store for persisting data"
|
|
19
20
|
)
|
|
20
21
|
|
|
21
|
-
def get_api_key(self
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
def get_api_key(self) -> str:
|
|
23
|
+
context = self.get_context()
|
|
24
|
+
skill_config = context.agent.skill_config(self.category)
|
|
25
|
+
api_key_provider = skill_config.get("api_key_provider")
|
|
26
|
+
if api_key_provider == "platform":
|
|
27
|
+
return self.skill_store.get_system_config("allora_api_key")
|
|
28
|
+
# for backward compatibility, may only have api_key in skill_config
|
|
29
|
+
elif skill_config.get("api_key"):
|
|
30
|
+
return skill_config.get("api_key")
|
|
31
|
+
else:
|
|
32
|
+
raise ToolException(
|
|
33
|
+
f"Invalid API key provider: {api_key_provider}, or no api_key in config"
|
|
34
|
+
)
|
|
25
35
|
|
|
26
36
|
@property
|
|
27
37
|
def category(self) -> str:
|
intentkit/skills/allora/price.py
CHANGED
|
@@ -2,7 +2,6 @@ from typing import Literal, Type
|
|
|
2
2
|
|
|
3
3
|
import httpx
|
|
4
4
|
from langchain.tools.base import ToolException
|
|
5
|
-
from langchain_core.runnables import RunnableConfig
|
|
6
5
|
from pydantic import BaseModel, Field
|
|
7
6
|
|
|
8
7
|
from intentkit.skills.allora.base import AlloraBaseTool
|
|
@@ -84,7 +83,7 @@ class AlloraGetPrice(AlloraBaseTool):
|
|
|
84
83
|
raise NotImplementedError("Use _arun instead")
|
|
85
84
|
|
|
86
85
|
async def _arun(
|
|
87
|
-
self, token: str, time_frame: str,
|
|
86
|
+
self, token: str, time_frame: str, **kwargs
|
|
88
87
|
) -> AlloraGetPriceOutput:
|
|
89
88
|
"""Run the tool to get the token price prediction from Allora API.
|
|
90
89
|
Args:
|
|
@@ -98,8 +97,7 @@ class AlloraGetPrice(AlloraBaseTool):
|
|
|
98
97
|
Raises:
|
|
99
98
|
Exception: If there's an error accessing the Allora API.
|
|
100
99
|
"""
|
|
101
|
-
|
|
102
|
-
api_key = self.get_api_key(context)
|
|
100
|
+
api_key = self.get_api_key()
|
|
103
101
|
if not api_key:
|
|
104
102
|
raise ValueError("Allora API key not found")
|
|
105
103
|
|
intentkit/skills/base.py
CHANGED
|
@@ -5,6 +5,7 @@ from typing import Any, Callable, Dict, Literal, NotRequired, Optional, TypedDic
|
|
|
5
5
|
from langchain_core.runnables import RunnableConfig
|
|
6
6
|
from langchain_core.tools import BaseTool
|
|
7
7
|
from langchain_core.tools.base import ToolException
|
|
8
|
+
from langgraph.runtime import get_runtime
|
|
8
9
|
from pydantic import (
|
|
9
10
|
BaseModel,
|
|
10
11
|
ValidationError,
|
|
@@ -13,12 +14,14 @@ from pydantic.v1 import ValidationError as ValidationErrorV1
|
|
|
13
14
|
from redis.exceptions import RedisError
|
|
14
15
|
|
|
15
16
|
from intentkit.abstracts.exception import RateLimitExceeded
|
|
17
|
+
from intentkit.abstracts.graph import AgentContext
|
|
16
18
|
from intentkit.abstracts.skill import SkillStoreABC
|
|
17
19
|
from intentkit.models.agent import Agent
|
|
18
20
|
from intentkit.models.redis import get_redis
|
|
19
21
|
|
|
20
22
|
SkillState = Literal["disabled", "public", "private"]
|
|
21
23
|
SkillOwnerState = Literal["disabled", "private"]
|
|
24
|
+
APIKeyProviderValue = Literal["platform", "agent_owner"]
|
|
22
25
|
|
|
23
26
|
|
|
24
27
|
class SkillConfig(TypedDict):
|
|
@@ -26,7 +29,7 @@ class SkillConfig(TypedDict):
|
|
|
26
29
|
|
|
27
30
|
enabled: bool
|
|
28
31
|
states: Dict[str, SkillState | SkillOwnerState]
|
|
29
|
-
api_key_provider: NotRequired[
|
|
32
|
+
api_key_provider: NotRequired[APIKeyProviderValue]
|
|
30
33
|
__extra__: NotRequired[Dict[str, Any]]
|
|
31
34
|
|
|
32
35
|
|
|
@@ -192,3 +195,7 @@ class IntentKitSkill(BaseTool):
|
|
|
192
195
|
entrypoint=configurable.get("entrypoint"),
|
|
193
196
|
is_private=configurable.get("is_private"),
|
|
194
197
|
)
|
|
198
|
+
|
|
199
|
+
def get_context(self) -> AgentContext:
|
|
200
|
+
runtime = get_runtime(AgentContext)
|
|
201
|
+
return runtime.context
|
intentkit/skills/carv/base.py
CHANGED
|
@@ -2,10 +2,11 @@ import logging
|
|
|
2
2
|
from typing import Any, Dict, Optional, Tuple, Type
|
|
3
3
|
|
|
4
4
|
import httpx # Ensure httpx is installed: pip install httpx
|
|
5
|
+
from langchain.tools.base import ToolException
|
|
5
6
|
from pydantic import BaseModel, Field
|
|
6
7
|
|
|
7
8
|
from intentkit.abstracts.skill import SkillStoreABC
|
|
8
|
-
from intentkit.skills.base import IntentKitSkill
|
|
9
|
+
from intentkit.skills.base import IntentKitSkill
|
|
9
10
|
|
|
10
11
|
logger = logging.getLogger(__name__)
|
|
11
12
|
|
|
@@ -24,7 +25,7 @@ class CarvBaseTool(IntentKitSkill):
|
|
|
24
25
|
def category(self) -> str:
|
|
25
26
|
return "carv"
|
|
26
27
|
|
|
27
|
-
def get_api_key(self
|
|
28
|
+
def get_api_key(self) -> str:
|
|
28
29
|
"""
|
|
29
30
|
Retrieves the CARV API key based on the api_key_provider setting.
|
|
30
31
|
|
|
@@ -35,10 +36,11 @@ class CarvBaseTool(IntentKitSkill):
|
|
|
35
36
|
ToolException: If the API key is not found or provider is invalid.
|
|
36
37
|
"""
|
|
37
38
|
try:
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
context = self.get_context()
|
|
40
|
+
skill_config = context.agent.skill_config(self.category)
|
|
41
|
+
api_key_provider = skill_config.get("api_key_provider")
|
|
40
42
|
if api_key_provider == "agent_owner":
|
|
41
|
-
agent_api_key: Optional[str] =
|
|
43
|
+
agent_api_key: Optional[str] = skill_config.get("api_key")
|
|
42
44
|
if agent_api_key:
|
|
43
45
|
logger.debug(
|
|
44
46
|
f"Using agent-specific CARV API key for skill {self.name} in category {self.category}"
|
|
@@ -70,15 +72,15 @@ class CarvBaseTool(IntentKitSkill):
|
|
|
70
72
|
raise
|
|
71
73
|
raise ToolException(f"Failed to retrieve CARV API key: {str(e)}") from e
|
|
72
74
|
|
|
73
|
-
async def apply_rate_limit(self, context
|
|
75
|
+
async def apply_rate_limit(self, context) -> None:
|
|
74
76
|
"""
|
|
75
77
|
Applies rate limiting ONLY if specified in the agent's config ('skill_config').
|
|
76
78
|
Checks for 'rate_limit_number' and 'rate_limit_minutes'.
|
|
77
79
|
If not configured, NO rate limiting is applied.
|
|
78
80
|
Raises ConnectionAbortedError if the configured limit is exceeded.
|
|
79
81
|
"""
|
|
80
|
-
skill_config = context.
|
|
81
|
-
user_id = context.
|
|
82
|
+
skill_config = context.agent.skill_config(self.category)
|
|
83
|
+
user_id = context.agent.id
|
|
82
84
|
|
|
83
85
|
limit_num = skill_config.get("rate_limit_number")
|
|
84
86
|
limit_min = skill_config.get("rate_limit_minutes")
|
|
@@ -98,7 +100,7 @@ class CarvBaseTool(IntentKitSkill):
|
|
|
98
100
|
|
|
99
101
|
async def _call_carv_api(
|
|
100
102
|
self,
|
|
101
|
-
context
|
|
103
|
+
context,
|
|
102
104
|
endpoint: str,
|
|
103
105
|
method: str = "GET",
|
|
104
106
|
params: Optional[Dict[str, Any]] = None,
|
|
@@ -122,7 +124,7 @@ class CarvBaseTool(IntentKitSkill):
|
|
|
122
124
|
url = f"{CARV_API_BASE_URL}{endpoint}"
|
|
123
125
|
|
|
124
126
|
try:
|
|
125
|
-
api_key = self.get_api_key(
|
|
127
|
+
api_key = self.get_api_key()
|
|
126
128
|
|
|
127
129
|
headers = {
|
|
128
130
|
"Authorization": api_key,
|
|
@@ -1,92 +1,90 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from typing import Any, Dict, Type
|
|
3
|
-
|
|
4
|
-
from
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
""
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
await self.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
#
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
|
|
91
|
-
"details": str(e),
|
|
92
|
-
}
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any, Dict, Type
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
from intentkit.skills.carv.base import CarvBaseTool
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CarvNewsInput(BaseModel):
|
|
12
|
+
"""
|
|
13
|
+
Input schema for CARV News API.
|
|
14
|
+
This API endpoint does not require any specific parameters from the user.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class FetchNewsTool(CarvBaseTool):
|
|
21
|
+
"""
|
|
22
|
+
Tool for fetching the latest news articles from the CARV API.
|
|
23
|
+
This tool retrieves a list of recent news items, each including a title, URL, and a short description (card_text).
|
|
24
|
+
It's useful for getting up-to-date information on various topics covered by CARV's news aggregation.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
name: str = "carv_fetch_news"
|
|
28
|
+
description: str = (
|
|
29
|
+
"Fetches the latest news articles from the CARV API. "
|
|
30
|
+
"Returns a list of news items, each with a title, URL, and a short summary (card_text)."
|
|
31
|
+
)
|
|
32
|
+
args_schema: Type[BaseModel] = CarvNewsInput
|
|
33
|
+
|
|
34
|
+
async def _arun(
|
|
35
|
+
self, # type: ignore
|
|
36
|
+
**kwargs: Any,
|
|
37
|
+
) -> Dict[str, Any]:
|
|
38
|
+
"""
|
|
39
|
+
Fetches news from the CARV API and returns the response.
|
|
40
|
+
The expected successful response structure is a dictionary containing an "infos" key,
|
|
41
|
+
which holds a list of news articles.
|
|
42
|
+
Example: {"infos": [{"title": "...", "url": "...", "card_text": "..."}, ...]}
|
|
43
|
+
"""
|
|
44
|
+
context = self.get_context()
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
await self.apply_rate_limit(context)
|
|
48
|
+
|
|
49
|
+
result, error = await self._call_carv_api(
|
|
50
|
+
context=context,
|
|
51
|
+
endpoint="/ai-agent-backend/news",
|
|
52
|
+
method="GET",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
if error is not None or result is None:
|
|
56
|
+
logger.error(f"Error returned from CARV API (News): {error}")
|
|
57
|
+
return {
|
|
58
|
+
"error": True,
|
|
59
|
+
"error_type": "APIError",
|
|
60
|
+
"message": "Failed to fetch news from CARV API.",
|
|
61
|
+
"details": error, # error is the detailed error dict from _call_carv_api
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# _call_carv_api returns response_json.get("data", response_json) on success.
|
|
65
|
+
# For this endpoint, the "data" field should be {"infos": [...]}.
|
|
66
|
+
# So, 'result' should be {"infos": [...]}.
|
|
67
|
+
if "infos" not in result or not isinstance(result.get("infos"), list):
|
|
68
|
+
logger.warning(
|
|
69
|
+
f"CARV API (News) response did not contain 'infos' list as expected: {result}"
|
|
70
|
+
)
|
|
71
|
+
return {
|
|
72
|
+
"error": True,
|
|
73
|
+
"error_type": "UnexpectedResponseFormat",
|
|
74
|
+
"message": "News data from CARV API is missing the 'infos' list or has incorrect format.",
|
|
75
|
+
"details": result,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# Successfully fetched and validated news data
|
|
79
|
+
return result # This will be {"infos": [...]}
|
|
80
|
+
|
|
81
|
+
except Exception as e:
|
|
82
|
+
logger.error(
|
|
83
|
+
f"An unexpected error occurred while fetching news: {e}", exc_info=True
|
|
84
|
+
)
|
|
85
|
+
return {
|
|
86
|
+
"error": True,
|
|
87
|
+
"error_type": type(e).__name__,
|
|
88
|
+
"message": "An unexpected error occurred while processing the news request.",
|
|
89
|
+
"details": str(e),
|
|
90
|
+
}
|