What would be the preferred way to build a MMSE (M...
# ask-ai
s
What would be the preferred way to build a MMSE (Mini mentBased on the codebase analysis, here are the core implementations for agent handoff and tool calls: ## Agent Handoff Implementation ### 1. Base Transition Mechanism
Copy code
75:85:hdsr_multiagent/agents/base_agent.py
async def transition_to(self, agent_cls: type, message: Optional[str] = None) -> Tuple[Agent, str]:
    """Transition to another agent with optional announcement."""
    from hdsr_multiagent.models.data_models import HDSRData

    hdsr_data: HDSRData = self.session.userdata
    hdsr_data.previous_agent = self

    new_agent = agent_cls()
    if message:
        new_agent._transition_message = message

    <http://logger.info|logger.info>(f"Transitioning from {self.__class__.__name__} to {agent_cls.__name__}")
    return new_agent, message or f"Transitioning to {agent_cls.__name__}"
### 2. Orchestrator → Question Agent Handoff
Copy code
60:75:hdsr_multiagent/agents/orchestrator_agent.py
@function_tool
async def record_consent(
    self,
    consent_given: Annotated[bool, Field(description="Whether the patient has given consent to participate")],
    context: RunContext_T
) -> tuple[Agent, str]:
    """Record patient consent and begin the assessment if consent is given"""
    hdsr_data: HDSRData = context.session.userdata

    if not consent_given:
        await self.say(CONSENT_DECLINED_MESSAGE)
        return None, "Assessment cancelled - no consent given"

    # Consent given - proceed directly to assessment
    hdsr_data.assessment_started = True
    hdsr_data.current_question = HDSRQuestion.AGE
    hdsr_data.transition_count += 1

    return await self.transition_to(
        HDSRQuestionAgent,
        "Thank you for your consent! Let's begin the assessment."
    )
### 3. Question Agent → Summary Agent Handoff
Copy code
520:540:hdsr_multiagent/agents/question_agent.py
@function_tool
async def record_backwards_response_second(
    self,
    backwards_sequence: Annotated[str, Field(description="The numbers the patient said backwards for the second sequence (4, 1, 5)")],
    context: RunContext_T
) -> tuple[Agent, str]:
    """Record response to second backwards digit span sequence and transition to summary"""
    hdsr_data: HDSRData = context.session.userdata

    # Store second sequence and combine both
    hdsr_data.backwards_second = backwards_sequence
    first_sequence = hdsr_data.backwards_first or "Not recorded"
    combined_response = f"First sequence: {first_sequence}, Second sequence: {backwards_sequence}"

    hdsr_data.record_response(HDSRQuestion.BACKWARDS, combined_response)
    hdsr_data.assessment_completed = True
    hdsr_data.transition_count += 1

    return await self.transition_to(
        HDSRSummaryAgent,
        "Perfect! We've completed all the questions. Thank you for your participation."
    )
## Tool Calls for Questionnaire State Handling ### 1. Age Question
Copy code
200:215:hdsr_multiagent/agents/question_agent.py
@function_tool
async def record_age_response(
    self,
    age: Annotated[int, Field(description="Patient's stated age")],
    context: RunContext_T,
) -> None:
    """Record response to age question (Question 1)"""
    hdsr_data: HDSRData = context.session.userdata
    if not hdsr_data.can_proceed_to_question(HDSRQuestion.AGE):
        await self.say(QUESTION_ORDER_ERROR_MESSAGE)
        return

    hdsr_data.record_response(HDSRQuestion.AGE, str(age))
    await self.say("Great! Let's move to the next question.")
    hdsr_data.current_question = HDSRQuestion.DATE_TIME

    # Automatically move to next question
    await self._ask_next_question(hdsr_data, context)
### 2. DateTime Question
Copy code
220:240:hdsr_multiagent/agents/question_agent.py
@function_tool
async def record_datetime_response(
    self,
    year: Annotated[str, Field(description="Year mentioned by patient")],
    month: Annotated[str, Field(description="Month mentioned by patient")],
    day: Annotated[str, Field(description="Day mentioned by patient")],
    day_of_week: Annotated[str, Field(description="Day of week mentioned by patient")],
    context: RunContext_T,
) -> None:
    """Record response to date/time question (Question 2)"""
    hdsr_data: HDSRData = context.session.userdata
    if not hdsr_data.can_proceed_to_question(HDSRQuestion.DATE_TIME):
        await self.say("We need to complete the previous question first.")
        return

    response = f"Year: {year}, Month: {month}, Day: {day}, Day of week: {day_of_week}"
    hdsr_data.record_response(HDSRQuestion.DATE_TIME, response)
    await self.say("Thank you. Moving to the next question.")
    hdsr_data.current_question = HDSRQuestion.THREE_WORDS_IMMEDIATE

    # Automatically move to next question
    await self._ask_next_question(hdsr_data, context)
### 3. Fluency Test (Special State Handling)
Copy code
380:420:hdsr_multiagent/agents/question_agent.py
@function_tool
async def start_fluency_test(
    self,
    understood: Annotated[bool, Field(description="Whether the patient understands the fluency instructions")],
    context: RunContext_T,
) -> None:
    """Start the fluency test after patient confirms understanding"""
    hdsr_data: HDSRData = context.session.userdata
    if not hdsr_data.can_proceed_to_question(HDSRQuestion.FLUENCY):
        await self.session.say("We need to complete the previous question first.")
        return

    if understood:
        await self.say("Great. After I say START, you'll have exactly one minute to name as many animals as you can. I will remain completely silent during your minute.")
        await asyncio.sleep(1.0)
        await self.say("3... 2... 1... START!")

        # Disable audio output channel and enable strict silent mode
        try:
            self.session.output.set_audio_enabled(False)
        except Exception:
            pass
        self._fluency_silent_mode = True

        # Schedule the strict silent timer
        self._schedule_fluency_timer()
### 4. State Validation
Copy code
70:85:hdsr_multiagent/models/data_models.py
def can_proceed_to_question(self, question: HDSRQuestion) -> bool:
    """Check if we can proceed to a specific question"""
    questions_order = QUESTION_SEQUENCE
    current_index = questions_order.index(question)

    # Can always start with first question
    if current_index == 0:
        return True

    # Check if previous question is completed
    previous_question = questions_order[current_index - 1]
    return previous_question in self.completed_questions

def get_next_question(self) -> Optional[HDSRQuestion]:
    """Get the next question that needs to be completed"""
    questions_order = QUESTION_SEQUENCE
    for question in questions_order:
        if question not in self.completed_questions:
            return question
    return None
### 5. Response Recording
Copy code
50:60:hdsr_multiagent/models/data_models.py
def record_response(self, question: HDSRQuestion, response: str, notes: str = ""):
    """Record a response and update state"""
    self.responses[question.value] = HDSRResponse(
        question=question.value,
        response=response,
        notes=notes
    )
    if question not in self.completed_questions:
        self.completed_questions.append(question)
    <http://logger.info|logger.info>(f"Recorded response for {question.value}: {response}")
The core pattern is: 1. Tool calls validate state and record responses 2. State updates happen in
HDSRData
3. Automatic progression to next question after each tool call 4. Agent transitions use
transition_to()
method with optional messages 5. Context preservation between agents via `userdata`al state examination) screening? It has very clear step-by-step test/list of questions that need to be answered. I have currently built it using three separate Agents (intro, questioner and summary) but I seem to be having some inconsistencies with the reliability and handoff. This is how I currently use the livekit framework:
t
Thanks for reaching out, Iivo. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
To build a Mini-Mental State Examination (MMSE) screening using the LiveKit framework, here’s a friendly step-by-step guide to help you get started: • Define Agents for Each Section: Think of creating a dedicated agent for each part of the MMSE exam—like orientation, registration, and recall. Each agent will take care of its own questions and logic, making things super organized. • Implement State Management: Use the session’s
userdata
to keep track of everything—user responses, where they are in the exam, and more. For example, you might do
session.userdata = MMSEState(responses={})
to get started. • Agent Handoff: When one section wraps up, smoothly hand off to the next agent using the
transition_to
method. So after finishing one part, you’d return a new agent instance for the next section. • Use Function Tools for Interaction: Inside each agent, set up function tools to handle user responses and decide what happens next. Something like
@function_tool() async def handle_response(...)
works great here. • Initialize the Workflow: Kick off the session with the first agent managing the initial section of the MMSE. For example,
await session.start(agent=MMSEAgent(job_context=ctx), room=ctx.room)
. This way, you keep everything neat and flowing smoothly—from clear handoffs between agents to tracking progress throughout the exam. If you want, I’m happy to dive deeper into any part, like specific sections or how to handle scoring. Just let me know! Sources: Tool definition and use | LiveKit Docs | Workflows | LiveKit Docs