Skip to content

Do not wrap pointer-to-struct functool inputs#527

Open
PratikDhanave wants to merge 1 commit into
microsoft:mainfrom
PratikDhanave:fix-functool-pointer-struct-input
Open

Do not wrap pointer-to-struct functool inputs#527
PratikDhanave wants to merge 1 commit into
microsoft:mainfrom
PratikDhanave:fix-functool-pointer-struct-input

Conversation

@PratikDhanave

Copy link
Copy Markdown
Contributor

Summary

inputFormatFor (tool/functool/func.go) wraps any input whose Kind is not reflect.Struct in inputWrapper[T]. A pointer-to-struct handler has Kind == reflect.Ptr, so it gets wrapped — producing a nested {"Arg0":{...}} schema and rejecting the flat arguments that the equivalent value-receiver handler accepts:

type In struct{ V string `json:"v"` }
functool.MustNew(cfg, func(ctx context.Context, in *In) (string, error) { ... }).
    Call(ctx, `{"v":"hi"}`)
// → validation error: validating root: unexpected additional properties ["v"]

This contradicts jsonformat.ForType, which deliberately dereferences pointers at the root ("Pointers are treated equivalently to non-pointers … with no benefit" to wrapping the root object). So *Struct and Struct handlers should produce the same flat schema, but today only Struct does.

Fix

Dereference pointers before the struct check, so only genuinely non-struct inputs are wrapped.

Public API

No exported symbols change.

Tests

Adds TestFuncTool_PointerStructInput_UsesFlatSchema (black-box): a *struct handler accepts flat arguments. It fails before this change (schema validation rejects the flat args) and passes after.

inputFormatFor wrapped any input whose Kind is not Struct in inputWrapper[T].
A pointer-to-struct handler (func(ctx, *In)) has Kind Ptr, so it was wrapped,
producing a nested {"Arg0":{...}} schema and rejecting the flat arguments a
value-receiver (func(ctx, In)) handler accepts — even though jsonformat.ForType
deliberately dereferences pointers to produce the same flat schema.

Dereference pointers before the struct check so *Struct and Struct inputs
behave identically; only genuinely non-struct inputs are wrapped.

Adds a black-box test that a *struct input accepts flat arguments.
Copilot AI review requested due to automatic review settings July 17, 2026 18:42
@PratikDhanave
PratikDhanave requested a review from a team as a code owner July 17, 2026 18:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aligns functool input schema generation with jsonformat.ForType by ensuring pointer-to-struct (*Struct) handler inputs are treated the same as value struct (Struct) inputs, avoiding an unnecessary root-level wrapper schema that breaks flat JSON arguments.

Changes:

  • Dereference pointer types before deciding whether to wrap the input type in inputWrapper[T].
  • Preserve wrapping only for genuinely non-struct root inputs.
  • Add a black-box test proving *struct handlers accept flat JSON arguments.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
tool/functool/func.go Dereferences pointer inputs before the struct-kind check to prevent *struct from being wrapped and producing nested schemas.
tool/functool/func_test.go Adds a regression test validating that *struct inputs use a flat schema and accept flat JSON args.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants