Skip to content

Use schemars for strict #[tool] parameter schemas #68

Description

@luckenco

Problem

#[tool] currently emits shallow JSON Schemas for tool parameters in macros/src/tool.rs.

Known weak spots:

  • Vec<T> becomes only { "type": "array" }, without an items schema.
  • Custom/complex parameter types become unconstrained { "type": "object" }.
  • Optionality is detected only for bare Option<T>, missing paths like std::option::Option<T>.
  • OpenAI strict mode is weaker than expected because the schema loses nested object, array item, enum, and nullability details.
  • Explicit null for optional fields can fail during execution because the macro strips Option<T> before parameter deserialization.

Proposed Direction

  • Generate a private params struct per tool.
  • Derive serde::Deserialize and schemars::JsonSchema on that struct.
  • Use docstring parameter descriptions as #[schemars(description = "...")].
  • Deserialize tool call arguments into the generated params struct before invoking the user function.
  • Require tool parameter types to implement both Deserialize and JsonSchema.
  • Keep Tool.parameters provider-neutral and Rust-shaped.
  • Normalize provider-specific schemas in adapters:
    • OpenAI/OpenRouter strict: recursively require all properties and set additionalProperties: false.
    • Gemini: preserve normal optional required semantics and convert schemars output into the Gemini supported schema subset.

Acceptance Criteria

  • Vec<String> schemas include items.
  • Nested structs/enums produce real schemas.
  • Option<T> and std::option::Option<T> behave as optional Rust parameters.
  • Missing and explicit null optional arguments both deserialize to None.
  • OpenAI strict request schemas satisfy strict requirements recursively.
  • Gemini request schemas preserve optional fields without forcing them into required.
  • Unsupported custom parameter types fail clearly at compile time.

Suggested Tests

  • Macro schema tests for arrays, nested structs, enums, and option paths.
  • Execution tests for missing and null optional values.
  • Provider conversion tests for OpenAI strict normalization and Gemini schema conversion.
  • Compile-fail test for a custom parameter type without JsonSchema.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions