diff --git a/.env.example b/.env.example index ad5cffd..2ef8321 100644 --- a/.env.example +++ b/.env.example @@ -39,7 +39,7 @@ OPENAI_API_KEY=sk-proj-... AGENT_GOAL=goal_choose_agent_type # (default) #Choose which category(ies) of goals you want to be listed by the Agent - options are system (always included), hr, travel, or all. -GOAL_CATEGORIES=hr,travel # default is all +GOAL_CATEGORIES=hr,travel,fin # default is all # Set if the UI should force a user confirmation step or not SHOW_CONFIRM=True \ No newline at end of file diff --git a/adding-goals-and-tools.md b/adding-goals-and-tools.md index ec5a3f3..68b867f 100644 --- a/adding-goals-and-tools.md +++ b/adding-goals-and-tools.md @@ -52,7 +52,7 @@ description="Help the user gather args for these tools in order: " 2. Define the tool - `name`: name of the tool - this is the name as defined in the goal description list of tools. The name should be (sort of) the same as the tool name given in the goal description. So, if the description lists "CurrentPTO" as a tool, the name here should be `current_pto_tool`. - `description`: LLM-facing description of tool -- `arguments`: These are the _input_ arguments to the tool. Each input argument should be defined as a [/models/tool_definitions.py](ToolArgument). Tools don't have to have arguments but the arguments list has to be declared. If the tool you're creating doesn't have inputs, define arguments as `arguments=[]` +- `arguments`: These are the _input_ arguments to the tool. Each input argument should be defined as a [ToolArgument](./models/tool_definitions.py). Tools don't have to have arguments but the arguments list has to be declared. If the tool you're creating doesn't have inputs, define arguments as `arguments=[]` #### Create Each Tool - The tools themselves are defined in their own files in `/tools` - you can add a subfolder to organize them, see the hr tools for an example. @@ -61,8 +61,8 @@ description="Help the user gather args for these tools in order: " - The return dict should match the output format you specified in the goal's `example_conversation_history` - tools are where the user input+model output becomes deterministic. Add validation here to make sure what the system is doing is valid and acceptable -#### Add to `tools/__init__.py` -- In `tools/__init__.py`, add an import statement for each new tool as well as an applicable return statement in `get_handler`. The tool name here should match the tool name as described in the goal's `description` field. +#### Add to `tools/__init__.py` and the tool get_handler() +- In [tools/__init__.py](./tools/__init__.py), add an import statement for each new tool as well as an applicable return statement in `get_handler`. The tool name here should match the tool name as described in the goal's `description` field. Example: ``` if tool_name == "CurrentPTO": diff --git a/todo.md b/todo.md index a30eeed..44653c0 100644 --- a/todo.md +++ b/todo.md @@ -11,13 +11,20 @@ [x] create people management scenarios
[ ] 2. Others HR goals:
--- book work travel
--- check insurance coverages
--- expense management
--- check in on the health of the team
+- book work travel
+- check insurance coverages
+- expense management
+- check in on the health of the team
+ +[ ] 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.
+- Personalized Financial Advice - An AI agent analyzes a customer’s financial data (e.g., income, spending habits, savings, investments) and provides tailored advice, such as budgeting tips, investment options, or debt repayment strategies.
+- Portfolio Management and Rebalancing - The AI monitors a customer’s investment portfolio, rebalancing it automatically based on market trends, risk tolerance, and financial goals (e.g., shifting assets between stocks, bonds, or crypto).
+- money movement - start money transfer
+- [x] account balance -
-[ ] 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 +[ ] 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/__init__.py b/tools/__init__.py index 41f85c4..0dd10c0 100644 --- a/tools/__init__.py +++ b/tools/__init__.py @@ -13,6 +13,9 @@ from .hr.book_pto import book_pto from .hr.future_pto_calc import future_pto_calc from .hr.checkpaybankstatus import checkpaybankstatus +from .fin.check_account_valid import check_account_valid +from .fin.get_account_balances import get_account_balance + from .give_hint import give_hint from .guess_location import guess_location @@ -44,6 +47,10 @@ def get_handler(tool_name: str): return future_pto_calc if tool_name == "CheckPayBankStatus": return checkpaybankstatus + if tool_name == "FinCheckAccountIsValid": + return check_account_valid + if tool_name == "FinCheckAccountBalance": + return get_account_balance if tool_name == "GiveHint": return give_hint if tool_name == "GuessLocation": diff --git a/tools/data/customer_account_data.json b/tools/data/customer_account_data.json new file mode 100644 index 0000000..630c698 --- /dev/null +++ b/tools/data/customer_account_data.json @@ -0,0 +1,58 @@ +{ + "accounts": [ + { + "name": "Matt Murdock", + "email": "matt.murdock@nelsonmurdock.com", + "account_id": "11235", + "checking_balance": 875.40, + "savings_balance": 3200.15, + "bitcoin_balance": 0.1378, + "account_creation_date": "2014-03-10" + }, + { + "name": "Foggy Nelson", + "email": "foggy.nelson@nelsonmurdock.com", + "account_id": "112358", + "checking_balance": 1523.67, + "savings_balance": 4875.90, + "bitcoin_balance": 0.0923, + "account_creation_date": "2014-03-10" + }, + { + "name": "Karen Page", + "email": "karen.page@nelsonmurdock.com", + "account_id": "112", + "checking_balance": 645.25, + "savings_balance": 1830.50, + "bitcoin_balance": 0.0456, + "account_creation_date": "2015-01-15" + }, + { + "name": "Wilson Fisk", + "email": "wilson.fisk@fiskcorp.com", + "account_id": "11", + "checking_balance": 25000.00, + "savings_balance": 150000.75, + "bitcoin_balance": 5987.6721, + "account_creation_date": "2013-09-20" + }, + { + "name": "Frank Castle", + "email": "frank.castle@vigilante.net", + "account_id": "1", + "checking_balance": 320.10, + "savings_balance": 0.30, + "bitcoin_balance": 15.2189, + "account_creation_date": "2016-02-05" + }, + { + "name": "Joshua Smith", + "email": "joshmsmith@gmail.com", + "account_id": "11235813", + "checking_balance": 3021.90, + "savings_balance": 500.50, + "bitcoin_balance": 0.001, + "account_creation_date": "2020-03-19" + } + ] +} \ No newline at end of file diff --git a/tools/fin/check_account_valid.py b/tools/fin/check_account_valid.py new file mode 100644 index 0000000..d339118 --- /dev/null +++ b/tools/fin/check_account_valid.py @@ -0,0 +1,24 @@ +from pathlib import Path +import json + +# this is made to demonstrate functionality but it could just as durably be an API call +# called as part of a temporal activity with automatic retries +def check_account_valid(args: dict) -> dict: + + email = args.get("email") + account_id = args.get("account_id") + + file_path = Path(__file__).resolve().parent.parent / "data" / "customer_account_data.json" + if not file_path.exists(): + return {"error": "Data file not found."} + + with open(file_path, "r") as file: + data = json.load(file) + account_list = data["accounts"] + + for account in account_list: + if account["email"] == email or account["account_id"] == account_id: + return{"status": "account valid"} + + return_msg = "Account not found with email address " + email + " or account ID: " + account_id + return {"error": return_msg} \ No newline at end of file diff --git a/tools/fin/get_account_balances.py b/tools/fin/get_account_balances.py new file mode 100644 index 0000000..ca44fb6 --- /dev/null +++ b/tools/fin/get_account_balances.py @@ -0,0 +1,24 @@ +from pathlib import Path +import json + +# this is made to demonstrate functionality but it could just as durably be an API call +# 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") + + file_path = Path(__file__).resolve().parent.parent / "data" / "customer_account_data.json" + if not file_path.exists(): + return {"error": "Data file not found."} + + with open(file_path, "r") as file: + data = json.load(file) + account_list = data["accounts"] + + for account in account_list: + if account["email"] == account_key or account["account_id"] == account_key: + #return{"status": "account valid"} + return{ "name": account["name"], "email": account["email"], "account_id": account["account_id"], "checking_balance": account["checking_balance"], "savings_balance": account["savings_balance"], "bitcoin_balance": account["bitcoin_balance"], "account_creation_date": account["account_creation_date"] } + + return_msg = "Account not found with email address " + email + " or account ID: " + account_id + return {"error": return_msg} \ No newline at end of file diff --git a/tools/goal_registry.py b/tools/goal_registry.py index ba60843..343bb32 100644 --- a/tools/goal_registry.py +++ b/tools/goal_registry.py @@ -248,12 +248,12 @@ goal_hr_check_pto = AgentGoal( ), ) -# This goal uses the data/employee_pto_data.json file as dummy data. +# check integration with bank goal_hr_check_paycheck_bank_integration_status = AgentGoal( id = "goal_hr_check_paycheck_bank_integration_status", category_tag="hr", agent_name="Check paycheck bank integration status", - agent_friendly_description="Check your available PTO.", + agent_friendly_description="Check your integration between paycheck payer and your financial institution.", tools=[ tool_registry.paycheck_bank_integration_status_check, tool_registry.list_agents_tool, #last tool must be list_agents to fasciliate changing back to picking an agent again at the end @@ -274,6 +274,41 @@ goal_hr_check_paycheck_bank_integration_status = AgentGoal( ), ) +# this tool checks account balances, and uses ./data/customer_account_data.json as dummy data +goal_fin_check_account_balances = AgentGoal( + id = "goal_fin_check_account_balances", + category_tag="fin", + agent_name="Check balances", + agent_friendly_description="Check your account balances in Checking, Savings, etc.", + tools=[ + tool_registry.financial_check_account_is_valid, + tool_registry.financial_get_account_balances, + tool_registry.list_agents_tool, #last tool must be list_agents to fasciliate changing back to picking an agent again at the end + ], + description="The user wants to check their account balances at the bank or financial institution. To assist with that goal, help the user gather args for these tools in order: " + "1. FinCheckAccountIsValid: validate the user's account is valid" + "2. FinCheckAccountBalance: Tell the user their account balance at the bank or financial institution", + starter_prompt=starter_prompt_generic, + 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?", + "user: email is bob.johnson@emailzzz.com ", + "user_confirmed_tool_run: ", + "tool_result: { 'status': account valid }", + "agent: Great! I can tell you what the your account balances are.", + "user_confirmed_tool_run: ", + "tool_result: { 'name': Matt Murdock, 'email': matt.murdock@nelsonmurdock.com, 'account_id': 11235, 'checking_balance': 875.40, 'savings_balance': 3200.15, 'bitcoin_balance': 0.1378, 'account_creation_date': 2014-03-10 }", + "agent: Your account balances are as follows: \n " + "Checking: $875.40. \n " + "Savings: $3200.15. \n " + "Bitcoint: 0.1378 \n " + "Thanks for being a customer since 2014!", + ] + ), +) + +#todo add money movement, fraud check (update with start) #Add the goals to a list for more generic processing, like listing available agents goal_list: List[AgentGoal] = [] goal_list.append(goal_choose_agent_type) @@ -283,4 +318,6 @@ goal_list.append(goal_match_train_invoice) goal_list.append(goal_hr_schedule_pto) goal_list.append(goal_hr_check_pto) goal_list.append(goal_hr_check_paycheck_bank_integration_status) +goal_list.append(goal_fin_check_account_balances) + diff --git a/tools/tool_registry.py b/tools/tool_registry.py index 79a4225..9a96d72 100644 --- a/tools/tool_registry.py +++ b/tools/tool_registry.py @@ -252,4 +252,36 @@ paycheck_bank_integration_status_check = ToolDefinition( description="email address of user", ), ], +) + +financial_check_account_is_valid = ToolDefinition( + name="FinCheckAccountIsValid", + description="Check if an account is valid by email address or account ID. " + "Returns the account status, valid or invalid. ", + arguments=[ + ToolArgument( + name="email", + type="string", + description="email address of user", + ), + ToolArgument( + name="account_id", + type="string", + description="account ID of user", + ), + ], +) + +financial_get_account_balances = ToolDefinition( + name="FinCheckAccountBalance", + description="Get account balance for your accounts. " + "Returns the account balances of your accounts. ", + + arguments=[ + ToolArgument( + name="accountkey", + type="string", + description="email address or account ID of user", + ), + ], ) \ No newline at end of file