Skip to content

Allow providers to prepare function declarations before tool-calling requests #256

Description

@gziolo

Context

This came out of the WordPress Core discussion in https://core.trac.wordpress.org/ticket/64955.

The original Core ticket explored compiling Abilities API schemas for AI/tool-calling compatibility. After tracing the flow more closely, the part that matters for tool calling is the input schema exposed as FunctionDeclaration::parameters.

The LLM only receives the tool declaration and generates a tool call with arguments. The actual tool execution happens later outside the model, so ability output schemas / structured response schemas are not part of this compatibility problem.

Current behavior

Today, function declarations are serialized into the provider request as-is. For OpenAI-compatible models, AbstractOpenAiCompatibleTextGenerationModel::prepareToolsParam() effectively does:

$tools[] = array(
    'type'     => 'function',
    'function' => $functionDeclaration->toArray(),
);

That means provider-specific JSON Schema compatibility rules cannot be handled by the provider model before the request is sent.

Different providers support different subsets or variants of JSON Schema for tool input schemas. For example, a provider may need to normalize or remove unsupported schema keywords, adjust object schemas, rewrite composition keywords, or otherwise prepare the schema used in parameters.

Proposal

Add a protected no-op method that provider models can override before a function declaration is serialized for a tool-calling request:

protected function prepareFunctionDeclarationForRequest(
    FunctionDeclaration $functionDeclaration
): FunctionDeclaration {
    return $functionDeclaration;
}

Then call it from prepareToolsParam():

protected function prepareToolsParam( array $functionDeclarations ): array {
    $tools = array();

    foreach ( $functionDeclarations as $functionDeclaration ) {
        $functionDeclaration = $this->prepareFunctionDeclarationForRequest( $functionDeclaration );

        $tools[] = array(
            'type'     => 'function',
            'function' => $functionDeclaration->toArray(),
        );
    }

    return $tools;
}

The default implementation would preserve current behavior exactly. Providers that need custom compatibility handling could return either the original declaration or a new FunctionDeclaration with adjusted name, description, or parameters.

Example override:

protected function prepareFunctionDeclarationForRequest(
    FunctionDeclaration $functionDeclaration
): FunctionDeclaration {
    return new FunctionDeclaration(
        $functionDeclaration->getName(),
        $functionDeclaration->getDescription(),
        $this->prepareToolInputSchemaForRequest( $functionDeclaration->getParameters() )
    );
}

Why provider-level?

This seems like a provider/model request-serialization concern rather than a WordPress Core schema compiler concern. The canonical schema can remain unchanged, while each provider decides whether and how to adapt tool input schemas for its own API.

Out of scope

This issue is only about function declarations / tool input schemas.

Structured output schemas and response_format handling are separate concerns and do not need to be changed for Abilities API tool calling compatibility.

Suggested tests

  • Default implementation preserves the current tools payload.
  • A provider model overriding prepareFunctionDeclarationForRequest() can change parameters before serialization.
  • A provider model overriding the method can return the same declaration unchanged.
  • Function declarations without parameters continue to serialize as they do today.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions