import streamlit as st
import asyncio
import shutil
from dotenv import load_dotenv
from agents import Agent, Runner, trace, ModelSettings
from agents.mcp import MCPServerStdio
from openai.types.shared import Reasoning
load_dotenv()
def run_async_task(coro):
"""
Runs an asynchronous coroutine, managing the event loop.
This creates a new event loop for each task, which is robust
if Streamlit's environment has an existing, potentially conflicting, loop.
"""
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
result = loop.run_until_complete(coro)
finally:
loop.close()
try:
main_loop = asyncio.get_event_loop_policy().get_event_loop()
asyncio.set_event_loop(main_loop)
except RuntimeError:
asyncio.set_event_loop(None)
return result
async def process_message_with_agent(conversation_history: list[dict[str, any]], uid: str):
"""
Processes the conversation history using the OMI agent and returns the response
along with reasoning/tool call details for the latest turn.
"""
print(
f"process_message_with_agent called with UID: {uid} and conversation history length: {len(conversation_history)}"
)
if conversation_history:
last_msg = conversation_history[-1]
print(f"Last message - Role: {last_msg.get('role')}, Content snippet: {str(last_msg.get('content'))[:100]}...")
if not uid:
st.error("Error: OMI_UID was not provided to the agent processing function.")
return (
"Error: OMI_UID is not configured. Please enter it in the sidebar settings.",
[],
)
agent_input_messages = []
for msg in conversation_history:
role = msg.get("role")
content = msg.get("content")
if role and content is not None:
agent_input_messages.append({"role": role, "content": content})
else:
print(f"Warning: Skipping message in history due to missing 'role' or 'content': {msg}")
if not agent_input_messages:
st.error("Error: No valid messages to process after filtering history.")
return ("Error: Conversation history is empty or invalid.", [])
try:
async with MCPServerStdio(
cache_tools_list=False,
params={"command": "uvx", "args": ["mcp-server-omi", "-v"]},
) as server:
omi_agent = Agent(
name="Omi Agent",
instructions=f"You are a helpful assistant that answers questions based on my Omi data, my UID is {uid}. You are processing a conversation, the history of which is provided.",
mcp_servers=[server],
model="o3",
model_settings=ModelSettings(reasoning=Reasoning(effort="high")),
)
with trace(workflow_name="Stramlit Omi MCP Example"):
run_output = await Runner.run(
starting_agent=omi_agent,
input=agent_input_messages,
)
print("run_output:", run_output)
final_response = (
run_output.final_output if run_output and run_output.final_output else "Sorry, I couldn't process that."
)
reasoning_details = []
if run_output and hasattr(run_output, "new_items") and run_output.new_items:
for item in run_output.new_items:
reasoning_details.append(item.raw_item)
elif run_output:
print("Note: run_output.new_items was empty or not present.")
else:
print("Warning: run_output was None.")
return final_response, reasoning_details
except Exception as e:
st.error(f"An error occurred during agent processing: {e}")
print(f"Detailed error in process_message_with_agent: {e}")
return "An error occurred while trying to get a response.", []
st.set_page_config(page_title="Omi Agent Chat", layout="wide")
st.title("🤖 Omi Agent Chat")
UVX_PATH = shutil.which("uvx")
if not UVX_PATH:
st.error(
"Critical Error: `uvx` command not found. "
"Please ensure it's installed and in your system's PATH. "
"The agent cannot function without it."
)
st.stop()
if "user_omi_uid" not in st.session_state:
st.session_state.user_omi_uid = ""
with st.sidebar:
st.header("Settings")
st.session_state.user_omi_uid = st.text_input(
"Enter your OMI UID:",
value=st.session_state.user_omi_uid,
help="Your OMI Unique Identifier is required to interact with the agent.",
)
if st.button("Clear Chat History"):
st.session_state.messages = []
st.rerun()
if not st.session_state.user_omi_uid.strip():
st.warning("Please enter your OMI UID in the sidebar settings to start chatting.")
st.stop()
if "messages" not in st.session_state:
st.session_state.messages = []
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
if message["role"] == "assistant" and "reasoning" in message and message["reasoning"]:
with st.expander("View Reasoning/Tool Calls", expanded=False):
for i, detail in enumerate(message["reasoning"]):
st.code(str(detail), language="json")
if i < len(message["reasoning"]) - 1:
st.markdown("---")
if prompt := st.chat_input("Ask Omi about your data..."):
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)
with st.chat_message("assistant"):
message_placeholder = st.empty()
message_placeholder.markdown("Thinking...")
uid = st.session_state.user_omi_uid
if not uid.strip():
message_placeholder.error("Error: OMI_UID not set. Please enter it in the sidebar.")
else:
response_text, reasoning_data = run_async_task(process_message_with_agent(st.session_state.messages, uid))
message_placeholder.markdown(response_text)
st.session_state.messages.append(
{
"role": "assistant",
"content": response_text,
"reasoning": reasoning_data,
}
)
if reasoning_data:
with st.expander(
"View Reasoning/Tool Calls", expanded=False
):
for i, detail in enumerate(reasoning_data):
st.code(str(detail), language="json")
if i < len(reasoning_data) - 1:
st.markdown("---")