-
Notifications
You must be signed in to change notification settings - Fork 250
Description
Bug
latest.Parse() and v4.Parse() call yaml.UnmarshalWithOptions(data, &cfg, yaml.Strict()) to reject unknown fields. However, strict mode is not propagated into agent blocks because Agents.UnmarshalYAML re-marshals each agent value to bytes and then calls plain yaml.Unmarshal — losing the strict option.
Impact
Unknown fields in agent blocks are silently ignored. For example, writing instructions (plural) instead of the correct instruction (singular) produces no error, but the instruction is completely lost — the agent runs with no instructions at all.
Root cause
In both pkg/config/latest/types.go and pkg/config/v4/types.go:
func (c *Agents) UnmarshalYAML(unmarshal func(any) error) error {
var items yaml.MapSlice
if err := unmarshal(&items); err != nil {
return err
}
for _, item := range items {
// ...
valueBytes, err := yaml.Marshal(item.Value) // re-marshal to bytes
// ...
var agent AgentConfig
if err := yaml.Unmarshal(valueBytes, &agent); err != nil { // ← plain Unmarshal, no strict!
return fmt.Errorf(...)
}
// ...
}
// ...
}The yaml.Strict() option from Parse() only applies to the top-level Config struct. Once Agents.UnmarshalYAML re-marshals and re-unmarshals agent values, the strictness is gone.
Reproduction
cfg, err := latest.Parse([]byte(`
version: "5"
agents:
root:
model: openai/gpt-4o
instructions: "You are a helpful assistant."
`))
// err == nil — no error!
// cfg.Agents[0].Instruction == "" — instruction silently lost!Expected behavior
latest.Parse (and v4.Parse) should return an error like:
unknown field "instructions"
Fix
Change yaml.Unmarshal(valueBytes, &agent) to yaml.UnmarshalWithOptions(valueBytes, &agent, yaml.DisallowUnknownField()) in both latest/types.go and v4/types.go.