how can i take the inputs for data inside the data...
# ask-ai
a
how can i take the inputs for data inside the data class with the help of an agent or task or function tool in livekit when i'm using nova sonic realtime model
t
Thanks for reaching out, Ok. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
I'm glad you're interested in taking inputs for data inside a data class using an agent, task, or function tool in LiveKit with the Nova Sonic real-time model. Let's walk through the steps together: 1. Define a Data Class: First, you'll want to create a data class to hold session-specific user data. Here's a simple example:
Copy code
@dataclass
class UserData:
    customer_name: Optional[str] = None
    customer_phone: Optional[str] = None
2. Create Function Tools: Next, use function tools to collect inputs and update the data class through the
RunContext
. For instance:
Copy code
@function_tool()
async def update_name(name: str, context: RunContext[UserData]) -> str:
    context.userdata.customer_name = name
    return f"The name is updated to {name}"
3. Initialize Agent Session: Then, start an agent session, making sure to specify your data class in the
userdata
parameter:
Copy code
session = AgentSession(
    llm=aws.realtime.RealtimeModel(),
    userdata=UserData(),
)
4. Integrate with Nova Sonic: To use the Nova Sonic model, simply specify
aws.realtime.RealtimeModel
when initializing your session. 5. Optional - Use Tasks: If you want to handle operations like form filling in a structured way, tasks can be very helpful. For example:
Copy code
class CollectConsent(AgentTask[bool]):
    ...
This setup is designed to make real-time, voice-driven data collection smooth and organized, keeping your data structured and persistent throughout agent sessions. If anything feels unclear or you’d like me to help you with a specific part, please don’t hesitate to ask—I’m here to help! Sources: livekit-agents/livekit/agents/voice/generation.py | complex-agents/nova-sonic/nova-sonic-form-agent/components/ui/select.tsx | Amazon Nova Sonic integration guide | LiveKit Docs | Workflows | LiveKit Docs
a
i tried the this but i get below error aws_sdk_bedrock_runtime.models.ValidationException: RequestId=90c-9b571c92f1fd : Tool Response parsing error
t
It looks like you're encountering the error
aws_sdk_bedrock_runtime.models.ValidationException: Tool Response parsing error
, which usually happens when the tool response isn't in a valid JSON format. Don’t worry, I’m here to help you work through this! Here are some friendly steps to get things back on track: 1. Make Sure Your Tool Returns JSON-Serializable Output: Your tool functions should always return a dictionary or something that can be easily converted to JSON. For example:
Copy code
@function_tool()
async def update_name(name: str, context: RunContext[UserData]) -> dict:
    context.userdata.customer_name = name
    return {"status": "success", "name": name}
2. Check JSON Serialization: If your tool returns a string, double-check that it’s valid JSON. You can use
json.dumps
to safely serialize more complex data:
Copy code
import json
return json.dumps({"result": "your string"})
3. Turn on Debug Logging: Setting the environment variable
LK_BEDROCK_DEBUG=1
can really help you see what’s being sent to AWS Bedrock and spot any formatting hiccups. 4. Review Tool Execution: Make sure your tool function is actually running, not throwing any exceptions, and returning something that can be serialized without issues. 5. Verify Tool Schema: It’s important your tool function has clear type hints so the right schema is generated for both input and output. Following these tips should smooth out the response formatting and prevent those pesky parsing errors. If you run into any bumps or want me to walk through this with you, just let me know—I’m happy to help! Sources: livekit-agents/livekit/agents/llm/_provider_format/aws.py | agents/src/voice/generation.ts
a
this is the error i see now: ERROR livekit.agents - AI function
get_user_profile
returned an invalid output {"call_id": "95c2b06c-0bac-4345-be98-7317bb5737c2", "output": {"status": "Profile Updated", "name": "<__mp_main__.PolicyAgent object at 0x000001A0F9137980>"}} here "get_user_profile" is the name of my tool and "PolicyAgent" is the name of my agent
t
It looks like the error is happening because the tool function
get_user_profile
is returning a non-serializable object (like
PolicyAgent
), which LiveKit doesn’t support. No worries though! To fix this, you’ll want to use the agent handoff pattern to smoothly transfer control to another agent. Here’s a friendly step-by-step on how to do it: 1. Return a Structured Handoff Object: Instead of sending back the agent object directly, wrap it in a structured way. For example:
Copy code
@function_tool()
async def transfer_to_policy_agent(context: RunContext):
    return PolicyAgent(), "Transferring to the policy specialist to assist with your inquiry"
2. How It Works: LiveKit recognizes this handoff pattern and handles it properly. The agent is transferred, and the accompanying message is shown as the tool output. 3. Key Things to Keep in Mind: ◦ Avoid returning raw agent objects or any non-serializable data directly. ◦ Make sure to return only one agent instance per function call. Following these steps should help you avoid those pesky invalid output errors and make sure your agent transitions are seamless. If anything’s unclear or you want to dive deeper, just let me know—I’m here to help! Sources: agents/src/llm/chat_context.ts | livekit-agents/livekit/agents/llm/_provider_format/utils.py
a
this is my complete code, I am not returning any raw object @dataclass class UserProfile: name: Optional[str]=None class PolicyAgent(Agent): def _init_(self, chat_ctx: Optional[ChatContext] = None): super()._init_( instructions="You are a policy help agent, You have to collect the user profile data with the help of get_user_profile tool at the start of the session, without that don't answer any questions.", chat_ctx=chat_ctx, ) @function_tool async def get_user_profile(name: str, context: RunContext[UserProfile]) -> dict: context.userdata.name=name return {"status":"Profile Updated", "name": name} async def entrypoint(ctx): await ctx.connect(auto_subscribe=AutoSubscribe.AUDIO_ONLY) session = AgentSession(llm=RealtimeModel(), userdata=UserProfile()) await session.start(agent=PolicyAgent(), room=ctx.room) if name == "_main_": agents.cli.run_app(agents.WorkerOptions(entrypoint_fnc=entrypoint))
t
It looks like the issue is happening because the function tool
get_user_profile
is returning a dictionary that contains a non-serializable object reference (like
PolicyAgent
). LiveKit needs all function outputs to be JSON-serializable, so it can’t handle direct object references in the output. Here’s a friendly step-by-step on how to fix this: 1. Update the Return Value: Make sure the function returns only JSON-serializable data. For example:
Copy code
@function_tool()
async def get_user_profile(name: str, context: RunContext[UserProfile]) -> dict:
    context.userdata.name = name
    return {"status": "Profile Updated", "name": name}
2. Debug the Output: It’s helpful to add some logging to check what’s being returned before sending it out:
<http://logger.info|logger.info>(f"Returning from get_user_profile: {type(output)} = {output}")
3. Validate JSON Serialization: Double-check that everything you return can be serialized into JSON. Avoid including objects like
PolicyAgent
directly in the output. By making sure your output is strictly JSON-serializable, you’ll be able to prevent this error from popping up. If you’d like, I’m here to help you walk through this or answer any other questions you might have! Sources: livekit-agents/livekit/agents/voice/agent.py | Tool definition and use | LiveKit Docs
a
can you give me the complete code with agent task and my current logic to collect name with it, also integrating it with nova sonic agent
t
Here’s the complete code integrating your logic to collect the name using an agent task and Nova Sonic:
Copy code
from dataclasses import dataclass
from typing import Optional
from livekit.agents import Agent, AgentSession, AgentTask, function_tool, RunContext
from livekit.aws.realtime import RealtimeModel
from livekit.core import AutoSubscribe

# Define the UserProfile data class
@dataclass
class UserProfile:
    name: Optional[str] = None

# Define the PolicyAgent class
class PolicyAgent(Agent):
    def __init__(self, chat_ctx=None):
        super().__init__(
            instructions=(
                "You are a policy help agent. You must collect the user profile data with the help of the 'get_user_profile' tool at the start of the session. Without that, don't answer any questions."
            ),
            chat_ctx=chat_ctx,
        )

    @function_tool()
    async def get_user_profile(self, name: str, context: RunContext[UserProfile]) -> dict:
        """Collects the user's name and updates the profile."""
        context.userdata.name = name
        return {"status": "Profile Updated", "name": name}

# Define the AgentTask to collect the name
class CollectNameTask(AgentTask[bool]):
    async def run(self, context: RunContext[UserProfile]) -> bool:
        """Runs the task to collect the user's name."""
        if not context.userdata.name:
            await context.agent.get_user_profile(name="John Doe", context=context)  # Example name
        return True

# Define the entrypoint function
async def entrypoint(ctx):
    await ctx.connect(auto_subscribe=AutoSubscribe.AUDIO_ONLY)

    # Initialize the agent session with Nova Sonic and the user profile
    session = AgentSession(
        llm=RealtimeModel(),
        userdata=UserProfile(),
    )

    # Start the session with the PolicyAgent and run the CollectNameTask
    await session.start(agent=PolicyAgent(), room=ctx.room)
    await session.run_task(CollectNameTask())

# Main entrypoint
if __name__ == "__main__":
    from livekit.agents import cli
    cli.run_app(cli.WorkerOptions(entrypoint_fnc=entrypoint))
This code: • Defines a
UserProfile
data class to store the user’s name. • Implements the
PolicyAgent
with a
get_user_profile
tool to collect and update the name. • Uses an
AgentTask
(
CollectNameTask
) to ensure the name is collected at the start of the session. • Integrates with Nova Sonic using
RealtimeModel
. If you have any questions or would like me to walk you through any part of this, please don’t hesitate to ask. I’m here to help you get everything working just the way you need!
a
getting this error await session.run_task(CollectNameTask()) ^^^^^^^^^^^^^^^^ AttributeError: 'AgentSession' object has no attribute 'run_task'
t
It looks like the error happens because the
AgentSession
class doesn’t have a
run_task
method. Instead,
AgentTask
is an experimental feature that runs automatically within the context of an existing agent session. To help you fix this, you can either integrate the task logic directly into the agent or make sure the task is triggered as part of the agent’s workflow. Here’s an example:
Copy code
# Inside the PolicyAgent class
class PolicyAgent(Agent):
    ...
    async def on_start(self, context: RunContext[UserProfile]):
        # Run the task logic here
        if not context.userdata.name:
            await self.get_user_profile(name="John Doe", context=context)
This way, the task logic runs as soon as the agent session starts. If anything’s unclear or you’d like a hand with this, please don’t hesitate to ask—I’m here to help! Sources: Workflows | LiveKit Docs | livekit-agents/livekit/agents/voice/agent_activity.py