Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions cmd/lk/simulate.go
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ func startSimulationAgent(c *simulateConfig, forwardOutput io.Writer) (*AgentPro
args = append(args, "--log-format", "colored")
}

return startAgent(AgentStartConfig{
cfg := AgentStartConfig{
Dir: c.projectDir,
Entrypoint: c.entrypoint,
ProjectType: c.projectType,
Expand All @@ -766,7 +766,13 @@ func startSimulationAgent(c *simulateConfig, forwardOutput io.Writer) (*AgentPro
},
ReadySignal: "registered worker",
ForwardOutput: forwardOutput,
})
}
if c.projectType.IsNode() {
if err := checkNodeSDKVersion(cfg, nodeSimulateMinVersion); err != nil {
return nil, err
}
}
return startAgent(cfg)
}

// ciFromEnv reports the pipeline that started this run, so the dashboard can
Expand Down
9 changes: 5 additions & 4 deletions cmd/lk/simulate_health.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ import (
// can cancel the run and surface the worker's error, while tolerating
// transient "no agent joined" timeouts from connection pacing.

// pythonFatalMarkers are livekit-agents (Python) log lines that only appear on
// a fatal, non-transient worker error. The JS framework will need its own set.
var pythonFatalMarkers = []string{
// fatalMarkers are livekit-agents (Python) and @livekit/agents (Node) log lines
// that only appear on a fatal, non-transient worker error.
var fatalMarkers = []string{
"unhandled exception while running the job task",
"error initializing process",
"closing due to unrecoverable error",
"error in entry function",
}

// a single fatal log line can be an isolated job crash
Expand Down Expand Up @@ -101,7 +102,7 @@ func countFatalMarkers(logs []string) int {

func isFatalMarker(line string) bool {
plain := ansiEscapeRe.ReplaceAllString(line, "")
for _, marker := range pythonFatalMarkers {
for _, marker := range fatalMarkers {
if strings.Contains(plain, marker) {
return true
}
Expand Down
14 changes: 9 additions & 5 deletions cmd/lk/simulate_subprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,14 @@ func checkTypeStrippingSupport(dir, nodeBin string) error {
// equivalent floor from server client settings.
const nodeAgentMinVersion = "1.0.0"

// checkNodeSDKVersion gates a Node agent on nodeAgentMinVersion, resolving the
// nodeSimulateMinVersion is the first @livekit/agents release with the
// --simulation flag and LIVEKIT_AGENT_NAME_OVERRIDE, which simulate relies on.
const nodeSimulateMinVersion = "1.4.11"

// checkNodeSDKVersion gates a Node agent on minVersion, resolving the
// installed @livekit/agents via the project's own runtime (see
// agentfs.ResolveInstalledSDKVersion).
func checkNodeSDKVersion(cfg AgentStartConfig) error {
func checkNodeSDKVersion(cfg AgentStartConfig, minVersion string) error {
// Surface a missing Node binary as its own error rather than folding it
// into "package not found".
if _, err := agentfs.FindNodeBinary(); err != nil {
Expand All @@ -114,8 +118,8 @@ func checkNodeSDKVersion(cfg AgentStartConfig) error {
return fmt.Errorf("@livekit/agents not found; install dependencies and make sure this is a LiveKit agent project")
}
// An unparseable version (e.g. a local "0.0.0-dev" tag) shouldn't block a run.
if ok, err := agentfs.IsVersionSatisfied(version, nodeAgentMinVersion); err == nil && !ok {
return fmt.Errorf("@livekit/agents version %s is too old, please upgrade to %s or newer", version, nodeAgentMinVersion)
if ok, err := agentfs.IsVersionSatisfied(version, minVersion); err == nil && !ok {
return fmt.Errorf("@livekit/agents version %s is too old, please upgrade to %s or newer", version, minVersion)
}
return nil
}
Expand Down Expand Up @@ -295,7 +299,7 @@ func startAgent(cfg AgentStartConfig) (*AgentProcess, error) {
// Node resolves the installed package via the runtime so workspace/monorepo
// layouts work; Python parses project files against the thin-CLI baseline.
if cfg.ProjectType.IsNode() {
if err := checkNodeSDKVersion(cfg); err != nil {
if err := checkNodeSDKVersion(cfg, nodeAgentMinVersion); err != nil {
return nil, err
}
} else if err := checkPythonSDKVersion(cfg); err != nil {
Expand Down
Loading