Skip to content

Commit 041c888

Browse files
committed
fixing tool calling, improve prompts, add query command
1 parent bf72028 commit 041c888

File tree

4 files changed

+98
-38
lines changed

4 files changed

+98
-38
lines changed

src/agent.py

+24-17
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class AgentState(TypedDict):
1717
action_plan: list
1818
action_log: list
1919
task_log: list
20+
process_flag: bool
2021

2122
class ZerePyAgent:
2223
def __init__(self, agent_config: dict):
@@ -191,12 +192,12 @@ def observation_step(self, state: AgentState):
191192
print("\n=== OBSERVATION STEP ===")
192193
print(f"Summarizing contextual information...")
193194

194-
# Update AgentState context
195195
state["context"] = self._replenish_inputs(state["context"])
196+
query = state['current_task']
196197

197198
try:
198199
observation_prompt = OBSERVATION_PROMPT.format(context=state['context'], task_log=state['task_log'])
199-
context_summary = self.driver_llm.invoke(observation_prompt).content
200+
context_summary = self.executor_agent.invoke(observation_prompt).content
200201
except Exception as e:
201202
logger.error(f"Error generating context summary: {e}")
202203
context_summary = "There is currently no additional context available."
@@ -206,21 +207,20 @@ def observation_step(self, state: AgentState):
206207

207208
def determination_step(self, state: AgentState):
208209
print("\n=== DETERMINATION STEP ===")
209-
print("Determining next task...")
210+
print("Determining task from user query...")
210211

211-
task = state['current_task']
212+
query = state['current_task']
212213

213-
if task is None or task.strip() == "":
214-
determination_prompt = DETERMINATION_PROMPT.format(context_summary=state['context_summary'], connection_action_list="\n\n".join(connection.__str__() for connection in self.connections.values()))
215-
task = self.character_llm.invoke(determination_prompt).content
214+
determination_prompt = DETERMINATION_PROMPT.format(user_query=query, connection_action_list="\n\n".join(connection.__str__() for connection in self.connections.values()))
215+
task = self.character_llm.invoke(determination_prompt).content
216216

217217
print(f"\nDETERMINED TASK: {task}")
218218
return {"current_task": task}
219219

220220
def division_step(self, state: AgentState):
221221
print("\n=== DIVISION STEP ===")
222222
print(f"Creating action plan for task: {state['current_task']}")
223-
division_prompt = DIVISION_PROMPT.format(current_task=state['current_task'], connection_action_list="\n\n".join(connection.__str__() for connection in self.connections.values()))
223+
division_prompt = DIVISION_PROMPT.format(current_task=state['current_task'], connection_action_list="\n\n".join(connection.__str__() for connection in self.connections.values()), preferred_llm_config=str(self.llm_prefs))
224224
action_plan_text = self.driver_llm.invoke(division_prompt).content
225225
action_plan = action_plan_text.split("\n")
226226

@@ -234,7 +234,7 @@ def execution_step(self, state: AgentState) -> AgentState:
234234

235235
if not action_plan:
236236
print("No actions to execute")
237-
return
237+
return state
238238

239239
for action in action_plan:
240240
print(f"\nExecuting action: {action}")
@@ -252,34 +252,40 @@ def evaluation_step(self, state: AgentState):
252252
evaluation_prompt = EVALUATION_PROMPT.format(current_task=state['current_task'], action_log = "\n".join(f"{action['action']}:\n" +f"Result: {action['result']}"for action in action_log))
253253
generated_task_log = self.driver_llm.invoke(evaluation_prompt).content
254254
print(f"Generated task log:\n{generated_task_log}")
255-
state["action_plan"] = []
256-
state["action_log"] = []
257255
state["current_task"] = state["current_task"] if self.loop_task else None
258256
state["task_log"].append(generated_task_log)
259257
state["task_log"] = state["task_log"][-3:] #trim to the last 3 task logs
260258

261-
# Delay before next loop
262-
logger.info(f"\n⏳ Waiting {self.loop_delay} seconds before next loop...")
259+
if (not state["process_flag"]): #only clear the action log if in a loop
260+
state["action_log"] = []
261+
state["action_plan"] = []
262+
logger.info(f"\n⏳ Waiting {self.loop_delay} seconds before next loop...") # Delay before next loop
263+
time.sleep(self.loop_delay)
264+
263265
print_h_bar()
264-
time.sleep(self.loop_delay)
265266
return state
266267

267-
def process_task(self, task: str): # Process a single task
268+
def process_task(self, task: str = None): # Process a single task
269+
if task is None:
270+
task = input("\n🔹 Enter the task to perform (e.g., 'Read the timeline, then write a tweet about it').\n\n➡️ YOUR TASK: ")
271+
268272
state = {
269273
"context": {},
270274
"current_task": task,
271275
"context_summary": "",
272276
"action_plan": [],
273277
"action_log": [],
274278
"task_log": [],
279+
"process_flag": True
275280
}
276-
277-
state.update(self.observation_step(state))
278281
state.update(self.determination_step(state))
279282
state.update(self.division_step(state))
280283
state = self.execution_step(state)
281284
state.update(self.evaluation_step(state))
282285

286+
#add final_response of the last action to the state
287+
state["final_response"] = state["action_log"][-1]["final_response"] if state["action_log"] else None
288+
283289
return state
284290

285291
def loop(self, task=None):
@@ -303,6 +309,7 @@ def loop(self, task=None):
303309
"action_plan": [],
304310
"action_log": [],
305311
"task_log": [],
312+
"process_flag": False
306313
}
307314
logger.info(f"\n🚀 Starting autonomous agent loop ...")
308315
logger.info("Press Ctrl+C at any time to stop the loop.")

src/cli.py

+31
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,17 @@ def _initialize_commands(self) -> None:
9999
aliases=['loop', 'start']
100100
)
101101
)
102+
103+
# Agent query command
104+
self._register_command(
105+
Command(
106+
name="agent-query",
107+
description="Allows for testing the response of the agent.",
108+
tips=["Press Ctrl+C to stop the execution"],
109+
handler=self.agent_query,
110+
aliases=['query', 'invoke']
111+
)
112+
)
102113

103114
# List agents command
104115
self._register_command(
@@ -429,6 +440,26 @@ def agent_loop(self, input_list: List[str]) -> None:
429440
logger.info("\n🛑 Agent loop stopped by user.")
430441
except Exception as e:
431442
logger.error(f"Error in agent loop: {e}")
443+
444+
def agent_query(self, input_list: List[str]) -> None:
445+
"""Handle agent loop command"""
446+
if self.agent is None:
447+
logger.info("No agent is currently loaded. Use 'load-agent' to load an agent.")
448+
return
449+
450+
if (isinstance(self.agent, LegacyZerePyAgent)):
451+
logger.info("This command is not supported for legacy agents.")
452+
return
453+
454+
try:
455+
state = self.agent.process_task()
456+
logger.debug(f"FINAL STATE: {state}")
457+
logger.info(f"Final response: {state['final_response']}")
458+
459+
except KeyboardInterrupt:
460+
logger.info("\n🛑 Agent loop stopped by user.")
461+
except Exception as e:
462+
logger.error(f"Error when querying agent: {e}")
432463

433464
def list_agents(self, input_list: List[str]) -> None:
434465
"""Handle list agents command"""

src/connections/solana_connection.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ def register_actions(self) -> None:
198198
parameters=[
199199
ActionParameter("ticker", True, str, "Token ticker symbol")
200200
],
201-
description="Get token data by ticker symbol",
201+
description="Get token data by ticker symbol/name",
202202
),
203203
"get-token-by-address": Action(
204204
name="get-token-by-address",

src/langgraph/prompts.py

+42-20
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,64 @@
44
"PREVIOUS TASKS:\n{task_log}\n\n"
55
"SUMMARY:\n")
66

7-
DETERMINATION_PROMPT = """Based on the given context and available actions, generate a complex task that you desire to perform. Only respond with the task, and do not include any other text in your response. Your task can involve multiple chained actions. You do not need to provide any reasoning for the task. If you are given context, you may choose whether or not to use it. If you do not have context, you must still choose a task to perform.\n\n"
8-
"CONTEXT SUMMARY:\n{context_summary}"
9-
"\n\nAVAILABLE ACTIONS FOR EACH CONNECTION:\n\n"
10-
"{connection_action_list}"
11-
"Example Outputs:\n
12-
1. Create a funny tweet and post it on Twitter
13-
2. Search for tweets about a specific topic and reply to them"""
14-
7+
DETERMINATION_PROMPT = """Based on the provided user query and the actions available to you, clearly state the task you need to perform. Only respond with the task, and do not include any other text in your response. Your task can involve multiple chained actions, and you can use actions to acquire information (Perplexity can be used to search for information, or if the user is asking about information pertaining to crypto, you may be able to use the associated crypto connection to retrieve the information). You do not need to provide any reasoning for the task. Your task should be clear and specific.\n\n"
8+
IF THE USER'S REQUEST IS A QUESTION AND NOT A TASK OR REQUEST THEN THE TASK IS: 'Answer the user's question: {user_query}'
9+
\n\nUSER QUERY:\n{user_query}
10+
\n\nAVAILABLE ACTIONS FOR EACH CONNECTION:\n\n
11+
{connection_action_list}
12+
"""
1513

1614
DIVISION_PROMPT = """Based on the given task and available actions, generate an action plan for the agent. Only respond with the list of steps needed (with the corresponding actions mentioned), and put each step on a new line. Only include actions that involve making requests—do not include actions like editing dialog boxes, clicking buttons, or other UI interactions.
1715
18-
TASK:
19-
{current_task}
16+
RULES:
17+
- Do not combine multiple actions into one step
18+
- Do not escape to a new line for a single step, until the step is complete
19+
- Each step should represent a single action
20+
- Be explicit about which parameters are required for each action
2021
2122
AVAILABLE ACTIONS FOR EACH CONNECTION:
2223
{connection_action_list}
2324
24-
Example :
25-
TASK: Create a funny tweet and post it on Twitter
25+
LLM Configuration: {preferred_llm_config}
26+
Choose the appropriate LLM connection based on the configuration provided above if the task involves generating text.
27+
28+
EXAMPLES:
29+
Example Task #1: Create a funny tweet and post it on Twitter
2630
2731
Output:
28-
1. Generate text using openai `generate-text` with the prompt "Create a funny tweet" and the specified system prompt
29-
2. Post the generated text using `post-tweet` with the output from step 1 as the 'message' parameter
32+
1. Generate text using openai `generate-text` with parameters {{"prompt": "Create a funny tweet", "system_prompt": "You are a witty comedian"}}
33+
2. Post the generated text using `post-tweet` with parameters {{"message": "<output from step 1>"}}
34+
35+
Example Task #2: swap 0.2 sol for zerebro
3036
31-
Rules:
32-
- Do not combine multiple actions into one step
33-
- Do not escape to a new line for a single step, until the step is complete
34-
- Each step should represent a single action
35-
- Be explicit about which parameters are required for each action"""
37+
Output:
38+
1. Find the mint address of zerebro using the `get-token-by-ticker` action with parameters {{"ticker": "zerebro"}}
39+
2. Swap 0.2 sol for zerebro using the `trade` action with parameters {{"input_token": "SOL", "output_token": "<mint address from step 1>", "amount": "0.2"}}
40+
41+
Example Task #3: Find the current price of Solana
42+
43+
Output:
44+
1. Get the mint address of Solana using the `get-token-by-ticker` action with parameters {{"ticker": "SOL"}}
45+
2. Get the price of Solana using the `get-price` action with parameters {{"mint_address": "<mint address from step 1>"}}
46+
47+
Notice how you should break down the task into smaller steps and you can use previous actions and their outputs to complete the task. Make sure to include all the necessary parameters for each action.
48+
TASK:
49+
{current_task}
50+
"""
3651

3752
EXECUTION_PROMPT = ("Before executing the following action, consider the previous action log:\n\n"
3853
"ACTION LOG:\n{action_log}\n\n"
3954
"Here is your preferred configurations for LLM related actions:\n\n"
4055
"LLM Configuration:\n{preferred_llm_config}\n\n"
41-
"Make sure to use the exact configuration provided above for the `generate-text` action. Copy the entire configuration, including the complete system prompt.When used to create a text for a tweet, always specify it under 280 characters in the prompt\n\n"
56+
"For the 'generate-text' action, extract only the system_prompt and model from the configuration above, ignoring the provider. When generating a tweet, ensure the output remains under 280 characters."
57+
"""EXECUTION FORMAT:
58+
- Always structure tool calls as: tool_name({{"param1": "value1", "param2": "value2"}})
59+
- Every parameter must be enclosed in quotes and provided as a key-value pair
60+
- Each tool requires specific parameters as defined in its function signature
61+
- Always include all required parameters for the tool being called
62+
- Parameter names in the dictionary must exactly match the function parameter names"""
4263
"Refer to the 'final_response' field in the tool action log to quickly see the final response from the agent\n\n"
64+
"Important: Only execute the specified action—do not perform any additional actions beyond what is provided. For instance, if the action does not mention Twitter, do not invoke a Twitter-related tool. Follow the instructions precisely, step by step."
4365
"Now, execute this action based on the prior results: {action}")
4466

4567
EVALUATION_PROMPT = ("Based on the action log, provide a summary of what the agent did based on the main task given. Only include the most important actions and the results of those actions. Do not include any actions that are irrelevant to the task or that did not produce a meaningful result.\n\n"

0 commit comments

Comments
 (0)