From 2a1624f621c30cb57dfd467b9b5ce0e81dc661f8 Mon Sep 17 00:00:00 2001 From: Joshua Smith Date: Mon, 21 Apr 2025 09:55:45 -0400 Subject: [PATCH 1/3] back to claud 3.5 prompts and adding list-agents automatically in goal registry fixing some finserv tool args --- activities/tool_activities.py | 4 ++-- tools/fin/get_account_balances.py | 2 +- tools/fin/move_money.py | 2 +- tools/fin/submit_loan_application.py | 2 +- tools/goal_registry.py | 29 ++++++++++++++++++++++------ tools/tool_registry.py | 6 +++--- 6 files changed, 31 insertions(+), 14 deletions(-) diff --git a/activities/tool_activities.py b/activities/tool_activities.py index 9d466bc..1b8d0b3 100644 --- a/activities/tool_activities.py +++ b/activities/tool_activities.py @@ -370,8 +370,8 @@ class ToolActivities: print("Initialized Anthropic client on demand") response = self.anthropic_client.messages.create( - #model="claude-3-5-sonnet-20241022", # todo try claude-3-7-sonnet-20250219 - model="claude-3-7-sonnet-20250219", # todo try claude-3-7-sonnet-20250219 + model="claude-3-5-sonnet-20241022", + #model="claude-3-7-sonnet-20250219", # doesn't do as well max_tokens=1024, system=input.context_instructions + ". The current date is " diff --git a/tools/fin/get_account_balances.py b/tools/fin/get_account_balances.py index be0854c..2c9ad2c 100644 --- a/tools/fin/get_account_balances.py +++ b/tools/fin/get_account_balances.py @@ -5,7 +5,7 @@ import json # this assumes it's a valid account - use check_account_valid() to verify that first def get_account_balance(args: dict) -> dict: - account_key = args.get("accountkey") + account_key = args.get("email_address_or_account_ID") file_path = Path(__file__).resolve().parent.parent / "data" / "customer_account_data.json" if not file_path.exists(): diff --git a/tools/fin/move_money.py b/tools/fin/move_money.py index f9569b7..e05b6e8 100644 --- a/tools/fin/move_money.py +++ b/tools/fin/move_money.py @@ -31,7 +31,7 @@ class MoneyMovementWorkflowParameterObj: # this assumes it's a valid account - use check_account_valid() to verify that first async def move_money(args: dict) -> dict: - account_key = args.get("accountkey") + account_key = args.get("email_address_or_account_ID") account_type: str = args.get("accounttype") amount = args.get("amount") destinationaccount = args.get("destinationaccount") diff --git a/tools/fin/submit_loan_application.py b/tools/fin/submit_loan_application.py index 4093ec0..41b59e4 100644 --- a/tools/fin/submit_loan_application.py +++ b/tools/fin/submit_loan_application.py @@ -31,7 +31,7 @@ class TxResult: #demonstrate starting a workflow and early return pattern while the workflow continues async def submit_loan_application(args: dict) -> dict: - account_key = args.get("accountkey") + account_key = args.get("email_address_or_account_ID") amount = args.get("amount") loan_status: dict = await start_workflow(amount=amount,account_name=account_key) diff --git a/tools/goal_registry.py b/tools/goal_registry.py index f86b59b..697f104 100644 --- a/tools/goal_registry.py +++ b/tools/goal_registry.py @@ -1,3 +1,4 @@ +import os from typing import List from models.tool_definitions import AgentGoal import tools.tool_registry as tool_registry @@ -33,14 +34,14 @@ goal_choose_agent_type = AgentGoal( "1. ListAgents: List agents available to interact with. Do not ask for user confirmation for this tool. " "2. ChangeGoal: Change goal of agent " "After these tools are complete, change your goal to the new goal as chosen by the user. ", - starter_prompt=starter_prompt_generic + " Begin by listing all details of all agents as provided by the output of the first tool included in this goal. ", + starter_prompt="Welcome me, give me a description of what you can do, then ask me for the details you need to do your job. Listi all details of all agents as provided by the output of the first tool included in this goal. ", example_conversation_history="\n ".join( [ "agent: Here are the currently available agents.", - "user_confirmed_tool_run: ", - "tool_result: { 'agent_name': 'Event Flight Finder', 'goal_id': 'goal_event_flight_invoice', 'agent_description': 'Helps users find interesting events and arrange travel to them' }", - "agent: The available agents are: 1. Event Flight Finder. \n Which agent would you like to speak to? (You can respond with name or number.)", - "user: 1, Event Flight Finder", + "tool_result: { agents: 'agent_name': 'Event Flight Finder', 'goal_id': 'goal_event_flight_invoice', 'agent_description': 'Helps users find interesting events and arrange travel to them'," + "'agent_name': 'Schedule PTO', 'goal_id': 'goal_hr_schedule_pto', 'agent_description': 'Schedule PTO based on your available PTO.' }", + "agent: The available agents are: Event Flight Finder and Schedule PTO. \n Which agent would you like to speak to? ", + "user: I'd like to find an event and book flights using the Event Flight Finder", "user_confirmed_tool_run: ", "tool_result: { 'new_goal': 'goal_event_flight_invoice' }", ] @@ -288,7 +289,7 @@ goal_fin_check_account_balances = AgentGoal( example_conversation_history="\n ".join( [ "user: I'd like to check my account balances", - "agent: Sure! I can help you out with that. May I have your email address or account number?", + "agent: Sure! I can help you out with that. May I have your email address and account number?", "user: email is bob.johnson@emailzzz.com ", "user_confirmed_tool_run: ", "tool_result: { 'status': account valid }", @@ -466,3 +467,19 @@ goal_list.append(goal_fin_loan_application) goal_list.append(goal_ecomm_list_orders) goal_list.append(goal_ecomm_order_status) + +# for multi-goal, just set list agents as the last tool +first_goal_value = os.getenv("AGENT_GOAL") +if first_goal_value is None: + multi_goal_mode = True # default if unset +elif first_goal_value is not None and first_goal_value.lower() != "goal_choose_agent_type": + multi_goal_mode = False +else: + multi_goal_mode = True + +if multi_goal_mode: + for goal in goal_list: + if any(goal.tools.name == "ListAgents" for goal in goal_list): + continue + else: + goal.tools.append(tool_registry.list_agents_tool) \ No newline at end of file diff --git a/tools/tool_registry.py b/tools/tool_registry.py index ed19e63..1d11e65 100644 --- a/tools/tool_registry.py +++ b/tools/tool_registry.py @@ -281,7 +281,7 @@ financial_get_account_balances = ToolDefinition( arguments=[ ToolArgument( - name="accountkey", + name="email_address_or_account_ID", type="string", description="email address or account ID of user", ), @@ -295,7 +295,7 @@ financial_move_money = ToolDefinition( arguments=[ ToolArgument( - name="accountkey", + name="email_address_or_account_ID", type="string", description="email address or account ID of user", ), @@ -325,7 +325,7 @@ financial_submit_loan_approval = ToolDefinition( arguments=[ ToolArgument( - name="accountkey", + name="email_address_or_account_ID", type="string", description="email address or account ID of user", ), From 823208db3cce547f9035c8d167e51493916496ac Mon Sep 17 00:00:00 2001 From: Joshua Smith Date: Tue, 22 Apr 2025 12:22:42 -0400 Subject: [PATCH 2/3] - adding Steve's updated confirm box UI - goal prompts and agent changes to smooth out that interaction and remove listagents duplication adding extra confirmation for money movement tool --- frontend/src/components/ConfirmInline.jsx | 196 ++++++++++++++++------ prompts/agent_prompt_generators.py | 2 +- todo.md | 11 +- tools/goal_registry.py | 28 ++-- tools/tool_registry.py | 12 +- workflows/agent_goal_workflow.py | 32 +--- 6 files changed, 177 insertions(+), 104 deletions(-) diff --git a/frontend/src/components/ConfirmInline.jsx b/frontend/src/components/ConfirmInline.jsx index c126fee..6e9d876 100644 --- a/frontend/src/components/ConfirmInline.jsx +++ b/frontend/src/components/ConfirmInline.jsx @@ -1,65 +1,153 @@ -import React, { memo } from "react"; +import React, { memo, useState } from "react"; +/** Inline SVG icons so we don’t need an extra library */ +const PlayIcon = ({ className }) => ( + +); + +const SpinnerIcon = ({ className }) => ( + +); + +/** + * User‑friendly confirmation card that surfaces tool invocation details + * without developer jargon. Tweaks include: + * • Left green accent‑border + compact heading (visual hierarchy) + * • Collapsible arg list & array support (argument‑list UX) + * • Mobile‑first, pulsing confirm button (button affordance) + */ const ConfirmInline = memo(({ data, confirmed, onConfirm }) => { - const { args, tool } = data || {}; + const { args = {}, tool } = data || {}; - const renderArgs = () => { - if (!args) return null; - - return ( -
- Args: -
-                    {JSON.stringify(args, null, 2)}
-                
-
- ); - }; + // Collapsible argument list if we have more than 4 root keys + const [showAll, setShowAll] = useState(false); + const argEntries = Object.entries(args); + const shouldCollapse = argEntries.length > 4 && !showAll; - if (confirmed) { - return ( -
-
-
- Tool: {tool ?? "Unknown"} -
- {renderArgs()} -
-
- Running {tool}... -
-
- ); + /** Recursively pretty‑print argument values (objects & arrays). */ + const RenderValue = ({ value }) => { + if (value === null || value === undefined) return ; + + if (Array.isArray(value)) { + return ( +
    + {value.map((v, i) => ( +
  1. + +
  2. + ))} +
+ ); } + if (typeof value === "object") { + return ( +
    + {Object.entries(value).map(([k, v]) => ( +
  • + {k}:  + +
  • + ))} +
+ ); + } + + return {String(value)}; + }; + + const cardBase = + "mt-2 p-3 rounded-lg border-l-4 border-green-500 bg-gray-100/60 dark:bg-gray-800/60 shadow-sm"; + + // ===== Running state ===== + if (confirmed) { return ( -
-
-
- Agent is ready to run the tool: {tool ?? "Unknown"} -
- {renderArgs()} -
- Please confirm to proceed. -
-
-
- -
-
+
+ + + Running {tool ?? "Unknown"} … + +
); + } + + // ===== Confirmation state ===== + return ( +
+ {/* Heading */} +
+ +

+ Ready to run {tool ?? "Unknown"} +

+
+ + {/* Dynamic argument list */} + {argEntries.length > 0 && ( +
+ {argEntries + .slice(0, shouldCollapse ? 4 : argEntries.length) + .map(([k, v]) => ( +
+ {k}:  + +
+ ))} + {shouldCollapse && ( + + )} + {showAll && argEntries.length > 4 && ( + + )} +
+ )} + + {/* Confirm button */} +
+ +
+
+ ); }); -ConfirmInline.displayName = 'ConfirmInline'; +ConfirmInline.displayName = "ConfirmInline"; -export default ConfirmInline; +export default ConfirmInline; \ No newline at end of file diff --git a/prompts/agent_prompt_generators.py b/prompts/agent_prompt_generators.py index aaa3844..5d5aad0 100644 --- a/prompts/agent_prompt_generators.py +++ b/prompts/agent_prompt_generators.py @@ -187,7 +187,7 @@ def generate_pick_new_goal_guidance()-> str: str: A prompt string prompting the LLM to when to go to pick-new-goal """ if is_multi_goal_mode(): - return 'Next should only be "pick-new-goal" if all tools have been run for the current goal (use the system prompt to figure that out) and the last successful tool was not ListAgents, or the user explicitly requested to pick a new goal.' + return 'Next should only be "pick-new-goal" if all tools have been run for the current goal (use the system prompt to figure that out), or the user explicitly requested to pick a new goal.' else: return 'Next should never be "pick-new-goal".' diff --git a/todo.md b/todo.md index 42c03cf..4e4e611 100644 --- a/todo.md +++ b/todo.md @@ -1,5 +1,6 @@ # todo list -[ ] expand [tests](./tests/agent_goal_workflow_test.py)
+[x] take steve's confirm box changes https://temporaltechnologies.slack.com/archives/D062SV8KEEM/p1745251279164319
+[ ] consider adding goal categories to goal picker [ ] adding fintech goals
- Fraud Detection and Prevention - The AI monitors transactions across accounts, flagging suspicious activities (e.g., unusual spending patterns or login attempts) and autonomously freezing accounts or notifying customers and compliance teams.
@@ -12,10 +13,6 @@ [ ] for demo simulate failure - add utilities/simulated failures from pipeline demo
-[x] ecommerce goals
-- [x] add to docs
-- [x] decide about api key names with Laine
- [ ] LLM failure->autoswitch:
- detect failure in the activity using failurecount
- activity switches to secondary LLM defined in .env @@ -23,6 +20,10 @@ [ ] for demo simulate failure - add utilities/simulated failures from pipeline demo
+[ ] expand [tests](./tests/agent_goal_workflow_test.py)
+[ ] collapse history/summarize after goal finished
+[ ] add aws bedrock
+ [ ] ask the ai agent how it did at the end of the conversation, was it efficient? successful? insert a search attribute to document that before return
- Insight into the agent’s performance
[ ] non-retry the api key error - "Invalid API Key provided: sk_test_**J..." and "AuthenticationError"
diff --git a/tools/goal_registry.py b/tools/goal_registry.py index 2bdc990..33e227c 100644 --- a/tools/goal_registry.py +++ b/tools/goal_registry.py @@ -24,23 +24,23 @@ goal_choose_agent_type = AgentGoal( id = "goal_choose_agent_type", category_tag="agent_selection", agent_name="Choose Agent", - agent_friendly_description="Choose the type of agent to assist you today.", + agent_friendly_description="Choose the type of agent to assist you today. You can always interrupt an existing agent to pick a new one.", tools=[ tool_registry.list_agents_tool, tool_registry.change_goal_tool, ], description="The user wants to choose which type of agent they will interact with. " - "Help the user gather args for these tools, in order: " + "Help the user select an agent by gathering args for the Changegoal tool, in order: " "1. ListAgents: List agents available to interact with. Do not ask for user confirmation for this tool. " "2. ChangeGoal: Change goal of agent " "After these tools are complete, change your goal to the new goal as chosen by the user. ", - starter_prompt="Welcome me, give me a description of what you can do, then ask me for the details you need to do your job. Listi all details of all agents as provided by the output of the first tool included in this goal. ", + starter_prompt= silly_prompt + "Welcome me, give me a description of what you can do, then ask me for the details you need to do your job. List all details of all agents as provided by the output of the first tool included in this goal. ", example_conversation_history="\n ".join( [ "agent: Here are the currently available agents.", "tool_result: { agents: 'agent_name': 'Event Flight Finder', 'goal_id': 'goal_event_flight_invoice', 'agent_description': 'Helps users find interesting events and arrange travel to them'," "'agent_name': 'Schedule PTO', 'goal_id': 'goal_hr_schedule_pto', 'agent_description': 'Schedule PTO based on your available PTO.' }", - "agent: The available agents are: Event Flight Finder and Schedule PTO. \n Which agent would you like to speak to? ", + "agent: The available agents are: Event Flight Finder and Schedule PTO. \n Which agent would you like to work with? ", "user: I'd like to find an event and book flights using the Event Flight Finder", "user_confirmed_tool_run: ", "tool_result: { 'new_goal': 'goal_event_flight_invoice' }", @@ -276,7 +276,7 @@ goal_hr_check_paycheck_bank_integration_status = AgentGoal( goal_fin_check_account_balances = AgentGoal( id = "goal_fin_check_account_balances", category_tag="fin", - agent_name="Check balances", + agent_name="Account Balances", agent_friendly_description="Check your account balances in Checking, Savings, etc.", tools=[ tool_registry.financial_check_account_is_valid, @@ -326,7 +326,7 @@ goal_fin_move_money = AgentGoal( [ "user: I'd like to transfer some money", "agent: Sure! I can help you out with that. May I have account number and email address?", - "user: account number is 11235813", + "user: my account number is 11235 and my email address is matt.murdock@nelsonmurdock.com", "user_confirmed_tool_run: ", "tool_result: { 'status': account valid }", "agent: Great! Here are your account balances:", @@ -350,8 +350,8 @@ goal_fin_move_money = AgentGoal( goal_fin_loan_application = AgentGoal( id = "goal_fin_loan_application", category_tag="fin", - agent_name="Easy Loan Apply", - agent_friendly_description="Initiate loan application.", + agent_name="Easy Loan", + agent_friendly_description="Initiate a simple loan application.", tools=[ tool_registry.financial_check_account_is_valid, tool_registry.financial_submit_loan_approval, @@ -478,7 +478,11 @@ else: if multi_goal_mode: for goal in goal_list: - if any(goal.tools.name == "ListAgents" for goal in goal_list): - continue - else: - goal.tools.append(tool_registry.list_agents_tool) \ No newline at end of file + list_agents_found:bool = False + for tool in goal.tools: + if tool.name == "ListAgents": + list_agents_found = True + continue + if list_agents_found == False: + goal.tools.append(tool_registry.list_agents_tool) + continue \ No newline at end of file diff --git a/tools/tool_registry.py b/tools/tool_registry.py index 1d11e65..1e76ab4 100644 --- a/tools/tool_registry.py +++ b/tools/tool_registry.py @@ -299,22 +299,26 @@ financial_move_money = ToolDefinition( type="string", description="email address or account ID of user", ), - ToolArgument( + ToolArgument( name="accounttype", type="string", description="account type, such as checking or savings", ), - ToolArgument( + ToolArgument( name="amount", type="string", description="amount to move in the order", ), - - ToolArgument( + ToolArgument( name="destinationaccount", type="string", description="account number to move the money to", ), + ToolArgument( + name="userConfirmation", + type="string", + description="Indication of user's desire to move money", + ), ], ) diff --git a/workflows/agent_goal_workflow.py b/workflows/agent_goal_workflow.py index 3b2757b..6bc6aee 100644 --- a/workflows/agent_goal_workflow.py +++ b/workflows/agent_goal_workflow.py @@ -169,35 +169,11 @@ class AgentGoalWorkflow: # if we have all needed arguments (handled above) and not holding for a debugging confirm, proceed: else: self.confirmed = True - - # else if the next step is to pick a new goal, set the goal and tool to do it + # else if the next step is to pick a new goal, set that to be the goal elif next_step == "pick-new-goal": - if self.goal.id != "goal_choose_agent_type": - self.add_message("agent", tool_data) - workflow.logger.info("All tools completed and new Agent Goal recommended. Resetting goal.") - self.change_goal("goal_choose_agent_type") - next_step = tool_data["next"] = "confirm" - current_tool = tool_data["tool"] = "ListAgents" - waiting_for_confirm = True - self.tool_data = tool_data - if self.show_tool_args_confirmation: - self.confirmed = False - # if we have all needed arguments (handled above) and not holding for a debugging confirm, proceed: - else: - self.confirmed = True - continue - else: - if not current_tool == "ListAgents": - current_tool = tool_data["tool"] = "ListAgents" - waiting_for_confirm = True - - self.tool_data = tool_data - next_step = tool_data["next"] = "confirm" - if self.show_tool_args_confirmation: - self.confirmed = False - # if we have all needed arguments (handled above) and not holding for a debugging confirm, proceed: - else: - self.confirmed = True + workflow.logger.info("All steps completed. Resetting goal.") + self.change_goal("goal_choose_agent_type") + # else if the next step is to be done with the conversation such as if the user requests it via asking to "end conversation" From 47c4b99f2c17bc008539df6a26b00f5404740e90 Mon Sep 17 00:00:00 2001 From: Joshua Smith Date: Tue, 22 Apr 2025 15:16:33 -0400 Subject: [PATCH 3/3] adjusting loan sample conversation --- tools/goal_registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/goal_registry.py b/tools/goal_registry.py index 33e227c..a25cd0c 100644 --- a/tools/goal_registry.py +++ b/tools/goal_registry.py @@ -363,7 +363,7 @@ goal_fin_loan_application = AgentGoal( example_conversation_history="\n ".join( [ "user: I'd like to apply for a loan", - "agent: Sure! I can help you out with that. May I have account number for confirmation?", + "agent: Sure! I can help you out with that. May I have account number and email address to validate your account?", "user: account number is 11235813", "user_confirmed_tool_run: ", "tool_result: { 'status': account valid }",