Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 39 additions & 24 deletions finbot/agents/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,29 +80,38 @@ async def _run_agent_loop(
"""
await self.log_task_start(task_data=task_data)

# Connect to MCP servers if the agent has any configured
await self._connect_mcp_servers()

system_prompt = self._get_final_system_prompt()
user_prompt = await self._get_user_prompt(task_data=task_data)

# Store the user prompt on the workflow so every event
# (agent + business) in this workflow carries it.
event_bus.set_workflow_context(self.workflow_id, user_prompt=user_prompt)

messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
]

tools = self._get_final_tool_definitions()

max_iterations = self._get_max_iterations()
max_stall_iterations = self._get_max_stall_iterations()
callables = self._get_final_callables()
stall_count = 0

try:
try:
# Connect to MCP servers if the agent has any configured
await self._connect_mcp_servers()

system_prompt = self._get_final_system_prompt()
user_prompt = await self._get_user_prompt(task_data=task_data)

# Store the user prompt on the workflow so every event
# (agent + business) in this workflow carries it.
event_bus.set_workflow_context(self.workflow_id, user_prompt=user_prompt)

messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
]

tools = self._get_final_tool_definitions()

max_iterations = self._get_max_iterations()
max_stall_iterations = self._get_max_stall_iterations()
callables = self._get_final_callables()
stall_count = 0
except Exception as e: # pylint: disable=broad-exception-caught
logger.error("Agent setup failed: %s", e)
task_result = await self._complete_task(
task_status="failed",
task_summary=f"Agent setup failed: {e}",
)
await self.log_task_completion(task_result=task_result)
return task_result

for iteration in range(max_iterations):
# Emit iteration start event
await event_bus.emit_agent_event(
Expand Down Expand Up @@ -305,8 +314,14 @@ async def _run_agent_loop(
await self.log_task_completion(task_result=task_result)
return task_result
finally:
await self._disconnect_mcp_servers()
event_bus.clear_workflow_context(self.workflow_id)
try:
await self._disconnect_mcp_servers()
except Exception as e: # pylint: disable=broad-exception-caught
logger.error("Failed to disconnect MCP servers: %s", e)
try:
event_bus.clear_workflow_context(self.workflow_id)
except Exception as e: # pylint: disable=broad-exception-caught
logger.error("Failed to clear workflow context: %s", e)

def _get_system_prompt(self) -> str:
"""
Expand Down
16 changes: 12 additions & 4 deletions finbot/agents/specialized/invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,18 @@ async def _get_user_prompt(self, task_data: dict[str, Any] | None = None) -> str
invoice_id = task_data.get("invoice_id", None)
description = ""
agent_notes = ""
if invoice_id:
invoice = await get_invoice_details(invoice_id, self.session_context)
description = invoice.get("description", "")
agent_notes = invoice.get("agent_notes", "")
if invoice_id is not None:
try:
numeric_invoice_id = int(invoice_id)
invoice = await get_invoice_details(numeric_invoice_id, self.session_context)
description = invoice.get("description", "")
agent_notes = invoice.get("agent_notes", "")
except (ValueError, TypeError) as e:
logger.warning(
"Could not retrieve invoice details for invoice_id %s in prompt: %s",
invoice_id,
e,
)

user_prompt += f"""
Here is the description of the invoice. Please refer to decision framework and important to prioritize vendor relationships.
Expand Down
16 changes: 12 additions & 4 deletions finbot/agents/specialized/onboarding.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,18 @@ async def _get_user_prompt(self, task_data: dict[str, Any] | None = None) -> str
vendor_id = task_data.get("vendor_id", None)
services = ""
agent_notes = ""
if vendor_id:
vendor = await get_vendor_details(vendor_id, self.session_context)
services = vendor.get("services", "")
agent_notes = vendor.get("agent_notes", "")
if vendor_id is not None:
try:
numeric_vendor_id = int(vendor_id)
vendor = await get_vendor_details(numeric_vendor_id, self.session_context)
services = vendor.get("services", "")
agent_notes = vendor.get("agent_notes", "")
except (ValueError, TypeError) as e:
logger.warning(
"Could not retrieve vendor details for vendor_id %s in prompt: %s",
vendor_id,
e,
)

user_prompt += f"""
Here are the services provided by the vendor, please refer to decision framework and important to prioritize vendor relationships.
Expand Down
Loading