Merge branch 'ecommerce' of https://github.com/joshmsmith/temporal-ai-agent into ecommerce

This commit is contained in:
Laine
2025-04-17 09:19:33 -04:00
20 changed files with 387 additions and 90 deletions

View File

@@ -16,6 +16,7 @@ from .hr.checkpaybankstatus import checkpaybankstatus
from .fin.check_account_valid import check_account_valid
from .fin.get_account_balances import get_account_balance
from .fin.move_money import move_money
from .fin.submit_loan_application import submit_loan_application
from .ecommerce.get_order import get_order
from .ecommerce.track_package import track_package
@@ -57,7 +58,9 @@ def get_handler(tool_name: str):
if tool_name == "FinCheckAccountBalance":
return get_account_balance
if tool_name == "FinMoveMoneyOrder":
return move_money
return move_money
if tool_name == "FinCheckAccountSubmitLoanApproval":
return submit_loan_application
if tool_name == "GetOrder":
return get_order
if tool_name == "TrackPackage":

View File

@@ -31,7 +31,6 @@ class MoneyMovementWorkflowParameterObj:
# this assumes it's a valid account - use check_account_valid() to verify that first
async def move_money(args: dict) -> dict:
print("in move_money")
account_key = args.get("accountkey")
account_type: str = args.get("accounttype")
amount = args.get("amount")

View File

@@ -0,0 +1,103 @@
from datetime import date, timedelta
import os
from pathlib import Path
import json
from temporalio.client import (
Client,
WithStartWorkflowOperation,
WorkflowHandle,
WorkflowUpdateFailedError,
)
from temporalio import common
from dataclasses import dataclass
from typing import Optional
import asyncio
from temporalio.exceptions import WorkflowAlreadyStartedError
from shared.config import get_temporal_client
# Define data structures to match the Java workflow's expected input/output
# see https://github.com/temporal-sa/temporal-latency-optimization-scenarios for more details
@dataclass
class TransactionRequest:
amount: float
sourceAccount: str
targetAccount: str
@dataclass
class TxResult:
transactionId: str
status: str
#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")
amount = args.get("amount")
loan_status: dict = await start_workflow(amount=amount,account_name=account_key)
if loan_status.get("error") is None:
return {'status': loan_status.get("loan_application_status"), 'detailed_status': loan_status.get("application_details"), 'next_step': loan_status.get("advisement"), 'confirmation_id': loan_status.get("transaction_id")}
else:
print(loan_status)
return loan_status
# Async function to start workflow
async def start_workflow(amount: str, account_name: str, )-> dict:
# Connect to Temporal
client = await get_temporal_client()
start_real_workflow = os.getenv("FIN_START_REAL_WORKFLOW")
if start_real_workflow is not None and start_real_workflow.lower() == "false":
START_REAL_WORKFLOW = False
return {'loan_application_status': "applied", 'application_details': "loan application is submitted and initial validation is complete",'transaction_id': "APPLICATION"+account_name, 'advisement': "You'll receive a confirmation for final approval in three business days", }
else:
START_REAL_WORKFLOW = True
# Define the workflow ID and task queue
workflow_id = "LOAN_APPLICATION-"+account_name+"-"+date.today().strftime('%Y-%m-%d')
task_queue = "LatencyOptimizationTEST"
# Create a TransactionRequest (matching the Java workflow's expected input)
tx_request = TransactionRequest(
amount=float(amount),
targetAccount=account_name,
sourceAccount=account_name,
)
start_op = WithStartWorkflowOperation(
"TransactionWorkflowLocalBeforeUpdate",
tx_request,
id=workflow_id,
id_conflict_policy=common.WorkflowIDConflictPolicy.USE_EXISTING,
task_queue=task_queue,
)
try:
print("trying update-with-start")
tx_result = TxResult(
await client.execute_update_with_start_workflow(
"returnInitResult",
start_workflow_operation=start_op,
)
)
except WorkflowUpdateFailedError:
print("aww man got exception WorkflowUpdateFailedError" )
tx_result = None
return_msg = "Loan could not be processed for " + account_name
return {"error": return_msg}
workflow_handle = await start_op.workflow_handle()
print(tx_result)
print(f"Update result: Transaction ID = {tx_result.transactionId}, Message = {tx_result.status}")
# Optionally, wait for the workflow to complete and get the final result
# final_result = await handle.result()
# print(f"Workflow completed with result: {final_result}")
# return {'status': loan_status.get("loan_status"), 'detailed_status': loan_status.get("results"), 'next_step': loan_status.get("advisement"), 'confirmation_id': loan_status.get("workflowID")}
return {'loan_application_status': "applied", 'application_details': "loan application is submitted and initial validation is complete",'transaction_id': tx_result.transactionId, 'advisement': "You'll receive a confirmation for final approval in three business days", }

View File

@@ -305,6 +305,7 @@ goal_fin_check_account_balances = AgentGoal(
)
# this tool checks account balances, and uses ./data/customer_account_data.json as dummy data
# it also uses a separate workflow/tool, see ./setup.md for details
goal_fin_move_money = AgentGoal(
id = "goal_fin_move_money",
category_tag="fin",
@@ -322,7 +323,7 @@ goal_fin_move_money = AgentGoal(
starter_prompt=starter_prompt_generic,
example_conversation_history="\n ".join(
[
"user: I'd like transfer some money",
"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_confirmed_tool_run: <user clicks confirm on FincheckAccountIsValid tool>",
@@ -343,6 +344,34 @@ goal_fin_move_money = AgentGoal(
),
)
# this starts a loan approval process
# it also uses a separate workflow/tool, see ./setup.md for details #todo
goal_fin_loan_application = AgentGoal(
id = "goal_fin_loan_application",
category_tag="fin",
agent_name="Easy Loan Apply",
agent_friendly_description="Initiate loan application.",
tools=[
tool_registry.financial_check_account_is_valid,
tool_registry.financial_submit_loan_approval, #todo
],
description="The user wants to apply for a loan at the 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. FinCheckAccountSubmitLoanApproval: submit the loan for approval",
starter_prompt=starter_prompt_generic,
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?",
"user: account number is 11235813",
"user_confirmed_tool_run: <user clicks confirm on FincheckAccountIsValid tool>",
"tool_result: { 'status': account valid }",
"agent: Great! We've validated your account. What will the loan amount be?",
"user: I'd like a loan for $500",
"user_confirmed_tool_run: <user clicks confirm on FinCheckAccountSubmitLoanApproval tool>",
"tool_result: { 'status': submitted, 'detailed_status': loan application is submitted and initial validation is complete, 'confirmation id': 333421, 'next_step': You'll receive a confirmation for final approval in three business days }",
"agent: I have submitted your loan application process and the initial validation is successful. Your application ID is 333421. You'll receive a notification for final approval from us in three business days. "
# ----- E-Commerce Goals ---
#todo: add goal to list all orders for last X amount of time?
# this tool checks account balances, and uses ./data/customer_account_data.json as dummy data
@@ -430,5 +459,7 @@ 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)
goal_list.append(goal_fin_move_money)
goal_list.append(goal_fin_loan_application)
goal_list.append(goal_ecomm_list_orders)
goal_list.append(goal_ecomm_order_status)
goal_list.append(goal_ecomm_order_status)

View File

@@ -318,6 +318,22 @@ financial_move_money = ToolDefinition(
],
)
financial_submit_loan_approval = ToolDefinition(
name="FinCheckAccountSubmitLoanApproval",
description="Submit a loan application. "
"Returns the loan status. ",
arguments=[
ToolArgument(
name="accountkey",
type="string",
description="email address or account ID of user",
),
ToolArgument(
name="amount",
type="string",
description="amount requested for the loan",
# ----- ECommerce Use Case Tools -----
ecomm_list_orders = ToolDefinition(
name="ListOrders",