sip icon indicating copy to clipboard operation
sip copied to clipboard

Unable to pass INVITE headers to SIP Participant

Open nharris-star2star opened this issue 9 months ago • 15 comments

Hello, I am able to make calls in to LLM agent without issue. The livekit ecosystem is really great. However, I am having a problem passing the INVITE headers along to the participant attributes.

inbound-trunk.json { "trunk": { "include_headers": 2, "headers_to_attributes: { "X-Test": "xTest" }, "name": "{REDACTED} inbound trunk", "numbers": ["+1{REDACTED}"] } }

I have tested using the v1.0.0 tag of the SIP service and v1.8.4 of livekit-server. I have tried various permutations and combinations of include_headers values along with or without headers_to_attributes and attributes_to_headers. I have used the python SDK as well as the lk-cIi to create the inbound trunk. I apologize if I am missing something or have something misconfigured. Any suggestions on how to get this working or is this feature not yet implemented?

Thanks

nharris-star2star avatar May 14 '25 18:05 nharris-star2star

Hey @nharris-star2star ! How are you accessing the headers after the call is established? Is it in the webhook?

dennwc avatar May 15 '25 06:05 dennwc

Hi @dennwc! Thanks for the quick response. I am using the python agents version 1.0.20 and looking for the headers on the participant attributes. I have all the standard SIP attributes described here, but none of the X-*, or any other headers for that matter make it to the participant.

participant = await ctx.wait_for_participant() logger.info(f"participant attributes: {participant.attributes}")

nharris-star2star avatar May 15 '25 13:05 nharris-star2star

Please note that header-related attributes won't be set immediately. Ideally, you should use the attributes changed hook on the participant to see the headers when they become available.

dennwc avatar May 15 '25 13:05 dennwc

Ok. I will check that out and report back. I don't know if it is helpful, but it appears the headers are null when the call is accepted. Is that in line with what you are saying and expected? 2025-05-15T14:12:07.239Z INFO sip sip/inbound.go:468 Accepting the call {"nodeID": "NE_uaTngg4pChwR", "callID": "SCL_Cm3REdULVnZA", "fromIP": "{REDACTED}", "toIP": "{REDACTED}:5060", "fromHost": "{REDACTED}", "fromUser": "ivr", "toHost": "{REDACTED}", "toUser": "is_1256900", "sipTag": "mmm0tmNZZa3mN", "sipCallID": "6b704f8c-ac39-123e-a59f-005056aa6183", "sipRule": "SDR_ETUTL7MEM3oA", "room": "call-_ivr_M2qRbfReCTf2", "participant": "sip_ivr", "participantName": "Phone ivr", "headers": null}

nharris-star2star avatar May 15 '25 14:05 nharris-star2star

I added a listener for the participant attributes, and I am seeing the default attributes update, but none of the INVITE headers ever make it in to the participant.

@ctx.room.on("participant_attributes_changed") def on_participant_attributes_changed(changed_attrs: dict[str, str], participant: rtc.Participant): print(f"Participant {participant.identity} updated attributes: {changed_attrs}") print(f"Current attributes: {participant.attributes}")

Participant sip_ivr updated attributes: {'sip.callStatus': 'active'} Current attributes: {'sip.ruleID': 'SDR_ETUTL7MEM3oA', 'sip.callTag': 'NDyD9BQgN57Bc', 'sip.callID': 'SCL_6X4JPegeXz2M', 'sip.callIDFull': '0ad07179-ac46-123e-a59f-005056aa6183', 'sip.trunkPhoneNumber': 'is_1256900', 'sip.phoneNumber': 'ivr', 'sip.callStatus': 'active'}

nharris-star2star avatar May 15 '25 15:05 nharris-star2star

I logged out the value of opts in types.go and it shows 2025/05/15 20:19:31 SIPHeaderOptions: SIP_NO_HEADERS So even though inboud-trunk.json has include_headers: 2 the if statement is skipping adding the headers to the attributes.

I confirmed the participant in the agent code has all the attributes by commenting out that check for testing (line 257 of pkg/sip/types.go). I'll see if I can figure out why this is.

nharris-star2star avatar May 15 '25 20:05 nharris-star2star

It looks like the resp in line 25 of pkg/service/psrpc.go is empty, therefore no TrunkID and if no TrunkID no trunk config?

I see there are some open PRs to sync up some of the libs with livekit server. I'm not sure if any of those updates will resolve the problem. I'll try to dig deeper as soon as I can.

nharris-star2star avatar May 19 '25 19:05 nharris-star2star

@nharris-star2star I've been investigating this. From my various tests, I will admit that there are a couple of race conditions at play that could cause this behaviour. However, I believe there are solutions to most of them by fixing the agent code. Do you mind sharing your Agent's code ?

nishadmusthafa avatar Jun 06 '25 07:06 nishadmusthafa

Hi @nishadmusthafa. Thanks for looking in to this. I'm not sure how the agent code could be the problem if commenting out line 257 of pkg/sip/types.go in the sip service code allows the agent to receive the headers.

It may be simpler if you could supply your inbound-trunk config for the sip service with version, and your test agent code with version that successfully receives all the sip headers?

nharris-star2star avatar Jun 06 '25 12:06 nharris-star2star

Sure. Here is the trunk

Image

and here is the agent code

from livekit.agents import (
    Agent,
    AgentSession,
    JobContext,
    RunContext,
    WorkerOptions,
    cli,
    function_tool,
)
from livekit.plugins import deepgram, elevenlabs, openai, silero
from livekit import rtc
from dotenv import load_dotenv

load_dotenv()


@function_tool
async def lookup_weather(
    context: RunContext,
    location: str,
):
    """Used to look up weather information."""

    return {"weather": "sunny", "temperature": 70}


async def entrypoint(ctx: JobContext):
    @ctx.room.on("participant_attributes_changed")
    def on_participant_attributes_changed(changed_attrs: dict[str, str], participant: rtc.Participant):
        print(f"Participant {participant.identity} updated attributes: {changed_attrs}")
        print(f"Current attributes: {participant.attributes}")

    await ctx.connect()

    agent = Agent(
        instructions="You are a friendly voice assistant built by LiveKit.",
        tools=[lookup_weather],
    )
    session = AgentSession(
        vad=silero.VAD.load(),
        # any combination of STT, LLM, TTS, or realtime API can be used
        stt=deepgram.STT(model="nova-3"),
        llm=openai.LLM(model="gpt-4o-mini"),
        tts=elevenlabs.TTS(),
    )

    await session.start(agent=agent, room=ctx.room)
    await session.generate_reply(instructions="greet the user and ask about their day")


if __name__ == "__main__":
    cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))

Strangely though, while it worked yesterday, It isn't passing the relevant headers now. I'm digging into this now. Could you confirm which exact lines you commented. The line you pointed out was https://github.com/livekit/sip/blob/main/pkg/sip/types.go#L257 .. right ? All I see there is a comment. Did you mean some other line or are you perhaps on another branch ?

Image

nishadmusthafa avatar Jun 06 '25 20:06 nishadmusthafa

Alright. I figured out what messed up my calls. I was calling in from a number that was NOT configured in my inbound trunk. The call works(although it should error out, will create another issue for that). In that situation the headers don't pass through. Is that what may be happening with you?

To summarise @nharris-star2star

  1. Check if there is any difference between the Agent code I posted and what you have.
  2. Check if you are calling in from a number that is not configured on your trunk.

If it's neither of these, I might need more context to reproduce the issue.

nishadmusthafa avatar Jun 06 '25 23:06 nishadmusthafa

@nishadmusthafa I commented out check of the trunk config headers setting in types.go on my local build for testing (not committed anywhere on this project).

With this config check commented out I get all the headers. Without this commented out, I get none of the SIP headers, regardless of what is configured in the inbound trunk.

Calls are processed without issue and my agents are working fine. I need the sip headers as they identify the configuration needed for the agent tools to execute with the right context.

Just to be clear, I am not talking about the standard room attributes that get set. I am talking about an "x-something" header in the invite (visible from sngrep or similar) making it through to the agent.

nharris-star2star avatar Jun 09 '25 13:06 nharris-star2star

When this issue be fix @nishadmusthafa

murugancmi avatar Aug 14 '25 06:08 murugancmi

Any update to this?

joshreola avatar Oct 05 '25 03:10 joshreola