intentkit 0.8.6.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 (312) 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 +10 -5
  5. intentkit/abstracts/skill.py +6 -144
  6. intentkit/abstracts/twitter.py +4 -5
  7. intentkit/clients/__init__.py +3 -2
  8. intentkit/clients/cdp.py +53 -92
  9. intentkit/clients/twitter.py +56 -57
  10. intentkit/clients/web3.py +1 -3
  11. intentkit/config/config.py +5 -0
  12. intentkit/core/agent.py +16 -388
  13. intentkit/core/asset.py +64 -18
  14. intentkit/core/client.py +1 -1
  15. intentkit/core/credit.py +19 -20
  16. intentkit/core/engine.py +26 -11
  17. intentkit/core/node.py +2 -1
  18. intentkit/core/prompt.py +53 -15
  19. intentkit/core/scheduler.py +9 -9
  20. intentkit/core/statistics.py +6 -7
  21. intentkit/models/agent.py +256 -176
  22. intentkit/models/agent_data.py +62 -36
  23. intentkit/models/agent_schema.json +6 -9
  24. intentkit/models/app_setting.py +6 -6
  25. intentkit/models/chat.py +28 -24
  26. intentkit/models/conversation.py +8 -8
  27. intentkit/models/credit.py +62 -64
  28. intentkit/models/db.py +8 -7
  29. intentkit/models/db_mig.py +2 -2
  30. intentkit/models/llm.csv +15 -12
  31. intentkit/models/llm.py +18 -16
  32. intentkit/models/redis.py +2 -3
  33. intentkit/models/skill.py +62 -66
  34. intentkit/models/skills.csv +30 -26
  35. intentkit/models/user.py +46 -21
  36. intentkit/skills/acolyt/__init__.py +2 -9
  37. intentkit/skills/acolyt/ask.py +3 -4
  38. intentkit/skills/acolyt/base.py +4 -9
  39. intentkit/skills/aixbt/__init__.py +2 -13
  40. intentkit/skills/aixbt/base.py +1 -7
  41. intentkit/skills/aixbt/projects.py +14 -15
  42. intentkit/skills/allora/__init__.py +2 -9
  43. intentkit/skills/allora/base.py +4 -9
  44. intentkit/skills/allora/price.py +3 -4
  45. intentkit/skills/base.py +175 -52
  46. intentkit/skills/basename/__init__.py +4 -8
  47. intentkit/skills/carv/__init__.py +115 -121
  48. intentkit/skills/carv/base.py +184 -185
  49. intentkit/skills/carv/fetch_news.py +3 -3
  50. intentkit/skills/carv/onchain_query.py +4 -4
  51. intentkit/skills/carv/token_info_and_price.py +5 -5
  52. intentkit/skills/casino/__init__.py +4 -15
  53. intentkit/skills/casino/base.py +1 -7
  54. intentkit/skills/casino/deck_draw.py +5 -8
  55. intentkit/skills/casino/deck_shuffle.py +6 -6
  56. intentkit/skills/casino/dice_roll.py +2 -4
  57. intentkit/skills/cdp/__init__.py +3 -10
  58. intentkit/skills/cdp/base.py +1 -7
  59. intentkit/skills/cdp/schema.json +1 -17
  60. intentkit/skills/chainlist/__init__.py +2 -7
  61. intentkit/skills/chainlist/base.py +1 -7
  62. intentkit/skills/chainlist/chain_lookup.py +18 -18
  63. intentkit/skills/common/__init__.py +2 -9
  64. intentkit/skills/common/base.py +1 -7
  65. intentkit/skills/common/current_time.py +1 -2
  66. intentkit/skills/cookiefun/__init__.py +6 -9
  67. intentkit/skills/cookiefun/base.py +2 -7
  68. intentkit/skills/cookiefun/get_account_details.py +7 -7
  69. intentkit/skills/cookiefun/get_account_feed.py +19 -19
  70. intentkit/skills/cookiefun/get_account_smart_followers.py +7 -7
  71. intentkit/skills/cookiefun/get_sectors.py +3 -3
  72. intentkit/skills/cookiefun/search_accounts.py +9 -9
  73. intentkit/skills/cryptocompare/__init__.py +7 -24
  74. intentkit/skills/cryptocompare/api.py +2 -3
  75. intentkit/skills/cryptocompare/base.py +10 -24
  76. intentkit/skills/cryptocompare/fetch_news.py +4 -5
  77. intentkit/skills/cryptocompare/fetch_price.py +6 -7
  78. intentkit/skills/cryptocompare/fetch_top_exchanges.py +4 -5
  79. intentkit/skills/cryptocompare/fetch_top_market_cap.py +4 -5
  80. intentkit/skills/cryptocompare/fetch_top_volume.py +4 -5
  81. intentkit/skills/cryptocompare/fetch_trading_signals.py +5 -6
  82. intentkit/skills/cryptopanic/__init__.py +7 -10
  83. intentkit/skills/cryptopanic/base.py +51 -55
  84. intentkit/skills/cryptopanic/fetch_crypto_news.py +4 -8
  85. intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +5 -7
  86. intentkit/skills/dapplooker/__init__.py +2 -9
  87. intentkit/skills/dapplooker/base.py +4 -9
  88. intentkit/skills/dapplooker/dapplooker_token_data.py +7 -7
  89. intentkit/skills/defillama/__init__.py +24 -74
  90. intentkit/skills/defillama/api.py +6 -9
  91. intentkit/skills/defillama/base.py +8 -19
  92. intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +8 -10
  93. intentkit/skills/defillama/coins/fetch_block.py +6 -8
  94. intentkit/skills/defillama/coins/fetch_current_prices.py +8 -10
  95. intentkit/skills/defillama/coins/fetch_first_price.py +7 -9
  96. intentkit/skills/defillama/coins/fetch_historical_prices.py +9 -11
  97. intentkit/skills/defillama/coins/fetch_price_chart.py +9 -11
  98. intentkit/skills/defillama/coins/fetch_price_percentage.py +7 -9
  99. intentkit/skills/defillama/config/chains.py +1 -3
  100. intentkit/skills/defillama/fees/fetch_fees_overview.py +24 -26
  101. intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +16 -18
  102. intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +8 -10
  103. intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +5 -7
  104. intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +7 -9
  105. intentkit/skills/defillama/tests/api_integration.test.py +1 -1
  106. intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +4 -6
  107. intentkit/skills/defillama/tvl/fetch_chains.py +9 -11
  108. intentkit/skills/defillama/tvl/fetch_historical_tvl.py +4 -6
  109. intentkit/skills/defillama/tvl/fetch_protocol.py +32 -38
  110. intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +3 -5
  111. intentkit/skills/defillama/tvl/fetch_protocols.py +37 -45
  112. intentkit/skills/defillama/volumes/fetch_dex_overview.py +42 -48
  113. intentkit/skills/defillama/volumes/fetch_dex_summary.py +35 -37
  114. intentkit/skills/defillama/volumes/fetch_options_overview.py +24 -28
  115. intentkit/skills/defillama/yields/fetch_pool_chart.py +10 -12
  116. intentkit/skills/defillama/yields/fetch_pools.py +26 -30
  117. intentkit/skills/dexscreener/__init__.py +97 -102
  118. intentkit/skills/dexscreener/base.py +125 -130
  119. intentkit/skills/dexscreener/get_pair_info.py +4 -5
  120. intentkit/skills/dexscreener/get_token_pairs.py +4 -5
  121. intentkit/skills/dexscreener/get_tokens_info.py +7 -8
  122. intentkit/skills/dexscreener/model/search_token_response.py +80 -82
  123. intentkit/skills/dexscreener/search_token.py +182 -184
  124. intentkit/skills/dexscreener/utils.py +15 -14
  125. intentkit/skills/dune_analytics/__init__.py +7 -9
  126. intentkit/skills/dune_analytics/base.py +48 -52
  127. intentkit/skills/dune_analytics/fetch_kol_buys.py +5 -7
  128. intentkit/skills/dune_analytics/fetch_nation_metrics.py +6 -8
  129. intentkit/skills/elfa/__init__.py +5 -18
  130. intentkit/skills/elfa/base.py +10 -14
  131. intentkit/skills/elfa/mention.py +19 -21
  132. intentkit/skills/elfa/stats.py +4 -4
  133. intentkit/skills/elfa/tokens.py +12 -12
  134. intentkit/skills/elfa/utils.py +26 -28
  135. intentkit/skills/enso/__init__.py +11 -31
  136. intentkit/skills/enso/base.py +9 -15
  137. intentkit/skills/enso/best_yield.py +5 -7
  138. intentkit/skills/enso/networks.py +3 -9
  139. intentkit/skills/enso/prices.py +2 -4
  140. intentkit/skills/enso/route.py +6 -12
  141. intentkit/skills/enso/tokens.py +4 -16
  142. intentkit/skills/enso/wallet.py +6 -6
  143. intentkit/skills/erc20/__init__.py +5 -11
  144. intentkit/skills/erc721/__init__.py +5 -9
  145. intentkit/skills/firecrawl/__init__.py +5 -18
  146. intentkit/skills/firecrawl/base.py +4 -9
  147. intentkit/skills/firecrawl/clear.py +4 -8
  148. intentkit/skills/firecrawl/crawl.py +19 -19
  149. intentkit/skills/firecrawl/query.py +4 -3
  150. intentkit/skills/firecrawl/scrape.py +17 -22
  151. intentkit/skills/firecrawl/utils.py +50 -42
  152. intentkit/skills/github/__init__.py +2 -7
  153. intentkit/skills/github/base.py +1 -7
  154. intentkit/skills/github/github_search.py +1 -2
  155. intentkit/skills/heurist/__init__.py +8 -27
  156. intentkit/skills/heurist/base.py +4 -9
  157. intentkit/skills/heurist/image_generation_animagine_xl.py +12 -13
  158. intentkit/skills/heurist/image_generation_arthemy_comics.py +12 -13
  159. intentkit/skills/heurist/image_generation_arthemy_real.py +12 -13
  160. intentkit/skills/heurist/image_generation_braindance.py +12 -13
  161. intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +12 -13
  162. intentkit/skills/heurist/image_generation_flux_1_dev.py +12 -13
  163. intentkit/skills/heurist/image_generation_sdxl.py +12 -13
  164. intentkit/skills/http/__init__.py +4 -15
  165. intentkit/skills/http/base.py +1 -7
  166. intentkit/skills/http/get.py +21 -16
  167. intentkit/skills/http/post.py +23 -18
  168. intentkit/skills/http/put.py +23 -18
  169. intentkit/skills/lifi/__init__.py +5 -10
  170. intentkit/skills/lifi/base.py +1 -7
  171. intentkit/skills/lifi/token_execute.py +14 -17
  172. intentkit/skills/lifi/token_quote.py +7 -9
  173. intentkit/skills/lifi/utils.py +16 -16
  174. intentkit/skills/moralis/__init__.py +6 -10
  175. intentkit/skills/moralis/api.py +6 -7
  176. intentkit/skills/moralis/base.py +5 -10
  177. intentkit/skills/moralis/fetch_chain_portfolio.py +10 -11
  178. intentkit/skills/moralis/fetch_nft_portfolio.py +22 -22
  179. intentkit/skills/moralis/fetch_solana_portfolio.py +11 -12
  180. intentkit/skills/moralis/fetch_wallet_portfolio.py +8 -9
  181. intentkit/skills/morpho/__init__.py +5 -9
  182. intentkit/skills/nation/__init__.py +4 -9
  183. intentkit/skills/nation/base.py +5 -10
  184. intentkit/skills/nation/nft_check.py +3 -4
  185. intentkit/skills/onchain.py +23 -0
  186. intentkit/skills/openai/__init__.py +17 -18
  187. intentkit/skills/openai/base.py +10 -14
  188. intentkit/skills/openai/dalle_image_generation.py +3 -8
  189. intentkit/skills/openai/gpt_avatar_generator.py +102 -0
  190. intentkit/skills/openai/gpt_image_generation.py +4 -8
  191. intentkit/skills/openai/gpt_image_mini_generator.py +91 -0
  192. intentkit/skills/openai/gpt_image_to_image.py +4 -8
  193. intentkit/skills/openai/image_to_text.py +3 -7
  194. intentkit/skills/openai/schema.json +32 -0
  195. intentkit/skills/portfolio/__init__.py +11 -35
  196. intentkit/skills/portfolio/base.py +33 -19
  197. intentkit/skills/portfolio/token_balances.py +21 -21
  198. intentkit/skills/portfolio/wallet_approvals.py +17 -18
  199. intentkit/skills/portfolio/wallet_defi_positions.py +3 -3
  200. intentkit/skills/portfolio/wallet_history.py +31 -31
  201. intentkit/skills/portfolio/wallet_net_worth.py +13 -13
  202. intentkit/skills/portfolio/wallet_nfts.py +19 -19
  203. intentkit/skills/portfolio/wallet_profitability.py +18 -18
  204. intentkit/skills/portfolio/wallet_profitability_summary.py +5 -5
  205. intentkit/skills/portfolio/wallet_stats.py +3 -3
  206. intentkit/skills/portfolio/wallet_swaps.py +19 -19
  207. intentkit/skills/pyth/__init__.py +4 -10
  208. intentkit/skills/skills.toml +4 -0
  209. intentkit/skills/slack/__init__.py +5 -17
  210. intentkit/skills/slack/base.py +3 -9
  211. intentkit/skills/slack/get_channel.py +8 -8
  212. intentkit/skills/slack/get_message.py +9 -9
  213. intentkit/skills/slack/schedule_message.py +5 -5
  214. intentkit/skills/slack/send_message.py +3 -5
  215. intentkit/skills/supabase/__init__.py +7 -23
  216. intentkit/skills/supabase/base.py +1 -7
  217. intentkit/skills/supabase/delete_data.py +4 -4
  218. intentkit/skills/supabase/fetch_data.py +12 -12
  219. intentkit/skills/supabase/insert_data.py +4 -4
  220. intentkit/skills/supabase/invoke_function.py +6 -6
  221. intentkit/skills/supabase/update_data.py +6 -6
  222. intentkit/skills/supabase/upsert_data.py +4 -4
  223. intentkit/skills/superfluid/__init__.py +5 -9
  224. intentkit/skills/system/__init__.py +7 -24
  225. intentkit/skills/system/add_autonomous_task.py +10 -12
  226. intentkit/skills/system/delete_autonomous_task.py +2 -2
  227. intentkit/skills/system/edit_autonomous_task.py +14 -18
  228. intentkit/skills/system/list_autonomous_tasks.py +3 -5
  229. intentkit/skills/system/read_agent_api_key.py +6 -4
  230. intentkit/skills/system/regenerate_agent_api_key.py +6 -4
  231. intentkit/skills/tavily/__init__.py +3 -12
  232. intentkit/skills/tavily/base.py +4 -9
  233. intentkit/skills/tavily/tavily_extract.py +2 -4
  234. intentkit/skills/tavily/tavily_search.py +4 -6
  235. intentkit/skills/token/__init__.py +5 -10
  236. intentkit/skills/token/base.py +7 -11
  237. intentkit/skills/token/erc20_transfers.py +19 -19
  238. intentkit/skills/token/token_analytics.py +3 -3
  239. intentkit/skills/token/token_price.py +13 -13
  240. intentkit/skills/token/token_search.py +9 -9
  241. intentkit/skills/twitter/__init__.py +11 -35
  242. intentkit/skills/twitter/base.py +22 -34
  243. intentkit/skills/twitter/follow_user.py +2 -6
  244. intentkit/skills/twitter/get_mentions.py +5 -12
  245. intentkit/skills/twitter/get_timeline.py +4 -12
  246. intentkit/skills/twitter/get_user_by_username.py +2 -6
  247. intentkit/skills/twitter/get_user_tweets.py +5 -13
  248. intentkit/skills/twitter/like_tweet.py +2 -6
  249. intentkit/skills/twitter/post_tweet.py +6 -9
  250. intentkit/skills/twitter/reply_tweet.py +6 -9
  251. intentkit/skills/twitter/retweet.py +2 -6
  252. intentkit/skills/twitter/search_tweets.py +4 -12
  253. intentkit/skills/unrealspeech/__init__.py +2 -7
  254. intentkit/skills/unrealspeech/base.py +2 -8
  255. intentkit/skills/unrealspeech/text_to_speech.py +8 -8
  256. intentkit/skills/venice_audio/__init__.py +98 -106
  257. intentkit/skills/venice_audio/base.py +117 -121
  258. intentkit/skills/venice_audio/input.py +41 -41
  259. intentkit/skills/venice_audio/venice_audio.py +7 -11
  260. intentkit/skills/venice_image/__init__.py +147 -154
  261. intentkit/skills/venice_image/api.py +138 -138
  262. intentkit/skills/venice_image/base.py +185 -192
  263. intentkit/skills/venice_image/config.py +33 -35
  264. intentkit/skills/venice_image/image_enhance/image_enhance.py +2 -3
  265. intentkit/skills/venice_image/image_enhance/image_enhance_base.py +21 -23
  266. intentkit/skills/venice_image/image_enhance/image_enhance_input.py +38 -40
  267. intentkit/skills/venice_image/image_generation/image_generation_base.py +9 -9
  268. intentkit/skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -26
  269. intentkit/skills/venice_image/image_generation/image_generation_flux_dev.py +27 -27
  270. intentkit/skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -26
  271. intentkit/skills/venice_image/image_generation/image_generation_input.py +158 -158
  272. intentkit/skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -26
  273. intentkit/skills/venice_image/image_generation/image_generation_pony_realism.py +26 -26
  274. intentkit/skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -28
  275. intentkit/skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -28
  276. intentkit/skills/venice_image/image_upscale/image_upscale.py +3 -3
  277. intentkit/skills/venice_image/image_upscale/image_upscale_base.py +21 -23
  278. intentkit/skills/venice_image/image_upscale/image_upscale_input.py +22 -22
  279. intentkit/skills/venice_image/image_vision/image_vision.py +2 -2
  280. intentkit/skills/venice_image/image_vision/image_vision_base.py +17 -17
  281. intentkit/skills/venice_image/image_vision/image_vision_input.py +9 -9
  282. intentkit/skills/venice_image/utils.py +77 -78
  283. intentkit/skills/web_scraper/__init__.py +5 -18
  284. intentkit/skills/web_scraper/base.py +21 -7
  285. intentkit/skills/web_scraper/document_indexer.py +7 -6
  286. intentkit/skills/web_scraper/scrape_and_index.py +15 -15
  287. intentkit/skills/web_scraper/utils.py +62 -63
  288. intentkit/skills/web_scraper/website_indexer.py +17 -19
  289. intentkit/skills/weth/__init__.py +5 -11
  290. intentkit/skills/wow/__init__.py +5 -11
  291. intentkit/skills/x402/__init__.py +61 -0
  292. intentkit/skills/x402/ask_agent.py +98 -0
  293. intentkit/skills/x402/base.py +99 -0
  294. intentkit/skills/x402/http_request.py +117 -0
  295. intentkit/skills/x402/schema.json +45 -0
  296. intentkit/skills/x402/x402.webp +0 -0
  297. intentkit/skills/xmtp/__init__.py +4 -15
  298. intentkit/skills/xmtp/base.py +5 -5
  299. intentkit/skills/xmtp/price.py +6 -6
  300. intentkit/skills/xmtp/swap.py +6 -8
  301. intentkit/skills/xmtp/transfer.py +4 -6
  302. intentkit/utils/error.py +2 -2
  303. intentkit/utils/logging.py +2 -4
  304. intentkit/utils/s3.py +8 -9
  305. intentkit/utils/schema.py +100 -0
  306. intentkit/utils/slack_alert.py +7 -8
  307. {intentkit-0.8.6.dev2.dist-info → intentkit-0.8.17.dist-info}/METADATA +3 -4
  308. intentkit-0.8.17.dist-info/RECORD +466 -0
  309. intentkit/models/generator.py +0 -347
  310. intentkit-0.8.6.dev2.dist-info/RECORD +0 -457
  311. {intentkit-0.8.6.dev2.dist-info → intentkit-0.8.17.dist-info}/WHEEL +0 -0
  312. {intentkit-0.8.6.dev2.dist-info → intentkit-0.8.17.dist-info}/licenses/LICENSE +0 -0
intentkit/models/agent.py CHANGED
@@ -1,12 +1,14 @@
1
+ from __future__ import annotations
2
+
1
3
  import hashlib
2
4
  import json
3
5
  import logging
4
6
  import re
5
7
  import textwrap
6
- from datetime import datetime, timezone
8
+ from datetime import UTC, datetime
7
9
  from decimal import Decimal
8
10
  from pathlib import Path
9
- from typing import Annotated, Any, Dict, List, Literal, Optional
11
+ from typing import Annotated, Any, Literal
10
12
 
11
13
  import jsonref
12
14
  import yaml
@@ -57,7 +59,7 @@ class AgentAutonomous(BaseModel):
57
59
  ),
58
60
  ]
59
61
  name: Annotated[
60
- Optional[str],
62
+ str | None,
61
63
  PydanticField(
62
64
  default=None,
63
65
  description="Display name of the autonomous configuration",
@@ -68,7 +70,7 @@ class AgentAutonomous(BaseModel):
68
70
  ),
69
71
  ]
70
72
  description: Annotated[
71
- Optional[str],
73
+ str | None,
72
74
  PydanticField(
73
75
  default=None,
74
76
  description="Description of the autonomous configuration",
@@ -79,7 +81,7 @@ class AgentAutonomous(BaseModel):
79
81
  ),
80
82
  ]
81
83
  minutes: Annotated[
82
- Optional[int],
84
+ int | None,
83
85
  PydanticField(
84
86
  default=None,
85
87
  description="Interval in minutes between operations, mutually exclusive with cron",
@@ -89,7 +91,7 @@ class AgentAutonomous(BaseModel):
89
91
  ),
90
92
  ]
91
93
  cron: Annotated[
92
- Optional[str],
94
+ str | None,
93
95
  PydanticField(
94
96
  default=None,
95
97
  description="Cron expression for scheduling operations, mutually exclusive with minutes",
@@ -109,7 +111,7 @@ class AgentAutonomous(BaseModel):
109
111
  ),
110
112
  ]
111
113
  enabled: Annotated[
112
- Optional[bool],
114
+ bool | None,
113
115
  PydanticField(
114
116
  default=False,
115
117
  description="Whether the autonomous configuration is enabled",
@@ -289,6 +291,17 @@ class AgentUserInputColumns:
289
291
  nullable=True,
290
292
  comment="Telegram integration configuration settings",
291
293
  )
294
+ discord_entrypoint_enabled = Column(
295
+ Boolean,
296
+ nullable=True,
297
+ default=False,
298
+ comment="Whether the agent can receive events from Discord",
299
+ )
300
+ discord_config = Column(
301
+ JSON().with_variant(JSONB(), "postgresql"),
302
+ nullable=True,
303
+ comment="Discord integration configuration settings",
304
+ )
292
305
  xmtp_entrypoint_prompt = Column(
293
306
  String,
294
307
  nullable=True,
@@ -421,7 +434,7 @@ class AgentTable(Base, AgentUserInputColumns):
421
434
  DateTime(timezone=True),
422
435
  nullable=False,
423
436
  server_default=func.now(),
424
- onupdate=lambda: datetime.now(timezone.utc),
437
+ onupdate=lambda: datetime.now(UTC),
425
438
  comment="Timestamp when the agent was last updated",
426
439
  )
427
440
 
@@ -430,75 +443,43 @@ class AgentCore(BaseModel):
430
443
  """Agent core model."""
431
444
 
432
445
  name: Annotated[
433
- Optional[str],
446
+ str | None,
434
447
  PydanticField(
435
448
  default=None,
436
449
  title="Name",
437
450
  description="Display name of the agent",
438
451
  max_length=50,
439
- json_schema_extra={
440
- "x-group": "basic",
441
- "x-placeholder": "Name your agent",
442
- },
443
452
  ),
444
453
  ]
445
454
  picture: Annotated[
446
- Optional[str],
455
+ str | None,
447
456
  PydanticField(
448
457
  default=None,
449
- description="Picture of the agent",
450
- json_schema_extra={
451
- "x-group": "experimental",
452
- "x-placeholder": "Upload a picture of your agent",
453
- },
458
+ description="Avatar of the agent",
454
459
  ),
455
460
  ]
456
461
  purpose: Annotated[
457
- Optional[str],
462
+ str | None,
458
463
  PydanticField(
459
464
  default=None,
460
465
  description="Purpose or role of the agent",
461
466
  max_length=20000,
462
- json_schema_extra={
463
- "x-group": "basic",
464
- "x-placeholder": "Enter agent purpose, it will be a part of the system prompt",
465
- "pattern": "^(([^#].*)|#[^# ].*|#{3,}[ ].*|$)(\n(([^#].*)|#[^# ].*|#{3,}[ ].*|$))*$",
466
- "errorMessage": {
467
- "pattern": "Level 1 and 2 headings (# and ##) are not allowed. Please use level 3+ headings (###, ####, etc.) instead."
468
- },
469
- },
470
467
  ),
471
468
  ]
472
469
  personality: Annotated[
473
- Optional[str],
470
+ str | None,
474
471
  PydanticField(
475
472
  default=None,
476
473
  description="Personality traits of the agent",
477
474
  max_length=20000,
478
- json_schema_extra={
479
- "x-group": "basic",
480
- "x-placeholder": "Enter agent personality, it will be a part of the system prompt",
481
- "pattern": "^(([^#].*)|#[^# ].*|#{3,}[ ].*|$)(\n(([^#].*)|#[^# ].*|#{3,}[ ].*|$))*$",
482
- "errorMessage": {
483
- "pattern": "Level 1 and 2 headings (# and ##) are not allowed. Please use level 3+ headings (###, ####, etc.) instead."
484
- },
485
- },
486
475
  ),
487
476
  ]
488
477
  principles: Annotated[
489
- Optional[str],
478
+ str | None,
490
479
  PydanticField(
491
480
  default=None,
492
481
  description="Principles or values of the agent",
493
482
  max_length=20000,
494
- json_schema_extra={
495
- "x-group": "basic",
496
- "x-placeholder": "Enter agent principles, it will be a part of the system prompt",
497
- "pattern": "^(([^#].*)|#[^# ].*|#{3,}[ ].*|$)(\n(([^#].*)|#[^# ].*|#{3,}[ ].*|$))*$",
498
- "errorMessage": {
499
- "pattern": "Level 1 and 2 headings (# and ##) are not allowed. Please use level 3+ headings (###, ####, etc.) instead."
500
- },
501
- },
502
483
  ),
503
484
  ]
504
485
  # AI part
@@ -506,128 +487,86 @@ class AgentCore(BaseModel):
506
487
  str,
507
488
  PydanticField(
508
489
  default="gpt-5-mini",
509
- description="AI model identifier to be used by this agent for processing requests.",
510
- json_schema_extra={
511
- "x-group": "ai",
512
- },
490
+ description="LLM of the agent",
513
491
  ),
514
492
  ]
515
493
  prompt: Annotated[
516
- Optional[str],
494
+ str | None,
517
495
  PydanticField(
518
496
  default=None,
519
497
  description="Base system prompt that defines the agent's behavior and capabilities",
520
498
  max_length=20000,
521
- json_schema_extra={
522
- "x-group": "ai",
523
- "pattern": "^(([^#].*)|#[^# ].*|#{3,}[ ].*|$)(\n(([^#].*)|#[^# ].*|#{3,}[ ].*|$))*$",
524
- "errorMessage": {
525
- "pattern": "Level 1 and 2 headings (# and ##) are not allowed. Please use level 3+ headings (###, ####, etc.) instead."
526
- },
527
- },
528
499
  ),
529
500
  ]
530
501
  prompt_append: Annotated[
531
- Optional[str],
502
+ str | None,
532
503
  PydanticField(
533
504
  default=None,
534
505
  description="Additional system prompt that has higher priority than the base prompt",
535
506
  max_length=20000,
536
- json_schema_extra={
537
- "x-group": "ai",
538
- "pattern": "^(([^#].*)|#[^# ].*|#{3,}[ ].*|$)(\n(([^#].*)|#[^# ].*|#{3,}[ ].*|$))*$",
539
- "errorMessage": {
540
- "pattern": "Level 1 and 2 headings (# and ##) are not allowed. Please use level 3+ headings (###, ####, etc.) instead."
541
- },
542
- },
543
507
  ),
544
508
  ]
545
509
  temperature: Annotated[
546
- Optional[float],
510
+ float | None,
547
511
  PydanticField(
548
512
  default=0.7,
549
513
  description="The randomness of the generated results is such that the higher the number, the more creative the results will be. However, this also makes them wilder and increases the likelihood of errors. For creative tasks, you can adjust it to above 1, but for rigorous tasks, such as quantitative trading, it's advisable to set it lower, around 0.2. (0.0~2.0)",
550
514
  ge=0.0,
551
515
  le=2.0,
552
- json_schema_extra={
553
- "x-group": "ai",
554
- },
555
516
  ),
556
517
  ]
557
518
  frequency_penalty: Annotated[
558
- Optional[float],
519
+ float | None,
559
520
  PydanticField(
560
521
  default=0.0,
561
522
  description="The frequency penalty is a measure of how much the AI is allowed to repeat itself. A lower value means the AI is more likely to repeat previous responses, while a higher value means the AI is more likely to generate new content. For creative tasks, you can adjust it to 1 or a bit higher. (-2.0~2.0)",
562
523
  ge=-2.0,
563
524
  le=2.0,
564
- json_schema_extra={
565
- "x-group": "ai",
566
- },
567
525
  ),
568
526
  ]
569
527
  presence_penalty: Annotated[
570
- Optional[float],
528
+ float | None,
571
529
  PydanticField(
572
530
  default=0.0,
573
531
  description="The presence penalty is a measure of how much the AI is allowed to deviate from the topic. A higher value means the AI is more likely to deviate from the topic, while a lower value means the AI is more likely to follow the topic. For creative tasks, you can adjust it to 1 or a bit higher. (-2.0~2.0)",
574
532
  ge=-2.0,
575
533
  le=2.0,
576
- json_schema_extra={
577
- "x-group": "ai",
578
- },
579
534
  ),
580
535
  ]
581
536
  wallet_provider: Annotated[
582
- Optional[Literal["cdp", "readonly", "none"]],
537
+ Literal["cdp", "readonly", "none"] | None,
583
538
  PydanticField(
584
539
  default=None,
585
540
  description="Provider of the agent's wallet",
586
- json_schema_extra={
587
- "x-group": "onchain",
588
- },
589
541
  ),
590
542
  ]
591
543
  readonly_wallet_address: Annotated[
592
- Optional[str],
544
+ str | None,
593
545
  PydanticField(
594
546
  default=None,
595
547
  description="Address of the agent's wallet, only used when wallet_provider is readonly. Agent will not be able to sign transactions.",
596
548
  ),
597
549
  ]
598
550
  network_id: Annotated[
599
- Optional[
600
- Literal[
601
- "base-mainnet",
602
- "base-sepolia",
603
- "ethereum-mainnet",
604
- "ethereum-sepolia",
605
- "polygon-mainnet",
606
- "polygon-mumbai",
607
- "arbitrum-mainnet",
608
- "arbitrum-sepolia",
609
- "optimism-mainnet",
610
- "optimism-sepolia",
611
- "solana",
612
- ]
613
- ],
551
+ Literal[
552
+ "base-mainnet",
553
+ "ethereum-mainnet",
554
+ "polygon-mainnet",
555
+ "arbitrum-mainnet",
556
+ "optimism-mainnet",
557
+ "solana",
558
+ ]
559
+ | None,
614
560
  PydanticField(
615
561
  default="base-mainnet",
616
562
  description="Network identifier",
617
- json_schema_extra={
618
- "x-group": "onchain",
619
- },
620
563
  ),
621
564
  ]
622
565
  skills: Annotated[
623
- Optional[Dict[str, Any]],
566
+ dict[str, Any] | None,
624
567
  PydanticField(
625
568
  default=None,
626
569
  description="Dict of skills and their corresponding configurations",
627
- json_schema_extra={
628
- "x-group": "skills",
629
- "x-inline": True,
630
- },
631
570
  ),
632
571
  ]
633
572
 
@@ -670,18 +609,15 @@ class AgentUserInput(AgentCore):
670
609
  )
671
610
 
672
611
  short_term_memory_strategy: Annotated[
673
- Optional[Literal["trim", "summarize"]],
612
+ Literal["trim", "summarize"] | None,
674
613
  PydanticField(
675
614
  default="trim",
676
615
  description="Strategy for managing short-term memory when context limit is reached. 'trim' removes oldest messages, 'summarize' creates summaries.",
677
- json_schema_extra={
678
- "x-group": "ai",
679
- },
680
616
  ),
681
617
  ]
682
618
  # autonomous mode
683
619
  autonomous: Annotated[
684
- Optional[List[AgentAutonomous]],
620
+ list[AgentAutonomous] | None,
685
621
  PydanticField(
686
622
  default=None,
687
623
  description=(
@@ -698,53 +634,57 @@ class AgentUserInput(AgentCore):
698
634
  " prompt: |-\n"
699
635
  " Say hi [sequence], use number for sequence.\n"
700
636
  ),
701
- json_schema_extra={
702
- "x-group": "autonomous",
703
- "x-inline": True,
704
- },
705
637
  ),
706
638
  ]
707
639
  # if telegram_entrypoint_enabled, the telegram_entrypoint_enabled will be enabled, telegram_config will be checked
708
640
  telegram_entrypoint_enabled: Annotated[
709
- Optional[bool],
641
+ bool | None,
710
642
  PydanticField(
711
643
  default=False,
712
644
  description="Whether the agent can play telegram bot",
713
- json_schema_extra={
714
- "x-group": "entrypoint",
715
- },
716
645
  ),
717
646
  ]
718
647
  telegram_entrypoint_prompt: Annotated[
719
- Optional[str],
648
+ str | None,
720
649
  PydanticField(
721
650
  default=None,
722
651
  description="Extra prompt for telegram entrypoint",
723
652
  max_length=10000,
653
+ ),
654
+ ]
655
+ telegram_config: Annotated[
656
+ dict | None,
657
+ PydanticField(
658
+ default=None,
659
+ description="Telegram integration configuration settings",
660
+ ),
661
+ ]
662
+ discord_entrypoint_enabled: Annotated[
663
+ bool | None,
664
+ PydanticField(
665
+ default=False,
666
+ description="Whether the agent can play discord bot",
724
667
  json_schema_extra={
725
668
  "x-group": "entrypoint",
726
669
  },
727
670
  ),
728
671
  ]
729
- telegram_config: Annotated[
730
- Optional[dict],
672
+ discord_config: Annotated[
673
+ dict | None,
731
674
  PydanticField(
732
675
  default=None,
733
- description="Telegram integration configuration settings",
676
+ description="Discord integration configuration settings including token, whitelists, and behavior settings",
734
677
  json_schema_extra={
735
678
  "x-group": "entrypoint",
736
679
  },
737
680
  ),
738
681
  ]
739
682
  xmtp_entrypoint_prompt: Annotated[
740
- Optional[str],
683
+ str | None,
741
684
  PydanticField(
742
685
  default=None,
743
686
  description="Extra prompt for xmtp entrypoint, xmtp support is in beta",
744
687
  max_length=10000,
745
- json_schema_extra={
746
- "x-group": "entrypoint",
747
- },
748
688
  ),
749
689
  ]
750
690
 
@@ -761,7 +701,7 @@ class AgentUpdate(AgentUserInput):
761
701
  )
762
702
 
763
703
  upstream_id: Annotated[
764
- Optional[str],
704
+ str | None,
765
705
  PydanticField(
766
706
  default=None,
767
707
  description="External reference ID for idempotent operations",
@@ -769,7 +709,7 @@ class AgentUpdate(AgentUserInput):
769
709
  ),
770
710
  ]
771
711
  upstream_extra: Annotated[
772
- Optional[Dict[str, Any]],
712
+ dict[str, Any] | None,
773
713
  PydanticField(
774
714
  default=None,
775
715
  description="Additional data store for upstream use",
@@ -781,7 +721,7 @@ class AgentUpdate(AgentUserInput):
781
721
 
782
722
  @field_validator("purpose", "personality", "principles", "prompt", "prompt_append")
783
723
  @classmethod
784
- def validate_no_level1_level2_headings(cls, v: Optional[str]) -> Optional[str]:
724
+ def validate_no_level1_level2_headings(cls, v: str | None) -> str | None:
785
725
  """Validate that the text doesn't contain level 1 or level 2 headings."""
786
726
  if v is None:
787
727
  return v
@@ -940,7 +880,7 @@ class AgentCreate(AgentUpdate):
940
880
  ),
941
881
  ]
942
882
  owner: Annotated[
943
- Optional[str],
883
+ str | None,
944
884
  PydanticField(
945
885
  default=None,
946
886
  description="Owner identifier of the agent, used for access control",
@@ -962,7 +902,7 @@ class AgentCreate(AgentUpdate):
962
902
  message="Upstream id already in use",
963
903
  )
964
904
 
965
- async def get_by_upstream_id(self) -> Optional["Agent"]:
905
+ async def get_by_upstream_id(self) -> Agent | None:
966
906
  if not self.upstream_id:
967
907
  return None
968
908
  async with get_session() as db:
@@ -1005,7 +945,7 @@ class AgentPublicInfo(BaseModel):
1005
945
  )
1006
946
 
1007
947
  description: Annotated[
1008
- Optional[str],
948
+ str | None,
1009
949
  PydanticField(
1010
950
  default=None,
1011
951
  description="Description of the agent, for public view, not contained in prompt",
@@ -1015,7 +955,7 @@ class AgentPublicInfo(BaseModel):
1015
955
  ),
1016
956
  ]
1017
957
  external_website: Annotated[
1018
- Optional[str],
958
+ str | None,
1019
959
  PydanticField(
1020
960
  default=None,
1021
961
  description="Link of external website of the agent, if you have one",
@@ -1026,7 +966,7 @@ class AgentPublicInfo(BaseModel):
1026
966
  ),
1027
967
  ]
1028
968
  ticker: Annotated[
1029
- Optional[str],
969
+ str | None,
1030
970
  PydanticField(
1031
971
  default=None,
1032
972
  description="Ticker symbol of the agent",
@@ -1038,7 +978,7 @@ class AgentPublicInfo(BaseModel):
1038
978
  ),
1039
979
  ]
1040
980
  token_address: Annotated[
1041
- Optional[str],
981
+ str | None,
1042
982
  PydanticField(
1043
983
  default=None,
1044
984
  description="Token address of the agent",
@@ -1049,7 +989,7 @@ class AgentPublicInfo(BaseModel):
1049
989
  ),
1050
990
  ]
1051
991
  token_pool: Annotated[
1052
- Optional[str],
992
+ str | None,
1053
993
  PydanticField(
1054
994
  default=None,
1055
995
  description="Pool of the agent token",
@@ -1060,7 +1000,7 @@ class AgentPublicInfo(BaseModel):
1060
1000
  ),
1061
1001
  ]
1062
1002
  fee_percentage: Annotated[
1063
- Optional[Decimal],
1003
+ Decimal | None,
1064
1004
  PydanticField(
1065
1005
  default=None,
1066
1006
  description="Fee percentage of the agent",
@@ -1071,7 +1011,7 @@ class AgentPublicInfo(BaseModel):
1071
1011
  ),
1072
1012
  ]
1073
1013
  example_intro: Annotated[
1074
- Optional[str],
1014
+ str | None,
1075
1015
  PydanticField(
1076
1016
  default=None,
1077
1017
  description="Introduction of the example",
@@ -1082,7 +1022,7 @@ class AgentPublicInfo(BaseModel):
1082
1022
  ),
1083
1023
  ]
1084
1024
  examples: Annotated[
1085
- Optional[List[AgentExample]],
1025
+ list[AgentExample] | None,
1086
1026
  PydanticField(
1087
1027
  default=None,
1088
1028
  description="List of example prompts for the agent",
@@ -1093,7 +1033,7 @@ class AgentPublicInfo(BaseModel):
1093
1033
  ),
1094
1034
  ]
1095
1035
  public_extra: Annotated[
1096
- Optional[Dict[str, Any]],
1036
+ dict[str, Any] | None,
1097
1037
  PydanticField(
1098
1038
  default=None,
1099
1039
  description="Public extra data of the agent",
@@ -1141,7 +1081,7 @@ class Agent(AgentCreate, AgentPublicInfo):
1141
1081
  model_config = ConfigDict(from_attributes=True)
1142
1082
 
1143
1083
  slug: Annotated[
1144
- Optional[str],
1084
+ str | None,
1145
1085
  PydanticField(
1146
1086
  default=None,
1147
1087
  description="Slug of the agent, used for URL generation",
@@ -1150,49 +1090,49 @@ class Agent(AgentCreate, AgentPublicInfo):
1150
1090
  ),
1151
1091
  ]
1152
1092
  version: Annotated[
1153
- Optional[str],
1093
+ str | None,
1154
1094
  PydanticField(
1155
1095
  default=None,
1156
1096
  description="Version hash of the agent",
1157
1097
  ),
1158
1098
  ]
1159
1099
  statistics: Annotated[
1160
- Optional[Dict[str, Any]],
1100
+ dict[str, Any] | None,
1161
1101
  PydanticField(
1162
1102
  default=None,
1163
1103
  description="Statistics of the agent, update every 1 hour for query",
1164
1104
  ),
1165
1105
  ]
1166
1106
  assets: Annotated[
1167
- Optional[Dict[str, Any]],
1107
+ dict[str, Any] | None,
1168
1108
  PydanticField(
1169
1109
  default=None,
1170
1110
  description="Assets of the agent, update every 1 hour for query",
1171
1111
  ),
1172
1112
  ]
1173
1113
  account_snapshot: Annotated[
1174
- Optional[CreditAccount],
1114
+ CreditAccount | None,
1175
1115
  PydanticField(
1176
1116
  default=None,
1177
1117
  description="Account snapshot of the agent, update every 1 hour for query",
1178
1118
  ),
1179
1119
  ]
1180
1120
  extra: Annotated[
1181
- Optional[Dict[str, Any]],
1121
+ dict[str, Any] | None,
1182
1122
  PydanticField(
1183
1123
  default=None,
1184
1124
  description="Other helper data fields for query, come from agent and agent data",
1185
1125
  ),
1186
1126
  ]
1187
1127
  deployed_at: Annotated[
1188
- Optional[datetime],
1128
+ datetime | None,
1189
1129
  PydanticField(
1190
1130
  default=None,
1191
1131
  description="Timestamp when the agent was deployed",
1192
1132
  ),
1193
1133
  ]
1194
1134
  public_info_updated_at: Annotated[
1195
- Optional[datetime],
1135
+ datetime | None,
1196
1136
  PydanticField(
1197
1137
  default=None,
1198
1138
  description="Timestamp when the agent public info was last updated",
@@ -1233,8 +1173,11 @@ class Agent(AgentCreate, AgentPublicInfo):
1233
1173
  return False
1234
1174
 
1235
1175
  async def is_model_support_image(self) -> bool:
1236
- model = await LLMModelInfo.get(self.model)
1237
- return model.supports_image_input
1176
+ try:
1177
+ model = await LLMModelInfo.get(self.model)
1178
+ return model.supports_image_input
1179
+ except Exception:
1180
+ return False
1238
1181
 
1239
1182
  def to_yaml(self) -> str:
1240
1183
  """
@@ -1327,7 +1270,7 @@ class Agent(AgentCreate, AgentPublicInfo):
1327
1270
  )
1328
1271
  yaml_lines.append(yaml_value.rstrip())
1329
1272
  elif isinstance(value, list) and value and hasattr(value[0], "model_dump"):
1330
- # Handle list of Pydantic models (e.g., List[AgentAutonomous])
1273
+ # Handle list of Pydantic models (e.g., list[AgentAutonomous])
1331
1274
  yaml_lines.append(f"{field_name}:")
1332
1275
  # Convert each Pydantic model to dict
1333
1276
  model_dicts = [item.model_dump(exclude_none=True) for item in value]
@@ -1373,18 +1316,154 @@ class Agent(AgentCreate, AgentPublicInfo):
1373
1316
  return await db.scalar(select(func.count(AgentTable.id)))
1374
1317
 
1375
1318
  @classmethod
1376
- async def get(cls, agent_id: str) -> Optional["Agent"]:
1319
+ async def get(cls, agent_id: str) -> "Agent" | None:
1377
1320
  async with get_session() as db:
1378
1321
  item = await db.scalar(select(AgentTable).where(AgentTable.id == agent_id))
1379
1322
  if item is None:
1380
1323
  return None
1381
1324
  return cls.model_validate(item)
1382
1325
 
1383
- def skill_config(self, category: str) -> Dict[str, Any]:
1326
+ @classmethod
1327
+ async def get_by_id_or_slug(cls, agent_id: str) -> "Agent" | None:
1328
+ """Get agent by ID or slug.
1329
+
1330
+ First tries to get by ID if agent_id length <= 20,
1331
+ then falls back to searching by slug if not found.
1332
+
1333
+ Args:
1334
+ agent_id: Agent ID or slug to search for
1335
+
1336
+ Returns:
1337
+ Agent if found, None otherwise
1338
+ """
1339
+ async with get_session() as db:
1340
+ agent = None
1341
+
1342
+ # Try to get by ID if length <= 20
1343
+ if len(agent_id) <= 20:
1344
+ agent = await Agent.get(agent_id)
1345
+
1346
+ # If not found, try to get by slug
1347
+ if agent is None:
1348
+ slug_stmt = select(AgentTable).where(AgentTable.slug == agent_id)
1349
+ agent_row = await db.scalar(slug_stmt)
1350
+ if agent_row is not None:
1351
+ agent = Agent.model_validate(agent_row)
1352
+
1353
+ return agent
1354
+
1355
+ @staticmethod
1356
+ def _deserialize_autonomous(
1357
+ autonomous_data: list[Any] | None,
1358
+ ) -> list[AgentAutonomous]:
1359
+ if not autonomous_data:
1360
+ return []
1361
+
1362
+ deserialized: list[AgentAutonomous] = []
1363
+ for entry in autonomous_data:
1364
+ if isinstance(entry, AgentAutonomous):
1365
+ deserialized.append(entry)
1366
+ else:
1367
+ deserialized.append(AgentAutonomous.model_validate(entry))
1368
+ return deserialized
1369
+
1370
+ @staticmethod
1371
+ def _serialize_autonomous(tasks: list[AgentAutonomous]) -> list[dict[str, Any]]:
1372
+ return [task.model_dump() for task in tasks]
1373
+
1374
+ @staticmethod
1375
+ def _autonomous_not_allowed_error() -> IntentKitAPIError:
1376
+ return IntentKitAPIError(
1377
+ 400,
1378
+ "AgentNotDeployed",
1379
+ "Only deployed agents can call this feature.",
1380
+ )
1381
+
1382
+ async def list_autonomous_tasks(self) -> list[AgentAutonomous]:
1383
+ persisted = await Agent.get(self.id)
1384
+ if persisted is None:
1385
+ raise self._autonomous_not_allowed_error()
1386
+
1387
+ tasks = persisted.autonomous or []
1388
+ # Keep local state in sync with persisted data
1389
+ self.autonomous = tasks
1390
+ return tasks
1391
+
1392
+ async def add_autonomous_task(self, task: AgentAutonomous) -> AgentAutonomous:
1393
+ async with get_session() as session:
1394
+ db_agent = await session.get(AgentTable, self.id)
1395
+ if db_agent is None:
1396
+ raise self._autonomous_not_allowed_error()
1397
+
1398
+ current_tasks = self._deserialize_autonomous(db_agent.autonomous)
1399
+ current_tasks.append(task)
1400
+
1401
+ db_agent.autonomous = self._serialize_autonomous(current_tasks)
1402
+ await session.commit()
1403
+
1404
+ self.autonomous = current_tasks
1405
+ return task
1406
+
1407
+ async def delete_autonomous_task(self, task_id: str) -> None:
1408
+ async with get_session() as session:
1409
+ db_agent = await session.get(AgentTable, self.id)
1410
+ if db_agent is None:
1411
+ raise self._autonomous_not_allowed_error()
1412
+
1413
+ current_tasks = self._deserialize_autonomous(db_agent.autonomous)
1414
+
1415
+ updated_tasks = [task for task in current_tasks if task.id != task_id]
1416
+ if len(updated_tasks) == len(current_tasks):
1417
+ raise IntentKitAPIError(
1418
+ 404,
1419
+ "TaskNotFound",
1420
+ f"Autonomous task with ID {task_id} not found.",
1421
+ )
1422
+
1423
+ db_agent.autonomous = self._serialize_autonomous(updated_tasks)
1424
+ await session.commit()
1425
+
1426
+ self.autonomous = updated_tasks
1427
+
1428
+ async def update_autonomous_task(
1429
+ self, task_id: str, task_updates: dict
1430
+ ) -> AgentAutonomous:
1431
+ async with get_session() as session:
1432
+ db_agent = await session.get(AgentTable, self.id)
1433
+ if db_agent is None:
1434
+ raise self._autonomous_not_allowed_error()
1435
+
1436
+ current_tasks = self._deserialize_autonomous(db_agent.autonomous)
1437
+
1438
+ updated_task: AgentAutonomous | None = None
1439
+ rewritten_tasks: list[AgentAutonomous] = []
1440
+ for task in current_tasks:
1441
+ if task.id == task_id:
1442
+ task_dict = task.model_dump()
1443
+ task_dict.update(task_updates)
1444
+ updated_task = AgentAutonomous.model_validate(task_dict)
1445
+ rewritten_tasks.append(updated_task)
1446
+ else:
1447
+ rewritten_tasks.append(task)
1448
+
1449
+ if updated_task is None:
1450
+ raise IntentKitAPIError(
1451
+ 404,
1452
+ "TaskNotFound",
1453
+ f"Autonomous task with ID {task_id} not found.",
1454
+ )
1455
+
1456
+ db_agent.autonomous = self._serialize_autonomous(rewritten_tasks)
1457
+ await session.commit()
1458
+
1459
+ self.autonomous = rewritten_tasks
1460
+ return updated_task
1461
+
1462
+ def skill_config(self, category: str) -> dict[str, Any]:
1384
1463
  return self.skills.get(category, {}) if self.skills else {}
1385
1464
 
1386
1465
  @staticmethod
1387
- def _is_agent_owner_only_skill(skill_schema: Dict[str, Any]) -> bool:
1466
+ def _is_agent_owner_only_skill(skill_schema: dict[str, Any]) -> bool:
1388
1467
  """Check if a skill requires agent owner API keys only based on its resolved schema."""
1389
1468
  if (
1390
1469
  skill_schema
@@ -1403,7 +1482,7 @@ class Agent(AgentCreate, AgentPublicInfo):
1403
1482
  cls,
1404
1483
  db: AsyncSession = None,
1405
1484
  filter_owner_api_skills: bool = False,
1406
- ) -> Dict:
1485
+ ) -> dict:
1407
1486
  """Get the JSON schema for Agent model with all $ref references resolved.
1408
1487
 
1409
1488
  This is the shared function that handles admin configuration filtering
@@ -1591,34 +1670,35 @@ class AgentResponse(Agent):
1591
1670
  )
1592
1671
 
1593
1672
  # Override privacy fields to exclude them from JSON schema
1594
- purpose: SkipJsonSchema[Optional[str]] = None
1595
- personality: SkipJsonSchema[Optional[str]] = None
1596
- principles: SkipJsonSchema[Optional[str]] = None
1597
- prompt: SkipJsonSchema[Optional[str]] = None
1598
- prompt_append: SkipJsonSchema[Optional[str]] = None
1599
- temperature: SkipJsonSchema[Optional[float]] = None
1600
- frequency_penalty: SkipJsonSchema[Optional[float]] = None
1601
- telegram_entrypoint_prompt: SkipJsonSchema[Optional[str]] = None
1602
- telegram_config: SkipJsonSchema[Optional[dict]] = None
1603
- xmtp_entrypoint_prompt: SkipJsonSchema[Optional[str]] = None
1673
+ purpose: SkipJsonSchema[str | None] = None
1674
+ personality: SkipJsonSchema[str | None] = None
1675
+ principles: SkipJsonSchema[str | None] = None
1676
+ prompt: SkipJsonSchema[str | None] = None
1677
+ prompt_append: SkipJsonSchema[str | None] = None
1678
+ temperature: SkipJsonSchema[float | None] = None
1679
+ frequency_penalty: SkipJsonSchema[float | None] = None
1680
+ telegram_entrypoint_prompt: SkipJsonSchema[str | None] = None
1681
+ telegram_config: SkipJsonSchema[dict | None] = None
1682
+ discord_config: SkipJsonSchema[dict | None] = None
1683
+ xmtp_entrypoint_prompt: SkipJsonSchema[str | None] = None
1604
1684
 
1605
1685
  # Additional fields specific to AgentResponse
1606
1686
  cdp_wallet_address: Annotated[
1607
- Optional[str],
1687
+ str | None,
1608
1688
  PydanticField(
1609
1689
  default=None,
1610
1690
  description="CDP wallet address of the agent",
1611
1691
  ),
1612
1692
  ]
1613
1693
  evm_wallet_address: Annotated[
1614
- Optional[str],
1694
+ str | None,
1615
1695
  PydanticField(
1616
1696
  default=None,
1617
1697
  description="EVM wallet address of the agent",
1618
1698
  ),
1619
1699
  ]
1620
1700
  solana_wallet_address: Annotated[
1621
- Optional[str],
1701
+ str | None,
1622
1702
  PydanticField(
1623
1703
  default=None,
1624
1704
  description="Solana wallet address of the agent",
@@ -1632,14 +1712,14 @@ class AgentResponse(Agent):
1632
1712
  ),
1633
1713
  ]
1634
1714
  linked_twitter_username: Annotated[
1635
- Optional[str],
1715
+ str | None,
1636
1716
  PydanticField(
1637
1717
  default=None,
1638
1718
  description="Linked Twitter username",
1639
1719
  ),
1640
1720
  ]
1641
1721
  linked_twitter_name: Annotated[
1642
- Optional[str],
1722
+ str | None,
1643
1723
  PydanticField(
1644
1724
  default=None,
1645
1725
  description="Linked Twitter display name",
@@ -1660,14 +1740,14 @@ class AgentResponse(Agent):
1660
1740
  ),
1661
1741
  ]
1662
1742
  linked_telegram_username: Annotated[
1663
- Optional[str],
1743
+ str | None,
1664
1744
  PydanticField(
1665
1745
  default=None,
1666
1746
  description="Linked Telegram username",
1667
1747
  ),
1668
1748
  ]
1669
1749
  linked_telegram_name: Annotated[
1670
- Optional[str],
1750
+ str | None,
1671
1751
  PydanticField(
1672
1752
  default=None,
1673
1753
  description="Linked Telegram display name",
@@ -1706,7 +1786,7 @@ class AgentResponse(Agent):
1706
1786
 
1707
1787
  @classmethod
1708
1788
  async def from_agent(
1709
- cls, agent: Agent, agent_data: Optional[AgentData] = None
1789
+ cls, agent: Agent, agent_data: AgentData | None = None
1710
1790
  ) -> "AgentResponse":
1711
1791
  """Create an AgentResponse from an Agent instance.
1712
1792
 
@@ -1731,8 +1811,7 @@ class AgentResponse(Agent):
1731
1811
  linked_twitter_name = agent_data.twitter_name
1732
1812
  if agent_data.twitter_access_token_expires_at:
1733
1813
  has_twitter_linked = (
1734
- agent_data.twitter_access_token_expires_at
1735
- > datetime.now(timezone.utc)
1814
+ agent_data.twitter_access_token_expires_at > datetime.now(UTC)
1736
1815
  )
1737
1816
  else:
1738
1817
  has_twitter_linked = True
@@ -1823,6 +1902,7 @@ class AgentResponse(Agent):
1823
1902
  "frequency_penalty",
1824
1903
  "telegram_entrypoint_prompt",
1825
1904
  "telegram_config",
1905
+ "discord_config",
1826
1906
  "xmtp_entrypoint_prompt",
1827
1907
  }
1828
1908
  for field in privacy_fields: