Skip to content

Fixes #2513: Add support for Free-Form Function Calling and Context Free Grammar constraints over tools #2572

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

matthewfranglen
Copy link
Contributor

@matthewfranglen matthewfranglen commented Aug 15, 2025

This is the PR to implement free-form function calling and context free constraints over tools. This implements:

  • Free Form Function calling for Tool, @agent.tool, @agent.tool_plain
  • Free Form Function calling for output tools
  • Context Free constraints over the free form functions
  • Documentation
  • Tests

I'm hoping to get a working implementation done today, after which we can have the rounds of feedback and improvement required before this can be merged. I will try to keep in mind the feedback that I got on the last PR.

Since there is a specific company voice that you wish to maintain, when suggesting changes to documentation et al please provide the exact wording that you desire.

the response from the model is not correctly handled yet
now produces appropriate warnings when misconfigured
I can now call the model with the following:

```
from pydantic_ai import Agent
import asyncio
import json
from pydantic_core import to_jsonable_python
from pydantic_ai.models.openai import OpenAIResponsesModel

agent = Agent(OpenAIResponsesModel("gpt-5-mini"), model_settings={"openai_reasoning_effort": "minimal"})

@agent.tool_plain(free_form=True)
def execute_lucene_query(query: str) -> str:
    """Use this to run a lucene query against the system.
    YOU MUST ALWAYS RUN A QUERY BEFORE ANSWERING THE USER.

    Args:
        query: the lucene query to run

    Returns:
        the result of executing the query, or an error message
    """
    return "The query failed to execute, the solr server is unavailable"

async def run() -> None:
    response = await agent.run("Execute the lucene query text:IKEA and give me the results")
    history = response.all_messages()
    as_json = json.dumps(to_jsonable_python(history), indent=2)
    print(as_json)
    print(response.output)

asyncio.run(run())
```
@matthewfranglen
Copy link
Contributor Author

I'm going to work on CI checks after getting something that at least supports the CFG tool calls.

@@ -977,6 +980,9 @@ def tool(
require_parameter_descriptions: bool = False,
schema_generator: type[GenerateJsonSchema] = GenerateToolJsonSchema,
strict: bool | None = None,
free_form: bool | None = None,
grammar_syntax: Literal['regex', 'lark'] | None = None,
grammar_definition: str | None = None,
Copy link
Collaborator

Choose a reason for hiding this comment

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

@matthewfranglen I know you still have some work planned on this PR before it's really ready for review, but please consider the API I proposed in #2513 (comment). I'd prefer one argument taking an object over 3 that need to be used together

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry I missed your intent with that part. It's a very good idea I will certainly do that, and it will clean up what I have done so far. Thanks for the reminder.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe I have addressed this now

@matthewfranglen
Copy link
Contributor Author

just coverage and documentation now, pending the actual review of course

@DouweM
Copy link
Collaborator

DouweM commented Aug 16, 2025

@matthewfranglen Just a heads-up that I'll be out this coming week and will be back the 25th. Assuming this is not urgent I'll review it then. If it is, please ping Kludex! Appreciate the patience :)

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

Successfully merging this pull request may close these issues.

2 participants