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,78 @@
|
|
|
1
|
+
from typing import TypedDict
|
|
2
|
+
|
|
3
|
+
from intentkit.abstracts.skill import SkillStoreABC
|
|
4
|
+
from intentkit.skills.base import SkillConfig, SkillState
|
|
5
|
+
from intentkit.skills.cookiefun.base import CookieFunBaseTool, logger
|
|
6
|
+
from intentkit.skills.cookiefun.get_account_details import GetAccountDetails
|
|
7
|
+
from intentkit.skills.cookiefun.get_account_feed import GetAccountFeed
|
|
8
|
+
from intentkit.skills.cookiefun.get_account_smart_followers import (
|
|
9
|
+
GetAccountSmartFollowers,
|
|
10
|
+
)
|
|
11
|
+
from intentkit.skills.cookiefun.get_sectors import GetSectors
|
|
12
|
+
from intentkit.skills.cookiefun.search_accounts import SearchAccounts
|
|
13
|
+
|
|
14
|
+
# Cache skills at the system level, because they are stateless
|
|
15
|
+
_cache: dict[str, CookieFunBaseTool] = {}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SkillStates(TypedDict):
|
|
19
|
+
"""States for CookieFun skills."""
|
|
20
|
+
|
|
21
|
+
get_sectors: SkillState
|
|
22
|
+
get_account_details: SkillState
|
|
23
|
+
get_account_smart_followers: SkillState
|
|
24
|
+
search_accounts: SkillState
|
|
25
|
+
get_account_feed: SkillState
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Config(SkillConfig):
|
|
29
|
+
"""Configuration for CookieFun skills."""
|
|
30
|
+
|
|
31
|
+
states: SkillStates
|
|
32
|
+
api_key: str
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
async def get_skills(
|
|
36
|
+
config: "Config",
|
|
37
|
+
is_private: bool,
|
|
38
|
+
store: SkillStoreABC,
|
|
39
|
+
**_,
|
|
40
|
+
) -> list[CookieFunBaseTool]:
|
|
41
|
+
"""Get all CookieFun skills."""
|
|
42
|
+
available_skills = []
|
|
43
|
+
|
|
44
|
+
# Include skills based on their state
|
|
45
|
+
for skill_name, state in config["states"].items():
|
|
46
|
+
if state == "disabled":
|
|
47
|
+
continue
|
|
48
|
+
elif state == "public" or (state == "private" and is_private):
|
|
49
|
+
available_skills.append(skill_name)
|
|
50
|
+
|
|
51
|
+
# Get each skill using the cached getter
|
|
52
|
+
skills = [get_cookiefun_skill(name, store) for name in available_skills]
|
|
53
|
+
logger.info("Returning %d CookieFun skills", len(skills))
|
|
54
|
+
return skills
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def get_cookiefun_skill(
|
|
58
|
+
name: str,
|
|
59
|
+
store: SkillStoreABC,
|
|
60
|
+
) -> CookieFunBaseTool:
|
|
61
|
+
"""Get a CookieFun skill by name."""
|
|
62
|
+
|
|
63
|
+
if name not in _cache:
|
|
64
|
+
if name == "get_sectors":
|
|
65
|
+
_cache[name] = GetSectors(skill_store=store)
|
|
66
|
+
elif name == "get_account_details":
|
|
67
|
+
_cache[name] = GetAccountDetails(skill_store=store)
|
|
68
|
+
elif name == "get_account_smart_followers":
|
|
69
|
+
_cache[name] = GetAccountSmartFollowers(skill_store=store)
|
|
70
|
+
elif name == "search_accounts":
|
|
71
|
+
_cache[name] = SearchAccounts(skill_store=store)
|
|
72
|
+
elif name == "get_account_feed":
|
|
73
|
+
_cache[name] = GetAccountFeed(skill_store=store)
|
|
74
|
+
else:
|
|
75
|
+
logger.error("Unknown CookieFun skill: %s", name)
|
|
76
|
+
raise ValueError(f"Unknown CookieFun skill: {name}")
|
|
77
|
+
|
|
78
|
+
return _cache[name]
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Optional, Type
|
|
3
|
+
|
|
4
|
+
from langchain_core.runnables import RunnableConfig
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
from intentkit.abstracts.skill import SkillStoreABC
|
|
8
|
+
from intentkit.skills.base import IntentKitSkill
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class CookieFunBaseTool(IntentKitSkill):
|
|
14
|
+
"""Base class for CookieFun tools."""
|
|
15
|
+
|
|
16
|
+
name: str = Field(description="The name of the tool")
|
|
17
|
+
description: str = Field(description="A description of what the tool does")
|
|
18
|
+
args_schema: Type[BaseModel]
|
|
19
|
+
skill_store: SkillStoreABC = Field(
|
|
20
|
+
description="The skill store for persisting data"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def category(self) -> str:
|
|
25
|
+
return "cookiefun"
|
|
26
|
+
|
|
27
|
+
def get_api_key(self, config: RunnableConfig) -> Optional[str]:
|
|
28
|
+
"""
|
|
29
|
+
Get the API key from configuration.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
config: The runnable configuration containing context
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
The API key or None if not configured
|
|
36
|
+
"""
|
|
37
|
+
context = self.context_from_config(config)
|
|
38
|
+
skill_config = context.config
|
|
39
|
+
if skill_config.get("api_key_provider") == "agent_owner":
|
|
40
|
+
return skill_config.get("api_key")
|
|
41
|
+
return self.skill_store.get_system_config("cookiefun_api_key")
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Constants for the CookieFun skills.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
# API Base URL
|
|
6
|
+
BASE_URL = "https://api.staging.cookie.fun/v3"
|
|
7
|
+
|
|
8
|
+
# API Endpoints
|
|
9
|
+
ENDPOINTS = {
|
|
10
|
+
"sectors": f"{BASE_URL}/sectors",
|
|
11
|
+
"account_details": f"{BASE_URL}/account/",
|
|
12
|
+
"smart_followers": f"{BASE_URL}/account/smart-followers",
|
|
13
|
+
"search_accounts": f"{BASE_URL}/account/query",
|
|
14
|
+
"account_feed": f"{BASE_URL}/account/feed",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
# Default Headers
|
|
18
|
+
DEFAULT_HEADERS = {"Content-Type": "application/json"}
|
|
Binary file
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional, Type, Union
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
from langchain_core.runnables import RunnableConfig
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
from intentkit.skills.cookiefun.base import CookieFunBaseTool, logger
|
|
8
|
+
from intentkit.skills.cookiefun.constants import DEFAULT_HEADERS, ENDPOINTS
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GetAccountDetailsInput(BaseModel):
|
|
12
|
+
"""Input for GetAccountDetails tool."""
|
|
13
|
+
|
|
14
|
+
username: Optional[str] = Field(
|
|
15
|
+
default=None,
|
|
16
|
+
description="Twitter username (either username or userId is required)",
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
userId: Optional[str] = Field(
|
|
20
|
+
default=None,
|
|
21
|
+
description="Twitter user ID (either username or userId is required)",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class GetAccountDetails(CookieFunBaseTool):
|
|
26
|
+
"""Tool to get detailed information about a Twitter account."""
|
|
27
|
+
|
|
28
|
+
name: str = "cookiefun_get_account_details"
|
|
29
|
+
description: str = "Retrieves detailed information about a Twitter account including followers, following, posts, metrics, and engagement data."
|
|
30
|
+
args_schema: Type[BaseModel] = GetAccountDetailsInput
|
|
31
|
+
|
|
32
|
+
async def _arun(
|
|
33
|
+
self,
|
|
34
|
+
config: RunnableConfig,
|
|
35
|
+
username: Optional[str] = None,
|
|
36
|
+
userId: Optional[str] = None,
|
|
37
|
+
**kwargs,
|
|
38
|
+
) -> Union[Dict[str, Any], str]:
|
|
39
|
+
"""
|
|
40
|
+
Get detailed information about a Twitter account.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
username: Twitter username (either username or userId is required)
|
|
44
|
+
userId: Twitter user ID (either username or userId is required)
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Account details including followers, following, posts, metrics, and engagement data.
|
|
48
|
+
"""
|
|
49
|
+
logger.info(
|
|
50
|
+
"Getting account details for username=%s, userId=%s", username, userId
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Validate input parameters
|
|
54
|
+
if not username and not userId:
|
|
55
|
+
logger.error("Neither username nor userId provided")
|
|
56
|
+
return "Error: Either username or userId must be provided."
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
# Get context to retrieve API key
|
|
60
|
+
api_key = self.get_api_key(config)
|
|
61
|
+
|
|
62
|
+
if not api_key:
|
|
63
|
+
logger.error("No API key provided for CookieFun API")
|
|
64
|
+
return "Error: No API key provided for CookieFun API. Please configure the API key in the agent settings."
|
|
65
|
+
|
|
66
|
+
# Prepare request payload
|
|
67
|
+
payload = {}
|
|
68
|
+
if username:
|
|
69
|
+
payload["username"] = username
|
|
70
|
+
if userId:
|
|
71
|
+
payload["userId"] = userId
|
|
72
|
+
|
|
73
|
+
# Make API request
|
|
74
|
+
headers = {**DEFAULT_HEADERS, "x-api-key": api_key}
|
|
75
|
+
|
|
76
|
+
async with httpx.AsyncClient() as client:
|
|
77
|
+
response = await client.post(
|
|
78
|
+
ENDPOINTS["account_details"], headers=headers, json=payload
|
|
79
|
+
)
|
|
80
|
+
logger.debug(
|
|
81
|
+
"Received response with status code: %d", response.status_code
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
response.raise_for_status()
|
|
85
|
+
data = response.json()
|
|
86
|
+
|
|
87
|
+
# Check different possible response structures
|
|
88
|
+
if (
|
|
89
|
+
data.get("success")
|
|
90
|
+
and "ok" in data
|
|
91
|
+
and isinstance(data["ok"], dict)
|
|
92
|
+
):
|
|
93
|
+
logger.info("Successfully retrieved account details")
|
|
94
|
+
return data["ok"]
|
|
95
|
+
elif data.get("success") and "ok" in data and "entry" in data["ok"]:
|
|
96
|
+
logger.info(
|
|
97
|
+
"Successfully retrieved account details from entry field"
|
|
98
|
+
)
|
|
99
|
+
return data["ok"]["entry"]
|
|
100
|
+
elif (
|
|
101
|
+
data.get("success")
|
|
102
|
+
and "ok" in data
|
|
103
|
+
and "entries" in data["ok"]
|
|
104
|
+
and len(data["ok"]["entries"]) > 0
|
|
105
|
+
):
|
|
106
|
+
# If entries is a list but we expect a single account, return the first one
|
|
107
|
+
logger.info(
|
|
108
|
+
"Successfully retrieved account details from entries array"
|
|
109
|
+
)
|
|
110
|
+
return data["ok"]["entries"][0]
|
|
111
|
+
elif data.get("success") and isinstance(data.get("account"), dict):
|
|
112
|
+
# If account is at the top level
|
|
113
|
+
logger.info("Successfully retrieved account details from top level")
|
|
114
|
+
return data["account"]
|
|
115
|
+
elif data.get("success") and isinstance(data.get("entry"), dict):
|
|
116
|
+
# If entry is at the top level
|
|
117
|
+
logger.info(
|
|
118
|
+
"Successfully retrieved account details from entry field"
|
|
119
|
+
)
|
|
120
|
+
return data["entry"]
|
|
121
|
+
elif (
|
|
122
|
+
data.get("success")
|
|
123
|
+
and isinstance(data.get("entries"), list)
|
|
124
|
+
and len(data.get("entries")) > 0
|
|
125
|
+
):
|
|
126
|
+
# If entries is at the top level
|
|
127
|
+
logger.info(
|
|
128
|
+
"Successfully retrieved account details from entries array at top level"
|
|
129
|
+
)
|
|
130
|
+
return data["entries"][0]
|
|
131
|
+
elif "account" in data and isinstance(data["account"], dict):
|
|
132
|
+
# If only account field exists
|
|
133
|
+
logger.info("Successfully retrieved account from direct field")
|
|
134
|
+
return data["account"]
|
|
135
|
+
elif "entry" in data and isinstance(data["entry"], dict):
|
|
136
|
+
# If only entry field exists
|
|
137
|
+
logger.info(
|
|
138
|
+
"Successfully retrieved account from direct entry field"
|
|
139
|
+
)
|
|
140
|
+
return data["entry"]
|
|
141
|
+
elif (
|
|
142
|
+
"entries" in data
|
|
143
|
+
and isinstance(data["entries"], list)
|
|
144
|
+
and len(data["entries"]) > 0
|
|
145
|
+
):
|
|
146
|
+
# If only entries field exists
|
|
147
|
+
logger.info(
|
|
148
|
+
"Successfully retrieved account from direct entries field"
|
|
149
|
+
)
|
|
150
|
+
return data["entries"][0]
|
|
151
|
+
else:
|
|
152
|
+
# If we can't find account details in the expected structure, log the full response
|
|
153
|
+
logger.error(
|
|
154
|
+
"Could not find account details in response structure. Full response: %s",
|
|
155
|
+
data,
|
|
156
|
+
)
|
|
157
|
+
error_msg = data.get(
|
|
158
|
+
"error", "Unknown error - check API response format"
|
|
159
|
+
)
|
|
160
|
+
logger.error("Error in API response: %s", error_msg)
|
|
161
|
+
return f"Error fetching account details: {error_msg}"
|
|
162
|
+
|
|
163
|
+
except httpx.HTTPStatusError as e:
|
|
164
|
+
logger.error("HTTP error: %d - %s", e.response.status_code, e.response.text)
|
|
165
|
+
return f"HTTP error occurred: {e.response.status_code} - {e.response.text}"
|
|
166
|
+
except httpx.RequestError as e:
|
|
167
|
+
logger.error("Request error: %s", str(e))
|
|
168
|
+
return f"Request error occurred: {str(e)}"
|
|
169
|
+
except Exception as e:
|
|
170
|
+
logger.exception("Unexpected error occurred")
|
|
171
|
+
return f"An unexpected error occurred: {str(e)}"
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
from enum import IntEnum
|
|
2
|
+
from typing import Any, Dict, List, Optional, Type, Union
|
|
3
|
+
|
|
4
|
+
import httpx
|
|
5
|
+
from langchain_core.runnables import RunnableConfig
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from intentkit.skills.cookiefun.base import CookieFunBaseTool, logger
|
|
9
|
+
from intentkit.skills.cookiefun.constants import DEFAULT_HEADERS, ENDPOINTS
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TweetType(IntEnum):
|
|
13
|
+
"""Tweet type for filtering."""
|
|
14
|
+
|
|
15
|
+
Original = 0
|
|
16
|
+
Reply = 1
|
|
17
|
+
Quote = 2
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SortBy(IntEnum):
|
|
21
|
+
"""Sort options for tweets."""
|
|
22
|
+
|
|
23
|
+
CreatedDate = 0
|
|
24
|
+
Impressions = 1
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class SortOrder(IntEnum):
|
|
28
|
+
"""Sort order options."""
|
|
29
|
+
|
|
30
|
+
Ascending = 0
|
|
31
|
+
Descending = 1
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class GetAccountFeedInput(BaseModel):
|
|
35
|
+
"""Input for GetAccountFeed tool."""
|
|
36
|
+
|
|
37
|
+
username: Optional[str] = Field(
|
|
38
|
+
default=None,
|
|
39
|
+
description="Twitter username (either username or userId is required)",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
userId: Optional[str] = Field(
|
|
43
|
+
default=None,
|
|
44
|
+
description="Twitter user ID (either username or userId is required)",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
startDate: Optional[str] = Field(
|
|
48
|
+
default=None,
|
|
49
|
+
description="Start date for filtering in format dd/mm/yyyy (default: 30 days ago)",
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
endDate: Optional[str] = Field(
|
|
53
|
+
default=None,
|
|
54
|
+
description="End date for filtering in format dd/mm/yyyy (default: now)",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
type: Optional[int] = Field(
|
|
58
|
+
default=None,
|
|
59
|
+
description="Type of tweets to filter: 0 for Original, 1 for Reply, 2 for Quote (leave empty for all types)",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
hasMedia: Optional[bool] = Field(
|
|
63
|
+
default=None,
|
|
64
|
+
description="Filter to only include tweets with media if true",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
sortBy: Optional[int] = Field(
|
|
68
|
+
default=None,
|
|
69
|
+
description="Sort by: 0 for CreatedDate, 1 for Impressions",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
sortOrder: Optional[int] = Field(
|
|
73
|
+
default=None,
|
|
74
|
+
description="Sort order: 0 for Ascending, 1 for Descending",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class GetAccountFeed(CookieFunBaseTool):
|
|
79
|
+
"""Tool to get the feed (tweets) of a Twitter account."""
|
|
80
|
+
|
|
81
|
+
name: str = "cookiefun_get_account_feed"
|
|
82
|
+
description: str = "Retrieves a list of tweets for a specific Twitter account with various filtering options."
|
|
83
|
+
args_schema: Type[BaseModel] = GetAccountFeedInput
|
|
84
|
+
|
|
85
|
+
async def _arun(
|
|
86
|
+
self,
|
|
87
|
+
config: RunnableConfig,
|
|
88
|
+
username: Optional[str] = None,
|
|
89
|
+
userId: Optional[str] = None,
|
|
90
|
+
startDate: Optional[str] = None,
|
|
91
|
+
endDate: Optional[str] = None,
|
|
92
|
+
type: Optional[int] = None,
|
|
93
|
+
hasMedia: Optional[bool] = None,
|
|
94
|
+
sortBy: Optional[int] = None,
|
|
95
|
+
sortOrder: Optional[int] = None,
|
|
96
|
+
**kwargs,
|
|
97
|
+
) -> Union[List[Dict[str, Any]], str]:
|
|
98
|
+
"""
|
|
99
|
+
Get the feed (tweets) of a Twitter account.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
username: Twitter username (either username or userId is required)
|
|
103
|
+
userId: Twitter user ID (either username or userId is required)
|
|
104
|
+
startDate: Start date for filtering in format dd/mm/yyyy (default: 30 days ago)
|
|
105
|
+
endDate: End date for filtering in format dd/mm/yyyy (default: now)
|
|
106
|
+
type: Type of tweets to filter (0=Original, 1=Reply, 2=Quote)
|
|
107
|
+
hasMedia: Filter to only include tweets with media if true
|
|
108
|
+
sortBy: Sort by field (0=CreatedDate, 1=Impressions)
|
|
109
|
+
sortOrder: Sort order (0=Ascending, 1=Descending)
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
List of tweets from the specified account matching the filter criteria.
|
|
113
|
+
"""
|
|
114
|
+
logger.info(
|
|
115
|
+
"Getting account feed for username=%s, userId=%s, startDate=%s, endDate=%s, type=%s, hasMedia=%s, sortBy=%s, sortOrder=%s",
|
|
116
|
+
username,
|
|
117
|
+
userId,
|
|
118
|
+
startDate,
|
|
119
|
+
endDate,
|
|
120
|
+
type,
|
|
121
|
+
hasMedia,
|
|
122
|
+
sortBy,
|
|
123
|
+
sortOrder,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# Validate input parameters
|
|
127
|
+
if not username and not userId:
|
|
128
|
+
logger.error("Neither username nor userId provided")
|
|
129
|
+
return "Error: Either username or userId must be provided."
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
# Get context to retrieve API key
|
|
133
|
+
api_key = self.get_api_key(config)
|
|
134
|
+
|
|
135
|
+
if not api_key:
|
|
136
|
+
logger.error("No API key provided for CookieFun API")
|
|
137
|
+
return "Error: No API key provided for CookieFun API. Please configure the API key in the agent settings."
|
|
138
|
+
|
|
139
|
+
# Prepare request payload
|
|
140
|
+
payload = {}
|
|
141
|
+
if username:
|
|
142
|
+
payload["username"] = username
|
|
143
|
+
if userId:
|
|
144
|
+
payload["userId"] = userId
|
|
145
|
+
if startDate:
|
|
146
|
+
payload["startDate"] = startDate
|
|
147
|
+
if endDate:
|
|
148
|
+
payload["endDate"] = endDate
|
|
149
|
+
if type is not None:
|
|
150
|
+
payload["type"] = type
|
|
151
|
+
if hasMedia is not None:
|
|
152
|
+
payload["hasMedia"] = hasMedia
|
|
153
|
+
if sortBy is not None:
|
|
154
|
+
payload["sortBy"] = sortBy
|
|
155
|
+
if sortOrder is not None:
|
|
156
|
+
payload["sortOrder"] = sortOrder
|
|
157
|
+
|
|
158
|
+
# Make API request
|
|
159
|
+
headers = {**DEFAULT_HEADERS, "x-api-key": api_key}
|
|
160
|
+
|
|
161
|
+
async with httpx.AsyncClient() as client:
|
|
162
|
+
response = await client.post(
|
|
163
|
+
ENDPOINTS["account_feed"], headers=headers, json=payload
|
|
164
|
+
)
|
|
165
|
+
logger.debug(
|
|
166
|
+
"Received response with status code: %d", response.status_code
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
response.raise_for_status()
|
|
170
|
+
data = response.json()
|
|
171
|
+
|
|
172
|
+
# Check different possible response structures
|
|
173
|
+
if data.get("success") and "ok" in data and "entries" in data["ok"]:
|
|
174
|
+
tweets = data["ok"]["entries"]
|
|
175
|
+
logger.info(
|
|
176
|
+
"Successfully retrieved %d tweets from entries field",
|
|
177
|
+
len(tweets),
|
|
178
|
+
)
|
|
179
|
+
return tweets
|
|
180
|
+
elif data.get("success") and "ok" in data and "tweets" in data["ok"]:
|
|
181
|
+
tweets = data["ok"]["tweets"]
|
|
182
|
+
logger.info("Successfully retrieved %d tweets", len(tweets))
|
|
183
|
+
return tweets
|
|
184
|
+
elif data.get("success") and "ok" in data and "posts" in data["ok"]:
|
|
185
|
+
tweets = data["ok"]["posts"]
|
|
186
|
+
logger.info(
|
|
187
|
+
"Successfully retrieved %d tweets from posts field", len(tweets)
|
|
188
|
+
)
|
|
189
|
+
return tweets
|
|
190
|
+
elif data.get("success") and "ok" in data and "feed" in data["ok"]:
|
|
191
|
+
tweets = data["ok"]["feed"]
|
|
192
|
+
logger.info(
|
|
193
|
+
"Successfully retrieved %d tweets from feed field", len(tweets)
|
|
194
|
+
)
|
|
195
|
+
return tweets
|
|
196
|
+
elif (
|
|
197
|
+
data.get("success")
|
|
198
|
+
and "ok" in data
|
|
199
|
+
and isinstance(data["ok"], list)
|
|
200
|
+
):
|
|
201
|
+
tweets = data["ok"]
|
|
202
|
+
logger.info(
|
|
203
|
+
"Successfully retrieved %d tweets from ok list", len(tweets)
|
|
204
|
+
)
|
|
205
|
+
return tweets
|
|
206
|
+
elif data.get("success") and isinstance(data.get("tweets"), list):
|
|
207
|
+
tweets = data["tweets"]
|
|
208
|
+
logger.info(
|
|
209
|
+
"Successfully retrieved %d tweets from top level tweets",
|
|
210
|
+
len(tweets),
|
|
211
|
+
)
|
|
212
|
+
return tweets
|
|
213
|
+
elif data.get("success") and isinstance(data.get("posts"), list):
|
|
214
|
+
tweets = data["posts"]
|
|
215
|
+
logger.info(
|
|
216
|
+
"Successfully retrieved %d tweets from top level posts",
|
|
217
|
+
len(tweets),
|
|
218
|
+
)
|
|
219
|
+
return tweets
|
|
220
|
+
elif data.get("success") and isinstance(data.get("feed"), list):
|
|
221
|
+
tweets = data["feed"]
|
|
222
|
+
logger.info(
|
|
223
|
+
"Successfully retrieved %d tweets from top level feed",
|
|
224
|
+
len(tweets),
|
|
225
|
+
)
|
|
226
|
+
return tweets
|
|
227
|
+
elif data.get("success") and isinstance(data.get("entries"), list):
|
|
228
|
+
tweets = data["entries"]
|
|
229
|
+
logger.info(
|
|
230
|
+
"Successfully retrieved %d tweets from top level entries",
|
|
231
|
+
len(tweets),
|
|
232
|
+
)
|
|
233
|
+
return tweets
|
|
234
|
+
elif "tweets" in data and isinstance(data["tweets"], list):
|
|
235
|
+
tweets = data["tweets"]
|
|
236
|
+
logger.info(
|
|
237
|
+
"Successfully retrieved %d tweets from direct tweets field",
|
|
238
|
+
len(tweets),
|
|
239
|
+
)
|
|
240
|
+
return tweets
|
|
241
|
+
elif "posts" in data and isinstance(data["posts"], list):
|
|
242
|
+
tweets = data["posts"]
|
|
243
|
+
logger.info(
|
|
244
|
+
"Successfully retrieved %d tweets from direct posts field",
|
|
245
|
+
len(tweets),
|
|
246
|
+
)
|
|
247
|
+
return tweets
|
|
248
|
+
elif "feed" in data and isinstance(data["feed"], list):
|
|
249
|
+
tweets = data["feed"]
|
|
250
|
+
logger.info(
|
|
251
|
+
"Successfully retrieved %d tweets from direct feed field",
|
|
252
|
+
len(tweets),
|
|
253
|
+
)
|
|
254
|
+
return tweets
|
|
255
|
+
elif "entries" in data and isinstance(data["entries"], list):
|
|
256
|
+
tweets = data["entries"]
|
|
257
|
+
logger.info(
|
|
258
|
+
"Successfully retrieved %d tweets from direct entries field",
|
|
259
|
+
len(tweets),
|
|
260
|
+
)
|
|
261
|
+
return tweets
|
|
262
|
+
else:
|
|
263
|
+
# If we can't find tweets in the expected structure, log the full response
|
|
264
|
+
logger.error(
|
|
265
|
+
"Could not find tweets in response structure. Full response: %s",
|
|
266
|
+
data,
|
|
267
|
+
)
|
|
268
|
+
error_msg = data.get(
|
|
269
|
+
"error", "Unknown error - check API response format"
|
|
270
|
+
)
|
|
271
|
+
logger.error("Error in API response: %s", error_msg)
|
|
272
|
+
return f"Error fetching account feed: {error_msg}"
|
|
273
|
+
|
|
274
|
+
except httpx.HTTPStatusError as e:
|
|
275
|
+
logger.error("HTTP error: %d - %s", e.response.status_code, e.response.text)
|
|
276
|
+
return f"HTTP error occurred: {e.response.status_code} - {e.response.text}"
|
|
277
|
+
except httpx.RequestError as e:
|
|
278
|
+
logger.error("Request error: %s", str(e))
|
|
279
|
+
return f"Request error occurred: {str(e)}"
|
|
280
|
+
except Exception as e:
|
|
281
|
+
logger.exception("Unexpected error occurred")
|
|
282
|
+
return f"An unexpected error occurred: {str(e)}"
|