internal/mcp/jsonschema: remove shared structure from schema inference

Schemas must form a tree. This is important for Schema.Resolve, and
also for modifying parts of the schema before resolution, as with
mcp SchemaOptions.

Remove the `seen` argument from inference, creating all schemas
afresh.

Change-Id: Ief8295e8470f3f575ef51cc2ba697901250bbe6f
Reviewed-on: https://go-review.googlesource.com/c/tools/+/676937
Auto-Submit: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Hongxiang Jiang <hxjiang@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Jonathan Amsterdam 2025-05-28 14:41:55 -04:00 • committed by Gopher Robot
commit a9a69a03e4

View file

@ -41,31 +41,52 @@ func TestForType(t *testing.T) {
Type: "object",
AdditionalProperties: &schema{},
}},
{"struct", forType[struct {
F int `json:"f"`
G []float64
P *bool
Skip string `json:"-"`
NoSkip string `json:",omitempty"`
unexported float64
unexported2 int `json:"No"`
}](), &schema{
Type: "object",
Properties: map[string]*schema{
"f": {Type: "integer"},
"G": {Type: "array", Items: &schema{Type: "number"}},
"P": {Type: "boolean"},
"NoSkip": {Type: "string"},
{
"struct",
forType[struct {
F int `json:"f"`
G []float64
P *bool
Skip string `json:"-"`
NoSkip string `json:",omitempty"`
unexported float64
unexported2 int `json:"No"`
}](),
&schema{
Type: "object",
Properties: map[string]*schema{
"f": {Type: "integer"},
"G": {Type: "array", Items: &schema{Type: "number"}},
"P": {Type: "boolean"},
"NoSkip": {Type: "string"},
},
Required: []string{"f", "G", "P"},
AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}},
},
Required: []string{"f", "G", "P"},
AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}},
}},
},
{
"no sharing",
forType[struct{ X, Y int }](),
&schema{
Type: "object",
Properties: map[string]*schema{
"X": {Type: "integer"},
"Y": {Type: "integer"},
},
Required: []string{"X", "Y"},
AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if diff := cmp.Diff(test.want, test.got, cmpopts.IgnoreUnexported(jsonschema.Schema{})); diff != "" {
t.Errorf("ForType mismatch (-want +got):\n%s", diff)
t.Fatalf("ForType mismatch (-want +got):\n%s", diff)
}
// These schemas should all resolve.
if _, err := test.got.Resolve(nil); err != nil {
t.Fatalf("Resolving: %v", err)
}
})
}