intentkit 0.5.0__py3-none-any.whl → 0.5.2__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 +17 -0
- intentkit/abstracts/__init__.py +0 -0
- intentkit/abstracts/agent.py +60 -0
- intentkit/abstracts/api.py +4 -0
- intentkit/abstracts/engine.py +38 -0
- intentkit/abstracts/exception.py +9 -0
- intentkit/abstracts/graph.py +25 -0
- intentkit/abstracts/skill.py +129 -0
- intentkit/abstracts/twitter.py +54 -0
- intentkit/clients/__init__.py +14 -0
- intentkit/clients/cdp.py +53 -0
- intentkit/clients/twitter.py +445 -0
- intentkit/config/__init__.py +0 -0
- intentkit/config/config.py +164 -0
- intentkit/core/__init__.py +0 -0
- intentkit/core/agent.py +191 -0
- intentkit/core/api.py +40 -0
- intentkit/core/client.py +45 -0
- intentkit/core/credit.py +1767 -0
- intentkit/core/engine.py +1018 -0
- intentkit/core/node.py +223 -0
- intentkit/core/prompt.py +58 -0
- intentkit/core/skill.py +124 -0
- intentkit/models/agent.py +1689 -0
- intentkit/models/agent_data.py +810 -0
- intentkit/models/agent_schema.json +733 -0
- intentkit/models/app_setting.py +156 -0
- intentkit/models/base.py +9 -0
- intentkit/models/chat.py +581 -0
- intentkit/models/conversation.py +286 -0
- intentkit/models/credit.py +1406 -0
- intentkit/models/db.py +120 -0
- intentkit/models/db_mig.py +102 -0
- intentkit/models/generator.py +347 -0
- intentkit/models/llm.py +746 -0
- intentkit/models/redis.py +132 -0
- intentkit/models/skill.py +466 -0
- intentkit/models/user.py +243 -0
- intentkit/skills/__init__.py +12 -0
- intentkit/skills/acolyt/__init__.py +83 -0
- intentkit/skills/acolyt/acolyt.jpg +0 -0
- intentkit/skills/acolyt/ask.py +128 -0
- intentkit/skills/acolyt/base.py +28 -0
- intentkit/skills/acolyt/schema.json +89 -0
- intentkit/skills/aixbt/README.md +71 -0
- intentkit/skills/aixbt/__init__.py +73 -0
- intentkit/skills/aixbt/aixbt.jpg +0 -0
- intentkit/skills/aixbt/base.py +21 -0
- intentkit/skills/aixbt/projects.py +153 -0
- intentkit/skills/aixbt/schema.json +99 -0
- intentkit/skills/allora/__init__.py +83 -0
- intentkit/skills/allora/allora.jpeg +0 -0
- intentkit/skills/allora/base.py +28 -0
- intentkit/skills/allora/price.py +130 -0
- intentkit/skills/allora/schema.json +89 -0
- intentkit/skills/base.py +174 -0
- intentkit/skills/carv/README.md +95 -0
- intentkit/skills/carv/__init__.py +121 -0
- intentkit/skills/carv/base.py +183 -0
- intentkit/skills/carv/carv.webp +0 -0
- intentkit/skills/carv/fetch_news.py +92 -0
- intentkit/skills/carv/onchain_query.py +164 -0
- intentkit/skills/carv/schema.json +137 -0
- intentkit/skills/carv/token_info_and_price.py +110 -0
- intentkit/skills/cdp/__init__.py +137 -0
- intentkit/skills/cdp/base.py +21 -0
- intentkit/skills/cdp/cdp.png +0 -0
- intentkit/skills/cdp/get_balance.py +81 -0
- intentkit/skills/cdp/schema.json +473 -0
- intentkit/skills/chainlist/README.md +38 -0
- intentkit/skills/chainlist/__init__.py +54 -0
- intentkit/skills/chainlist/base.py +21 -0
- intentkit/skills/chainlist/chain_lookup.py +208 -0
- intentkit/skills/chainlist/chainlist.png +0 -0
- intentkit/skills/chainlist/schema.json +47 -0
- intentkit/skills/common/__init__.py +82 -0
- intentkit/skills/common/base.py +21 -0
- intentkit/skills/common/common.jpg +0 -0
- intentkit/skills/common/current_time.py +84 -0
- intentkit/skills/common/schema.json +57 -0
- intentkit/skills/cookiefun/README.md +121 -0
- intentkit/skills/cookiefun/__init__.py +78 -0
- intentkit/skills/cookiefun/base.py +41 -0
- intentkit/skills/cookiefun/constants.py +18 -0
- intentkit/skills/cookiefun/cookiefun.png +0 -0
- intentkit/skills/cookiefun/get_account_details.py +171 -0
- intentkit/skills/cookiefun/get_account_feed.py +282 -0
- intentkit/skills/cookiefun/get_account_smart_followers.py +181 -0
- intentkit/skills/cookiefun/get_sectors.py +128 -0
- intentkit/skills/cookiefun/schema.json +155 -0
- intentkit/skills/cookiefun/search_accounts.py +225 -0
- intentkit/skills/cryptocompare/__init__.py +130 -0
- intentkit/skills/cryptocompare/api.py +159 -0
- intentkit/skills/cryptocompare/base.py +303 -0
- intentkit/skills/cryptocompare/cryptocompare.png +0 -0
- intentkit/skills/cryptocompare/fetch_news.py +96 -0
- intentkit/skills/cryptocompare/fetch_price.py +99 -0
- intentkit/skills/cryptocompare/fetch_top_exchanges.py +113 -0
- intentkit/skills/cryptocompare/fetch_top_market_cap.py +109 -0
- intentkit/skills/cryptocompare/fetch_top_volume.py +108 -0
- intentkit/skills/cryptocompare/fetch_trading_signals.py +107 -0
- intentkit/skills/cryptocompare/schema.json +168 -0
- intentkit/skills/cryptopanic/__init__.py +108 -0
- intentkit/skills/cryptopanic/base.py +51 -0
- intentkit/skills/cryptopanic/cryptopanic.png +0 -0
- intentkit/skills/cryptopanic/fetch_crypto_news.py +153 -0
- intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +136 -0
- intentkit/skills/cryptopanic/schema.json +103 -0
- intentkit/skills/dapplooker/README.md +92 -0
- intentkit/skills/dapplooker/__init__.py +83 -0
- intentkit/skills/dapplooker/base.py +26 -0
- intentkit/skills/dapplooker/dapplooker.jpg +0 -0
- intentkit/skills/dapplooker/dapplooker_token_data.py +476 -0
- intentkit/skills/dapplooker/schema.json +91 -0
- intentkit/skills/defillama/__init__.py +323 -0
- intentkit/skills/defillama/api.py +315 -0
- intentkit/skills/defillama/base.py +135 -0
- intentkit/skills/defillama/coins/__init__.py +0 -0
- intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +116 -0
- intentkit/skills/defillama/coins/fetch_block.py +98 -0
- intentkit/skills/defillama/coins/fetch_current_prices.py +105 -0
- intentkit/skills/defillama/coins/fetch_first_price.py +100 -0
- intentkit/skills/defillama/coins/fetch_historical_prices.py +110 -0
- intentkit/skills/defillama/coins/fetch_price_chart.py +109 -0
- intentkit/skills/defillama/coins/fetch_price_percentage.py +93 -0
- intentkit/skills/defillama/config/__init__.py +0 -0
- intentkit/skills/defillama/config/chains.py +433 -0
- intentkit/skills/defillama/defillama.jpeg +0 -0
- intentkit/skills/defillama/fees/__init__.py +0 -0
- intentkit/skills/defillama/fees/fetch_fees_overview.py +130 -0
- intentkit/skills/defillama/schema.json +383 -0
- intentkit/skills/defillama/stablecoins/__init__.py +0 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +100 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +129 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +83 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +126 -0
- intentkit/skills/defillama/tests/__init__.py +0 -0
- intentkit/skills/defillama/tests/api_integration.test.py +192 -0
- intentkit/skills/defillama/tests/api_unit.test.py +583 -0
- intentkit/skills/defillama/tvl/__init__.py +0 -0
- intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +106 -0
- intentkit/skills/defillama/tvl/fetch_chains.py +107 -0
- intentkit/skills/defillama/tvl/fetch_historical_tvl.py +91 -0
- intentkit/skills/defillama/tvl/fetch_protocol.py +207 -0
- intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +93 -0
- intentkit/skills/defillama/tvl/fetch_protocols.py +196 -0
- intentkit/skills/defillama/volumes/__init__.py +0 -0
- intentkit/skills/defillama/volumes/fetch_dex_overview.py +157 -0
- intentkit/skills/defillama/volumes/fetch_dex_summary.py +123 -0
- intentkit/skills/defillama/volumes/fetch_options_overview.py +131 -0
- intentkit/skills/defillama/yields/__init__.py +0 -0
- intentkit/skills/defillama/yields/fetch_pool_chart.py +100 -0
- intentkit/skills/defillama/yields/fetch_pools.py +126 -0
- intentkit/skills/dexscreener/__init__.py +93 -0
- intentkit/skills/dexscreener/base.py +133 -0
- intentkit/skills/dexscreener/dexscreener.png +0 -0
- intentkit/skills/dexscreener/model/__init__.py +0 -0
- intentkit/skills/dexscreener/model/search_token_response.py +82 -0
- intentkit/skills/dexscreener/schema.json +48 -0
- intentkit/skills/dexscreener/search_token.py +321 -0
- intentkit/skills/dune_analytics/__init__.py +103 -0
- intentkit/skills/dune_analytics/base.py +46 -0
- intentkit/skills/dune_analytics/dune.png +0 -0
- intentkit/skills/dune_analytics/fetch_kol_buys.py +128 -0
- intentkit/skills/dune_analytics/fetch_nation_metrics.py +237 -0
- intentkit/skills/dune_analytics/schema.json +99 -0
- intentkit/skills/elfa/README.md +100 -0
- intentkit/skills/elfa/__init__.py +123 -0
- intentkit/skills/elfa/base.py +28 -0
- intentkit/skills/elfa/elfa.jpg +0 -0
- intentkit/skills/elfa/mention.py +504 -0
- intentkit/skills/elfa/schema.json +153 -0
- intentkit/skills/elfa/stats.py +118 -0
- intentkit/skills/elfa/tokens.py +126 -0
- intentkit/skills/enso/README.md +75 -0
- intentkit/skills/enso/__init__.py +114 -0
- intentkit/skills/enso/abi/__init__.py +0 -0
- intentkit/skills/enso/abi/approval.py +279 -0
- intentkit/skills/enso/abi/erc20.py +14 -0
- intentkit/skills/enso/abi/route.py +129 -0
- intentkit/skills/enso/base.py +44 -0
- intentkit/skills/enso/best_yield.py +286 -0
- intentkit/skills/enso/enso.jpg +0 -0
- intentkit/skills/enso/networks.py +105 -0
- intentkit/skills/enso/prices.py +93 -0
- intentkit/skills/enso/route.py +300 -0
- intentkit/skills/enso/schema.json +212 -0
- intentkit/skills/enso/tokens.py +223 -0
- intentkit/skills/enso/wallet.py +381 -0
- intentkit/skills/github/README.md +63 -0
- intentkit/skills/github/__init__.py +54 -0
- intentkit/skills/github/base.py +21 -0
- intentkit/skills/github/github.jpg +0 -0
- intentkit/skills/github/github_search.py +183 -0
- intentkit/skills/github/schema.json +59 -0
- intentkit/skills/heurist/__init__.py +143 -0
- intentkit/skills/heurist/base.py +26 -0
- intentkit/skills/heurist/heurist.png +0 -0
- intentkit/skills/heurist/image_generation_animagine_xl.py +162 -0
- intentkit/skills/heurist/image_generation_arthemy_comics.py +162 -0
- intentkit/skills/heurist/image_generation_arthemy_real.py +162 -0
- intentkit/skills/heurist/image_generation_braindance.py +162 -0
- intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +162 -0
- intentkit/skills/heurist/image_generation_flux_1_dev.py +162 -0
- intentkit/skills/heurist/image_generation_sdxl.py +161 -0
- intentkit/skills/heurist/schema.json +196 -0
- intentkit/skills/lifi/README.md +294 -0
- intentkit/skills/lifi/__init__.py +141 -0
- intentkit/skills/lifi/base.py +21 -0
- intentkit/skills/lifi/lifi.png +0 -0
- intentkit/skills/lifi/schema.json +89 -0
- intentkit/skills/lifi/token_execute.py +472 -0
- intentkit/skills/lifi/token_quote.py +190 -0
- intentkit/skills/lifi/utils.py +656 -0
- intentkit/skills/moralis/README.md +490 -0
- intentkit/skills/moralis/__init__.py +110 -0
- intentkit/skills/moralis/api.py +281 -0
- intentkit/skills/moralis/base.py +55 -0
- intentkit/skills/moralis/fetch_chain_portfolio.py +191 -0
- intentkit/skills/moralis/fetch_nft_portfolio.py +284 -0
- intentkit/skills/moralis/fetch_solana_portfolio.py +331 -0
- intentkit/skills/moralis/fetch_wallet_portfolio.py +301 -0
- intentkit/skills/moralis/moralis.png +0 -0
- intentkit/skills/moralis/schema.json +156 -0
- intentkit/skills/moralis/tests/__init__.py +0 -0
- intentkit/skills/moralis/tests/test_wallet.py +511 -0
- intentkit/skills/nation/__init__.py +62 -0
- intentkit/skills/nation/base.py +31 -0
- intentkit/skills/nation/nation.png +0 -0
- intentkit/skills/nation/nft_check.py +106 -0
- intentkit/skills/nation/schema.json +58 -0
- intentkit/skills/openai/__init__.py +107 -0
- intentkit/skills/openai/base.py +32 -0
- intentkit/skills/openai/dalle_image_generation.py +128 -0
- intentkit/skills/openai/gpt_image_generation.py +152 -0
- intentkit/skills/openai/gpt_image_to_image.py +186 -0
- intentkit/skills/openai/image_to_text.py +126 -0
- intentkit/skills/openai/openai.png +0 -0
- intentkit/skills/openai/schema.json +139 -0
- intentkit/skills/portfolio/README.md +55 -0
- intentkit/skills/portfolio/__init__.py +151 -0
- intentkit/skills/portfolio/base.py +107 -0
- intentkit/skills/portfolio/constants.py +9 -0
- intentkit/skills/portfolio/moralis.png +0 -0
- intentkit/skills/portfolio/schema.json +237 -0
- intentkit/skills/portfolio/token_balances.py +155 -0
- intentkit/skills/portfolio/wallet_approvals.py +102 -0
- intentkit/skills/portfolio/wallet_defi_positions.py +80 -0
- intentkit/skills/portfolio/wallet_history.py +155 -0
- intentkit/skills/portfolio/wallet_net_worth.py +112 -0
- intentkit/skills/portfolio/wallet_nfts.py +139 -0
- intentkit/skills/portfolio/wallet_profitability.py +101 -0
- intentkit/skills/portfolio/wallet_profitability_summary.py +91 -0
- intentkit/skills/portfolio/wallet_stats.py +79 -0
- intentkit/skills/portfolio/wallet_swaps.py +147 -0
- intentkit/skills/skills.toml +103 -0
- intentkit/skills/slack/__init__.py +98 -0
- intentkit/skills/slack/base.py +55 -0
- intentkit/skills/slack/get_channel.py +109 -0
- intentkit/skills/slack/get_message.py +136 -0
- intentkit/skills/slack/schedule_message.py +92 -0
- intentkit/skills/slack/schema.json +135 -0
- intentkit/skills/slack/send_message.py +81 -0
- intentkit/skills/slack/slack.jpg +0 -0
- intentkit/skills/system/__init__.py +90 -0
- intentkit/skills/system/base.py +22 -0
- intentkit/skills/system/read_agent_api_key.py +87 -0
- intentkit/skills/system/regenerate_agent_api_key.py +77 -0
- intentkit/skills/system/schema.json +53 -0
- intentkit/skills/system/system.svg +76 -0
- intentkit/skills/tavily/README.md +86 -0
- intentkit/skills/tavily/__init__.py +91 -0
- intentkit/skills/tavily/base.py +27 -0
- intentkit/skills/tavily/schema.json +119 -0
- intentkit/skills/tavily/tavily.jpg +0 -0
- intentkit/skills/tavily/tavily_extract.py +147 -0
- intentkit/skills/tavily/tavily_search.py +139 -0
- intentkit/skills/token/README.md +89 -0
- intentkit/skills/token/__init__.py +107 -0
- intentkit/skills/token/base.py +154 -0
- intentkit/skills/token/constants.py +9 -0
- intentkit/skills/token/erc20_transfers.py +145 -0
- intentkit/skills/token/moralis.png +0 -0
- intentkit/skills/token/schema.json +141 -0
- intentkit/skills/token/token_analytics.py +81 -0
- intentkit/skills/token/token_price.py +132 -0
- intentkit/skills/token/token_search.py +121 -0
- intentkit/skills/twitter/__init__.py +146 -0
- intentkit/skills/twitter/base.py +68 -0
- intentkit/skills/twitter/follow_user.py +69 -0
- intentkit/skills/twitter/get_mentions.py +124 -0
- intentkit/skills/twitter/get_timeline.py +111 -0
- intentkit/skills/twitter/get_user_by_username.py +84 -0
- intentkit/skills/twitter/get_user_tweets.py +123 -0
- intentkit/skills/twitter/like_tweet.py +65 -0
- intentkit/skills/twitter/post_tweet.py +90 -0
- intentkit/skills/twitter/reply_tweet.py +98 -0
- intentkit/skills/twitter/retweet.py +76 -0
- intentkit/skills/twitter/schema.json +258 -0
- intentkit/skills/twitter/search_tweets.py +115 -0
- intentkit/skills/twitter/twitter.png +0 -0
- intentkit/skills/unrealspeech/__init__.py +55 -0
- intentkit/skills/unrealspeech/base.py +21 -0
- intentkit/skills/unrealspeech/schema.json +100 -0
- intentkit/skills/unrealspeech/text_to_speech.py +177 -0
- intentkit/skills/unrealspeech/unrealspeech.jpg +0 -0
- intentkit/skills/venice_audio/__init__.py +106 -0
- intentkit/skills/venice_audio/base.py +119 -0
- intentkit/skills/venice_audio/input.py +41 -0
- intentkit/skills/venice_audio/schema.json +152 -0
- intentkit/skills/venice_audio/venice_audio.py +240 -0
- intentkit/skills/venice_audio/venice_logo.jpg +0 -0
- intentkit/skills/venice_image/README.md +119 -0
- intentkit/skills/venice_image/__init__.py +154 -0
- intentkit/skills/venice_image/api.py +138 -0
- intentkit/skills/venice_image/base.py +188 -0
- intentkit/skills/venice_image/config.py +35 -0
- intentkit/skills/venice_image/image_enhance/README.md +119 -0
- intentkit/skills/venice_image/image_enhance/__init__.py +0 -0
- intentkit/skills/venice_image/image_enhance/image_enhance.py +80 -0
- intentkit/skills/venice_image/image_enhance/image_enhance_base.py +23 -0
- intentkit/skills/venice_image/image_enhance/image_enhance_input.py +40 -0
- intentkit/skills/venice_image/image_generation/README.md +144 -0
- intentkit/skills/venice_image/image_generation/__init__.py +0 -0
- intentkit/skills/venice_image/image_generation/image_generation_base.py +117 -0
- intentkit/skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_flux_dev.py +27 -0
- intentkit/skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_input.py +158 -0
- intentkit/skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_pony_realism.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -0
- intentkit/skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -0
- intentkit/skills/venice_image/image_upscale/README.md +111 -0
- intentkit/skills/venice_image/image_upscale/__init__.py +0 -0
- intentkit/skills/venice_image/image_upscale/image_upscale.py +90 -0
- intentkit/skills/venice_image/image_upscale/image_upscale_base.py +23 -0
- intentkit/skills/venice_image/image_upscale/image_upscale_input.py +22 -0
- intentkit/skills/venice_image/image_vision/README.md +112 -0
- intentkit/skills/venice_image/image_vision/__init__.py +0 -0
- intentkit/skills/venice_image/image_vision/image_vision.py +100 -0
- intentkit/skills/venice_image/image_vision/image_vision_base.py +17 -0
- intentkit/skills/venice_image/image_vision/image_vision_input.py +9 -0
- intentkit/skills/venice_image/schema.json +267 -0
- intentkit/skills/venice_image/utils.py +78 -0
- intentkit/skills/venice_image/venice_image.jpg +0 -0
- intentkit/skills/web_scraper/README.md +82 -0
- intentkit/skills/web_scraper/__init__.py +92 -0
- intentkit/skills/web_scraper/base.py +21 -0
- intentkit/skills/web_scraper/langchain.png +0 -0
- intentkit/skills/web_scraper/schema.json +115 -0
- intentkit/skills/web_scraper/scrape_and_index.py +327 -0
- intentkit/utils/__init__.py +1 -0
- intentkit/utils/chain.py +436 -0
- intentkit/utils/error.py +134 -0
- intentkit/utils/logging.py +70 -0
- intentkit/utils/middleware.py +61 -0
- intentkit/utils/random.py +16 -0
- intentkit/utils/s3.py +267 -0
- intentkit/utils/slack_alert.py +79 -0
- intentkit/utils/tx.py +37 -0
- {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/METADATA +1 -1
- intentkit-0.5.2.dist-info/RECORD +365 -0
- intentkit-0.5.0.dist-info/RECORD +0 -4
- {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/WHEEL +0 -0
- {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from datetime import datetime, timedelta, timezone
|
|
3
|
+
from typing import Type
|
|
4
|
+
|
|
5
|
+
from langchain_core.runnables import RunnableConfig
|
|
6
|
+
from langchain_core.tools import ToolException
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
|
|
9
|
+
from intentkit.clients.twitter import Tweet, get_twitter_client
|
|
10
|
+
|
|
11
|
+
from .base import TwitterBaseTool
|
|
12
|
+
|
|
13
|
+
NAME = "twitter_get_mentions"
|
|
14
|
+
PROMPT = (
|
|
15
|
+
"Get tweets that mention you, the result is a json object containing a list of tweets."
|
|
16
|
+
'If the result is `{"meta": {"result_count": 0}}`, means no new mentions, don\'t retry this tool.'
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TwitterGetMentionsInput(BaseModel):
|
|
23
|
+
"""Input for TwitterGetMentions tool."""
|
|
24
|
+
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TwitterGetMentions(TwitterBaseTool):
|
|
29
|
+
"""Tool for getting mentions from Twitter.
|
|
30
|
+
|
|
31
|
+
This tool uses the Twitter API v2 to retrieve mentions (tweets in which the authenticated
|
|
32
|
+
user is mentioned) from Twitter.
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
name: The name of the tool.
|
|
36
|
+
description: A description of what the tool does.
|
|
37
|
+
args_schema: The schema for the tool's input arguments.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
name: str = NAME
|
|
41
|
+
description: str = PROMPT
|
|
42
|
+
args_schema: Type[BaseModel] = TwitterGetMentionsInput
|
|
43
|
+
|
|
44
|
+
async def _arun(self, config: RunnableConfig, **kwargs) -> list[Tweet]:
|
|
45
|
+
try:
|
|
46
|
+
context = self.context_from_config(config)
|
|
47
|
+
twitter = get_twitter_client(
|
|
48
|
+
agent_id=context.agent.id,
|
|
49
|
+
skill_store=self.skill_store,
|
|
50
|
+
config=context.config,
|
|
51
|
+
)
|
|
52
|
+
client = await twitter.get_client()
|
|
53
|
+
|
|
54
|
+
logger.debug(f"Use Key: {twitter.use_key}")
|
|
55
|
+
|
|
56
|
+
# Check rate limit only when not using OAuth
|
|
57
|
+
if not twitter.use_key:
|
|
58
|
+
await self.check_rate_limit(
|
|
59
|
+
context.agent.id,
|
|
60
|
+
max_requests=1,
|
|
61
|
+
interval=59, # TODO: tmp to 59, back to 240 later
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# get since id from store
|
|
65
|
+
last = await self.skill_store.get_agent_skill_data(
|
|
66
|
+
context.agent.id, self.name, "last"
|
|
67
|
+
)
|
|
68
|
+
last = last or {}
|
|
69
|
+
max_results = 10
|
|
70
|
+
since_id = last.get("since_id")
|
|
71
|
+
if since_id:
|
|
72
|
+
max_results = 30
|
|
73
|
+
|
|
74
|
+
# Always get mentions for the last day
|
|
75
|
+
start_time = datetime.now(tz=timezone.utc) - timedelta(days=1)
|
|
76
|
+
|
|
77
|
+
user_id = twitter.self_id
|
|
78
|
+
if not user_id:
|
|
79
|
+
raise ToolException("Failed to get Twitter user ID.")
|
|
80
|
+
|
|
81
|
+
mentions = await client.get_users_mentions(
|
|
82
|
+
user_auth=twitter.use_key,
|
|
83
|
+
id=user_id,
|
|
84
|
+
max_results=max_results,
|
|
85
|
+
since_id=since_id,
|
|
86
|
+
start_time=start_time,
|
|
87
|
+
expansions=[
|
|
88
|
+
"referenced_tweets.id",
|
|
89
|
+
"referenced_tweets.id.attachments.media_keys",
|
|
90
|
+
"referenced_tweets.id.author_id",
|
|
91
|
+
"attachments.media_keys",
|
|
92
|
+
"author_id",
|
|
93
|
+
],
|
|
94
|
+
tweet_fields=[
|
|
95
|
+
"created_at",
|
|
96
|
+
"author_id",
|
|
97
|
+
"text",
|
|
98
|
+
"referenced_tweets",
|
|
99
|
+
"attachments",
|
|
100
|
+
],
|
|
101
|
+
user_fields=[
|
|
102
|
+
"username",
|
|
103
|
+
"name",
|
|
104
|
+
"profile_image_url",
|
|
105
|
+
"description",
|
|
106
|
+
"public_metrics",
|
|
107
|
+
"location",
|
|
108
|
+
"connection_status",
|
|
109
|
+
],
|
|
110
|
+
media_fields=["url", "type", "width", "height"],
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Update since_id in store
|
|
114
|
+
if mentions.get("meta") and mentions["meta"].get("newest_id"):
|
|
115
|
+
last["since_id"] = mentions["meta"].get("newest_id")
|
|
116
|
+
await self.skill_store.save_agent_skill_data(
|
|
117
|
+
context.agent.id, self.name, "last", last
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
return mentions
|
|
121
|
+
|
|
122
|
+
except Exception as e:
|
|
123
|
+
logger.error(f"[agent:{context.agent.id}]: {e}")
|
|
124
|
+
raise type(e)(f"[agent:{context.agent.id}]: {e}") from e
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Type
|
|
3
|
+
|
|
4
|
+
from langchain_core.runnables import RunnableConfig
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
from intentkit.clients import get_twitter_client
|
|
8
|
+
|
|
9
|
+
from .base import TwitterBaseTool
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
NAME = "twitter_get_timeline"
|
|
14
|
+
PROMPT = (
|
|
15
|
+
"Get tweets from your timeline, the result is a json object containing a list of tweets."
|
|
16
|
+
'If the result is `{"meta": {"result_count": 0}}`, means no new tweets, don\'t retry this tool.'
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TwitterGetTimelineInput(BaseModel):
|
|
21
|
+
"""Input for TwitterGetTimeline tool."""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TwitterGetTimeline(TwitterBaseTool):
|
|
25
|
+
"""Tool for getting the user's timeline from Twitter.
|
|
26
|
+
|
|
27
|
+
This tool uses the Twitter API v2 to retrieve tweets from the authenticated user's
|
|
28
|
+
timeline.
|
|
29
|
+
|
|
30
|
+
Attributes:
|
|
31
|
+
name: The name of the tool.
|
|
32
|
+
description: A description of what the tool does.
|
|
33
|
+
args_schema: The schema for the tool's input arguments.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
name: str = NAME
|
|
37
|
+
description: str = PROMPT
|
|
38
|
+
args_schema: Type[BaseModel] = TwitterGetTimelineInput
|
|
39
|
+
|
|
40
|
+
async def _arun(self, config: RunnableConfig, **kwargs):
|
|
41
|
+
try:
|
|
42
|
+
# Ensure max_results is an integer
|
|
43
|
+
max_results = 10
|
|
44
|
+
|
|
45
|
+
context = self.context_from_config(config)
|
|
46
|
+
twitter = get_twitter_client(
|
|
47
|
+
agent_id=context.agent.id,
|
|
48
|
+
skill_store=self.skill_store,
|
|
49
|
+
config=context.config,
|
|
50
|
+
)
|
|
51
|
+
client = await twitter.get_client()
|
|
52
|
+
|
|
53
|
+
# Check rate limit only when not using OAuth
|
|
54
|
+
if not twitter.use_key:
|
|
55
|
+
await self.check_rate_limit(
|
|
56
|
+
context.agent.id, max_requests=3, interval=60 * 24
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# get since id from store
|
|
60
|
+
last = await self.skill_store.get_agent_skill_data(
|
|
61
|
+
context.agent.id, self.name, "last"
|
|
62
|
+
)
|
|
63
|
+
last = last or {}
|
|
64
|
+
since_id = last.get("since_id")
|
|
65
|
+
|
|
66
|
+
user_id = twitter.self_id
|
|
67
|
+
if not user_id:
|
|
68
|
+
raise ValueError("Failed to get Twitter user ID.")
|
|
69
|
+
|
|
70
|
+
timeline = await client.get_home_timeline(
|
|
71
|
+
user_auth=twitter.use_key,
|
|
72
|
+
max_results=max_results,
|
|
73
|
+
since_id=since_id,
|
|
74
|
+
expansions=[
|
|
75
|
+
"referenced_tweets.id",
|
|
76
|
+
"referenced_tweets.id.attachments.media_keys",
|
|
77
|
+
"referenced_tweets.id.author_id",
|
|
78
|
+
"attachments.media_keys",
|
|
79
|
+
"author_id",
|
|
80
|
+
],
|
|
81
|
+
tweet_fields=[
|
|
82
|
+
"created_at",
|
|
83
|
+
"author_id",
|
|
84
|
+
"text",
|
|
85
|
+
"referenced_tweets",
|
|
86
|
+
"attachments",
|
|
87
|
+
],
|
|
88
|
+
user_fields=[
|
|
89
|
+
"username",
|
|
90
|
+
"name",
|
|
91
|
+
"profile_image_url",
|
|
92
|
+
"description",
|
|
93
|
+
"public_metrics",
|
|
94
|
+
"location",
|
|
95
|
+
"connection_status",
|
|
96
|
+
],
|
|
97
|
+
media_fields=["url", "type", "width", "height"],
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Update the since_id in store for the next request
|
|
101
|
+
if timeline.get("meta") and timeline["meta"].get("newest_id"):
|
|
102
|
+
last["since_id"] = timeline["meta"]["newest_id"]
|
|
103
|
+
await self.skill_store.save_agent_skill_data(
|
|
104
|
+
context.agent.id, self.name, "last", last
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
return timeline
|
|
108
|
+
|
|
109
|
+
except Exception as e:
|
|
110
|
+
logger.error("Error getting timeline: %s", str(e))
|
|
111
|
+
raise type(e)(f"[agent:{context.agent.id}]: {e}") from e
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Type
|
|
3
|
+
|
|
4
|
+
from langchain_core.runnables import RunnableConfig
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
from intentkit.clients import get_twitter_client
|
|
8
|
+
|
|
9
|
+
from .base import TwitterBaseTool
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
NAME = "twitter_get_user_by_username"
|
|
14
|
+
PROMPT = (
|
|
15
|
+
"Get a Twitter user's information by their username."
|
|
16
|
+
"Returns detailed user information as a json object."
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TwitterGetUserByUsernameInput(BaseModel):
|
|
21
|
+
"""Input for TwitterGetUserByUsername tool."""
|
|
22
|
+
|
|
23
|
+
username: str = Field(description="The Twitter username to lookup")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TwitterGetUserByUsername(TwitterBaseTool):
|
|
27
|
+
"""Tool for getting a Twitter user by their username.
|
|
28
|
+
|
|
29
|
+
This tool uses the Twitter API v2 to retrieve user information by username.
|
|
30
|
+
|
|
31
|
+
Attributes:
|
|
32
|
+
name: The name of the tool.
|
|
33
|
+
description: A description of what the tool does.
|
|
34
|
+
args_schema: The schema for the tool's input arguments.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
name: str = NAME
|
|
38
|
+
description: str = PROMPT
|
|
39
|
+
args_schema: Type[BaseModel] = TwitterGetUserByUsernameInput
|
|
40
|
+
|
|
41
|
+
async def _arun(self, username: str, config: RunnableConfig, **kwargs):
|
|
42
|
+
try:
|
|
43
|
+
context = self.context_from_config(config)
|
|
44
|
+
twitter = get_twitter_client(
|
|
45
|
+
agent_id=context.agent.id,
|
|
46
|
+
skill_store=self.skill_store,
|
|
47
|
+
config=context.config,
|
|
48
|
+
)
|
|
49
|
+
client = await twitter.get_client()
|
|
50
|
+
|
|
51
|
+
# Check rate limit only when not using OAuth
|
|
52
|
+
if not twitter.use_key:
|
|
53
|
+
await self.check_rate_limit(
|
|
54
|
+
context.agent.id, max_requests=3, interval=60 * 24
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
user_data = await client.get_user(
|
|
58
|
+
username=username,
|
|
59
|
+
user_auth=twitter.use_key,
|
|
60
|
+
user_fields=[
|
|
61
|
+
"created_at",
|
|
62
|
+
"description",
|
|
63
|
+
"entities",
|
|
64
|
+
"connection_status",
|
|
65
|
+
"id",
|
|
66
|
+
"location",
|
|
67
|
+
"name",
|
|
68
|
+
"pinned_tweet_id",
|
|
69
|
+
"profile_image_url",
|
|
70
|
+
"protected",
|
|
71
|
+
"public_metrics",
|
|
72
|
+
"url",
|
|
73
|
+
"username",
|
|
74
|
+
"verified",
|
|
75
|
+
"verified_type",
|
|
76
|
+
"withheld",
|
|
77
|
+
],
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
return user_data
|
|
81
|
+
|
|
82
|
+
except Exception as e:
|
|
83
|
+
logger.error(f"Error getting user by username: {str(e)}")
|
|
84
|
+
raise type(e)(f"[agent:{context.agent.id}]: {e}") from e
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import List, Optional, Type
|
|
3
|
+
|
|
4
|
+
from langchain_core.runnables import RunnableConfig
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
from intentkit.clients import get_twitter_client
|
|
8
|
+
|
|
9
|
+
from .base import TwitterBaseTool
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
NAME = "twitter_get_user_tweets"
|
|
14
|
+
PROMPT = (
|
|
15
|
+
"Get tweets from a specific Twitter user by their user ID. "
|
|
16
|
+
"The result is a json object containing a list of tweets."
|
|
17
|
+
'If the result is `{"meta": {"result_count": 0}}`, means no tweets found, don\'t retry this tool.'
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TwitterGetUserTweetsInput(BaseModel):
|
|
22
|
+
"""Input for TwitterGetUserTweets tool."""
|
|
23
|
+
|
|
24
|
+
user_id: str = Field(description="The Twitter user ID to fetch tweets from")
|
|
25
|
+
exclude: Optional[List[str]] = Field(
|
|
26
|
+
default=["replies", "retweets"],
|
|
27
|
+
description="Types of tweets to exclude (e.g., 'replies', 'retweets')",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TwitterGetUserTweets(TwitterBaseTool):
|
|
32
|
+
"""Tool for getting tweets from a specific Twitter user.
|
|
33
|
+
|
|
34
|
+
This tool uses the Twitter API v2 to retrieve tweets from a specific user
|
|
35
|
+
by their user ID.
|
|
36
|
+
|
|
37
|
+
Attributes:
|
|
38
|
+
name: The name of the tool.
|
|
39
|
+
description: A description of what the tool does.
|
|
40
|
+
args_schema: The schema for the tool's input arguments.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
name: str = NAME
|
|
44
|
+
description: str = PROMPT
|
|
45
|
+
args_schema: Type[BaseModel] = TwitterGetUserTweetsInput
|
|
46
|
+
|
|
47
|
+
async def _arun(self, config: RunnableConfig, **kwargs):
|
|
48
|
+
try:
|
|
49
|
+
user_id = kwargs.get("user_id")
|
|
50
|
+
if not user_id:
|
|
51
|
+
raise ValueError("User ID is required")
|
|
52
|
+
|
|
53
|
+
# Hardcode max_results to 10
|
|
54
|
+
max_results = 10
|
|
55
|
+
|
|
56
|
+
# Get exclude parameter with default
|
|
57
|
+
exclude = kwargs.get("exclude", ["replies", "retweets"])
|
|
58
|
+
|
|
59
|
+
context = self.context_from_config(config)
|
|
60
|
+
twitter = get_twitter_client(
|
|
61
|
+
agent_id=context.agent.id,
|
|
62
|
+
skill_store=self.skill_store,
|
|
63
|
+
config=context.config,
|
|
64
|
+
)
|
|
65
|
+
client = await twitter.get_client()
|
|
66
|
+
|
|
67
|
+
# Check rate limit only when not using OAuth
|
|
68
|
+
if not twitter.use_key:
|
|
69
|
+
await self.check_rate_limit(
|
|
70
|
+
context.agent.id, max_requests=3, interval=60 * 24
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# get since id from store
|
|
74
|
+
last = await self.skill_store.get_agent_skill_data(
|
|
75
|
+
context.agent.id, self.name, user_id
|
|
76
|
+
)
|
|
77
|
+
last = last or {}
|
|
78
|
+
since_id = last.get("since_id")
|
|
79
|
+
|
|
80
|
+
tweets = await client.get_users_tweets(
|
|
81
|
+
user_auth=twitter.use_key,
|
|
82
|
+
id=user_id,
|
|
83
|
+
max_results=max_results,
|
|
84
|
+
since_id=since_id,
|
|
85
|
+
exclude=exclude,
|
|
86
|
+
expansions=[
|
|
87
|
+
"referenced_tweets.id",
|
|
88
|
+
"referenced_tweets.id.attachments.media_keys",
|
|
89
|
+
"referenced_tweets.id.author_id",
|
|
90
|
+
"attachments.media_keys",
|
|
91
|
+
"author_id",
|
|
92
|
+
],
|
|
93
|
+
tweet_fields=[
|
|
94
|
+
"created_at",
|
|
95
|
+
"author_id",
|
|
96
|
+
"text",
|
|
97
|
+
"referenced_tweets",
|
|
98
|
+
"attachments",
|
|
99
|
+
],
|
|
100
|
+
user_fields=[
|
|
101
|
+
"username",
|
|
102
|
+
"name",
|
|
103
|
+
"profile_image_url",
|
|
104
|
+
"description",
|
|
105
|
+
"public_metrics",
|
|
106
|
+
"location",
|
|
107
|
+
"connection_status",
|
|
108
|
+
],
|
|
109
|
+
media_fields=["url", "type", "width", "height"],
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Update the since_id in store for the next request
|
|
113
|
+
if tweets.get("meta") and tweets["meta"].get("newest_id"):
|
|
114
|
+
last["since_id"] = tweets["meta"]["newest_id"]
|
|
115
|
+
await self.skill_store.save_agent_skill_data(
|
|
116
|
+
context.agent.id, self.name, user_id, last
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
return tweets
|
|
120
|
+
|
|
121
|
+
except Exception as e:
|
|
122
|
+
logger.error("Error getting user tweets: %s", str(e))
|
|
123
|
+
raise type(e)(f"[agent:{context.agent.id}]: {e}") from e
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Type
|
|
3
|
+
|
|
4
|
+
from langchain_core.runnables import RunnableConfig
|
|
5
|
+
from langchain_core.tools import ToolException
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from intentkit.clients import get_twitter_client
|
|
9
|
+
from intentkit.skills.twitter.base import TwitterBaseTool
|
|
10
|
+
|
|
11
|
+
NAME = "twitter_like_tweet"
|
|
12
|
+
PROMPT = "Like a tweet on Twitter"
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TwitterLikeTweetInput(BaseModel):
|
|
18
|
+
"""Input for TwitterLikeTweet tool."""
|
|
19
|
+
|
|
20
|
+
tweet_id: str = Field(description="The ID of the tweet to like")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TwitterLikeTweet(TwitterBaseTool):
|
|
24
|
+
"""Tool for liking tweets on Twitter.
|
|
25
|
+
|
|
26
|
+
This tool uses the Twitter API v2 to like tweets on Twitter.
|
|
27
|
+
|
|
28
|
+
Attributes:
|
|
29
|
+
name: The name of the tool.
|
|
30
|
+
description: A description of what the tool does.
|
|
31
|
+
args_schema: The schema for the tool's input arguments.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
name: str = NAME
|
|
35
|
+
description: str = PROMPT
|
|
36
|
+
args_schema: Type[BaseModel] = TwitterLikeTweetInput
|
|
37
|
+
|
|
38
|
+
async def _arun(self, tweet_id: str, config: RunnableConfig, **kwargs):
|
|
39
|
+
try:
|
|
40
|
+
context = self.context_from_config(config)
|
|
41
|
+
twitter = get_twitter_client(
|
|
42
|
+
agent_id=context.agent.id,
|
|
43
|
+
skill_store=self.skill_store,
|
|
44
|
+
config=context.config,
|
|
45
|
+
)
|
|
46
|
+
client = await twitter.get_client()
|
|
47
|
+
|
|
48
|
+
# Check rate limit only when not using OAuth
|
|
49
|
+
if not twitter.use_key:
|
|
50
|
+
await self.check_rate_limit(
|
|
51
|
+
context.agent.id, max_requests=100, interval=1440
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Like the tweet using tweepy client
|
|
55
|
+
response = await client.like(tweet_id=tweet_id, user_auth=twitter.use_key)
|
|
56
|
+
|
|
57
|
+
if "data" in response and "liked" in response["data"]:
|
|
58
|
+
return response
|
|
59
|
+
else:
|
|
60
|
+
logger.error(f"Error liking tweet: {str(response)}")
|
|
61
|
+
raise ToolException("Failed to like tweet.")
|
|
62
|
+
|
|
63
|
+
except Exception as e:
|
|
64
|
+
logger.error(f"Error liking tweet: {str(e)}")
|
|
65
|
+
raise type(e)(f"[agent:{context.agent.id}]: {e}") from e
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Optional, Type
|
|
3
|
+
|
|
4
|
+
from langchain_core.runnables import RunnableConfig
|
|
5
|
+
from langchain_core.tools import ToolException
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from intentkit.clients import get_twitter_client
|
|
9
|
+
from intentkit.skills.twitter.base import TwitterBaseTool
|
|
10
|
+
|
|
11
|
+
NAME = "twitter_post_tweet"
|
|
12
|
+
PROMPT = (
|
|
13
|
+
"Post a new tweet to Twitter. If you want to post image, "
|
|
14
|
+
"you must provide image url in parameters, do not add image link in text."
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TwitterPostTweetInput(BaseModel):
|
|
21
|
+
"""Input for TwitterPostTweet tool."""
|
|
22
|
+
|
|
23
|
+
text: str = Field(
|
|
24
|
+
description="Tweet text (280 chars for regular users, 25,000 bytes for verified)",
|
|
25
|
+
max_length=25000,
|
|
26
|
+
)
|
|
27
|
+
image: Optional[str] = Field(
|
|
28
|
+
default=None, description="Optional URL of an image to attach to the tweet"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TwitterPostTweet(TwitterBaseTool):
|
|
33
|
+
"""Tool for posting tweets to Twitter.
|
|
34
|
+
|
|
35
|
+
This tool uses the Twitter API v2 to post new tweets to Twitter.
|
|
36
|
+
|
|
37
|
+
Attributes:
|
|
38
|
+
name: The name of the tool.
|
|
39
|
+
description: A description of what the tool does.
|
|
40
|
+
args_schema: The schema for the tool's input arguments.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
name: str = NAME
|
|
44
|
+
description: str = PROMPT
|
|
45
|
+
args_schema: Type[BaseModel] = TwitterPostTweetInput
|
|
46
|
+
|
|
47
|
+
async def _arun(
|
|
48
|
+
self,
|
|
49
|
+
text: str,
|
|
50
|
+
image: Optional[str] = None,
|
|
51
|
+
config: RunnableConfig = None,
|
|
52
|
+
**kwargs,
|
|
53
|
+
):
|
|
54
|
+
try:
|
|
55
|
+
context = self.context_from_config(config)
|
|
56
|
+
twitter = get_twitter_client(
|
|
57
|
+
agent_id=context.agent.id,
|
|
58
|
+
skill_store=self.skill_store,
|
|
59
|
+
config=context.config,
|
|
60
|
+
)
|
|
61
|
+
client = await twitter.get_client()
|
|
62
|
+
|
|
63
|
+
# Check rate limit only when not using OAuth
|
|
64
|
+
if not twitter.use_key:
|
|
65
|
+
await self.check_rate_limit(
|
|
66
|
+
context.agent.id, max_requests=24, interval=1440
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
media_ids = []
|
|
70
|
+
|
|
71
|
+
# Handle image upload if provided
|
|
72
|
+
if image:
|
|
73
|
+
# Use the TwitterClient method to upload the image
|
|
74
|
+
media_ids = await twitter.upload_media(context.agent.id, image)
|
|
75
|
+
|
|
76
|
+
# Post tweet using tweepy client
|
|
77
|
+
tweet_params = {"text": text, "user_auth": twitter.use_key}
|
|
78
|
+
if media_ids:
|
|
79
|
+
tweet_params["media_ids"] = media_ids
|
|
80
|
+
|
|
81
|
+
response = await client.create_tweet(**tweet_params)
|
|
82
|
+
if "data" in response and "id" in response["data"]:
|
|
83
|
+
return response
|
|
84
|
+
else:
|
|
85
|
+
logger.error(f"Error posting tweet: {str(response)}")
|
|
86
|
+
raise ToolException("Failed to post tweet.")
|
|
87
|
+
|
|
88
|
+
except Exception as e:
|
|
89
|
+
logger.error(f"Error posting tweet: {str(e)}")
|
|
90
|
+
raise type(e)(f"[agent:{context.agent.id}]: {e}") from e
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Optional, Type
|
|
3
|
+
|
|
4
|
+
from langchain_core.runnables import RunnableConfig
|
|
5
|
+
from langchain_core.tools import ToolException
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from intentkit.clients import get_twitter_client
|
|
9
|
+
from intentkit.skills.twitter.base import TwitterBaseTool
|
|
10
|
+
|
|
11
|
+
NAME = "twitter_reply_tweet"
|
|
12
|
+
PROMPT = (
|
|
13
|
+
"Reply to an existing tweet on Twitter. If you want to post image, "
|
|
14
|
+
"you must provide image url in parameters, do not add image link in text."
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TwitterReplyTweetInput(BaseModel):
|
|
21
|
+
"""Input for TwitterReplyTweet tool."""
|
|
22
|
+
|
|
23
|
+
tweet_id: str = Field(description="The ID of the tweet to reply to")
|
|
24
|
+
text: str = Field(
|
|
25
|
+
description="Tweet text (280 chars for regular users, 25,000 bytes for verified)",
|
|
26
|
+
max_length=25000,
|
|
27
|
+
)
|
|
28
|
+
image: Optional[str] = Field(
|
|
29
|
+
default=None, description="Optional URL of an image to attach to the reply"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class TwitterReplyTweet(TwitterBaseTool):
|
|
34
|
+
"""Tool for replying to tweets on Twitter.
|
|
35
|
+
|
|
36
|
+
This tool uses the Twitter API v2 to post reply tweets to existing tweets.
|
|
37
|
+
|
|
38
|
+
Attributes:
|
|
39
|
+
name: The name of the tool.
|
|
40
|
+
description: A description of what the tool does.
|
|
41
|
+
args_schema: The schema for the tool's input arguments.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
name: str = NAME
|
|
45
|
+
description: str = PROMPT
|
|
46
|
+
args_schema: Type[BaseModel] = TwitterReplyTweetInput
|
|
47
|
+
|
|
48
|
+
async def _arun(
|
|
49
|
+
self,
|
|
50
|
+
tweet_id: str,
|
|
51
|
+
text: str,
|
|
52
|
+
image: Optional[str] = None,
|
|
53
|
+
config: RunnableConfig = None,
|
|
54
|
+
**kwargs,
|
|
55
|
+
):
|
|
56
|
+
try:
|
|
57
|
+
context = self.context_from_config(config)
|
|
58
|
+
twitter = get_twitter_client(
|
|
59
|
+
agent_id=context.agent.id,
|
|
60
|
+
skill_store=self.skill_store,
|
|
61
|
+
config=context.config,
|
|
62
|
+
)
|
|
63
|
+
client = await twitter.get_client()
|
|
64
|
+
|
|
65
|
+
# Check rate limit only when not using OAuth
|
|
66
|
+
if not twitter.use_key:
|
|
67
|
+
await self.check_rate_limit(
|
|
68
|
+
context.agent.id, max_requests=48, interval=1440
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
media_ids = []
|
|
72
|
+
|
|
73
|
+
# Handle image upload if provided
|
|
74
|
+
if image:
|
|
75
|
+
# Use the TwitterClient method to upload the image
|
|
76
|
+
media_ids = await twitter.upload_media(context.agent.id, image)
|
|
77
|
+
|
|
78
|
+
# Post reply tweet using tweepy client
|
|
79
|
+
tweet_params = {
|
|
80
|
+
"text": text,
|
|
81
|
+
"user_auth": twitter.use_key,
|
|
82
|
+
"in_reply_to_tweet_id": tweet_id,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if media_ids:
|
|
86
|
+
tweet_params["media_ids"] = media_ids
|
|
87
|
+
|
|
88
|
+
response = await client.create_tweet(**tweet_params)
|
|
89
|
+
|
|
90
|
+
if "data" in response and "id" in response["data"]:
|
|
91
|
+
return response
|
|
92
|
+
else:
|
|
93
|
+
logger.error(f"Error replying to tweet: {str(response)}")
|
|
94
|
+
raise ToolException("Failed to post reply tweet.")
|
|
95
|
+
|
|
96
|
+
except Exception as e:
|
|
97
|
+
logger.error(f"Error replying to tweet: {str(e)}")
|
|
98
|
+
raise type(e)(f"[agent:{context.agent.id}]: {e}") from e
|