intentkit 0.7.5.dev23__py3-none-any.whl → 0.7.5.dev25__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.7.5-dev23"
6
+ __version__ = "0.7.5-dev25"
7
7
  __author__ = "hyacinthus"
8
8
  __email__ = "hyacinthus@gmail.com"
9
9
 
@@ -34,6 +34,8 @@ class AgentContext(BaseModel):
34
34
  app_id: Optional[str] = None
35
35
  entrypoint: AuthorType
36
36
  is_private: bool
37
+ search: bool = False
38
+ thinking: bool = False
37
39
  payer: Optional[str] = None
38
40
 
39
41
  @property
@@ -1,4 +1,4 @@
1
- from intentkit.clients.cdp import CdpClient, get_cdp_client
1
+ from intentkit.clients.cdp import get_origin_cdp_client, get_wallet_provider
2
2
  from intentkit.clients.twitter import (
3
3
  TwitterClient,
4
4
  TwitterClientConfig,
@@ -10,7 +10,7 @@ __all__ = [
10
10
  "TwitterClient",
11
11
  "TwitterClientConfig",
12
12
  "get_twitter_client",
13
- "CdpClient",
14
- "get_cdp_client",
13
+ "get_origin_cdp_client",
14
+ "get_wallet_provider",
15
15
  "get_web3_client",
16
16
  ]
intentkit/clients/cdp.py CHANGED
@@ -1,11 +1,10 @@
1
1
  import asyncio
2
2
  import json
3
3
  import logging
4
- from typing import Dict, Optional
4
+ from typing import Dict, Optional, Tuple
5
5
 
6
6
  from bip32 import BIP32
7
7
  from cdp import CdpClient as OriginCdpClient # noqa: E402
8
- from cdp import EvmServerAccount # noqa: E402
9
8
  from coinbase_agentkit import ( # noqa: E402
10
9
  CdpEvmWalletProvider,
11
10
  CdpEvmWalletProviderConfig,
@@ -13,11 +12,12 @@ from coinbase_agentkit import ( # noqa: E402
13
12
  from eth_keys.datatypes import PrivateKey
14
13
  from eth_utils import to_checksum_address
15
14
 
16
- from intentkit.abstracts.skill import SkillStoreABC # noqa: E402
15
+ from intentkit.config.config import config
17
16
  from intentkit.models.agent import Agent # noqa: E402
18
- from intentkit.models.agent_data import AgentData # noqa: E402
17
+ from intentkit.models.agent_data import AgentData
18
+ from intentkit.utils.error import IntentKitAPIError # noqa: E402
19
19
 
20
- _clients: Dict[str, "CdpClient"] = {}
20
+ _wallet_providers: Dict[str, Tuple[str, str, CdpEvmWalletProvider]] = {}
21
21
  _origin_cdp_client: Optional[OriginCdpClient] = None
22
22
 
23
23
  logger = logging.getLogger(__name__)
@@ -58,15 +58,15 @@ def bip39_seed_to_eth_keys(seed_hex: str) -> Dict[str, str]:
58
58
  }
59
59
 
60
60
 
61
- def get_origin_cdp_client(skill_store: SkillStoreABC) -> OriginCdpClient:
61
+ def get_origin_cdp_client() -> OriginCdpClient:
62
62
  global _origin_cdp_client
63
63
  if _origin_cdp_client:
64
64
  return _origin_cdp_client
65
65
 
66
- # Get credentials from skill store system config
67
- api_key_id = skill_store.get_system_config("cdp_api_key_id")
68
- api_key_secret = skill_store.get_system_config("cdp_api_key_secret")
69
- wallet_secret = skill_store.get_system_config("cdp_wallet_secret")
66
+ # Get credentials from global configuration
67
+ api_key_id = config.cdp_api_key_id
68
+ api_key_secret = config.cdp_api_key_secret
69
+ wallet_secret = config.cdp_wallet_secret
70
70
 
71
71
  _origin_cdp_client = OriginCdpClient(
72
72
  api_key_id=api_key_id,
@@ -76,96 +76,84 @@ def get_origin_cdp_client(skill_store: SkillStoreABC) -> OriginCdpClient:
76
76
  return _origin_cdp_client
77
77
 
78
78
 
79
- class CdpClient:
80
- def __init__(self, agent_id: str, skill_store: SkillStoreABC) -> None:
81
- self._agent_id = agent_id
82
- self._skill_store = skill_store
83
- self._wallet_provider: Optional[CdpEvmWalletProvider] = None
84
- self._wallet_provider_config: Optional[CdpEvmWalletProviderConfig] = None
85
-
86
- async def get_wallet_provider(self) -> CdpEvmWalletProvider:
87
- if self._wallet_provider:
88
- return self._wallet_provider
89
- agent: Agent = await self._skill_store.get_agent_config(self._agent_id)
90
- agent_data: AgentData = await self._skill_store.get_agent_data(self._agent_id)
91
- network_id = agent.network_id
79
+ async def get_wallet_provider(agent: Agent) -> CdpEvmWalletProvider:
80
+ if agent.wallet_provider != "cdp":
81
+ raise IntentKitAPIError(
82
+ 400,
83
+ "BadWalletProvider",
84
+ "Your agent wallet provider is not cdp but you selected a skill that requires a cdp wallet.",
85
+ )
92
86
 
93
- # Get credentials from skill store system config
94
- api_key_id = self._skill_store.get_system_config("cdp_api_key_id")
95
- api_key_secret = self._skill_store.get_system_config("cdp_api_key_secret")
96
- wallet_secret = self._skill_store.get_system_config("cdp_wallet_secret")
87
+ if not agent.network_id:
88
+ raise IntentKitAPIError(
89
+ 400,
90
+ "BadNetworkID",
91
+ "Your agent network ID is not set. Please set it in the agent config.",
92
+ )
97
93
 
98
- # already have address
99
- address = agent_data.evm_wallet_address
94
+ agent_data = await AgentData.get(agent.id)
95
+ address = agent_data.evm_wallet_address
100
96
 
101
- # new agent or address not migrated yet
102
- if not address:
103
- # create cdp client for later use
104
- cdp_client = get_origin_cdp_client(self._skill_store)
105
- # try migrating from v1 cdp_wallet_data
106
- if agent_data.cdp_wallet_data:
107
- wallet_data = json.loads(agent_data.cdp_wallet_data)
108
- if not isinstance(wallet_data, dict):
109
- raise ValueError("Invalid wallet data format")
110
- if wallet_data.get("default_address_id") and wallet_data.get("seed"):
111
- # verify seed and convert to pk
112
- keys = bip39_seed_to_eth_keys(wallet_data["seed"])
113
- if keys["address"] != wallet_data["default_address_id"]:
114
- raise ValueError(
115
- "Bad wallet data, seed does not match default_address_id"
116
- )
117
- # try to import wallet to v2
118
- logger.info("Migrating wallet data to v2...")
119
- await cdp_client.evm.import_account(
120
- name=agent.id,
121
- private_key=keys["private_key"],
122
- )
123
- address = keys["address"]
124
- logger.info("Migrated wallet data to v2 successfully: %s", address)
125
- # still not address
97
+ cache_entry = _wallet_providers.get(agent.id)
98
+ if cache_entry:
99
+ cached_network_id, cached_address, provider = cache_entry
100
+ if cached_network_id == agent.network_id:
126
101
  if not address:
127
- logger.info("Creating new wallet...")
128
- new_account = await cdp_client.evm.create_account(
102
+ address = cached_address or provider.get_address()
103
+ if cached_address == address:
104
+ return provider
105
+
106
+ # Get credentials from global config
107
+ api_key_id = config.cdp_api_key_id
108
+ api_key_secret = config.cdp_api_key_secret
109
+ wallet_secret = config.cdp_wallet_secret
110
+
111
+ network_id = agent.network_id
112
+
113
+ # new agent or address not migrated yet
114
+ if not address:
115
+ cdp_client = get_origin_cdp_client()
116
+ # try migrating from v1 cdp_wallet_data
117
+ if agent_data.cdp_wallet_data:
118
+ wallet_data = json.loads(agent_data.cdp_wallet_data)
119
+ if not isinstance(wallet_data, dict):
120
+ raise ValueError("Invalid wallet data format")
121
+ if wallet_data.get("default_address_id") and wallet_data.get("seed"):
122
+ # verify seed and convert to pk
123
+ keys = bip39_seed_to_eth_keys(wallet_data["seed"])
124
+ if keys["address"] != wallet_data["default_address_id"]:
125
+ raise ValueError(
126
+ "Bad wallet data, seed does not match default_address_id"
127
+ )
128
+ # try to import wallet to v2
129
+ logger.info("Migrating wallet data to v2...")
130
+ await cdp_client.evm.import_account(
129
131
  name=agent.id,
132
+ private_key=keys["private_key"],
130
133
  )
131
- address = new_account.address
132
- logger.info("Created new wallet: %s", address)
133
-
134
- # do not close cached global client
135
- # now it should be created or migrated, store it
136
- agent_data.evm_wallet_address = address
137
- await agent_data.save()
138
-
139
- # it must have v2 account now, load agentkit wallet provider
140
- self._wallet_provider_config = CdpEvmWalletProviderConfig(
141
- api_key_id=api_key_id,
142
- api_key_secret=api_key_secret,
143
- network_id=network_id,
144
- address=address,
145
- wallet_secret=wallet_secret,
146
- )
147
- self._wallet_provider = await asyncio.to_thread(
148
- CdpEvmWalletProvider, self._wallet_provider_config
149
- )
150
- return self._wallet_provider
151
-
152
- async def get_account(self) -> EvmServerAccount:
153
- """Get the account object from the wallet provider.
154
-
155
- Returns:
156
- EvmServerAccount: The account object that can be used for balance checks, transfers, etc.
157
- """
158
- wallet_provider = await self.get_wallet_provider()
159
- # Access the internal account object
160
- return wallet_provider._account
161
-
162
- async def get_provider_config(self) -> CdpEvmWalletProviderConfig:
163
- if not self._wallet_provider_config:
164
- await self.get_wallet_provider()
165
- return self._wallet_provider_config
134
+ address = keys["address"]
135
+ logger.info("Migrated wallet data to v2 successfully: %s", address)
136
+ # still not address
137
+ if not address:
138
+ logger.info("Creating new wallet...")
139
+ new_account = await cdp_client.evm.create_account(
140
+ name=agent.id,
141
+ )
142
+ address = new_account.address
143
+ logger.info("Created new wallet: %s", address)
166
144
 
145
+ agent_data.evm_wallet_address = address
146
+ await agent_data.save()
167
147
 
168
- async def get_cdp_client(agent_id: str, skill_store: SkillStoreABC) -> "CdpClient":
169
- if agent_id not in _clients:
170
- _clients[agent_id] = CdpClient(agent_id, skill_store)
171
- return _clients[agent_id]
148
+ wallet_provider_config = CdpEvmWalletProviderConfig(
149
+ api_key_id=api_key_id,
150
+ api_key_secret=api_key_secret,
151
+ network_id=network_id,
152
+ address=address,
153
+ wallet_secret=wallet_secret,
154
+ )
155
+ wallet_provider = await asyncio.to_thread(
156
+ CdpEvmWalletProvider, wallet_provider_config
157
+ )
158
+ _wallet_providers[agent.id] = (network_id, address, wallet_provider)
159
+ return wallet_provider
intentkit/core/agent.py CHANGED
@@ -7,7 +7,7 @@ from typing import Any, Dict, List, Optional, Tuple
7
7
  from sqlalchemy import func, select, text, update
8
8
 
9
9
  from intentkit.abstracts.skill import SkillStoreABC
10
- from intentkit.clients.cdp import get_cdp_client
10
+ from intentkit.clients.cdp import get_wallet_provider
11
11
  from intentkit.config.config import config
12
12
  from intentkit.models.agent import (
13
13
  Agent,
@@ -73,8 +73,7 @@ async def process_agent_wallet(
73
73
 
74
74
  # 4. Initialize wallet based on provider type
75
75
  if config.cdp_api_key_id and current_wallet_provider == "cdp":
76
- cdp_client = await get_cdp_client(agent.id, agent_store)
77
- await cdp_client.get_wallet_provider()
76
+ await get_wallet_provider(agent)
78
77
  agent_data = await AgentData.get(agent.id)
79
78
  elif current_wallet_provider == "readonly":
80
79
  agent_data = await AgentData.patch(
@@ -158,7 +157,7 @@ def send_agent_notification(agent: Agent, agent_data: AgentData, message: str) -
158
157
  {
159
158
  "title": "Network",
160
159
  "short": True,
161
- "value": agent.network_id or "Default",
160
+ "value": agent.network_id or "Not Set",
162
161
  },
163
162
  {
164
163
  "title": "X Username",
intentkit/core/engine.py CHANGED
@@ -96,12 +96,6 @@ async def build_agent(agent: Agent, agent_data: AgentData) -> CompiledStateGraph
96
96
  presence_penalty=agent.presence_penalty,
97
97
  )
98
98
 
99
- # Get the LLM instance
100
- llm = await llm_model.create_instance(config)
101
-
102
- # Get the token limit from the model info
103
- input_token_limit = min(config.input_token_limit, llm_model.info.context_length)
104
-
105
99
  # ==== Store buffered conversation history in memory.
106
100
  memory = get_langgraph_checkpointer()
107
101
 
@@ -118,13 +112,13 @@ async def build_agent(agent: Agent, agent_data: AgentData) -> CompiledStateGraph
118
112
  if hasattr(skill_module, "get_skills"):
119
113
  # all
120
114
  skill_tools = await skill_module.get_skills(
121
- v, False, agent_store, agent_id=agent.id
115
+ v, False, agent_store, agent_id=agent.id, agent=agent
122
116
  )
123
117
  if skill_tools and len(skill_tools) > 0:
124
118
  tools.extend(skill_tools)
125
119
  # private
126
120
  skill_private_tools = await skill_module.get_skills(
127
- v, True, agent_store, agent_id=agent.id
121
+ v, True, agent_store, agent_id=agent.id, agent=agent
128
122
  )
129
123
  if skill_private_tools and len(skill_private_tools) > 0:
130
124
  private_tools.extend(skill_private_tools)
@@ -137,24 +131,27 @@ async def build_agent(agent: Agent, agent_data: AgentData) -> CompiledStateGraph
137
131
  tools = list({tool.name: tool for tool in tools}.values())
138
132
  private_tools = list({tool.name: tool for tool in private_tools}.values())
139
133
 
140
- # Add search tools if requested
141
- if (
142
- llm_model.info.provider == LLMProvider.OPENAI and llm_model.info.supports_search
143
- # and not agent.model.startswith(
144
- # "gpt-5"
145
- # ) # tmp disable gpt-5 search since package bugs
146
- ):
147
- tools.append({"type": "web_search"})
148
- private_tools.append({"type": "web_search"})
149
-
150
134
  # Create the formatted_prompt function using the refactored prompt module
151
135
  formatted_prompt = create_formatted_prompt_function(agent, agent_data)
152
136
 
153
137
  # bind tools to llm
154
- def select_model(
138
+ async def select_model(
155
139
  state: AgentState, runtime: Runtime[AgentContext]
156
140
  ) -> BaseChatModel:
141
+ llm_params = {}
157
142
  context = runtime.context
143
+ if context.search:
144
+ if llm_model.info.supports_search:
145
+ if llm_model.info.provider == LLMProvider.OPENAI:
146
+ tools.append({"type": "web_search"})
147
+ private_tools.append({"type": "web_search"})
148
+ if agent.model.startswith("gpt-5-"):
149
+ llm_params["reasoning_effort"] = "low"
150
+ if llm_model.info.provider == LLMProvider.XAI:
151
+ llm_params["search_parameters"] = {"mode": "auto"}
152
+ # TODO: else use a search skill
153
+ # build llm now
154
+ llm = await llm_model.create_instance(llm_params)
158
155
  if context.is_private:
159
156
  return llm.bind_tools(private_tools)
160
157
  return llm.bind_tools(tools)
@@ -165,10 +162,12 @@ async def build_agent(agent: Agent, agent_data: AgentData) -> CompiledStateGraph
165
162
  )
166
163
 
167
164
  # Pre model hook
165
+ summarize_llm = await create_llm_model(model_name="gpt-5-mini")
166
+ summarize_model = await summarize_llm.create_instance()
168
167
  pre_model_hook = PreModelNode(
169
- model=llm,
168
+ model=summarize_model,
170
169
  short_term_memory_strategy=agent.short_term_memory_strategy,
171
- max_tokens=input_token_limit // 2,
170
+ max_tokens=llm_model.info.context_length // 2,
172
171
  max_summary_tokens=2048,
173
172
  )
174
173
 
@@ -403,9 +402,11 @@ async def stream_agent_raw(
403
402
  input_message = re.sub(r"\b@super\b", "", input_message).strip()
404
403
 
405
404
  # llm native search
405
+ search = False
406
406
  if re.search(r"\b@search\b", input_message) or re.search(
407
407
  r"\b@web\b", input_message
408
408
  ):
409
+ search = True
409
410
  if model.supports_search:
410
411
  input_message = re.sub(
411
412
  r"\b@search\b",
@@ -467,6 +468,7 @@ async def stream_agent_raw(
467
468
  app_id=user_message.app_id,
468
469
  entrypoint=user_message.author_type,
469
470
  is_private=is_private,
471
+ search=search,
470
472
  payer=payer if payment_enabled else None,
471
473
  )
472
474
 
intentkit/core/node.py CHANGED
@@ -66,7 +66,7 @@ class PreModelNode(RunnableCallable):
66
66
  model: LanguageModelLike,
67
67
  short_term_memory_strategy: str,
68
68
  max_tokens: int,
69
- max_summary_tokens: int = 1024,
69
+ max_summary_tokens: int = 2048,
70
70
  ) -> None:
71
71
  super().__init__(self._func, self._afunc, name="pre_model_node", trace=False)
72
72
  self.model = model
intentkit/models/agent.py CHANGED
@@ -581,13 +581,13 @@ class AgentCore(BaseModel):
581
581
  wallet_provider: Annotated[
582
582
  Optional[Literal["cdp", "readonly"]],
583
583
  PydanticField(
584
- default="cdp",
584
+ default=None,
585
585
  description="Provider of the agent's wallet",
586
586
  json_schema_extra={
587
587
  "x-group": "onchain",
588
588
  },
589
589
  ),
590
- ] = "cdp"
590
+ ]
591
591
  readonly_wallet_address: Annotated[
592
592
  Optional[str],
593
593
  PydanticField(
@@ -598,12 +598,12 @@ class AgentCore(BaseModel):
598
598
  network_id: Annotated[
599
599
  Optional[
600
600
  Literal[
601
+ "base-mainnet",
602
+ "base-sepolia",
601
603
  "ethereum-mainnet",
602
604
  "ethereum-sepolia",
603
605
  "polygon-mainnet",
604
606
  "polygon-mumbai",
605
- "base-mainnet",
606
- "base-sepolia",
607
607
  "arbitrum-mainnet",
608
608
  "arbitrum-sepolia",
609
609
  "optimism-mainnet",
@@ -79,80 +79,11 @@
79
79
  "type": "string",
80
80
  "description": "Select the LLM for your agent. Note that each LLM has its specific advantages, behaviour and cost.",
81
81
  "default": "gpt-5-mini",
82
- "enum": [
83
- "gpt-5-nano",
84
- "gpt-5-mini",
85
- "gpt-5",
86
- "gpt-4.1-nano",
87
- "gpt-4.1-mini",
88
- "gpt-4.1",
89
- "gpt-4o",
90
- "gpt-4o-mini",
91
- "o3",
92
- "o4-mini",
93
- "deepseek-chat",
94
- "deepseek-reasoner",
95
- "grok-2",
96
- "grok-3",
97
- "grok-3-mini",
98
- "eternalai",
99
- "reigent",
100
- "venice-uncensored",
101
- "venice-llama-4-maverick-17b"
102
- ],
82
+ "enum": [],
103
83
  "x-component": "category-select",
104
- "x-enum-title": [
105
- "GPT-5 nano",
106
- "GPT-5 mini",
107
- "GPT-5",
108
- "GPT-4.1 nano",
109
- "GPT-4.1 mini",
110
- "GPT-4.1",
111
- "GPT-4o",
112
- "GPT-4o mini",
113
- "OpenAI o3",
114
- "OpenAI o4-mini",
115
- "Deepseek V3.1",
116
- "Deepseek V3.1 Thinking",
117
- "Grok 2",
118
- "Grok 3",
119
- "Grok 3 Mini"
120
- ],
121
- "x-enum-category": [
122
- "OpenAI",
123
- "OpenAI",
124
- "OpenAI",
125
- "OpenAI",
126
- "OpenAI",
127
- "OpenAI",
128
- "OpenAI",
129
- "OpenAI",
130
- "OpenAI",
131
- "OpenAI",
132
- "Deepseek",
133
- "Deepseek",
134
- "Grok",
135
- "Grok",
136
- "Grok"
137
- ],
138
- "x-support-skill": [
139
- true,
140
- true,
141
- true,
142
- true,
143
- true,
144
- true,
145
- true,
146
- true,
147
- true,
148
- true,
149
- true,
150
- true,
151
- true,
152
- true,
153
- true,
154
- true
155
- ],
84
+ "x-enum-title": [],
85
+ "x-enum-category": [],
86
+ "x-support-skill": [],
156
87
  "x-group": "llm"
157
88
  },
158
89
  "purpose": {
@@ -218,6 +149,17 @@
218
149
  "x-str-type": "prompt",
219
150
  "x-group": "llm"
220
151
  },
152
+ "short_term_memory_strategy": {
153
+ "title": "Short Term Memory Strategy",
154
+ "type": "string",
155
+ "description": "Strategy for managing short-term memory when context limit is reached. 'trim' removes oldest messages, 'summarize' creates summaries.",
156
+ "default": "trim",
157
+ "enum": [
158
+ "trim",
159
+ "summarize"
160
+ ],
161
+ "x-group": "llm"
162
+ },
221
163
  "temperature": {
222
164
  "title": "Temperature",
223
165
  "type": "number",
@@ -236,7 +178,8 @@
236
178
  "minimum": -2.0,
237
179
  "maximum": 2.0,
238
180
  "x-group": "llm",
239
- "x-step": 0.1
181
+ "x-step": 0.1,
182
+ "x-advanced": true
240
183
  },
241
184
  "presence_penalty": {
242
185
  "title": "Presence Penalty",
@@ -246,18 +189,8 @@
246
189
  "minimum": -2.0,
247
190
  "maximum": 2.0,
248
191
  "x-group": "llm",
249
- "x-step": 0.1
250
- },
251
- "short_term_memory_strategy": {
252
- "title": "Short Term Memory Strategy",
253
- "type": "string",
254
- "description": "Strategy for managing short-term memory when context limit is reached. 'trim' removes oldest messages, 'summarize' creates summaries.",
255
- "default": "trim",
256
- "enum": [
257
- "trim",
258
- "summarize"
259
- ],
260
- "x-group": "llm"
192
+ "x-step": 0.1,
193
+ "x-advanced": true
261
194
  },
262
195
  "telegram_entrypoint_enabled": {
263
196
  "title": "Enable Telegram Communication",
@@ -402,7 +335,6 @@
402
335
  "Coinbase Server Wallet V2",
403
336
  "Readonly Wallet"
404
337
  ],
405
- "default": "cdp",
406
338
  "x-group": "onchain"
407
339
  },
408
340
  "network_id": {