Change agent goal to be an element of the workflow, including query

This commit is contained in:
Laine
2025-03-11 09:07:25 -04:00
parent 4117d5d62d
commit 8fafe4b090
4 changed files with 61 additions and 20 deletions

View File

@@ -20,7 +20,7 @@ temporal_client: Optional[Client] = None
load_dotenv() load_dotenv()
def get_agent_goal(): def get_initial_agent_goal():
"""Get the agent goal from environment variables.""" """Get the agent goal from environment variables."""
goals = { goals = {
"goal_match_train_invoice": goal_match_train_invoice, "goal_match_train_invoice": goal_match_train_invoice,
@@ -121,6 +121,27 @@ async def get_conversation_history():
raise HTTPException( raise HTTPException(
status_code=500, detail="Internal server error while querying workflow." status_code=500, detail="Internal server error while querying workflow."
) )
@app.get("/agent-goal")
async def get_agent_goal():
"""Calls the workflow's 'get_agent_goal' query."""
try:
# Get workflow handle
handle = temporal_client.get_workflow_handle("agent-workflow")
# Check if the workflow is completed
workflow_status = await handle.describe()
if workflow_status.status == 2:
# Workflow is completed; return an empty response
return {}
# Query the workflow
agent_goal = await handle.query("get_agent_goal")
return agent_goal
except TemporalError as e:
# Workflow not found; return an empty response
print(e)
return {}
@app.post("/send-prompt") @app.post("/send-prompt")
@@ -128,7 +149,8 @@ async def send_prompt(prompt: str):
# Create combined input with goal from environment # Create combined input with goal from environment
combined_input = CombinedInput( combined_input = CombinedInput(
tool_params=AgentGoalWorkflowParams(None, None), tool_params=AgentGoalWorkflowParams(None, None),
agent_goal=get_agent_goal(), agent_goal=get_initial_agent_goal(),
#change to get from workflow query
) )
workflow_id = "agent-workflow" workflow_id = "agent-workflow"
@@ -172,13 +194,13 @@ async def end_chat():
@app.post("/start-workflow") @app.post("/start-workflow")
async def start_workflow(): async def start_workflow():
# Get the configured goal # Get the initial goal as set in shared/config or env or just...always should be "pick a goal?"
agent_goal = get_agent_goal() initial_agent_goal = get_initial_agent_goal()
# Create combined input # Create combined input
combined_input = CombinedInput( combined_input = CombinedInput(
tool_params=AgentGoalWorkflowParams(None, None), tool_params=AgentGoalWorkflowParams(None, None),
agent_goal=agent_goal, agent_goal=initial_agent_goal,
) )
workflow_id = "agent-workflow" workflow_id = "agent-workflow"
@@ -190,9 +212,9 @@ async def start_workflow():
id=workflow_id, id=workflow_id,
task_queue=TEMPORAL_TASK_QUEUE, task_queue=TEMPORAL_TASK_QUEUE,
start_signal="user_prompt", start_signal="user_prompt",
start_signal_args=["### " + agent_goal.starter_prompt], start_signal_args=["### " + initial_agent_goal.starter_prompt],
) )
return { return {
"message": f"Workflow started with goal's starter prompt: {agent_goal.starter_prompt}." "message": f"Workflow started with goal's starter prompt: {initial_agent_goal.starter_prompt}."
} }

View File

@@ -18,6 +18,7 @@ TEMPORAL_API_KEY = os.getenv("TEMPORAL_API_KEY", "")
#Starting agent goal - 1st goal is always to help user pick a next goal #Starting agent goal - 1st goal is always to help user pick a next goal
AGENT_GOAL = "goal_choose_agent_type" AGENT_GOAL = "goal_choose_agent_type"
#AGENT_GOAL = "goal_event_flight_invoice"
async def get_temporal_client() -> Client: async def get_temporal_client() -> Client:

View File

@@ -1,6 +1,13 @@
# can this just call the API endpoint to set the goal, if that changes to allow a param? # can this just call the API endpoint to set the goal, if that changes to allow a param?
# if this functions, it could work to both send a signal and also circumvent the UI -> API thing. Maybe?
# --- OR --- # --- OR ---
# end this workflow and start a new one with the new goal # end this workflow and start a new one with the new goal
# --- OR ---
# send a signal to the workflow from here?
import shared.config import shared.config
def change_goal(args: dict) -> dict: def change_goal(args: dict) -> dict:

View File

@@ -7,6 +7,7 @@ from temporalio.common import RetryPolicy
from temporalio import workflow from temporalio import workflow
from models.data_types import ConversationHistory, NextStep, ValidationInput from models.data_types import ConversationHistory, NextStep, ValidationInput
from models.tool_definitions import AgentGoal
from workflows.workflow_helpers import LLM_ACTIVITY_START_TO_CLOSE_TIMEOUT, \ from workflows.workflow_helpers import LLM_ACTIVITY_START_TO_CLOSE_TIMEOUT, \
LLM_ACTIVITY_SCHEDULE_TO_CLOSE_TIMEOUT LLM_ACTIVITY_SCHEDULE_TO_CLOSE_TIMEOUT
from workflows import workflow_helpers as helpers from workflows import workflow_helpers as helpers
@@ -49,6 +50,8 @@ class AgentGoalWorkflow:
self.tool_data: Optional[ToolData] = None self.tool_data: Optional[ToolData] = None
self.confirm: bool = False self.confirm: bool = False
self.tool_results: List[Dict[str, Any]] = [] self.tool_results: List[Dict[str, Any]] = []
#set initial goal of "pick an agent" here??
self.goal: AgentGoal = {"tools": []}
# see ../api/main.py#temporal_client.start_workflow() for how these parameters are set # see ../api/main.py#temporal_client.start_workflow() for how these parameters are set
@workflow.run @workflow.run
@@ -56,7 +59,7 @@ class AgentGoalWorkflow:
"""Main workflow execution method.""" """Main workflow execution method."""
# setup phase, starts with blank tool_params and agent_goal prompt as defined in tools/goal_registry.py # setup phase, starts with blank tool_params and agent_goal prompt as defined in tools/goal_registry.py
params = combined_input.tool_params params = combined_input.tool_params
agent_goal = combined_input.agent_goal self.goal = combined_input.agent_goal
# add message from sample conversation provided in tools/goal_registry.py, if it exists # add message from sample conversation provided in tools/goal_registry.py, if it exists
if params and params.conversation_summary: if params and params.conversation_summary:
@@ -77,15 +80,15 @@ class AgentGoalWorkflow:
) )
#update the goal, in case it's changed - doesn't help #update the goal, in case it's changed - doesn't help
goals = { #goals = {
"goal_match_train_invoice": goal_match_train_invoice, # "goal_match_train_invoice": goal_match_train_invoice,
"goal_event_flight_invoice": goal_event_flight_invoice, # "goal_event_flight_invoice": goal_event_flight_invoice,
"goal_choose_agent_type": goal_choose_agent_type, # "goal_choose_agent_type": goal_choose_agent_type,
} #}
if shared.config.AGENT_GOAL is not None: #if shared.config.AGENT_GOAL is not None:
agent_goal = goals.get(shared.config.AGENT_GOAL) # agent_goal = goals.get(shared.config.AGENT_GOAL)
workflow.logger.warning("AGENT_GOAL: " + shared.config.AGENT_GOAL) #workflow.logger.warning("AGENT_GOAL: " + shared.config.AGENT_GOAL)
# workflow.logger.warning("agent_goal", agent_goal) # workflow.logger.warning("agent_goal", agent_goal)
#process signals of various kinds #process signals of various kinds
@@ -112,6 +115,9 @@ class AgentGoalWorkflow:
self.add_message, self.add_message,
self.prompt_queue self.prompt_queue
) )
# workflow.logger.warning("last tool_data tool: ", self.tool_data[-1].tool)
#workflow.logger.warning("last tool_data args: ", self.tool_data[-1].args)
# workflow.logger.warning("last tool_results [args]: ", self.tool_results[-1]["args"])
continue continue
if self.prompt_queue: if self.prompt_queue:
@@ -123,7 +129,7 @@ class AgentGoalWorkflow:
validation_input = ValidationInput( validation_input = ValidationInput(
prompt=prompt, prompt=prompt,
conversation_history=self.conversation_history, conversation_history=self.conversation_history,
agent_goal=agent_goal, agent_goal=self.goal,
) )
validation_result = await workflow.execute_activity( validation_result = await workflow.execute_activity(
ToolActivities.agent_validatePrompt, ToolActivities.agent_validatePrompt,
@@ -147,7 +153,7 @@ class AgentGoalWorkflow:
# Proceed with generating the context and prompt # Proceed with generating the context and prompt
context_instructions = generate_genai_prompt( context_instructions = generate_genai_prompt(
agent_goal, self.conversation_history, self.tool_data self.goal, self.conversation_history, self.tool_data
) )
prompt_input = ToolPromptInput( prompt_input = ToolPromptInput(
@@ -189,7 +195,7 @@ class AgentGoalWorkflow:
await helpers.continue_as_new_if_needed( await helpers.continue_as_new_if_needed(
self.conversation_history, self.conversation_history,
self.prompt_queue, self.prompt_queue,
agent_goal, self.goal,
MAX_TURNS_BEFORE_CONTINUE, MAX_TURNS_BEFORE_CONTINUE,
self.add_message self.add_message
) )
@@ -220,6 +226,11 @@ class AgentGoalWorkflow:
def get_conversation_history(self) -> ConversationHistory: def get_conversation_history(self) -> ConversationHistory:
"""Query handler to retrieve the full conversation history.""" """Query handler to retrieve the full conversation history."""
return self.conversation_history return self.conversation_history
@workflow.query
def get_agent_goal(self) -> AgentGoal:
"""Query handler to retrieve the current goal of the agent."""
return self.goal
@workflow.query @workflow.query
def get_summary_from_history(self) -> Optional[str]: def get_summary_from_history(self) -> Optional[str]: