From aec8d035e5529210b771b3d03e035696d4984344 Mon Sep 17 00:00:00 2001 From: Jason Lernerman <43508353+u9g@users.noreply.github.com> Date: Mon, 26 Oct 2026 12:08:34 -0400 Subject: [PATCH 1/4] chore: bump protocol for the simulation run's SIP fields --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 873cb981..ce274a54 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 github.com/joho/godotenv v1.5.1 github.com/klauspost/compress v1.20.1 - github.com/livekit/protocol v1.53.1-0.20261022182030-f1ed0814615a + github.com/livekit/protocol v1.53.1-0.20261026160605-4f6eb29d1d13 github.com/livekit/server-sdk-go/v2 v2.19.0 github.com/mattn/go-isatty v0.0.22 github.com/moby/moby/client v0.4.1 @@ -132,7 +132,7 @@ require ( github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/gammazero/deque v1.2.1 // indirect github.com/getkin/kin-openapi v0.144.0 // indirect - github.com/go-jose/go-jose/v4 v4.1.4 // indirect + github.com/go-jose/go-jose/v4 v4.1.5 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.23.1 // indirect github.com/go-openapi/swag/jsonname v0.26.1 // indirect diff --git a/go.sum b/go.sum index 730122e1..e91431f1 100644 --- a/go.sum +++ b/go.sum @@ -253,8 +253,8 @@ github.com/gammazero/deque v1.2.1 h1:9fnQVFCCZ9/NOc7ccTNqzoKd1tCWOqeI05/lPqFPMGQ github.com/gammazero/deque v1.2.1/go.mod h1:5nSFkzVm+afG9+gy0VIowlqVAW4N8zNcMne+CMQVD2g= github.com/getkin/kin-openapi v0.144.0 h1:hIRcTH+KjLfkLpYU6bSSfdFpi0fZi1fp+hSPi4aQu9Y= github.com/getkin/kin-openapi v0.144.0/go.mod h1:3BH9M9XDe/y9M5DSvEocVYAYq1w0qrhJHjC/vZi0AaY= -github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= -github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-jose/go-jose/v4 v4.1.5 h1:RjgjO2LOtWOJKUC5wpwY9LR3B3vwVAz6JS2YHfYU6eA= +github.com/go-jose/go-jose/v4 v4.1.5/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -364,8 +364,8 @@ github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5AT github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ= github.com/livekit/mediatransportutil v0.0.0-20260821083140-f234b534b095 h1:BcliKAXoMhl/nWmzQweQ5kmh4Qqagxl4s3Z5pvM/7AY= github.com/livekit/mediatransportutil v0.0.0-20260821083140-f234b534b095/go.mod h1:o8CFmAdrVwzJNOCsQCLUzXRjokkufNshnQHOe4fRaqU= -github.com/livekit/protocol v1.53.1-0.20261022182030-f1ed0814615a h1:+2yEcpXySowdY80dJJ5uXhiykNh6M+HE5KdScn/Kx1w= -github.com/livekit/protocol v1.53.1-0.20261022182030-f1ed0814615a/go.mod h1:kUTAI2TrTngGOiWP6MTAOkJpru6YYGd0MP9wzlDATy4= +github.com/livekit/protocol v1.53.1-0.20261026160605-4f6eb29d1d13 h1:7oLWRReWzQByVSawN0tYKn0g7b98up/WsNgoPrXsAQ4= +github.com/livekit/protocol v1.53.1-0.20261026160605-4f6eb29d1d13/go.mod h1:h9P4KCc3K715NCgCrkkFsb8/RRY1kKqOS1EIHUNRlCk= github.com/livekit/psrpc v0.8.2 h1:7tbkhBJoYlK5Csfkdv1XYbZjyAQeaEZgupvIXNCv7Dc= github.com/livekit/psrpc v0.8.2/go.mod h1:6KnU8vULoizX0Er9NNfeKJDV8ug87j3fuo19M0bhj6Q= github.com/livekit/server-sdk-go/v2 v2.19.0 h1:fZ0zmeC/5V+rXiI/MeC05EjwTfXmpaGkr/DXLG3EzgA= From 277207e77b7a9c433e2e4f736c02a5d5f006c099 Mon Sep 17 00:00:00 2001 From: Jason Lernerman <43508353+u9g@users.noreply.github.com> Date: Mon, 26 Oct 2026 12:08:34 -0400 Subject: [PATCH 2/4] feat(simulate): run audio simulations against a phone number with --to-phone-number --- cmd/lk/simulate.go | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/cmd/lk/simulate.go b/cmd/lk/simulate.go index c0fd6e49..ffb4e6b9 100644 --- a/cmd/lk/simulate.go +++ b/cmd/lk/simulate.go @@ -175,6 +175,18 @@ var simulateAudioCommand = &cli.Command{ Name: "packet-loss", Usage: "Drop packets from the simulated user's audio track", }, + &cli.StringFlag{ + Name: "to-phone-number", + Usage: "Call this `NUMBER` over SIP and simulate against whoever answers, instead of dispatching an agent. Requires --from-phone-number and --scenarios.", + }, + &cli.StringFlag{ + Name: "from-trunk", + Usage: "Outbound SIP trunk `ID` to place --to-phone-number calls through. Without it, calls go out from a LiveKit phone number.", + }, + &cli.StringFlag{ + Name: "from-phone-number", + Usage: "Caller `NUMBER` for --to-phone-number calls: a LiveKit phone number the project owns, or a number on --from-trunk", + }, }, } @@ -410,7 +422,7 @@ type simulateConfig struct { scenarioGroup *livekit.ScenarioGroup scenariosPath string // path to the --scenarios file (empty when generating from source) viewModeRunID string // non-empty when `view` opens a pre-existing run - liveAgent bool // --agent-name: run against an already-running agent, don't spawn one + liveAgent bool // --agent-name or --to-phone-number: run against an already-running agent, don't spawn one warnings []string // config-level warnings surfaced at setup (e.g. ignored flags) // impairments on the simulated user's audio, set only in SIMULATION_MODE_AUDIO @@ -418,6 +430,11 @@ type simulateConfig struct { lowQualityMicrophone bool packetLoss bool + // --to-phone-number: dial this number over SIP in place of dispatching agentName + sipCallTo string + sipTrunkID string + sipNumber string + // TODO (steveyoon): add agent deployment support // agentDeployment string } @@ -522,6 +539,19 @@ func runSimulate(ctx context.Context, cmd *cli.Command, simulationMode livekit.S samples := int32(cmd.Int("samples")) passRate := cmd.Float("pass-rate") liveAgentName := cmd.String("agent-name") + var phoneNumber, fromTrunk, fromPhoneNumber string + if simulationMode == livekit.SimulationMode_SIMULATION_MODE_AUDIO { + phoneNumber = cmd.String("to-phone-number") + fromTrunk = cmd.String("from-trunk") + fromPhoneNumber = cmd.String("from-phone-number") + } + if fromTrunk != "" && phoneNumber == "" { + return fmt.Errorf("--from-trunk requires --to-phone-number") + } + // every call needs a caller: the number simulations are placed from + if phoneNumber != "" && fromPhoneNumber == "" { + return fmt.Errorf("--to-phone-number requires --from-phone-number") + } // never auto-discovered: an explicit --scenarios file is the source of // truth, otherwise scenarios are generated from the agent's source @@ -547,7 +577,13 @@ func runSimulate(ctx context.Context, cmd *cli.Command, simulationMode livekit.S // --agent-name (even empty) means: run against an already-running agent, // don't spawn one. https://docs.livekit.io/agents/server/agent-dispatch/#automatic - if cmd.IsSet("agent-name") { + if phoneNumber != "" { + // nothing is spawned, so there's no source to generate scenarios from. + if scenariosPath == "" { + return fmt.Errorf("--to-phone-number requires --scenarios (no source to generate scenarios from when calling a number)") + } + liveAgent = true + } else if cmd.IsSet("agent-name") { // nothing is spawned, so there's no source to generate scenarios from. if scenariosPath == "" { return fmt.Errorf("--agent-name requires --scenarios (no source to generate scenarios from when running against a live agent)") @@ -628,6 +664,9 @@ func runSimulate(ctx context.Context, cmd *cli.Command, simulationMode livekit.S simCfg.backgroundNoise = cmd.Bool("background-noise") simCfg.lowQualityMicrophone = cmd.Bool("low-quality-microphone") simCfg.packetLoss = cmd.Bool("packet-loss") + simCfg.sipCallTo = phoneNumber + simCfg.sipTrunkID = fromTrunk + simCfg.sipNumber = fromPhoneNumber } if !isInteractive() { @@ -801,6 +840,9 @@ func createSimulationRun(ctx context.Context, c *simulateConfig) (string, *livek BackgroundNoise: c.backgroundNoise, LowQualityMicrophone: c.lowQualityMicrophone, PacketLoss: c.packetLoss, + SipCallTo: c.sipCallTo, + SipTrunkId: c.sipTrunkID, + SipNumber: c.sipNumber, Ci: ciFromEnv(), } if c.concurrency > 0 { From 9f26636c1b7d992c4d297e6ec9752eac47114bc3 Mon Sep 17 00:00:00 2001 From: Jason Lernerman <43508353+u9g@users.noreply.github.com> Date: Mon, 26 Oct 2026 11:41:26 -0400 Subject: [PATCH 3/4] fix(simulate): reject --from-phone-number without --to-phone-number Without a number to call, a caller number would be dropped and the run would dispatch an agent instead. --- cmd/lk/simulate.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/lk/simulate.go b/cmd/lk/simulate.go index ffb4e6b9..be1bce5a 100644 --- a/cmd/lk/simulate.go +++ b/cmd/lk/simulate.go @@ -548,6 +548,9 @@ func runSimulate(ctx context.Context, cmd *cli.Command, simulationMode livekit.S if fromTrunk != "" && phoneNumber == "" { return fmt.Errorf("--from-trunk requires --to-phone-number") } + if fromPhoneNumber != "" && phoneNumber == "" { + return fmt.Errorf("--from-phone-number requires --to-phone-number") + } // every call needs a caller: the number simulations are placed from if phoneNumber != "" && fromPhoneNumber == "" { return fmt.Errorf("--to-phone-number requires --from-phone-number") From 61228934f65e6ca6c82dde7c242c2718f56d8025 Mon Sep 17 00:00:00 2001 From: Jason Lernerman <43508353+u9g@users.noreply.github.com> Date: Mon, 26 Oct 2026 16:59:33 -0400 Subject: [PATCH 4/4] chore: bump protocol to the merged SIP fields --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ce274a54..90eee86b 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 github.com/joho/godotenv v1.5.1 github.com/klauspost/compress v1.20.1 - github.com/livekit/protocol v1.53.1-0.20261026160605-4f6eb29d1d13 + github.com/livekit/protocol v1.53.2-0.20261026205625-e87b8f61d18c github.com/livekit/server-sdk-go/v2 v2.19.0 github.com/mattn/go-isatty v0.0.22 github.com/moby/moby/client v0.4.1 diff --git a/go.sum b/go.sum index e91431f1..f9559682 100644 --- a/go.sum +++ b/go.sum @@ -364,8 +364,8 @@ github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5AT github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ= github.com/livekit/mediatransportutil v0.0.0-20260821083140-f234b534b095 h1:BcliKAXoMhl/nWmzQweQ5kmh4Qqagxl4s3Z5pvM/7AY= github.com/livekit/mediatransportutil v0.0.0-20260821083140-f234b534b095/go.mod h1:o8CFmAdrVwzJNOCsQCLUzXRjokkufNshnQHOe4fRaqU= -github.com/livekit/protocol v1.53.1-0.20261026160605-4f6eb29d1d13 h1:7oLWRReWzQByVSawN0tYKn0g7b98up/WsNgoPrXsAQ4= -github.com/livekit/protocol v1.53.1-0.20261026160605-4f6eb29d1d13/go.mod h1:h9P4KCc3K715NCgCrkkFsb8/RRY1kKqOS1EIHUNRlCk= +github.com/livekit/protocol v1.53.2-0.20261026205625-e87b8f61d18c h1:vGLJnV6d5WUPsZ84DO1uHcBtiMcxHQw7R1/13kdrdo8= +github.com/livekit/protocol v1.53.2-0.20261026205625-e87b8f61d18c/go.mod h1:h9P4KCc3K715NCgCrkkFsb8/RRY1kKqOS1EIHUNRlCk= github.com/livekit/psrpc v0.8.2 h1:7tbkhBJoYlK5Csfkdv1XYbZjyAQeaEZgupvIXNCv7Dc= github.com/livekit/psrpc v0.8.2/go.mod h1:6KnU8vULoizX0Er9NNfeKJDV8ug87j3fuo19M0bhj6Q= github.com/livekit/server-sdk-go/v2 v2.19.0 h1:fZ0zmeC/5V+rXiI/MeC05EjwTfXmpaGkr/DXLG3EzgA=