Skip to content

Commit 6b42590

Browse files
committed
fix(agentfs): parse resolved livekit-agents version from uv.lock
checkUvLock matched a `livekit-agents = "x"` line that never appears in uv.lock. uv.lock uses poetry.lock's TOML layout ([[package]] / name / version), so the resolved version was never found, and the SDK version check fell back to the pyproject.toml constraint floor — reading `>=1.0` as 1.0 and rejecting it as older than the minimum (e.g. 1.6.0) even when the lock resolved a newer version. Use the same [[package]] block regex as checkPoetryLock so the resolved version is read and preferred, matching how the Node lockfile parsers already read the installed version. Also replaces the test's fake uv.lock fixture with the real format and adds a regression test for the pyproject-floor-vs-resolved-version case.
1 parent 1b45769 commit 6b42590

2 files changed

Lines changed: 43 additions & 3 deletions

File tree

pkg/agentfs/sdk_version_check.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -582,8 +582,10 @@ func checkUvLock(filePath, minVersion string) VersionCheckResult {
582582
return VersionCheckResult{Error: err}
583583
}
584584

585-
// Look for livekit-agents in the lock file
586-
pattern := regexp.MustCompile(`(?m)^\s*livekit-agents\s*=\s*"([^"]+)"`)
585+
// Look for the [[package]] block with livekit-agents. uv.lock shares
586+
// poetry.lock's TOML layout (name then version on separate lines), so the
587+
// resolved version lives in the block, not on a `livekit-agents = "..."` line.
588+
pattern := regexp.MustCompile(`(?s)\[\[package\]\]\s*\nname\s*=\s*"livekit-agents"\s*\nversion\s*=\s*"([^"]+)"`)
587589
matches := pattern.FindStringSubmatch(string(content))
588590
if matches != nil {
589591
version := matches[1]

pkg/agentfs/sdk_version_check_test.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,10 @@ version = "1.5.0"`,
138138
name: "Python uv.lock with valid version",
139139
projectType: ProjectTypePythonUV,
140140
setupFiles: map[string]string{
141-
"uv.lock": `livekit-agents = "1.5.0"`,
141+
"uv.lock": `[[package]]
142+
name = "livekit-agents"
143+
version = "1.5.0"
144+
source = { registry = "https://pypi.org/simple" }`,
142145
},
143146
expectError: false,
144147
},
@@ -200,6 +203,41 @@ version = "1.5.0"`,
200203
}
201204
}
202205

206+
// TestCheckSDKVersion_UvLockPreferredOverPyprojectFloor reproduces the case where
207+
// pyproject.toml declares a loose lower bound (e.g. >=1.0) but uv.lock pins a
208+
// resolved version that satisfies the minimum. The resolved lock version must win,
209+
// otherwise the loose floor is misread as the installed version and wrongly rejected.
210+
func TestCheckSDKVersion_UvLockPreferredOverPyprojectFloor(t *testing.T) {
211+
tempDir, err := os.MkdirTemp("", "sdk-version-uvlock-test")
212+
if err != nil {
213+
t.Fatalf("Failed to create temp dir: %v", err)
214+
}
215+
defer os.RemoveAll(tempDir)
216+
217+
settingsMap := map[string]string{
218+
"python-min-sdk-version": "1.6.0",
219+
"node-min-sdk-version": "1.6.0",
220+
}
221+
222+
files := map[string]string{
223+
"pyproject.toml": `[project]
224+
dependencies = ["livekit-agents>=1.0"]`,
225+
"uv.lock": `[[package]]
226+
name = "livekit-agents"
227+
version = "1.6.7"
228+
source = { registry = "https://pypi.org/simple" }`,
229+
}
230+
for filename, content := range files {
231+
if err := os.WriteFile(filepath.Join(tempDir, filename), []byte(content), 0644); err != nil {
232+
t.Fatalf("Failed to create test file %s: %v", filename, err)
233+
}
234+
}
235+
236+
if err := CheckSDKVersion(tempDir, ProjectTypePythonUV, settingsMap); err != nil {
237+
t.Errorf("Expected no error (uv.lock resolves 1.6.7 >= 1.6.0), got: %v", err)
238+
}
239+
}
240+
203241
func TestIsVersionSatisfied(t *testing.T) {
204242
tests := []struct {
205243
version string

0 commit comments

Comments
 (0)