intentkit 0.6.0.dev16__py3-none-any.whl → 0.6.0.dev17__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 CHANGED
@@ -3,7 +3,7 @@
3
3
  A powerful platform for building AI agents with blockchain and cryptocurrency capabilities.
4
4
  """
5
5
 
6
- __version__ = "0.6.0-dev.16"
6
+ __version__ = "0.6.0-dev.17"
7
7
  __author__ = "hyacinthus"
8
8
  __email__ = "hyacinthus@gmail.com"
9
9
 
intentkit/clients/cdp.py CHANGED
@@ -2,11 +2,15 @@ import json
2
2
  import logging
3
3
  from typing import Dict, Optional
4
4
 
5
+ from bip32 import BIP32
6
+ from cdp import CdpClient as OriginCdpClient
5
7
  from cdp import EvmServerAccount
6
8
  from coinbase_agentkit import (
7
9
  CdpEvmServerWalletProvider,
8
10
  CdpEvmServerWalletProviderConfig,
9
11
  )
12
+ from eth_keys.datatypes import PrivateKey
13
+ from eth_utils import to_checksum_address
10
14
 
11
15
  from intentkit.abstracts.skill import SkillStoreABC
12
16
  from intentkit.models.agent import Agent
@@ -14,6 +18,43 @@ from intentkit.models.agent_data import AgentData
14
18
 
15
19
  _clients: Dict[str, "CdpClient"] = {}
16
20
 
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ def bip39_seed_to_eth_keys(seed_hex: str) -> Dict[str, str]:
25
+ """
26
+ Converts a BIP39 seed to an Ethereum private key, public key, and address.
27
+
28
+ Args:
29
+ seed_hex: The BIP39 seed in hexadecimal format
30
+
31
+ Returns:
32
+ Dict containing private_key, public_key, and address
33
+ """
34
+ # Convert the hex seed to bytes
35
+ seed_bytes = bytes.fromhex(seed_hex)
36
+
37
+ # Derive the master key from the seed
38
+ bip32 = BIP32.from_seed(seed_bytes)
39
+
40
+ # Derive the Ethereum address using the standard derivation path
41
+ private_key_bytes = bip32.get_privkey_from_path("m/44'/60'/0'/0/0")
42
+
43
+ # Create a private key object
44
+ private_key = PrivateKey(private_key_bytes)
45
+
46
+ # Get the public key
47
+ public_key = private_key.public_key
48
+
49
+ # Get the Ethereum address
50
+ address = public_key.to_address()
51
+
52
+ return {
53
+ "private_key": private_key.to_hex(),
54
+ "public_key": public_key.to_hex(),
55
+ "address": to_checksum_address(address),
56
+ }
57
+
17
58
 
18
59
  class CdpClient:
19
60
  def __init__(self, agent_id: str, skill_store: SkillStoreABC) -> None:
@@ -29,37 +70,55 @@ class CdpClient:
29
70
  agent_data: AgentData = await self._skill_store.get_agent_data(self._agent_id)
30
71
  network_id = agent.network_id or agent.cdp_network_id
31
72
 
32
- logger = logging.getLogger(__name__)
33
-
34
73
  # Get credentials from skill store system config
35
74
  api_key_id = self._skill_store.get_system_config("cdp_api_key_id")
36
75
  api_key_secret = self._skill_store.get_system_config("cdp_api_key_secret")
37
76
  wallet_secret = self._skill_store.get_system_config("cdp_wallet_secret")
38
77
 
39
- address = None
40
-
41
- # Attempt to override with any wallet-specific secret stored in wallet_data
42
- if agent_data.cdp_wallet_data:
43
- try:
78
+ # already have address
79
+ address = agent_data.evm_wallet_address
80
+
81
+ # new agent or address not migrated yet
82
+ if not address:
83
+ # create cdp client for later use
84
+ cdp_client = OriginCdpClient(
85
+ api_key_id=api_key_id,
86
+ api_key_secret=api_key_secret,
87
+ wallet_secret=wallet_secret,
88
+ )
89
+ # try migrating from v1 cdp_wallet_data
90
+ if agent_data.cdp_wallet_data:
44
91
  wallet_data = json.loads(agent_data.cdp_wallet_data)
45
- # Try to get address from the new format or fallback to old format
46
- if "default_address_id" in wallet_data:
47
- address = wallet_data["default_address_id"]
48
-
49
- # Prefer wallet_secret stored alongside the wallet data if present
50
- if "wallet_secret" in wallet_data:
51
- wallet_secret = wallet_data["wallet_secret"]
52
- elif "account_data" in wallet_data and wallet_data["account_data"]:
53
- # Some versions may nest the secret inside account_data
54
- wallet_secret = (
55
- wallet_data["account_data"].get("wallet_secret")
56
- or wallet_secret
92
+ if not isinstance(wallet_data, dict):
93
+ raise ValueError("Invalid wallet data format")
94
+ if wallet_data.get("default_address_id") and wallet_data.get("seed"):
95
+ # verify seed and convert to pk
96
+ keys = bip39_seed_to_eth_keys(wallet_data["seed"])
97
+ if keys["address"] != wallet_data["default_address_id"]:
98
+ raise ValueError(
99
+ "Bad wallet data, seed does not match default_address_id"
100
+ )
101
+ # try to import wallet to v2
102
+ logger.info("Migrating wallet data to v2...")
103
+ await cdp_client.evm.import_account(
104
+ name=agent.id,
105
+ private_key=keys["private_key"],
57
106
  )
58
- except json.JSONDecodeError:
59
- logger.warning(
60
- "Invalid JSON in cdp_wallet_data for agent %s", self._agent_id
107
+ address = keys["address"]
108
+ logger.info("Migrated wallet data to v2 successfully: %s", address)
109
+ # still not address
110
+ if not address:
111
+ logger.info("Creating new wallet...")
112
+ new_account = await cdp_client.evm.create_account(
113
+ name=agent.id,
61
114
  )
115
+ address = new_account.address
116
+ logger.info("Created new wallet: %s", address)
117
+ # now it should be created or migrated, store it
118
+ agent_data.evm_wallet_address = address
119
+ await agent_data.save()
62
120
 
121
+ # it must have v2 account now, load agentkit wallet provider
63
122
  self._wallet_provider_config = CdpEvmServerWalletProviderConfig(
64
123
  api_key_id=api_key_id,
65
124
  api_key_secret=api_key_secret,
intentkit/core/prompt.py CHANGED
@@ -1,5 +1,3 @@
1
- import json
2
-
3
1
  from intentkit.config.config import config
4
2
  from intentkit.models.agent import Agent
5
3
  from intentkit.models.agent_data import AgentData
@@ -34,10 +32,11 @@ def agent_prompt(agent: Agent, agent_data: AgentData) -> str:
34
32
  if agent_data.telegram_name:
35
33
  prompt += f"Your telegram bot name is {agent_data.telegram_name}.\n"
36
34
  # CDP
37
- if agent_data.cdp_wallet_data:
38
- network_id = agent.network_id or agent.cdp_network_id
39
- wallet_data = json.loads(agent_data.cdp_wallet_data)
40
- prompt += f"Your wallet address in {network_id} is {wallet_data['default_address_id']} .\n"
35
+ network_id = agent.network_id or agent.cdp_network_id
36
+ if agent_data.evm_wallet_address and network_id != "solana":
37
+ prompt += f"Your wallet address in {network_id} is {agent_data.evm_wallet_address} .\n"
38
+ if agent_data.solana_wallet_address and network_id == "solana":
39
+ prompt += f"Your wallet address in {network_id} is {agent_data.solana_wallet_address} .\n"
41
40
  prompt += "\n"
42
41
  if agent.purpose:
43
42
  prompt += f"## Purpose\n\n{agent.purpose}\n\n"
intentkit/models/agent.py CHANGED
@@ -1564,7 +1564,6 @@ class AgentResponse(BaseModel):
1564
1564
  str: ETag value for the agent
1565
1565
  """
1566
1566
  import hashlib
1567
- import json
1568
1567
 
1569
1568
  # Generate hash from the entire object data using json mode to handle datetime objects
1570
1569
  # Sort keys to ensure consistent ordering of dictionary keys
@@ -1622,13 +1621,7 @@ class AgentResponse(BaseModel):
1622
1621
  data["skills"] = filtered_skills
1623
1622
 
1624
1623
  # Process CDP wallet address
1625
- cdp_wallet_address = None
1626
- if agent_data and agent_data.cdp_wallet_data:
1627
- try:
1628
- wallet_data = json.loads(agent_data.cdp_wallet_data)
1629
- cdp_wallet_address = wallet_data.get("default_address_id")
1630
- except (json.JSONDecodeError, AttributeError):
1631
- pass
1624
+ cdp_wallet_address = agent_data.evm_wallet_address if agent_data else None
1632
1625
 
1633
1626
  # Process Twitter linked status
1634
1627
  has_twitter_linked = False
@@ -29,6 +29,10 @@ class AgentDataTable(Base):
29
29
  __tablename__ = "agent_data"
30
30
 
31
31
  id = Column(String, primary_key=True, comment="Same as Agent.id")
32
+ evm_wallet_address = Column(String, nullable=True, comment="EVM wallet address")
33
+ solana_wallet_address = Column(
34
+ String, nullable=True, comment="Solana wallet address"
35
+ )
32
36
  cdp_wallet_data = Column(String, nullable=True, comment="CDP wallet data")
33
37
  crossmint_wallet_data = Column(
34
38
  JSON().with_variant(JSONB(), "postgresql"),
@@ -94,6 +98,20 @@ class AgentData(BaseModel):
94
98
  description="Same as Agent.id",
95
99
  ),
96
100
  ]
101
+ evm_wallet_address: Annotated[
102
+ Optional[str],
103
+ PydanticField(
104
+ default=None,
105
+ description="EVM wallet address",
106
+ ),
107
+ ]
108
+ solana_wallet_address: Annotated[
109
+ Optional[str],
110
+ PydanticField(
111
+ default=None,
112
+ description="Solana wallet address",
113
+ ),
114
+ ]
97
115
  cdp_wallet_data: Annotated[
98
116
  Optional[str],
99
117
  PydanticField(
@@ -25,9 +25,6 @@ from intentkit.skills.base import SkillConfig, SkillState
25
25
  from intentkit.skills.cdp.base import CDPBaseTool
26
26
  from intentkit.skills.cdp.get_balance import GetBalance
27
27
 
28
- # Cache skills at the system level, because they are stateless
29
- _cache: dict[str, CDPBaseTool] = {}
30
-
31
28
 
32
29
  class SkillStates(TypedDict):
33
30
  get_balance: SkillState
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: intentkit
3
- Version: 0.6.0.dev16
3
+ Version: 0.6.0.dev17
4
4
  Summary: Intent-based AI Agent Platform - Core Package
5
5
  Project-URL: Homepage, https://github.com/crestal-network/intentkit
6
6
  Project-URL: Repository, https://github.com/crestal-network/intentkit
@@ -1,4 +1,4 @@
1
- intentkit/__init__.py,sha256=hUWe3DJJ3b06wVI7VvqEEKBqFWh0FfoB-KjBqef10fM,385
1
+ intentkit/__init__.py,sha256=oMztmHNzrAOrgpnkdinwmAhTrI5tdiQ98QZm6WfZWGA,385
2
2
  intentkit/abstracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  intentkit/abstracts/agent.py,sha256=108gb5W8Q1Sy4G55F2_ZFv2-_CnY76qrBtpIr0Oxxqk,1489
4
4
  intentkit/abstracts/api.py,sha256=ZUc24vaQvQVbbjznx7bV0lbbQxdQPfEV8ZxM2R6wZWo,166
@@ -8,7 +8,7 @@ intentkit/abstracts/graph.py,sha256=QhaVLtKyo9iTotIWhjgUi7BbmRCcb8yrHCTSq4Hsvnw,
8
8
  intentkit/abstracts/skill.py,sha256=WS8G_XP0Ukw1eUB-dhbx6FrJUbvV4tqzRnkWa2dt9ck,3573
9
9
  intentkit/abstracts/twitter.py,sha256=cEtP7ygR_b-pHdc9i8kBuyooz1cPoGUGwsBHDpowJyY,1262
10
10
  intentkit/clients/__init__.py,sha256=sQ_6_bRC2MPWLPH-skQ3qsEe8ce-dUGL7i8VJOautHg,298
11
- intentkit/clients/cdp.py,sha256=9iK5t-zSITIWS-bdv1ymF-86FeblAh9QI9GjNP2Mg5Y,3783
11
+ intentkit/clients/cdp.py,sha256=P-JbnrATEJhczsgByhnioZEkYKsMvI6TtCqV8AszXHY,5856
12
12
  intentkit/clients/twitter.py,sha256=JAc-skIhZZjAFcwzLSTiOPOonteGjrl_JwXoA8IVBmI,16934
13
13
  intentkit/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  intentkit/config/config.py,sha256=6RreVvQH1xuHVOnIJ3AcaRYzdMw1RLo0vYYtvPKvTds,7453
@@ -19,10 +19,10 @@ intentkit/core/client.py,sha256=rIwtJVVm-7piXtFNDbeykt9vWdNTecgjW0aA3N-lHnM,1495
19
19
  intentkit/core/credit.py,sha256=fpRe8BRNGGaumAvJFgce1T2zkclExSFWQdoUVnl6k5g,60789
20
20
  intentkit/core/engine.py,sha256=ZoMk8fBUg1fqbELT8Pi8vB667ytFqAT4mQfUNt5g_H0,41192
21
21
  intentkit/core/node.py,sha256=30ivwRfVRBCMrzgzXlBKfkkobZVbpIon5E4cuavmvvA,9155
22
- intentkit/core/prompt.py,sha256=9jxRYUUqSdBj8bdmCUAa-5yTbiQFVInOJsDqbAuUcfo,3512
22
+ intentkit/core/prompt.py,sha256=RfLhlUktkB2kCr3wfldqq6ZP2l8heZIMc8jVp31KIyQ,3631
23
23
  intentkit/core/skill.py,sha256=fFM_HVc8Qam2zICb_dH3nRcInEXdtfgzFnL0vvMNz2Y,3830
24
- intentkit/models/agent.py,sha256=5amc4rjPHmZp7a4Z6chomDiFHaxgyr0Md5mKeI90jWQ,57487
25
- intentkit/models/agent_data.py,sha256=h__b3658ZOclV1Pwpp3UCCu0Nt49CKYfc2JZKG1dKeE,26929
24
+ intentkit/models/agent.py,sha256=I9wAsDqdfILpXsj5H0sE0fNwX-enzuEdEvmx-rWt_5E,57221
25
+ intentkit/models/agent_data.py,sha256=x3pYRpI0QUcaK09r0m8-06rSbQB4pKEymF5d9JCemlo,27465
26
26
  intentkit/models/agent_schema.json,sha256=M5MMMAVNJnp6kE8hjti6D0WLdFIGtIdF66_Cg6nZfJU,21724
27
27
  intentkit/models/app_setting.py,sha256=WgW-9t0EbiVemRLrVaC6evdfRU5QFSDK0elsnUU5nIo,5008
28
28
  intentkit/models/base.py,sha256=o-zRjVrak-f5Jokdvj8BjLm8gcC3yYiYMCTLegwT2lA,185
@@ -63,7 +63,7 @@ intentkit/skills/carv/fetch_news.py,sha256=-xCWPvdVQxI0tEynR8mnjNEFpDkE4k4vNo1A-
63
63
  intentkit/skills/carv/onchain_query.py,sha256=EYV7N2Y-CisyhNVyUm2NbJhdikeFg0Y_a6lToJ5iqDM,6371
64
64
  intentkit/skills/carv/schema.json,sha256=oSReeG50ZJTOxSRniQBJW6KfilscZfp66PiBVOjphS4,5021
65
65
  intentkit/skills/carv/token_info_and_price.py,sha256=R7M5-nkjrauvxaNkORYtLcP9yOYj8PvYu1xRkOBT6lU,4275
66
- intentkit/skills/cdp/__init__.py,sha256=wvPP3XfkHYddu2XlIeDKwLF_SteyX-MF1rFBsoqHKtw,4589
66
+ intentkit/skills/cdp/__init__.py,sha256=VTBCyycdxsrrUaM8OZIbJDkEXeLDVun5Lo5a8oBW6mg,4489
67
67
  intentkit/skills/cdp/base.py,sha256=BcleKSXm0oNcHYky4uUPCJ3roXxMeTJs2OUS-8MkfMI,581
68
68
  intentkit/skills/cdp/cdp.png,sha256=dxPF6jPbKVfxJNMvbGTmBhXM-rSDvweF06txoX1cIM4,4425
69
69
  intentkit/skills/cdp/get_balance.py,sha256=IAsU7mQAPSQqCbYQsokkklsqESEVl82VxMt8dEDJ6cM,4211
@@ -390,7 +390,7 @@ intentkit/utils/random.py,sha256=DymMxu9g0kuQLgJUqalvgksnIeLdS-v0aRk5nQU0mLI,452
390
390
  intentkit/utils/s3.py,sha256=9trQNkKQ5VgxWsewVsV8Y0q_pXzGRvsCYP8xauyUYkg,8549
391
391
  intentkit/utils/slack_alert.py,sha256=s7UpRgyzLW7Pbmt8cKzTJgMA9bm4EP-1rQ5KXayHu6E,2264
392
392
  intentkit/utils/tx.py,sha256=2yLLGuhvfBEY5n_GJ8wmIWLCzn0FsYKv5kRNzw_sLUI,1454
393
- intentkit-0.6.0.dev16.dist-info/METADATA,sha256=w1LdgxgEmc6a3V6c0DEnlOOgRStElpNRjhNUg_gcF2I,7286
394
- intentkit-0.6.0.dev16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
395
- intentkit-0.6.0.dev16.dist-info/licenses/LICENSE,sha256=Bln6DhK-LtcO4aXy-PBcdZv2f24MlJFm_qn222biJtE,1071
396
- intentkit-0.6.0.dev16.dist-info/RECORD,,
393
+ intentkit-0.6.0.dev17.dist-info/METADATA,sha256=ml-xJtWAndVheeiJIfeEz1QKhlerzjoBejx9CXcrK2w,7286
394
+ intentkit-0.6.0.dev17.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
395
+ intentkit-0.6.0.dev17.dist-info/licenses/LICENSE,sha256=Bln6DhK-LtcO4aXy-PBcdZv2f24MlJFm_qn222biJtE,1071
396
+ intentkit-0.6.0.dev17.dist-info/RECORD,,