intentkit 0.6.13.dev2__py3-none-any.whl → 0.8.17__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of intentkit might be problematic. Click here for more details.

Files changed (385) hide show
  1. intentkit/__init__.py +1 -1
  2. intentkit/abstracts/agent.py +4 -5
  3. intentkit/abstracts/engine.py +5 -5
  4. intentkit/abstracts/graph.py +14 -7
  5. intentkit/abstracts/skill.py +6 -144
  6. intentkit/abstracts/twitter.py +4 -5
  7. intentkit/clients/__init__.py +5 -2
  8. intentkit/clients/cdp.py +101 -141
  9. intentkit/clients/twitter.py +83 -62
  10. intentkit/clients/web3.py +29 -0
  11. intentkit/config/config.py +8 -5
  12. intentkit/core/agent.py +472 -195
  13. intentkit/core/asset.py +253 -0
  14. intentkit/core/chat.py +51 -0
  15. intentkit/core/client.py +1 -1
  16. intentkit/core/credit.py +460 -130
  17. intentkit/core/engine.py +262 -233
  18. intentkit/core/node.py +15 -16
  19. intentkit/core/prompt.py +62 -28
  20. intentkit/core/scheduler.py +92 -0
  21. intentkit/core/statistics.py +168 -0
  22. intentkit/models/agent.py +1096 -949
  23. intentkit/models/agent_data.py +68 -38
  24. intentkit/models/agent_public.json +98 -0
  25. intentkit/models/agent_schema.json +54 -439
  26. intentkit/models/app_setting.py +96 -33
  27. intentkit/models/chat.py +74 -27
  28. intentkit/models/conversation.py +8 -8
  29. intentkit/models/credit.py +362 -74
  30. intentkit/models/db.py +26 -8
  31. intentkit/models/db_mig.py +2 -2
  32. intentkit/models/llm.csv +28 -0
  33. intentkit/models/llm.py +185 -350
  34. intentkit/models/redis.py +6 -4
  35. intentkit/models/skill.py +186 -72
  36. intentkit/models/skills.csv +174 -0
  37. intentkit/models/user.py +82 -24
  38. intentkit/skills/acolyt/__init__.py +2 -9
  39. intentkit/skills/acolyt/ask.py +3 -4
  40. intentkit/skills/acolyt/base.py +4 -9
  41. intentkit/skills/acolyt/schema.json +4 -3
  42. intentkit/skills/aixbt/__init__.py +2 -13
  43. intentkit/skills/aixbt/base.py +1 -7
  44. intentkit/skills/aixbt/projects.py +14 -15
  45. intentkit/skills/aixbt/schema.json +4 -4
  46. intentkit/skills/allora/__init__.py +2 -9
  47. intentkit/skills/allora/base.py +4 -9
  48. intentkit/skills/allora/price.py +3 -4
  49. intentkit/skills/allora/schema.json +3 -2
  50. intentkit/skills/base.py +248 -85
  51. intentkit/skills/basename/__init__.py +51 -0
  52. intentkit/skills/basename/base.py +11 -0
  53. intentkit/skills/basename/basename.svg +11 -0
  54. intentkit/skills/basename/schema.json +58 -0
  55. intentkit/skills/carv/__init__.py +115 -121
  56. intentkit/skills/carv/base.py +184 -185
  57. intentkit/skills/carv/fetch_news.py +3 -3
  58. intentkit/skills/carv/onchain_query.py +4 -4
  59. intentkit/skills/carv/schema.json +134 -137
  60. intentkit/skills/carv/token_info_and_price.py +5 -5
  61. intentkit/skills/casino/README.md +254 -0
  62. intentkit/skills/casino/__init__.py +86 -0
  63. intentkit/skills/casino/base.py +17 -0
  64. intentkit/skills/casino/casino.png +0 -0
  65. intentkit/skills/casino/deck_draw.py +127 -0
  66. intentkit/skills/casino/deck_shuffle.py +118 -0
  67. intentkit/skills/casino/dice_roll.py +100 -0
  68. intentkit/skills/casino/schema.json +77 -0
  69. intentkit/skills/casino/utils.py +107 -0
  70. intentkit/skills/cdp/__init__.py +22 -84
  71. intentkit/skills/cdp/base.py +1 -7
  72. intentkit/skills/cdp/schema.json +11 -314
  73. intentkit/skills/chainlist/__init__.py +2 -7
  74. intentkit/skills/chainlist/base.py +1 -7
  75. intentkit/skills/chainlist/chain_lookup.py +18 -18
  76. intentkit/skills/chainlist/schema.json +3 -5
  77. intentkit/skills/common/__init__.py +2 -9
  78. intentkit/skills/common/base.py +1 -7
  79. intentkit/skills/common/current_time.py +1 -2
  80. intentkit/skills/common/schema.json +2 -2
  81. intentkit/skills/cookiefun/__init__.py +6 -9
  82. intentkit/skills/cookiefun/base.py +2 -7
  83. intentkit/skills/cookiefun/get_account_details.py +7 -7
  84. intentkit/skills/cookiefun/get_account_feed.py +19 -19
  85. intentkit/skills/cookiefun/get_account_smart_followers.py +7 -7
  86. intentkit/skills/cookiefun/get_sectors.py +3 -3
  87. intentkit/skills/cookiefun/schema.json +1 -3
  88. intentkit/skills/cookiefun/search_accounts.py +9 -9
  89. intentkit/skills/cryptocompare/__init__.py +7 -24
  90. intentkit/skills/cryptocompare/api.py +2 -3
  91. intentkit/skills/cryptocompare/base.py +11 -25
  92. intentkit/skills/cryptocompare/fetch_news.py +4 -5
  93. intentkit/skills/cryptocompare/fetch_price.py +6 -7
  94. intentkit/skills/cryptocompare/fetch_top_exchanges.py +4 -5
  95. intentkit/skills/cryptocompare/fetch_top_market_cap.py +4 -5
  96. intentkit/skills/cryptocompare/fetch_top_volume.py +4 -5
  97. intentkit/skills/cryptocompare/fetch_trading_signals.py +5 -6
  98. intentkit/skills/cryptocompare/schema.json +3 -3
  99. intentkit/skills/cryptopanic/__init__.py +7 -10
  100. intentkit/skills/cryptopanic/base.py +51 -55
  101. intentkit/skills/cryptopanic/fetch_crypto_news.py +4 -8
  102. intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +5 -7
  103. intentkit/skills/cryptopanic/schema.json +105 -103
  104. intentkit/skills/dapplooker/__init__.py +2 -9
  105. intentkit/skills/dapplooker/base.py +4 -9
  106. intentkit/skills/dapplooker/dapplooker_token_data.py +7 -7
  107. intentkit/skills/dapplooker/schema.json +3 -5
  108. intentkit/skills/defillama/__init__.py +24 -74
  109. intentkit/skills/defillama/api.py +6 -9
  110. intentkit/skills/defillama/base.py +11 -21
  111. intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +8 -10
  112. intentkit/skills/defillama/coins/fetch_block.py +6 -8
  113. intentkit/skills/defillama/coins/fetch_current_prices.py +8 -10
  114. intentkit/skills/defillama/coins/fetch_first_price.py +7 -9
  115. intentkit/skills/defillama/coins/fetch_historical_prices.py +9 -11
  116. intentkit/skills/defillama/coins/fetch_price_chart.py +9 -11
  117. intentkit/skills/defillama/coins/fetch_price_percentage.py +7 -9
  118. intentkit/skills/defillama/config/chains.py +1 -3
  119. intentkit/skills/defillama/fees/fetch_fees_overview.py +24 -26
  120. intentkit/skills/defillama/schema.json +5 -1
  121. intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +16 -18
  122. intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +8 -10
  123. intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +5 -7
  124. intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +7 -9
  125. intentkit/skills/defillama/tests/api_integration.test.py +1 -1
  126. intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +4 -6
  127. intentkit/skills/defillama/tvl/fetch_chains.py +9 -11
  128. intentkit/skills/defillama/tvl/fetch_historical_tvl.py +4 -6
  129. intentkit/skills/defillama/tvl/fetch_protocol.py +32 -38
  130. intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +3 -5
  131. intentkit/skills/defillama/tvl/fetch_protocols.py +37 -45
  132. intentkit/skills/defillama/volumes/fetch_dex_overview.py +42 -48
  133. intentkit/skills/defillama/volumes/fetch_dex_summary.py +35 -37
  134. intentkit/skills/defillama/volumes/fetch_options_overview.py +24 -28
  135. intentkit/skills/defillama/yields/fetch_pool_chart.py +10 -12
  136. intentkit/skills/defillama/yields/fetch_pools.py +26 -30
  137. intentkit/skills/dexscreener/README.md +154 -0
  138. intentkit/skills/dexscreener/__init__.py +97 -93
  139. intentkit/skills/dexscreener/base.py +125 -133
  140. intentkit/skills/dexscreener/get_pair_info.py +158 -0
  141. intentkit/skills/dexscreener/get_token_pairs.py +165 -0
  142. intentkit/skills/dexscreener/get_tokens_info.py +212 -0
  143. intentkit/skills/dexscreener/model/search_token_response.py +80 -82
  144. intentkit/skills/dexscreener/schema.json +91 -48
  145. intentkit/skills/dexscreener/search_token.py +182 -321
  146. intentkit/skills/dexscreener/utils.py +420 -0
  147. intentkit/skills/dune_analytics/__init__.py +7 -9
  148. intentkit/skills/dune_analytics/base.py +48 -52
  149. intentkit/skills/dune_analytics/fetch_kol_buys.py +5 -7
  150. intentkit/skills/dune_analytics/fetch_nation_metrics.py +6 -8
  151. intentkit/skills/dune_analytics/schema.json +104 -99
  152. intentkit/skills/elfa/__init__.py +5 -18
  153. intentkit/skills/elfa/base.py +10 -14
  154. intentkit/skills/elfa/mention.py +19 -21
  155. intentkit/skills/elfa/schema.json +3 -2
  156. intentkit/skills/elfa/stats.py +4 -4
  157. intentkit/skills/elfa/tokens.py +12 -12
  158. intentkit/skills/elfa/utils.py +26 -28
  159. intentkit/skills/enso/__init__.py +11 -31
  160. intentkit/skills/enso/base.py +50 -35
  161. intentkit/skills/enso/best_yield.py +16 -24
  162. intentkit/skills/enso/networks.py +6 -11
  163. intentkit/skills/enso/prices.py +11 -13
  164. intentkit/skills/enso/route.py +34 -38
  165. intentkit/skills/enso/schema.json +3 -2
  166. intentkit/skills/enso/tokens.py +29 -38
  167. intentkit/skills/enso/wallet.py +76 -191
  168. intentkit/skills/erc20/__init__.py +50 -0
  169. intentkit/skills/erc20/base.py +11 -0
  170. intentkit/skills/erc20/erc20.svg +5 -0
  171. intentkit/skills/erc20/schema.json +74 -0
  172. intentkit/skills/erc721/__init__.py +53 -0
  173. intentkit/skills/erc721/base.py +11 -0
  174. intentkit/skills/erc721/erc721.svg +5 -0
  175. intentkit/skills/erc721/schema.json +90 -0
  176. intentkit/skills/firecrawl/README.md +11 -5
  177. intentkit/skills/firecrawl/__init__.py +5 -18
  178. intentkit/skills/firecrawl/base.py +4 -11
  179. intentkit/skills/firecrawl/clear.py +4 -8
  180. intentkit/skills/firecrawl/crawl.py +19 -19
  181. intentkit/skills/firecrawl/query.py +4 -3
  182. intentkit/skills/firecrawl/schema.json +6 -8
  183. intentkit/skills/firecrawl/scrape.py +150 -40
  184. intentkit/skills/firecrawl/utils.py +50 -42
  185. intentkit/skills/github/__init__.py +2 -7
  186. intentkit/skills/github/base.py +1 -7
  187. intentkit/skills/github/github_search.py +1 -2
  188. intentkit/skills/github/schema.json +3 -4
  189. intentkit/skills/heurist/__init__.py +8 -27
  190. intentkit/skills/heurist/base.py +4 -9
  191. intentkit/skills/heurist/image_generation_animagine_xl.py +12 -13
  192. intentkit/skills/heurist/image_generation_arthemy_comics.py +12 -13
  193. intentkit/skills/heurist/image_generation_arthemy_real.py +12 -13
  194. intentkit/skills/heurist/image_generation_braindance.py +12 -13
  195. intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +12 -13
  196. intentkit/skills/heurist/image_generation_flux_1_dev.py +12 -13
  197. intentkit/skills/heurist/image_generation_sdxl.py +12 -13
  198. intentkit/skills/heurist/schema.json +2 -2
  199. intentkit/skills/http/__init__.py +4 -15
  200. intentkit/skills/http/base.py +1 -7
  201. intentkit/skills/http/get.py +21 -16
  202. intentkit/skills/http/post.py +23 -18
  203. intentkit/skills/http/put.py +23 -18
  204. intentkit/skills/http/schema.json +4 -5
  205. intentkit/skills/lifi/__init__.py +8 -13
  206. intentkit/skills/lifi/base.py +1 -7
  207. intentkit/skills/lifi/schema.json +17 -8
  208. intentkit/skills/lifi/token_execute.py +36 -30
  209. intentkit/skills/lifi/token_quote.py +8 -10
  210. intentkit/skills/lifi/utils.py +104 -51
  211. intentkit/skills/moralis/__init__.py +6 -10
  212. intentkit/skills/moralis/api.py +6 -7
  213. intentkit/skills/moralis/base.py +5 -10
  214. intentkit/skills/moralis/fetch_chain_portfolio.py +10 -11
  215. intentkit/skills/moralis/fetch_nft_portfolio.py +22 -22
  216. intentkit/skills/moralis/fetch_solana_portfolio.py +11 -12
  217. intentkit/skills/moralis/fetch_wallet_portfolio.py +8 -9
  218. intentkit/skills/moralis/schema.json +7 -2
  219. intentkit/skills/morpho/__init__.py +52 -0
  220. intentkit/skills/morpho/base.py +11 -0
  221. intentkit/skills/morpho/morpho.svg +12 -0
  222. intentkit/skills/morpho/schema.json +73 -0
  223. intentkit/skills/nation/__init__.py +4 -9
  224. intentkit/skills/nation/base.py +5 -10
  225. intentkit/skills/nation/nft_check.py +3 -4
  226. intentkit/skills/nation/schema.json +4 -3
  227. intentkit/skills/onchain.py +23 -0
  228. intentkit/skills/openai/__init__.py +17 -18
  229. intentkit/skills/openai/base.py +10 -14
  230. intentkit/skills/openai/dalle_image_generation.py +3 -8
  231. intentkit/skills/openai/gpt_avatar_generator.py +102 -0
  232. intentkit/skills/openai/gpt_image_generation.py +4 -8
  233. intentkit/skills/openai/gpt_image_mini_generator.py +91 -0
  234. intentkit/skills/openai/gpt_image_to_image.py +4 -8
  235. intentkit/skills/openai/image_to_text.py +3 -7
  236. intentkit/skills/openai/schema.json +34 -3
  237. intentkit/skills/portfolio/__init__.py +11 -35
  238. intentkit/skills/portfolio/base.py +33 -19
  239. intentkit/skills/portfolio/schema.json +3 -5
  240. intentkit/skills/portfolio/token_balances.py +21 -21
  241. intentkit/skills/portfolio/wallet_approvals.py +17 -18
  242. intentkit/skills/portfolio/wallet_defi_positions.py +3 -3
  243. intentkit/skills/portfolio/wallet_history.py +31 -31
  244. intentkit/skills/portfolio/wallet_net_worth.py +13 -13
  245. intentkit/skills/portfolio/wallet_nfts.py +19 -19
  246. intentkit/skills/portfolio/wallet_profitability.py +18 -18
  247. intentkit/skills/portfolio/wallet_profitability_summary.py +5 -5
  248. intentkit/skills/portfolio/wallet_stats.py +3 -3
  249. intentkit/skills/portfolio/wallet_swaps.py +19 -19
  250. intentkit/skills/pyth/__init__.py +50 -0
  251. intentkit/skills/pyth/base.py +11 -0
  252. intentkit/skills/pyth/pyth.svg +6 -0
  253. intentkit/skills/pyth/schema.json +75 -0
  254. intentkit/skills/skills.toml +40 -0
  255. intentkit/skills/slack/__init__.py +5 -17
  256. intentkit/skills/slack/base.py +3 -9
  257. intentkit/skills/slack/get_channel.py +8 -8
  258. intentkit/skills/slack/get_message.py +9 -9
  259. intentkit/skills/slack/schedule_message.py +5 -5
  260. intentkit/skills/slack/schema.json +2 -2
  261. intentkit/skills/slack/send_message.py +3 -5
  262. intentkit/skills/supabase/__init__.py +7 -23
  263. intentkit/skills/supabase/base.py +9 -13
  264. intentkit/skills/supabase/delete_data.py +5 -6
  265. intentkit/skills/supabase/fetch_data.py +13 -14
  266. intentkit/skills/supabase/insert_data.py +5 -6
  267. intentkit/skills/supabase/invoke_function.py +7 -8
  268. intentkit/skills/supabase/schema.json +2 -3
  269. intentkit/skills/supabase/update_data.py +7 -8
  270. intentkit/skills/supabase/upsert_data.py +5 -6
  271. intentkit/skills/superfluid/__init__.py +53 -0
  272. intentkit/skills/superfluid/base.py +11 -0
  273. intentkit/skills/superfluid/schema.json +89 -0
  274. intentkit/skills/superfluid/superfluid.svg +6 -0
  275. intentkit/skills/system/__init__.py +7 -24
  276. intentkit/skills/system/add_autonomous_task.py +10 -12
  277. intentkit/skills/system/delete_autonomous_task.py +2 -2
  278. intentkit/skills/system/edit_autonomous_task.py +14 -18
  279. intentkit/skills/system/list_autonomous_tasks.py +3 -5
  280. intentkit/skills/system/read_agent_api_key.py +6 -4
  281. intentkit/skills/system/regenerate_agent_api_key.py +6 -4
  282. intentkit/skills/system/schema.json +6 -8
  283. intentkit/skills/tavily/__init__.py +3 -12
  284. intentkit/skills/tavily/base.py +4 -9
  285. intentkit/skills/tavily/schema.json +3 -5
  286. intentkit/skills/tavily/tavily_extract.py +2 -4
  287. intentkit/skills/tavily/tavily_search.py +4 -6
  288. intentkit/skills/token/__init__.py +5 -10
  289. intentkit/skills/token/base.py +7 -11
  290. intentkit/skills/token/erc20_transfers.py +19 -19
  291. intentkit/skills/token/schema.json +3 -6
  292. intentkit/skills/token/token_analytics.py +3 -3
  293. intentkit/skills/token/token_price.py +13 -13
  294. intentkit/skills/token/token_search.py +9 -9
  295. intentkit/skills/twitter/__init__.py +11 -35
  296. intentkit/skills/twitter/base.py +23 -35
  297. intentkit/skills/twitter/follow_user.py +3 -7
  298. intentkit/skills/twitter/get_mentions.py +6 -13
  299. intentkit/skills/twitter/get_timeline.py +5 -13
  300. intentkit/skills/twitter/get_user_by_username.py +3 -7
  301. intentkit/skills/twitter/get_user_tweets.py +6 -14
  302. intentkit/skills/twitter/like_tweet.py +3 -7
  303. intentkit/skills/twitter/post_tweet.py +23 -12
  304. intentkit/skills/twitter/reply_tweet.py +21 -12
  305. intentkit/skills/twitter/retweet.py +3 -7
  306. intentkit/skills/twitter/schema.json +1 -0
  307. intentkit/skills/twitter/search_tweets.py +5 -13
  308. intentkit/skills/unrealspeech/__init__.py +2 -7
  309. intentkit/skills/unrealspeech/base.py +2 -8
  310. intentkit/skills/unrealspeech/schema.json +2 -5
  311. intentkit/skills/unrealspeech/text_to_speech.py +8 -8
  312. intentkit/skills/venice_audio/__init__.py +98 -106
  313. intentkit/skills/venice_audio/base.py +117 -121
  314. intentkit/skills/venice_audio/input.py +41 -41
  315. intentkit/skills/venice_audio/schema.json +151 -152
  316. intentkit/skills/venice_audio/venice_audio.py +38 -21
  317. intentkit/skills/venice_image/__init__.py +147 -154
  318. intentkit/skills/venice_image/api.py +138 -138
  319. intentkit/skills/venice_image/base.py +185 -192
  320. intentkit/skills/venice_image/config.py +33 -35
  321. intentkit/skills/venice_image/image_enhance/image_enhance.py +2 -3
  322. intentkit/skills/venice_image/image_enhance/image_enhance_base.py +21 -23
  323. intentkit/skills/venice_image/image_enhance/image_enhance_input.py +38 -40
  324. intentkit/skills/venice_image/image_generation/image_generation_base.py +9 -9
  325. intentkit/skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -26
  326. intentkit/skills/venice_image/image_generation/image_generation_flux_dev.py +27 -27
  327. intentkit/skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -26
  328. intentkit/skills/venice_image/image_generation/image_generation_input.py +158 -158
  329. intentkit/skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -26
  330. intentkit/skills/venice_image/image_generation/image_generation_pony_realism.py +26 -26
  331. intentkit/skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -28
  332. intentkit/skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -28
  333. intentkit/skills/venice_image/image_upscale/image_upscale.py +3 -3
  334. intentkit/skills/venice_image/image_upscale/image_upscale_base.py +21 -23
  335. intentkit/skills/venice_image/image_upscale/image_upscale_input.py +22 -22
  336. intentkit/skills/venice_image/image_vision/image_vision.py +2 -2
  337. intentkit/skills/venice_image/image_vision/image_vision_base.py +17 -17
  338. intentkit/skills/venice_image/image_vision/image_vision_input.py +9 -9
  339. intentkit/skills/venice_image/schema.json +267 -267
  340. intentkit/skills/venice_image/utils.py +77 -78
  341. intentkit/skills/web_scraper/__init__.py +5 -18
  342. intentkit/skills/web_scraper/base.py +21 -7
  343. intentkit/skills/web_scraper/document_indexer.py +7 -6
  344. intentkit/skills/web_scraper/schema.json +2 -6
  345. intentkit/skills/web_scraper/scrape_and_index.py +15 -15
  346. intentkit/skills/web_scraper/utils.py +62 -63
  347. intentkit/skills/web_scraper/website_indexer.py +17 -19
  348. intentkit/skills/weth/__init__.py +49 -0
  349. intentkit/skills/weth/base.py +11 -0
  350. intentkit/skills/weth/schema.json +58 -0
  351. intentkit/skills/weth/weth.svg +6 -0
  352. intentkit/skills/wow/__init__.py +51 -0
  353. intentkit/skills/wow/base.py +11 -0
  354. intentkit/skills/wow/schema.json +89 -0
  355. intentkit/skills/wow/wow.svg +7 -0
  356. intentkit/skills/x402/__init__.py +61 -0
  357. intentkit/skills/x402/ask_agent.py +98 -0
  358. intentkit/skills/x402/base.py +99 -0
  359. intentkit/skills/x402/http_request.py +117 -0
  360. intentkit/skills/x402/schema.json +45 -0
  361. intentkit/skills/x402/x402.webp +0 -0
  362. intentkit/skills/xmtp/__init__.py +4 -15
  363. intentkit/skills/xmtp/base.py +61 -2
  364. intentkit/skills/xmtp/price.py +18 -13
  365. intentkit/skills/xmtp/schema.json +69 -71
  366. intentkit/skills/xmtp/swap.py +22 -25
  367. intentkit/skills/xmtp/transfer.py +71 -32
  368. intentkit/utils/chain.py +3 -3
  369. intentkit/utils/error.py +14 -1
  370. intentkit/utils/logging.py +2 -4
  371. intentkit/utils/s3.py +59 -7
  372. intentkit/utils/schema.py +100 -0
  373. intentkit/utils/slack_alert.py +7 -8
  374. {intentkit-0.6.13.dev2.dist-info → intentkit-0.8.17.dist-info}/METADATA +14 -16
  375. intentkit-0.8.17.dist-info/RECORD +466 -0
  376. intentkit/abstracts/exception.py +0 -9
  377. intentkit/core/skill.py +0 -200
  378. intentkit/models/generator.py +0 -347
  379. intentkit/skills/cdp/get_balance.py +0 -110
  380. intentkit/skills/cdp/swap.py +0 -121
  381. intentkit/skills/moralis/tests/__init__.py +0 -0
  382. intentkit/skills/moralis/tests/test_wallet.py +0 -511
  383. intentkit-0.6.13.dev2.dist-info/RECORD +0 -409
  384. {intentkit-0.6.13.dev2.dist-info → intentkit-0.8.17.dist-info}/WHEEL +0 -0
  385. {intentkit-0.6.13.dev2.dist-info → intentkit-0.8.17.dist-info}/licenses/LICENSE +0 -0
@@ -3,7 +3,6 @@
3
3
  import logging
4
4
  from typing import NotRequired, TypedDict
5
5
 
6
- from intentkit.abstracts.skill import SkillStoreABC
7
6
  from intentkit.skills.base import SkillConfig, SkillState
8
7
  from intentkit.skills.supabase.base import SupabaseBaseTool
9
8
  from intentkit.skills.supabase.delete_data import SupabaseDeleteData
@@ -41,7 +40,6 @@ class Config(SkillConfig):
41
40
  async def get_skills(
42
41
  config: "Config",
43
42
  is_private: bool,
44
- store: SkillStoreABC,
45
43
  **_,
46
44
  ) -> list[SupabaseBaseTool]:
47
45
  """Get all Supabase skills."""
@@ -57,7 +55,7 @@ async def get_skills(
57
55
  # Get each skill using the cached getter
58
56
  result = []
59
57
  for name in available_skills:
60
- skill = get_supabase_skill(name, store)
58
+ skill = get_supabase_skill(name)
61
59
  if skill:
62
60
  result.append(skill)
63
61
  return result
@@ -65,52 +63,38 @@ async def get_skills(
65
63
 
66
64
  def get_supabase_skill(
67
65
  name: str,
68
- store: SkillStoreABC,
69
66
  ) -> SupabaseBaseTool:
70
67
  """Get a Supabase skill by name.
71
68
 
72
69
  Args:
73
70
  name: The name of the skill to get
74
- store: The skill store for persisting data
75
71
 
76
72
  Returns:
77
73
  The requested Supabase skill
78
74
  """
79
75
  if name == "fetch_data":
80
76
  if name not in _cache:
81
- _cache[name] = SupabaseFetchData(
82
- skill_store=store,
83
- )
77
+ _cache[name] = SupabaseFetchData()
84
78
  return _cache[name]
85
79
  elif name == "insert_data":
86
80
  if name not in _cache:
87
- _cache[name] = SupabaseInsertData(
88
- skill_store=store,
89
- )
81
+ _cache[name] = SupabaseInsertData()
90
82
  return _cache[name]
91
83
  elif name == "update_data":
92
84
  if name not in _cache:
93
- _cache[name] = SupabaseUpdateData(
94
- skill_store=store,
95
- )
85
+ _cache[name] = SupabaseUpdateData()
96
86
  return _cache[name]
97
87
  elif name == "upsert_data":
98
88
  if name not in _cache:
99
- _cache[name] = SupabaseUpsertData(
100
- skill_store=store,
101
- )
89
+ _cache[name] = SupabaseUpsertData()
102
90
  return _cache[name]
103
91
  elif name == "delete_data":
104
92
  if name not in _cache:
105
- _cache[name] = SupabaseDeleteData(
106
- skill_store=store,
107
- )
93
+ _cache[name] = SupabaseDeleteData()
108
94
  return _cache[name]
109
95
  elif name == "invoke_function":
110
96
  if name not in _cache:
111
- _cache[name] = SupabaseInvokeFunction(
112
- skill_store=store,
113
- )
97
+ _cache[name] = SupabaseInvokeFunction()
114
98
  return _cache[name]
115
99
  else:
116
100
  logger.warning(f"Unknown Supabase skill: {name}")
@@ -1,10 +1,8 @@
1
- from typing import Type
2
-
3
1
  from langchain_core.tools import ToolException
4
2
  from pydantic import BaseModel, Field
5
3
 
6
- from intentkit.abstracts.skill import SkillStoreABC
7
- from intentkit.skills.base import IntentKitSkill, SkillContext
4
+ from intentkit.abstracts.graph import AgentContext
5
+ from intentkit.skills.base import IntentKitSkill
8
6
 
9
7
 
10
8
  class SupabaseBaseTool(IntentKitSkill):
@@ -12,18 +10,13 @@ class SupabaseBaseTool(IntentKitSkill):
12
10
 
13
11
  name: str = Field(description="The name of the tool")
14
12
  description: str = Field(description="A description of what the tool does")
15
- args_schema: Type[BaseModel]
16
- skill_store: SkillStoreABC = Field(
17
- description="The skill store for persisting data"
18
- )
13
+ args_schema: type[BaseModel]
19
14
 
20
15
  @property
21
16
  def category(self) -> str:
22
17
  return "supabase"
23
18
 
24
- def get_supabase_config(
25
- self, config: dict, context: SkillContext
26
- ) -> tuple[str, str]:
19
+ def get_supabase_config(self, context: AgentContext) -> tuple[str, str]:
27
20
  """Get Supabase URL and key from config.
28
21
 
29
22
  Args:
@@ -36,6 +29,7 @@ class SupabaseBaseTool(IntentKitSkill):
36
29
  Raises:
37
30
  ValueError: If required config is missing
38
31
  """
32
+ config = context.agent.skill_config(self.category)
39
33
  supabase_url = config.get("supabase_url")
40
34
 
41
35
  # Use public_key for public operations if available, otherwise fall back to supabase_key
@@ -52,7 +46,7 @@ class SupabaseBaseTool(IntentKitSkill):
52
46
 
53
47
  return supabase_url, supabase_key
54
48
 
55
- def validate_table_access(self, table: str, context: SkillContext) -> None:
49
+ def validate_table_access(self, table: str, context: AgentContext) -> None:
56
50
  """Validate if the table can be accessed for write operations in public mode.
57
51
 
58
52
  Args:
@@ -66,8 +60,10 @@ class SupabaseBaseTool(IntentKitSkill):
66
60
  if context.is_private:
67
61
  return
68
62
 
63
+ config = context.agent.skill_config(self.category)
64
+
69
65
  # In public mode, check if table is in allowed list
70
- public_write_tables = context.config.get("public_write_tables", "")
66
+ public_write_tables = config.get("public_write_tables", "")
71
67
  if not public_write_tables:
72
68
  return
73
69
 
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Any, Dict, Type
2
+ from typing import Any
3
3
 
4
4
  from langchain_core.tools import ToolException
5
5
  from pydantic import BaseModel, Field
@@ -17,7 +17,7 @@ class SupabaseDeleteDataInput(BaseModel):
17
17
  """Input for SupabaseDeleteData tool."""
18
18
 
19
19
  table: str = Field(description="The name of the table to delete data from")
20
- filters: Dict[str, Any] = Field(
20
+ filters: dict[str, Any] = Field(
21
21
  description="Dictionary of filters to identify which records to delete (e.g., {'id': 123})"
22
22
  )
23
23
  returning: str = Field(
@@ -34,23 +34,22 @@ class SupabaseDeleteData(SupabaseBaseTool):
34
34
 
35
35
  name: str = NAME
36
36
  description: str = PROMPT
37
- args_schema: Type[BaseModel] = SupabaseDeleteDataInput
37
+ args_schema: type[BaseModel] = SupabaseDeleteDataInput
38
38
 
39
39
  async def _arun(
40
40
  self,
41
41
  table: str,
42
- filters: Dict[str, Any],
42
+ filters: dict[str, Any],
43
43
  returning: str = "*",
44
44
  **kwargs,
45
45
  ):
46
46
  try:
47
47
  context = self.get_context()
48
- skill_config = context.agent.skill_config(self.category)
49
48
 
50
49
  # Validate table access for public mode
51
50
  self.validate_table_access(table, context)
52
51
 
53
- supabase_url, supabase_key = self.get_supabase_config(skill_config, context)
52
+ supabase_url, supabase_key = self.get_supabase_config(context)
54
53
 
55
54
  # Create Supabase client
56
55
  supabase: Client = create_client(supabase_url, supabase_key)
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Any, Dict, Optional, Type
2
+ from typing import Any
3
3
 
4
4
  from langchain_core.tools import ToolException
5
5
  from pydantic import BaseModel, Field
@@ -17,22 +17,22 @@ class SupabaseFetchDataInput(BaseModel):
17
17
  """Input for SupabaseFetchData tool."""
18
18
 
19
19
  table: str = Field(description="The name of the table to fetch data from")
20
- columns: Optional[str] = Field(
20
+ columns: str | None = Field(
21
21
  default="*",
22
22
  description="Comma-separated list of columns to select (default: '*' for all)",
23
23
  )
24
- filters: Optional[Dict[str, Any]] = Field(
24
+ filters: dict[str, Any] | None = Field(
25
25
  default=None,
26
26
  description="Dictionary of filters to apply (e.g., {'column': 'value', 'age': {'gte': 18}})",
27
27
  )
28
- order_by: Optional[str] = Field(default=None, description="Column to order by")
28
+ order_by: str | None = Field(default=None, description="Column to order by")
29
29
  ascending: bool = Field(
30
30
  default=True, description="Whether to order in ascending order (default: True)"
31
31
  )
32
- limit: Optional[int] = Field(
32
+ limit: int | None = Field(
33
33
  default=None, description="Maximum number of records to return"
34
34
  )
35
- offset: Optional[int] = Field(
35
+ offset: int | None = Field(
36
36
  default=None, description="Number of records to skip for pagination"
37
37
  )
38
38
 
@@ -45,23 +45,22 @@ class SupabaseFetchData(SupabaseBaseTool):
45
45
 
46
46
  name: str = NAME
47
47
  description: str = PROMPT
48
- args_schema: Type[BaseModel] = SupabaseFetchDataInput
48
+ args_schema: type[BaseModel] = SupabaseFetchDataInput
49
49
 
50
50
  async def _arun(
51
51
  self,
52
52
  table: str,
53
- columns: Optional[str] = "*",
54
- filters: Optional[Dict[str, Any]] = None,
55
- order_by: Optional[str] = None,
53
+ columns: str | None = "*",
54
+ filters: dict[str, Any] | None = None,
55
+ order_by: str | None = None,
56
56
  ascending: bool = True,
57
- limit: Optional[int] = None,
58
- offset: Optional[int] = None,
57
+ limit: int | None = None,
58
+ offset: int | None = None,
59
59
  **kwargs,
60
60
  ):
61
61
  try:
62
62
  context = self.get_context()
63
- skill_config = context.agent.skill_config(self.category)
64
- supabase_url, supabase_key = self.get_supabase_config(skill_config, context)
63
+ supabase_url, supabase_key = self.get_supabase_config(context)
65
64
 
66
65
  # Create Supabase client
67
66
  supabase: Client = create_client(supabase_url, supabase_key)
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Any, Dict, List, Type, Union
2
+ from typing import Any
3
3
 
4
4
  from langchain_core.tools import ToolException
5
5
  from pydantic import BaseModel, Field
@@ -17,7 +17,7 @@ class SupabaseInsertDataInput(BaseModel):
17
17
  """Input for SupabaseInsertData tool."""
18
18
 
19
19
  table: str = Field(description="The name of the table to insert data into")
20
- data: Union[Dict[str, Any], List[Dict[str, Any]]] = Field(
20
+ data: dict[str, Any] | list[dict[str, Any]] = Field(
21
21
  description="The data to insert. Can be a single object or a list of objects"
22
22
  )
23
23
  returning: str = Field(
@@ -34,23 +34,22 @@ class SupabaseInsertData(SupabaseBaseTool):
34
34
 
35
35
  name: str = NAME
36
36
  description: str = PROMPT
37
- args_schema: Type[BaseModel] = SupabaseInsertDataInput
37
+ args_schema: type[BaseModel] = SupabaseInsertDataInput
38
38
 
39
39
  async def _arun(
40
40
  self,
41
41
  table: str,
42
- data: Union[Dict[str, Any], List[Dict[str, Any]]],
42
+ data: dict[str, Any] | list[dict[str, Any]],
43
43
  returning: str = "*",
44
44
  **kwargs,
45
45
  ):
46
46
  try:
47
47
  context = self.get_context()
48
- skill_config = context.agent.skill_config(self.category)
49
48
 
50
49
  # Validate table access for public mode
51
50
  self.validate_table_access(table, context)
52
51
 
53
- supabase_url, supabase_key = self.get_supabase_config(skill_config, context)
52
+ supabase_url, supabase_key = self.get_supabase_config(context)
54
53
 
55
54
  # Create Supabase client
56
55
  supabase: Client = create_client(supabase_url, supabase_key)
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Any, Dict, Optional, Type
2
+ from typing import Any
3
3
 
4
4
  from langchain_core.tools import ToolException
5
5
  from pydantic import BaseModel, Field
@@ -17,10 +17,10 @@ class SupabaseInvokeFunctionInput(BaseModel):
17
17
  """Input for SupabaseInvokeFunction tool."""
18
18
 
19
19
  function_name: str = Field(description="The name of the Edge Function to invoke")
20
- parameters: Optional[Dict[str, Any]] = Field(
20
+ parameters: dict[str, Any] | None = Field(
21
21
  default=None, description="Optional parameters to pass to the function"
22
22
  )
23
- headers: Optional[Dict[str, str]] = Field(
23
+ headers: dict[str, str] | None = Field(
24
24
  default=None, description="Optional headers to include in the request"
25
25
  )
26
26
 
@@ -33,19 +33,18 @@ class SupabaseInvokeFunction(SupabaseBaseTool):
33
33
 
34
34
  name: str = NAME
35
35
  description: str = PROMPT
36
- args_schema: Type[BaseModel] = SupabaseInvokeFunctionInput
36
+ args_schema: type[BaseModel] = SupabaseInvokeFunctionInput
37
37
 
38
38
  async def _arun(
39
39
  self,
40
40
  function_name: str,
41
- parameters: Optional[Dict[str, Any]] = None,
42
- headers: Optional[Dict[str, str]] = None,
41
+ parameters: dict[str, Any] | None = None,
42
+ headers: dict[str, str] | None = None,
43
43
  **kwargs,
44
44
  ):
45
45
  try:
46
46
  context = self.get_context()
47
- skill_config = context.agent.skill_config(self.category)
48
- supabase_url, supabase_key = self.get_supabase_config(skill_config, context)
47
+ supabase_url, supabase_key = self.get_supabase_config(context)
49
48
 
50
49
  # Create Supabase client
51
50
  supabase: Client = create_client(supabase_url, supabase_key)
@@ -5,8 +5,7 @@
5
5
  "description": "Integration with Supabase backend-as-a-service platform enabling database operations and Edge Function invocations",
6
6
  "x-icon": "https://ai.service.crestal.dev/skills/supabase/supabase.svg",
7
7
  "x-tags": [
8
- "Database",
9
- "Backend"
8
+ "Infrastructure"
10
9
  ],
11
10
  "properties": {
12
11
  "enabled": {
@@ -173,4 +172,4 @@
173
172
  "supabase_key"
174
173
  ]
175
174
  }
176
- }
175
+ }
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Any, Dict, Type
2
+ from typing import Any
3
3
 
4
4
  from langchain_core.tools import ToolException
5
5
  from pydantic import BaseModel, Field
@@ -17,10 +17,10 @@ class SupabaseUpdateDataInput(BaseModel):
17
17
  """Input for SupabaseUpdateData tool."""
18
18
 
19
19
  table: str = Field(description="The name of the table to update data in")
20
- data: Dict[str, Any] = Field(
20
+ data: dict[str, Any] = Field(
21
21
  description="The data to update (key-value pairs of columns and new values)"
22
22
  )
23
- filters: Dict[str, Any] = Field(
23
+ filters: dict[str, Any] = Field(
24
24
  description="Dictionary of filters to identify which records to update (e.g., {'id': 123})"
25
25
  )
26
26
  returning: str = Field(
@@ -36,24 +36,23 @@ class SupabaseUpdateData(SupabaseBaseTool):
36
36
 
37
37
  name: str = NAME
38
38
  description: str = PROMPT
39
- args_schema: Type[BaseModel] = SupabaseUpdateDataInput
39
+ args_schema: type[BaseModel] = SupabaseUpdateDataInput
40
40
 
41
41
  async def _arun(
42
42
  self,
43
43
  table: str,
44
- data: Dict[str, Any],
45
- filters: Dict[str, Any],
44
+ data: dict[str, Any],
45
+ filters: dict[str, Any],
46
46
  returning: str = "*",
47
47
  **kwargs,
48
48
  ):
49
49
  try:
50
50
  context = self.get_context()
51
- skill_config = context.agent.skill_config(self.category)
52
51
 
53
52
  # Validate table access for public mode
54
53
  self.validate_table_access(table, context)
55
54
 
56
- supabase_url, supabase_key = self.get_supabase_config(skill_config, context)
55
+ supabase_url, supabase_key = self.get_supabase_config(context)
57
56
 
58
57
  # Create Supabase client
59
58
  supabase: Client = create_client(supabase_url, supabase_key)
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Any, Dict, List, Type, Union
2
+ from typing import Any
3
3
 
4
4
  from langchain_core.tools import ToolException
5
5
  from pydantic import BaseModel, Field
@@ -19,7 +19,7 @@ class SupabaseUpsertDataInput(BaseModel):
19
19
  """Input for SupabaseUpsertData tool."""
20
20
 
21
21
  table: str = Field(description="The name of the table to upsert data into")
22
- data: Union[Dict[str, Any], List[Dict[str, Any]]] = Field(
22
+ data: dict[str, Any] | list[dict[str, Any]] = Field(
23
23
  description="The data to upsert. Can be a single object or a list of objects"
24
24
  )
25
25
  on_conflict: str = Field(
@@ -38,24 +38,23 @@ class SupabaseUpsertData(SupabaseBaseTool):
38
38
 
39
39
  name: str = NAME
40
40
  description: str = PROMPT
41
- args_schema: Type[BaseModel] = SupabaseUpsertDataInput
41
+ args_schema: type[BaseModel] = SupabaseUpsertDataInput
42
42
 
43
43
  async def _arun(
44
44
  self,
45
45
  table: str,
46
- data: Union[Dict[str, Any], List[Dict[str, Any]]],
46
+ data: dict[str, Any] | list[dict[str, Any]],
47
47
  on_conflict: str,
48
48
  returning: str = "*",
49
49
  **kwargs,
50
50
  ):
51
51
  try:
52
52
  context = self.get_context()
53
- skill_config = context.agent.skill_config(self.category)
54
53
 
55
54
  # Validate table access for public mode
56
55
  self.validate_table_access(table, context)
57
56
 
58
- supabase_url, supabase_key = self.get_supabase_config(skill_config, context)
57
+ supabase_url, supabase_key = self.get_supabase_config(context)
59
58
 
60
59
  # Create Supabase client
61
60
  supabase: Client = create_client(supabase_url, supabase_key)
@@ -0,0 +1,53 @@
1
+ """Superfluid AgentKit skills."""
2
+
3
+ from typing import TypedDict
4
+
5
+ from coinbase_agentkit import superfluid_action_provider
6
+
7
+ from intentkit.models.agent import Agent
8
+ from intentkit.skills.base import (
9
+ SkillConfig,
10
+ SkillState,
11
+ action_to_structured_tool,
12
+ get_agentkit_actions,
13
+ )
14
+ from intentkit.skills.superfluid.base import SuperfluidBaseTool
15
+
16
+
17
+ class SkillStates(TypedDict):
18
+ SuperfluidActionProvider_create_flow: SkillState
19
+ SuperfluidActionProvider_delete_flow: SkillState
20
+ SuperfluidActionProvider_update_flow: SkillState
21
+
22
+
23
+ class Config(SkillConfig):
24
+ """Configuration for Superfluid skills."""
25
+
26
+ states: SkillStates
27
+
28
+
29
+ async def get_skills(
30
+ config: Config,
31
+ is_private: bool,
32
+ agent_id: str,
33
+ agent: Agent | None = None,
34
+ **_,
35
+ ) -> list[SuperfluidBaseTool]:
36
+ """Get all Superfluid skills."""
37
+
38
+ available_skills: list[str] = []
39
+ for skill_name, state in config["states"].items():
40
+ if state == "disabled":
41
+ continue
42
+ if state == "public" or (state == "private" and is_private):
43
+ available_skills.append(skill_name)
44
+
45
+ actions = await get_agentkit_actions(
46
+ agent_id, [superfluid_action_provider], agent=agent
47
+ )
48
+ tools: list[SuperfluidBaseTool] = []
49
+ for skill in available_skills:
50
+ for action in actions:
51
+ if action.name.endswith(skill):
52
+ tools.append(action_to_structured_tool(action))
53
+ return tools
@@ -0,0 +1,11 @@
1
+ """Superfluid AgentKit skills base class."""
2
+
3
+ from intentkit.skills.cdp.base import CDPBaseTool
4
+
5
+
6
+ class SuperfluidBaseTool(CDPBaseTool):
7
+ """Base class for Superfluid tools."""
8
+
9
+ @property
10
+ def category(self) -> str:
11
+ return "superfluid"
@@ -0,0 +1,89 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "title": "Superfluid",
5
+ "description": "Superfluid streaming actions via Coinbase AgentKit",
6
+ "x-icon": "https://ai.service.crestal.dev/skills/superfluid/superfluid.svg",
7
+ "x-tags": [
8
+ "DeFi"
9
+ ],
10
+ "properties": {
11
+ "enabled": {
12
+ "type": "boolean",
13
+ "title": "Enabled",
14
+ "description": "Whether this skill is enabled",
15
+ "default": false
16
+ },
17
+ "states": {
18
+ "type": "object",
19
+ "properties": {
20
+ "SuperfluidActionProvider_create_flow": {
21
+ "type": "string",
22
+ "title": "Create Flow",
23
+ "enum": [
24
+ "disabled",
25
+ "public",
26
+ "private"
27
+ ],
28
+ "x-enum-title": [
29
+ "Disabled",
30
+ "Agent Owner + All Users",
31
+ "Agent Owner Only"
32
+ ],
33
+ "description": "State for SuperfluidActionProvider_create_flow",
34
+ "default": "disabled"
35
+ },
36
+ "SuperfluidActionProvider_delete_flow": {
37
+ "type": "string",
38
+ "title": "Delete Flow",
39
+ "enum": [
40
+ "disabled",
41
+ "public",
42
+ "private"
43
+ ],
44
+ "x-enum-title": [
45
+ "Disabled",
46
+ "Agent Owner + All Users",
47
+ "Agent Owner Only"
48
+ ],
49
+ "description": "State for SuperfluidActionProvider_delete_flow",
50
+ "default": "disabled"
51
+ },
52
+ "SuperfluidActionProvider_update_flow": {
53
+ "type": "string",
54
+ "title": "Update Flow",
55
+ "enum": [
56
+ "disabled",
57
+ "public",
58
+ "private"
59
+ ],
60
+ "x-enum-title": [
61
+ "Disabled",
62
+ "Agent Owner + All Users",
63
+ "Agent Owner Only"
64
+ ],
65
+ "description": "State for SuperfluidActionProvider_update_flow",
66
+ "default": "disabled"
67
+ }
68
+ },
69
+ "description": "States for each Superfluid skill (disabled, public, or private)"
70
+ },
71
+ "api_key_provider": {
72
+ "type": "string",
73
+ "title": "API Key Provider",
74
+ "description": "Who provides the API key",
75
+ "enum": [
76
+ "platform"
77
+ ],
78
+ "x-enum-title": [
79
+ "Nation Hosted"
80
+ ],
81
+ "default": "platform"
82
+ }
83
+ },
84
+ "required": [
85
+ "states",
86
+ "enabled"
87
+ ],
88
+ "additionalProperties": true
89
+ }
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
2
+ <rect width="128" height="128" fill="#0f172a" rx="16" />
3
+ <path d="M32 72c0-18 14-32 32-32s32 14 32 32" fill="none" stroke="#38bdf8" stroke-width="10" stroke-linecap="round" />
4
+ <path d="M32 72c0 18 14 32 32 32s32-14 32-32" fill="none" stroke="#22d3ee" stroke-width="10" stroke-linecap="round" />
5
+ <circle cx="64" cy="72" r="12" fill="#f8fafc" />
6
+ </svg>