Compare commits

..
2 Commits
Author SHA1 Message Date
lukaszraczylo 12e448ca39 fix(deps): require Go 1.26.8
Go 1.26.0 carries 17 standard library vulnerabilities that govulncheck reports. The security workflow takes its toolchain from go.mod, so the scan failed. Go 1.26.8 clears them.
2026-10-02 16:18:05 +01:00
lukaszraczylo 0865c405fb feat(pi): emit model context and output limits when set
The pi adapter writes contextWindow and maxTokens to models.json only
when the profile sets them. Pi keeps its own defaults for every other
model. Tests cover both cases.
2026-10-02 05:11:46 +01:00
3 changed files with 47 additions and 1 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
module github.com/lukaszraczylo/harness-sync module github.com/lukaszraczylo/harness-sync
go 1.26.0 go 1.26.8
require ( require (
github.com/charmbracelet/huh v1.0.0 github.com/charmbracelet/huh v1.0.0
+11
View File
@@ -116,6 +116,17 @@ func piModelsJSON(b *canonical.Bundle) ([]byte, error) {
if m.Alias != "" { if m.Alias != "" {
entry["name"] = m.Alias entry["name"] = m.Alias
} }
// Emit limits only when the profile sets them explicitly. Pi applies
// its own defaults (contextWindow 128000, maxTokens 16384) to a model
// definition that omits them, so writing ContextLimit()/OutputLimit()
// unconditionally would push canonical's defaults onto every model
// that never asked for them.
if m.Context > 0 {
entry["contextWindow"] = m.Context
}
if m.Output > 0 {
entry["maxTokens"] = m.Output
}
modelEntries = append(modelEntries, entry) modelEntries = append(modelEntries, entry)
} }
if len(modelEntries) == 0 && b.Profile.Gateway.DefaultModel != "" { if len(modelEntries) == 0 && b.Profile.Gateway.DefaultModel != "" {
+35
View File
@@ -56,6 +56,41 @@ func TestPiRender(t *testing.T) {
first := modelList[0].(map[string]any) first := modelList[0].(map[string]any)
assert.Equal(t, "claude-sonnet-4-6", first["id"]) assert.Equal(t, "claude-sonnet-4-6", first["id"])
assert.Equal(t, "Sonnet", first["name"]) assert.Equal(t, "Sonnet", first["name"])
// A model with no explicit limits must carry none, so pi keeps applying
// its own defaults rather than inheriting canonical's.
assert.NotContains(t, first, "contextWindow")
assert.NotContains(t, first, "maxTokens")
}
func TestPiRenderEmitsExplicitModelLimits(t *testing.T) {
home := t.TempDir()
ad := New(WithHome(home))
b := &canonical.Bundle{
Profile: canonical.Profile{
Gateway: canonical.Gateway{URL: "https://gw", Token: "dummy"},
Models: []canonical.Model{
{ID: "local/current-model", Alias: "Local", Context: 1048576, Output: 32768},
{ID: "bare/model"},
},
},
}
fs, err := ad.Render(b)
require.NoError(t, err)
seen := map[string]adapter.File{}
fs.ForEach(func(f adapter.File) { seen[f.Dest] = f })
var models map[string]any
require.NoError(t, json.Unmarshal(seen[filepath.Join(home, ".pi", "agent", "models.json")].Content, &models))
list := models["providers"].(map[string]any)["hs-gw"].(map[string]any)["models"].([]any)
withLimits := list[0].(map[string]any)
assert.InDelta(t, float64(1048576), withLimits["contextWindow"], 0)
assert.InDelta(t, float64(32768), withLimits["maxTokens"], 0)
withoutLimits := list[1].(map[string]any)
assert.NotContains(t, withoutLimits, "contextWindow")
assert.NotContains(t, withoutLimits, "maxTokens")
} }
func TestPiRenderMergesExistingSettings(t *testing.T) { func TestPiRenderMergesExistingSettings(t *testing.T) {