tool_schema_generator 0.2.1 copy "tool_schema_generator: ^0.2.1" to clipboard
tool_schema_generator: ^0.2.1 copied to clipboard

Annotations and a code generator for automatic LLM tool schema generation. Mark functions with @Tool() and parameters with @Describe() to generate JSON Schema Draft 2020-12 definitions and a type-safe [...]

tool_schema_generator #

A code generator for Dart that automatically produces JSON Schema (Draft 2020-12) tool definitions for Large Language Models (LLMs) from your annotated Dart functions.

pub package

If you are building AI agents with Gemini, OpenAI, Claude, or other LLMs, you often need to provide a JSON schema describing the tools (functions) the model can call. Instead of writing and maintaining massive JSON maps by hand, tool_schema_generator lets you write standard Dart functions and automatically generates the precise schemas your LLM needs.


🌟 Features #

  • Zero Boilerplate: Automatically infers types, names, and nullability directly from Dart syntax.
  • Full Analyzer Support: Supports String, int, double, bool, List<T>, Map<String, dynamic>, enums, and custom nested classes.
  • Seamless Integration: Uses the canonical source_gen combining builder. It outputs to a standard .g.dart file and plays nicely alongside other generators like json_serializable.
  • Customizable: Override tool names and descriptions, or let it automatically extract descriptions from your Dart doc comments.

📦 Installation #

Add the package to your pubspec.yaml:

dependencies:
  tool_schema_generator: ^0.2.0

dev_dependencies:
  build_runner: ^2.4.0

🚀 Quick Start #

1. Annotate your functions #

Create a .dart file and use the @Tool() annotation on your top-level functions. You can use the @Describe() annotation to add rich descriptions to individual parameters.

// lib/tools.dart
import 'package:tool_schema_generator/tool_schema_generator.dart';

// IMPORTANT: Declare the part file
part 'tools.g.dart';

/// Sends an email to a specific user.
@Tool()
void sendEmail(
  @Describe('The email address of the recipient') String to,
  @Describe('The subject line of the email') String subject, {
  @Describe('The main body content') required String body,
  bool isHtml = false,
}) {
  // Your logic here
}

2. Run the generator #

Run the build runner command in your terminal:

dart run build_runner build -d

3. Use the generated schemas and dispatcher #

The generator creates a tools.g.dart file containing a toolRegistry instance. This registry contains all your schemas and automatically routes LLM tool calls back to your Dart functions safely.

You can pass the schemas directly to your LLM framework using toolRegistry.allSchemas, or select individual ones via strongly-typed getters like toolRegistry.sendEmail.

  • toolRegistry.allSchemas gives you List<Map<String, dynamic>> (all schemas in the file).
  • toolRegistry.sendEmail gives you a single Map<String, dynamic> just for that tool. (You pass these directly into your LLM's tools parameter).

then disispatching (When the LLM replies)

final result = await toolRegistry.call(
  toolCall.name,
  toolCall.arguments
);

The registry takes the raw string name and raw JSON Map<String, dynamic> from the LLM, finds the right Dart closure, safely parses and casts all arguments, calls your function, and awaits the result.

This makes us reach to our final life cycle which what the tool returns after its been called and processed. It guarantees a return of the sealed class ToolResult. You never have to try/catch argument parsing errors yourself.

  • ToolSuccess: Contains the raw return .value of your Dart function.
  • ToolError: Contains structured data (.code, .message, .field) if the LLM hallucinated an argument, forgot a required field, or if your function threw an internal exception. You can feed this error message directly back to the LLM so it can fix its mistake!

This gives you a completely type-safe, boilerplate-free bridge between Dart code and LLM agent loops.

import 'tools.dart';

void main() async {
  // 1. Pass the schemas to your LLM
  final response = await llm.generate(
    prompt: "Send an email to hello@example.com saying Hi!",
    // toolRegistry.allSchemas -> is a List<Map<String, dynamic>>
    // toolRegistry.sendEmail -> is a Map<String, dynamic>
    tools: toolRegistry.allSchemas, // or [toolRegistry.sendEmail]
  );

  // 2. When the LLM decides to call a tool,
  // you just simply call the dispatch method on the
  for (final toolCall in response.toolCalls) {
    // The registry safely casts arguments,
    // which handles missing required fields,
    // and catches internal exceptions.
    final result = await toolRegistry.call(
      toolCall.name,
      toolCall.arguments,
    );

    switch (result) {
      case ToolSuccess(:final value):
        print("Tool returned: $value");
      case ToolError(:final code, :final message):
        print("Tool failed (\$code): \$message");
    }
  }
}

🧠 Advanced Usage #

Enums #

Enums are automatically converted to JSON Schema string enums:

enum Priority { low, normal, high }

@Tool()
void setTaskPriority(Priority priority) {}
// Generates: {"type": "string", "enum": ["low", "normal", "high"]}

Nested Objects #

Custom classes are introspected. The generator looks at the class's constructor parameters to build a nested JSON Schema object:

class Location {
  final double lat;
  final double lng;
  Location({required this.lat, required this.lng});
}

@Tool()
void updateLocation(Location location) {}
// Generates nested object with properties `lat` and `lng` (both required).

Overriding Names and Descriptions #

If you don't want to use the Dart function name or doc comment, you can override them directly in the annotation:

@Tool(
  name: 'custom_search_tool',
  description: 'A highly specific search tool description.'
)
void search(String query) {}

🤝 Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License #

This project is licensed under the MIT License.

0
likes
0
points
291
downloads

Publisher

unverified uploader

Weekly Downloads

Annotations and a code generator for automatic LLM tool schema generation. Mark functions with @Tool() and parameters with @Describe() to generate JSON Schema Draft 2020-12 definitions and a type-safe ToolRegistry dispatcher.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

analyzer, build, source_gen

More

Packages that depend on tool_schema_generator