fix(studio): read an alias's model settings from its target

The chat harness took the context window, agent options and input
modalities from the config of the name a chat asked for. An alias has
no model of its own and the loader gives it the generic default
window, so a chat on an alias budgeted against 4096 tokens and failed
on tool schemas even when the target ran with a far larger window.
Resolve the alias to its target first, as the capabilities endpoint
already does.

Assisted-by: Claude Code:claude-sonnet-5-5
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
Ettore Di Giacinto committed 2026-11-03 12:07:30 +00:00
1 parent e0173d8096
commit 13e96219ba
2 files changed
+33 -3

No files matched your search

+12 -3
View File
@@ -314,10 +314,19 @@ func (a *Application) loadStudioUser(ctx context.Context, id string) (*auth.User
return &u, nil
}
// studioModelConfig is the config of the model that serves a name. An alias is
// a redirect whose own config carries no model settings (the loader gives it the
// generic default window), so the settings come from its target.
func (a *Application) studioModelConfig(model string) (config.ModelConfig, bool) {
bcl := a.ModelConfigLoader()
name, _ := bcl.ResolveAliasName(model)
return bcl.GetModelConfig(name)
}
// studioContextTokens is the context window of a model, or zero when its config
// does not say.
func (a *Application) studioContextTokens(model string) int {
cfg, ok := a.ModelConfigLoader().GetModelConfig(model)
cfg, ok := a.studioModelConfig(model)
if !ok || cfg.ContextSize == nil {
return 0
}
@@ -327,7 +336,7 @@ func (a *Application) studioContextTokens(model string) int {
// studioModalities says which inputs a chat model takes natively, from its
// configuration. An unknown model takes none.
func (a *Application) studioModalities(model string) studio.Modalities {
cfg, ok := a.ModelConfigLoader().GetModelConfig(model)
cfg, ok := a.studioModelConfig(model)
if !ok {
return studio.Modalities{}
}
@@ -340,7 +349,7 @@ func (a *Application) studioModalities(model string) studio.Modalities {
// limit is the model's agent.max_iterations, else chats_max_iterations.
func (a *Application) studioAgentOptions(model string) nibharness.AgentOptions {
opts := nibharness.AgentOptions{Iterations: a.applicationConfig.EffectiveChatsMaxIterations()}
cfg, ok := a.ModelConfigLoader().GetModelConfig(model)
cfg, ok := a.studioModelConfig(model)
if !ok {
return opts
}
+21
View File
@@ -93,6 +93,27 @@ var _ = Describe("studio service at startup", func() {
Expect(app.studioContextTokens("missing")).To(Equal(0))
})
It("reads the window of an alias from its target, not from the alias", func() {
app := newApp()
big, fallback := 100096, 4096
app.ModelConfigLoader().ReplaceModelConfigs([]config.ModelConfig{
{Name: "target-model", LLMConfig: config.LLMConfig{ContextSize: &big}},
// The loader gives every alias the generic default window.
{Name: "default", Alias: "target-model", LLMConfig: config.LLMConfig{ContextSize: &fallback}},
})
Expect(app.studioContextTokens("default")).To(Equal(100096))
Expect(app.studioContextTokens("target-model")).To(Equal(100096))
})
It("reads the agent options of an alias from its target", func() {
app := newApp()
app.ModelConfigLoader().ReplaceModelConfigs([]config.ModelConfig{
{Name: "target-model", Agent: config.AgentConfig{MaxIterations: 7}},
{Name: "default", Alias: "target-model"},
})
Expect(app.studioAgentOptions("default").Iterations).To(Equal(7))
})
Describe("MCP servers of a chat", func() {
servers := "mcpServers:\n crm:\n url: http://127.0.0.1:1/crm\n mail:\n url: http://127.0.0.1:1/mail\n"