intentkit 0.6.11.dev2__py3-none-any.whl → 0.6.11.dev3__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.11-dev2"
6
+ __version__ = "0.6.11-dev3"
7
7
  __author__ = "hyacinthus"
8
8
  __email__ = "hyacinthus@gmail.com"
9
9
 
intentkit/core/engine.py CHANGED
@@ -26,12 +26,10 @@ from langchain_core.messages import (
26
26
  BaseMessage,
27
27
  HumanMessage,
28
28
  )
29
- from langchain_core.prompts import ChatPromptTemplate
30
29
  from langchain_core.tools import BaseTool
31
30
  from langgraph.errors import GraphRecursionError
32
31
  from langgraph.graph.state import CompiledStateGraph
33
32
  from langgraph.prebuilt import create_react_agent
34
- from langgraph.runtime import Runtime
35
33
  from sqlalchemy import func, update
36
34
  from sqlalchemy.exc import SQLAlchemyError
37
35
 
@@ -39,7 +37,10 @@ from intentkit.abstracts.graph import AgentContext, AgentError, AgentState
39
37
  from intentkit.config.config import config
40
38
  from intentkit.core.credit import expense_message, expense_skill
41
39
  from intentkit.core.node import PreModelNode, post_model_node
42
- from intentkit.core.prompt import agent_prompt
40
+ from intentkit.core.prompt import (
41
+ create_formatted_prompt_function,
42
+ explain_prompt,
43
+ )
43
44
  from intentkit.core.skill import skill_store
44
45
  from intentkit.models.agent import Agent, AgentTable
45
46
  from intentkit.models.agent_data import AgentData, AgentQuota
@@ -53,51 +54,13 @@ from intentkit.models.chat import (
53
54
  from intentkit.models.credit import CreditAccount, OwnerType
54
55
  from intentkit.models.db import get_langgraph_checkpointer, get_session
55
56
  from intentkit.models.llm import LLMModelInfo, LLMProvider
56
- from intentkit.models.skill import AgentSkillData, Skill, ThreadSkillData
57
+ from intentkit.models.skill import AgentSkillData, ThreadSkillData
57
58
  from intentkit.models.user import User
58
59
  from intentkit.utils.error import IntentKitAPIError
59
60
 
60
61
  logger = logging.getLogger(__name__)
61
62
 
62
63
 
63
- async def explain_prompt(message: str) -> str:
64
- """
65
- Process message to replace @skill:*:* patterns with (call skill xxxxx) format.
66
-
67
- Args:
68
- message (str): The input message to process
69
-
70
- Returns:
71
- str: The processed message with @skill patterns replaced
72
- """
73
- # Pattern to match @skill:category:config_name with word boundaries
74
- pattern = r"\b@skill:([^:]+):([^\s]+)\b"
75
-
76
- async def replace_skill_pattern(match):
77
- category = match.group(1)
78
- config_name = match.group(2)
79
-
80
- # Get skill by category and config_name
81
- skill = await Skill.get_by_config_name(category, config_name)
82
-
83
- if skill:
84
- return f"(call skill {skill.name})"
85
- else:
86
- # If skill not found, keep original pattern
87
- return match.group(0)
88
-
89
- # Find all matches
90
- matches = list(re.finditer(pattern, message))
91
-
92
- # Process matches in reverse order to maintain string positions
93
- result = message
94
- for match in reversed(matches):
95
- replacement = await replace_skill_pattern(match)
96
- result = result[: match.start()] + replacement + result[match.end() :]
97
-
98
- return result
99
-
100
-
101
64
  # Global variable to cache all agent executors
102
65
  _agents: dict[str, CompiledStateGraph] = {}
103
66
  _private_agents: dict[str, CompiledStateGraph] = {}
@@ -176,106 +139,15 @@ async def create_agent(
176
139
  has_search
177
140
  and llm_model.info.provider == LLMProvider.OPENAI
178
141
  and llm_model.info.supports_search
142
+ and not agent.model.contains(
143
+ "gpt-5"
144
+ ) # tmp disable gpt-5 search since package bugs
179
145
  ):
180
146
  tools.append({"type": "web_search_preview"})
181
147
 
182
- # finally, set up the system prompt
183
- prompt = agent_prompt(agent, agent_data)
184
- # Escape curly braces in the prompt
185
- escaped_prompt = prompt.replace("{", "{{").replace("}", "}}")
186
- # Process message to handle @skill patterns
187
- if config.admin_llm_skill_control:
188
- escaped_prompt = await explain_prompt(escaped_prompt)
189
- prompt_array = [
190
- ("placeholder", "{system_prompt}"),
191
- ("placeholder", "{messages}"),
192
- ]
193
- if agent.prompt_append:
194
- # Escape any curly braces in prompt_append
195
- escaped_append = agent.prompt_append.replace("{", "{{").replace("}", "}}")
196
- # Process message to handle @skill patterns
197
- if config.admin_llm_skill_control:
198
- escaped_append = await explain_prompt(escaped_append)
199
- prompt_array.append(("system", escaped_append))
200
-
201
- prompt_temp = ChatPromptTemplate.from_messages(prompt_array)
202
-
203
- async def formatted_prompt(
204
- state: AgentState, runtime: Runtime[AgentContext]
205
- ) -> list[BaseMessage]:
206
- final_system_prompt = escaped_prompt
207
- context = runtime.context
208
- logger.debug(f"formatted_prompt, context: {context}")
209
- if context.entrypoint:
210
- entrypoint = context.entrypoint
211
- entrypoint_prompt = None
212
- if (
213
- agent.twitter_entrypoint_enabled
214
- and agent.twitter_entrypoint_prompt
215
- and entrypoint == AuthorType.TWITTER.value
216
- ):
217
- entrypoint_prompt = agent.twitter_entrypoint_prompt
218
- logger.debug("twitter entrypoint prompt added")
219
- elif (
220
- agent.telegram_entrypoint_enabled
221
- and agent.telegram_entrypoint_prompt
222
- and entrypoint == AuthorType.TELEGRAM.value
223
- ):
224
- entrypoint_prompt = agent.telegram_entrypoint_prompt
225
- logger.debug("telegram entrypoint prompt added")
226
- elif entrypoint == AuthorType.TRIGGER.value:
227
- task_id = context.chat_id.removeprefix("autonomous-")
228
- # Find the autonomous task by task_id
229
- autonomous_task = None
230
- if agent.autonomous:
231
- for task in agent.autonomous:
232
- if task.id == task_id:
233
- autonomous_task = task
234
- break
235
-
236
- if autonomous_task:
237
- # Build detailed task info - always include task_id
238
- if autonomous_task.name:
239
- task_info = f"You are running an autonomous task '{autonomous_task.name}' (ID: {task_id})"
240
- else:
241
- task_info = (
242
- f"You are running an autonomous task (ID: {task_id})"
243
- )
244
-
245
- # Add description if available
246
- if autonomous_task.description:
247
- task_info += f": {autonomous_task.description}"
248
-
249
- # Add cycle info
250
- if autonomous_task.minutes:
251
- task_info += f". This task runs every {autonomous_task.minutes} minute(s)"
252
- elif autonomous_task.cron:
253
- task_info += (
254
- f". This task runs on schedule: {autonomous_task.cron}"
255
- )
148
+ # Create the formatted_prompt function using the refactored prompt module
149
+ formatted_prompt = create_formatted_prompt_function(agent, agent_data)
256
150
 
257
- entrypoint_prompt = f"{task_info}. "
258
- else:
259
- # Fallback if task not found
260
- entrypoint_prompt = f"You are running an autonomous task. The task id is {task_id}. "
261
- if entrypoint_prompt:
262
- entrypoint_prompt = await explain_prompt(entrypoint_prompt)
263
- final_system_prompt = f"{final_system_prompt}## Entrypoint rules\n\n{entrypoint_prompt}\n\n"
264
- final_system_prompt = f"{final_system_prompt}## Internal Info\n\n"
265
- "These are for your internal use. You can use them when querying or storing data, "
266
- "but please do not directly share this information with users.\n\n"
267
- final_system_prompt = f"{final_system_prompt}chat_id: {context.chat_id}\n\n"
268
- if context.user_id:
269
- final_system_prompt = f"{final_system_prompt}user_id: {context.user_id}\n\n"
270
- system_prompt = [("system", final_system_prompt)]
271
- return prompt_temp.invoke(
272
- {"messages": state["messages"], "system_prompt": system_prompt}
273
- )
274
-
275
- # log final prompt and all skills
276
- logger.debug(
277
- f"[{agent.id}{'-private' if is_private else ''}] init prompt: {escaped_prompt}"
278
- )
279
151
  for tool in tools:
280
152
  logger.info(
281
153
  f"[{agent.id}{'-private' if is_private else ''}] loaded tool: {tool.name if isinstance(tool, BaseTool) else tool}"
intentkit/core/prompt.py CHANGED
@@ -1,57 +1,438 @@
1
+ import re
2
+ from typing import Callable, Optional
3
+
4
+ from eth_utils import is_address
5
+ from langchain_core.messages import BaseMessage
6
+ from langchain_core.prompts import ChatPromptTemplate
7
+ from langgraph.runtime import Runtime
8
+
9
+ from intentkit.abstracts.graph import AgentContext, AgentState
1
10
  from intentkit.config.config import config
2
11
  from intentkit.models.agent import Agent
3
12
  from intentkit.models.agent_data import AgentData
13
+ from intentkit.models.chat import AuthorType
14
+ from intentkit.models.skill import Skill
4
15
 
16
+ # ============================================================================
17
+ # CONSTANTS AND CONFIGURATION
18
+ # ============================================================================
5
19
 
6
- def agent_prompt(agent: Agent, agent_data: AgentData) -> str:
20
+ # Base system prompt components
21
+ BASE_SYSTEM_PROMPT = """You are an AI agent built using IntentKit.
22
+ Your tools are called 'skills'.
23
+ If your skill fails to execute due to a technical error ask the user to try again later, don't retry by yourself. If someone asks you to do something you can't do with your currently available skills, you must say so, recommend them to submit their feedback to the IntentKit team at https://github.com/crestalnetwork/intentkit. Be concise and helpful with your responses."""
24
+
25
+ ENSO_SKILLS_GUIDE = """## ENSO Skills Guide
26
+
27
+ You are integrated with the Enso API. You can use enso_get_tokens to retrieve token information,
28
+ including APY, Protocol Slug, Symbol, Address, Decimals, and underlying tokens. When interacting with token amounts,
29
+ ensure to multiply input amounts by the token's decimal places and divide output amounts by the token's decimals.
30
+ Utilize enso_route_shortcut to find the best swap or deposit route. Set broadcast_request to True only when the
31
+ user explicitly requests a transaction broadcast. Insufficient funds or insufficient spending approval can cause
32
+ Route Shortcut broadcasts to fail. To avoid this, use the enso_broadcast_wallet_approve tool that requires explicit
33
+ user confirmation before broadcasting any approval transactions for security reasons.
34
+
35
+ """
36
+
37
+
38
+ # ============================================================================
39
+ # CORE PROMPT BUILDING FUNCTIONS
40
+ # ============================================================================
41
+
42
+
43
+ def _build_system_header() -> str:
44
+ """Build the system prompt header."""
7
45
  prompt = "# SYSTEM PROMPT\n\n"
8
46
  if config.system_prompt:
9
47
  prompt += config.system_prompt + "\n\n"
10
- prompt += "You are an AI agent built using IntentKit.\n"
11
- prompt += "Your tools are called 'skills'.\n"
12
- prompt += "If your skill fails to execute due to a technical error ask the user to try again later, don't retry by yourself. If someone asks you to do something you can't do with your currently available skills, you must say so, recommend them to submit their feedback to the IntentKit team at https://github.com/crestalnetwork/intentkit. Be concise and helpful with your responses.\n"
48
+ prompt += BASE_SYSTEM_PROMPT + "\n"
49
+ return prompt
50
+
51
+
52
+ def _build_agent_identity_section(agent: Agent) -> str:
53
+ """Build agent identity information section."""
54
+ identity_parts = []
55
+
13
56
  if agent.name:
14
- prompt += f"Your name is {agent.name}.\n"
57
+ identity_parts.append(f"Your name is {agent.name}.")
15
58
  if agent.ticker:
16
- prompt += f"Your ticker symbol is {agent.ticker}.\n"
17
- if agent_data:
18
- if agent_data.twitter_id:
19
- prompt += f"Your twitter id is {agent_data.twitter_id}, never reply or retweet yourself.\n"
20
- if agent_data.twitter_username:
21
- prompt += f"Your twitter username is {agent_data.twitter_username}.\n"
22
- if agent_data.twitter_name:
23
- prompt += f"Your twitter name is {agent_data.twitter_name}.\n"
24
- if agent_data.twitter_is_verified:
25
- prompt += "Your twitter account is verified.\n"
26
- else:
27
- prompt += "Your twitter account is not verified.\n"
28
- if agent_data.telegram_id:
29
- prompt += f"Your telegram bot id is {agent_data.telegram_id}.\n"
30
- if agent_data.telegram_username:
31
- prompt += f"Your telegram bot username is {agent_data.telegram_username}.\n"
32
- if agent_data.telegram_name:
33
- prompt += f"Your telegram bot name is {agent_data.telegram_name}.\n"
34
- # CDP
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"
40
- prompt += "\n"
59
+ identity_parts.append(f"Your ticker symbol is {agent.ticker}.")
60
+
61
+ return "\n".join(identity_parts) + ("\n" if identity_parts else "")
62
+
63
+
64
+ def _build_social_accounts_section(agent_data: AgentData) -> str:
65
+ """Build social accounts information section."""
66
+ if not agent_data:
67
+ return ""
68
+
69
+ social_parts = []
70
+
71
+ # Twitter info
72
+ if agent_data.twitter_id:
73
+ social_parts.append(
74
+ f"Your twitter id is {agent_data.twitter_id}, never reply or retweet yourself."
75
+ )
76
+ if agent_data.twitter_username:
77
+ social_parts.append(f"Your twitter username is {agent_data.twitter_username}.")
78
+ if agent_data.twitter_name:
79
+ social_parts.append(f"Your twitter name is {agent_data.twitter_name}.")
80
+
81
+ # Twitter verification status
82
+ if agent_data.twitter_is_verified:
83
+ social_parts.append("Your twitter account is verified.")
84
+ else:
85
+ social_parts.append("Your twitter account is not verified.")
86
+
87
+ # Telegram info
88
+ if agent_data.telegram_id:
89
+ social_parts.append(f"Your telegram bot id is {agent_data.telegram_id}.")
90
+ if agent_data.telegram_username:
91
+ social_parts.append(
92
+ f"Your telegram bot username is {agent_data.telegram_username}."
93
+ )
94
+ if agent_data.telegram_name:
95
+ social_parts.append(f"Your telegram bot name is {agent_data.telegram_name}.")
96
+
97
+ return "\n".join(social_parts) + ("\n" if social_parts else "")
98
+
99
+
100
+ def _build_wallet_section(agent: Agent, agent_data: AgentData) -> str:
101
+ """Build wallet information section."""
102
+ if not agent_data:
103
+ return ""
104
+
105
+ wallet_parts = []
106
+ network_id = agent.network_id or agent.cdp_network_id
107
+
108
+ if agent_data.evm_wallet_address and network_id != "solana":
109
+ wallet_parts.append(
110
+ f"Your wallet address in {network_id} is {agent_data.evm_wallet_address}."
111
+ )
112
+ if agent_data.solana_wallet_address and network_id == "solana":
113
+ wallet_parts.append(
114
+ f"Your wallet address in {network_id} is {agent_data.solana_wallet_address}."
115
+ )
116
+
117
+ return "\n".join(wallet_parts) + ("\n" if wallet_parts else "")
118
+
119
+
120
+ def _build_user_info_section(context: AgentContext) -> str:
121
+ """Build user information section when user_id is a valid EVM wallet address."""
122
+ if not context.user_id:
123
+ return ""
124
+
125
+ # Check if user_id is a valid EVM wallet address
126
+ try:
127
+ if is_address(context.user_id):
128
+ return f"## User Info\n\nThe person you are talking to has wallet address: {context.user_id}\n\n"
129
+ except Exception:
130
+ # If validation fails, don't include the section
131
+ pass
132
+
133
+ return ""
134
+
135
+
136
+ def _build_agent_characteristics_section(agent: Agent) -> str:
137
+ """Build agent characteristics section (purpose, personality, principles, etc.)."""
138
+ sections = []
139
+
41
140
  if agent.purpose:
42
- prompt += f"## Purpose\n\n{agent.purpose}\n\n"
141
+ sections.append(f"## Purpose\n\n{agent.purpose}")
43
142
  if agent.personality:
44
- prompt += f"## Personality\n\n{agent.personality}\n\n"
143
+ sections.append(f"## Personality\n\n{agent.personality}")
45
144
  if agent.principles:
46
- prompt += f"## Principles\n\n{agent.principles}\n\n"
145
+ sections.append(f"## Principles\n\n{agent.principles}")
47
146
  if agent.prompt:
48
- prompt += f"## Initial Rules\n\n{agent.prompt}\n\n"
147
+ sections.append(f"## Initial Rules\n\n{agent.prompt}")
148
+
149
+ return "\n\n".join(sections) + ("\n\n" if sections else "")
150
+
151
+
152
+ def _build_skills_guides_section(agent: Agent) -> str:
153
+ """Build skills-specific guides section."""
154
+ guides = []
155
+
156
+ # ENSO skills guide
49
157
  if agent.skills and "enso" in agent.skills and agent.skills["enso"].get("enabled"):
50
- prompt += """## ENSO Skills Guide\n\nYou are integrated with the Enso API. You can use enso_get_tokens to retrieve token information,
51
- including APY, Protocol Slug, Symbol, Address, Decimals, and underlying tokens. When interacting with token amounts,
52
- ensure to multiply input amounts by the token's decimal places and divide output amounts by the token's decimals.
53
- Utilize enso_route_shortcut to find the best swap or deposit route. Set broadcast_request to True only when the
54
- user explicitly requests a transaction broadcast. Insufficient funds or insufficient spending approval can cause
55
- Route Shortcut broadcasts to fail. To avoid this, use the enso_broadcast_wallet_approve tool that requires explicit
56
- user confirmation before broadcasting any approval transactions for security reasons.\n\n"""
57
- return prompt
158
+ guides.append(ENSO_SKILLS_GUIDE)
159
+
160
+ return "".join(guides)
161
+
162
+
163
+ def build_agent_prompt(agent: Agent, agent_data: AgentData) -> str:
164
+ """
165
+ Build the complete agent system prompt.
166
+
167
+ This function orchestrates the building of different prompt sections:
168
+ - System header and base prompt
169
+ - Agent identity (name, ticker)
170
+ - Social accounts (Twitter, Telegram)
171
+ - Wallet information
172
+ - Agent characteristics (purpose, personality, principles)
173
+ - Skills-specific guides
174
+
175
+ Args:
176
+ agent: The agent configuration
177
+ agent_data: The agent's runtime data
178
+
179
+ Returns:
180
+ str: The complete system prompt
181
+ """
182
+ prompt_sections = [
183
+ _build_system_header(),
184
+ _build_agent_identity_section(agent),
185
+ _build_social_accounts_section(agent_data),
186
+ _build_wallet_section(agent, agent_data),
187
+ "\n", # Add spacing before characteristics
188
+ _build_agent_characteristics_section(agent),
189
+ _build_skills_guides_section(agent),
190
+ ]
191
+
192
+ return "".join(section for section in prompt_sections if section)
193
+
194
+
195
+ # Legacy function name for backward compatibility
196
+ def agent_prompt(agent: Agent, agent_data: AgentData) -> str:
197
+ """Legacy function name. Use build_agent_prompt instead."""
198
+ return build_agent_prompt(agent, agent_data)
199
+
200
+
201
+ async def explain_prompt(message: str) -> str:
202
+ """
203
+ Process message to replace @skill:*:* patterns with (call skill xxxxx) format.
204
+ This function is used when admin_llm_skill_control is enabled.
205
+
206
+ Args:
207
+ message (str): The input message to process
208
+
209
+ Returns:
210
+ str: The processed message with @skill patterns replaced
211
+ """
212
+ # Pattern to match @skill:category:config_name with word boundaries
213
+ pattern = r"\b@skill:([^:]+):([^\s]+)\b"
214
+
215
+ async def replace_skill_pattern(match):
216
+ category = match.group(1)
217
+ config_name = match.group(2)
218
+
219
+ # Get skill by category and config_name
220
+ skill = await Skill.get_by_config_name(category, config_name)
221
+
222
+ if skill:
223
+ return f"(call skill {skill.name})"
224
+ else:
225
+ # If skill not found, keep original pattern
226
+ return match.group(0)
227
+
228
+ # Find all matches
229
+ matches = list(re.finditer(pattern, message))
230
+
231
+ # Process matches in reverse order to maintain string positions
232
+ result = message
233
+ for match in reversed(matches):
234
+ replacement = await replace_skill_pattern(match)
235
+ result = result[: match.start()] + replacement + result[match.end() :]
236
+
237
+ return result
238
+
239
+
240
+ # ============================================================================
241
+ # UTILITY FUNCTIONS
242
+ # ============================================================================
243
+
244
+
245
+ def escape_prompt(prompt: str) -> str:
246
+ """Escape curly braces in the prompt for template processing."""
247
+ return prompt.replace("{", "{{").replace("}", "}}")
248
+
249
+
250
+ # ============================================================================
251
+ # ENTRYPOINT PROCESSING FUNCTIONS
252
+ # ============================================================================
253
+
254
+
255
+ def _build_social_entrypoint_prompt(agent: Agent, entrypoint: str) -> Optional[str]:
256
+ """Build prompt for social media entrypoints (Twitter, Telegram)."""
257
+ if (
258
+ agent.twitter_entrypoint_enabled
259
+ and agent.twitter_entrypoint_prompt
260
+ and entrypoint == AuthorType.TWITTER.value
261
+ ):
262
+ return agent.twitter_entrypoint_prompt
263
+ elif (
264
+ agent.telegram_entrypoint_enabled
265
+ and agent.telegram_entrypoint_prompt
266
+ and entrypoint == AuthorType.TELEGRAM.value
267
+ ):
268
+ return agent.telegram_entrypoint_prompt
269
+ return None
270
+
271
+
272
+ def _build_autonomous_task_prompt(agent: Agent, context: AgentContext) -> str:
273
+ """Build prompt for autonomous task entrypoint."""
274
+ task_id = context.chat_id.removeprefix("autonomous-")
275
+
276
+ # Find the autonomous task by task_id
277
+ autonomous_task = None
278
+ if agent.autonomous:
279
+ for task in agent.autonomous:
280
+ if task.id == task_id:
281
+ autonomous_task = task
282
+ break
283
+
284
+ if not autonomous_task:
285
+ # Fallback if task not found
286
+ return f"You are running an autonomous task. The task id is {task_id}. "
287
+
288
+ # Build detailed task info - always include task_id
289
+ if autonomous_task.name:
290
+ task_info = f"You are running an autonomous task '{autonomous_task.name}' (ID: {task_id})"
291
+ else:
292
+ task_info = f"You are running an autonomous task (ID: {task_id})"
293
+
294
+ # Add description if available
295
+ if autonomous_task.description:
296
+ task_info += f": {autonomous_task.description}"
297
+
298
+ # Add cycle info
299
+ if autonomous_task.minutes:
300
+ task_info += f". This task runs every {autonomous_task.minutes} minute(s)"
301
+ elif autonomous_task.cron:
302
+ task_info += f". This task runs on schedule: {autonomous_task.cron}"
303
+
304
+ return f"{task_info}. "
305
+
306
+
307
+ async def build_entrypoint_prompt(agent: Agent, context: AgentContext) -> Optional[str]:
308
+ """
309
+ Build entrypoint-specific prompt based on context.
310
+
311
+ Supports different entrypoint types:
312
+ - Twitter: Uses agent.twitter_entrypoint_prompt
313
+ - Telegram: Uses agent.telegram_entrypoint_prompt
314
+ - Autonomous tasks: Builds task-specific prompt with scheduling info
315
+
316
+ Args:
317
+ agent: The agent configuration
318
+ context: The agent context containing entrypoint information
319
+
320
+ Returns:
321
+ Optional[str]: The entrypoint-specific prompt, or None if no entrypoint
322
+ """
323
+ if not context.entrypoint:
324
+ return None
325
+
326
+ entrypoint = context.entrypoint
327
+ entrypoint_prompt = None
328
+
329
+ # Handle social media entrypoints
330
+ entrypoint_prompt = _build_social_entrypoint_prompt(agent, entrypoint)
331
+
332
+ # Handle autonomous task entrypoint
333
+ if not entrypoint_prompt and entrypoint == AuthorType.TRIGGER.value:
334
+ entrypoint_prompt = _build_autonomous_task_prompt(agent, context)
335
+
336
+ # Process with admin LLM skill control if enabled
337
+ if entrypoint_prompt and config.admin_llm_skill_control:
338
+ entrypoint_prompt = await explain_prompt(entrypoint_prompt)
339
+
340
+ return entrypoint_prompt
341
+
342
+
343
+ def build_internal_info_prompt(context: AgentContext) -> str:
344
+ """Build internal info prompt with context information."""
345
+ internal_info = "## Internal Info\n\n"
346
+ internal_info += "These are for your internal use. You can use them when querying or storing data, "
347
+ internal_info += "but please do not directly share this information with users.\n\n"
348
+ internal_info += f"chat_id: {context.chat_id}\n\n"
349
+ if context.user_id:
350
+ internal_info += f"user_id: {context.user_id}\n\n"
351
+ return internal_info
352
+
353
+
354
+ # ============================================================================
355
+ # MAIN PROMPT FACTORY FUNCTION
356
+ # ============================================================================
357
+
358
+
359
+ def create_formatted_prompt_function(agent: Agent, agent_data: AgentData) -> Callable:
360
+ """
361
+ Create the formatted_prompt function with agent-specific configuration.
362
+
363
+ This is the main factory function that creates a prompt formatting function
364
+ tailored to a specific agent. The returned function will be used by the
365
+ agent's runtime to format prompts for each conversation.
366
+
367
+ Args:
368
+ agent: The agent configuration
369
+ agent_data: The agent's runtime data
370
+
371
+ Returns:
372
+ Callable: An async function that formats prompts based on agent state and context
373
+ """
374
+ # Build base prompt using the new function name
375
+ prompt = build_agent_prompt(agent, agent_data)
376
+ escaped_prompt = escape_prompt(prompt)
377
+
378
+ # Process with admin LLM skill control if enabled
379
+ async def get_base_prompt():
380
+ if config.admin_llm_skill_control:
381
+ return await explain_prompt(escaped_prompt)
382
+ return escaped_prompt
383
+
384
+ # Build prompt array
385
+ prompt_array = [
386
+ ("placeholder", "{system_prompt}"),
387
+ ("placeholder", "{messages}"),
388
+ ]
389
+
390
+ if agent.prompt_append:
391
+ # Escape any curly braces in prompt_append
392
+ escaped_append = escape_prompt(agent.prompt_append)
393
+ prompt_array.append(("system", escaped_append))
394
+
395
+ prompt_temp = ChatPromptTemplate.from_messages(prompt_array)
396
+
397
+ async def formatted_prompt(
398
+ state: AgentState, runtime: Runtime[AgentContext]
399
+ ) -> list[BaseMessage]:
400
+ # Get base prompt (with potential admin LLM skill control processing)
401
+ final_system_prompt = await get_base_prompt()
402
+
403
+ context = runtime.context
404
+
405
+ # Add entrypoint prompt if applicable
406
+ entrypoint_prompt = await build_entrypoint_prompt(agent, context)
407
+ if entrypoint_prompt:
408
+ final_system_prompt = (
409
+ f"{final_system_prompt}## Entrypoint rules\n\n{entrypoint_prompt}\n\n"
410
+ )
411
+
412
+ # Add user info if user_id is a valid EVM wallet address
413
+ user_info = _build_user_info_section(context)
414
+ if user_info:
415
+ final_system_prompt = f"{final_system_prompt}{user_info}"
416
+
417
+ # Add internal info
418
+ internal_info = build_internal_info_prompt(context)
419
+ final_system_prompt = f"{final_system_prompt}{internal_info}"
420
+
421
+ # Process prompt_append with admin LLM skill control if needed
422
+ if agent.prompt_append and config.admin_llm_skill_control:
423
+ # Find the system message in prompt_array and process it
424
+ for i, (role, content) in enumerate(prompt_array):
425
+ if role == "system":
426
+ processed_append = await explain_prompt(content)
427
+ prompt_array[i] = ("system", processed_append)
428
+ break
429
+
430
+ system_prompt = [("system", final_system_prompt)]
431
+ return prompt_temp.invoke(
432
+ {
433
+ "messages": state["messages"],
434
+ "system_prompt": system_prompt,
435
+ }
436
+ )
437
+
438
+ return formatted_prompt
intentkit/models/llm.py CHANGED
@@ -623,7 +623,7 @@ class DeepseekLLM(LLMModel):
623
623
  async def create_instance(self, config: Any) -> LanguageModelLike:
624
624
  """Create and return a ChatDeepseek instance."""
625
625
 
626
- from langchain_openai import ChatOpenAI
626
+ from langchain_deepseek import ChatDeepSeek
627
627
 
628
628
  info = await self.model_info()
629
629
 
@@ -646,7 +646,7 @@ class DeepseekLLM(LLMModel):
646
646
  if info.api_base:
647
647
  kwargs["openai_api_base"] = info.api_base
648
648
 
649
- return ChatOpenAI(**kwargs)
649
+ return ChatDeepSeek(**kwargs)
650
650
 
651
651
 
652
652
  class XAILLM(LLMModel):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: intentkit
3
- Version: 0.6.11.dev2
3
+ Version: 0.6.11.dev3
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
@@ -58,6 +58,7 @@ Requires-Dist: httpx>=0.28.1
58
58
  Requires-Dist: jsonref>=1.1.0
59
59
  Requires-Dist: langchain-community>=0.3.19
60
60
  Requires-Dist: langchain-core>=0.3.43
61
+ Requires-Dist: langchain-deepseek>=0.1.4
61
62
  Requires-Dist: langchain-mcp-adapters>=0.0.11
62
63
  Requires-Dist: langchain-openai>=0.3.8
63
64
  Requires-Dist: langchain-text-splitters>=0.3.8
@@ -1,4 +1,4 @@
1
- intentkit/__init__.py,sha256=bHsUzcFd-XdSi9M2iFW-p1x3-hntZ5xAoxpEA4kIadU,384
1
+ intentkit/__init__.py,sha256=L3MeNqTVKVhtQpOK1Tq4ZEIq_bUh-6E7orxvxP36kA4,384
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
@@ -17,9 +17,9 @@ intentkit/core/agent.py,sha256=GIKDn1dTenIHWMRxe-ud7hd1cQaHzbTDdypy5IAgPfU,16658
17
17
  intentkit/core/api.py,sha256=3GIMJpwduLUSbVPNW6mQVxZncYHH3OlLwdiqFtYtEAE,1208
18
18
  intentkit/core/client.py,sha256=rIwtJVVm-7piXtFNDbeykt9vWdNTecgjW0aA3N-lHnM,1495
19
19
  intentkit/core/credit.py,sha256=Y5cjShFFqGBhz7Uc_ziqejyW-2FP58TYxsSNc4N_6hI,63039
20
- intentkit/core/engine.py,sha256=ibaPSez5IuNys5AT3xifBsKUwNElFiJMmsXCjuziRdE,43555
20
+ intentkit/core/engine.py,sha256=qfxcpNHZu8PxdiCFyQueK2zkr8w1FQ58jShUzAxrl1M,38018
21
21
  intentkit/core/node.py,sha256=7h9zgDSd928bzUi3m3EZnKkhbwqlbRAQUr_uz7gKB5Y,8880
22
- intentkit/core/prompt.py,sha256=RfLhlUktkB2kCr3wfldqq6ZP2l8heZIMc8jVp31KIyQ,3631
22
+ intentkit/core/prompt.py,sha256=eaa2FyFptpsWlEGWCL8jVmZMGB6Pl9hBnt-y8Yq37RU,16041
23
23
  intentkit/core/skill.py,sha256=vPK37sDRT9kzkMBymPwqZ5uEdxTTRtb_DfREIeyz-Xw,5788
24
24
  intentkit/models/agent.py,sha256=pKeafRhmFMJwuIEBJkBEIl_oEu_CQ5AkvsBVfNfoxuQ,67168
25
25
  intentkit/models/agent_data.py,sha256=mVsiK8TziYa1W1ujU1KwI9osIVIeSM7XJEogGRL1WVU,28263
@@ -32,7 +32,7 @@ intentkit/models/credit.py,sha256=bcasHyrCwforLGrH8ZWEvN6y6ml7NeAFrGl8cfqvqbI,42
32
32
  intentkit/models/db.py,sha256=nuDX6NEtnfD5YLr2iVpAAXsgHbSpG5diqfLC-PkHsA4,4406
33
33
  intentkit/models/db_mig.py,sha256=vT6Tanm-BHC2T7dTztuB1UG494EFBAlHADKsNzR6xaQ,3577
34
34
  intentkit/models/generator.py,sha256=lyZu9U9rZUGkqd_QT5SAhay9DY358JJY8EhDSpN8I1M,10298
35
- intentkit/models/llm.py,sha256=TTTuea6f9aFxmS1X1SVUuMhvTh5rvIiqMn9A14lFxPY,26911
35
+ intentkit/models/llm.py,sha256=VCSeK_AfyQDbkYO2ZjcF0A2JxxheqmW1T92Ow08lLCk,26917
36
36
  intentkit/models/redis.py,sha256=UoN8jqLREO1VO9_w6m-JhldpP19iEHj4TiGVCMutQW4,3702
37
37
  intentkit/models/skill.py,sha256=h_2wtKEbYE29TLsMdaSnjfOv6vXY6GwMU_abw-ONX28,16374
38
38
  intentkit/models/user.py,sha256=P7l6LOsZmXZ5tDPTczTbqDtDB_MKc_9_ddZkAB2npPk,9288
@@ -401,7 +401,7 @@ intentkit/utils/random.py,sha256=DymMxu9g0kuQLgJUqalvgksnIeLdS-v0aRk5nQU0mLI,452
401
401
  intentkit/utils/s3.py,sha256=9trQNkKQ5VgxWsewVsV8Y0q_pXzGRvsCYP8xauyUYkg,8549
402
402
  intentkit/utils/slack_alert.py,sha256=s7UpRgyzLW7Pbmt8cKzTJgMA9bm4EP-1rQ5KXayHu6E,2264
403
403
  intentkit/utils/tx.py,sha256=2yLLGuhvfBEY5n_GJ8wmIWLCzn0FsYKv5kRNzw_sLUI,1454
404
- intentkit-0.6.11.dev2.dist-info/METADATA,sha256=0u5l0TiIRv2CAvfKEQAO0L6iDKysSuuH7TkrivT2-Gg,6373
405
- intentkit-0.6.11.dev2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
406
- intentkit-0.6.11.dev2.dist-info/licenses/LICENSE,sha256=Bln6DhK-LtcO4aXy-PBcdZv2f24MlJFm_qn222biJtE,1071
407
- intentkit-0.6.11.dev2.dist-info/RECORD,,
404
+ intentkit-0.6.11.dev3.dist-info/METADATA,sha256=h3k4XpLhiazptmdImgGO9vWD0JB920dPjVDEInDonHc,6414
405
+ intentkit-0.6.11.dev3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
406
+ intentkit-0.6.11.dev3.dist-info/licenses/LICENSE,sha256=Bln6DhK-LtcO4aXy-PBcdZv2f24MlJFm_qn222biJtE,1071
407
+ intentkit-0.6.11.dev3.dist-info/RECORD,,