Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,14 @@ protected function prepareToolsParam(array $functionDeclarations): array
/**
* Prepares the response format parameter for the API request.
*
* This is only called if the output MIME type is `application/json`.
* This is only called if the output MIME type is `application/json`. When an output schema is
* provided, it is wrapped in the `json_schema` envelope expected by the OpenAI Chat Completions
* API, which requires a `name` field and the schema under the `schema` key. The `name` uses a
* fixed identifier that satisfies the API's `^[a-zA-Z0-9_-]{1,64}$` constraint, rather than a
* value derived from the schema, to avoid producing an invalid name. If a caller already
* supplies a wrapped payload (i.e. an array containing both `name` and `schema` keys), it is
* passed through unchanged, allowing callers to opt into provider-specific options such as
* `strict`.
*
* @since 0.1.0
*
Expand All @@ -513,15 +520,29 @@ protected function prepareToolsParam(array $functionDeclarations): array
*/
protected function prepareResponseFormatParam(?array $outputSchema): array
{
if (is_array($outputSchema)) {
if ($outputSchema === null) {
return [
'type' => 'json_object',
];
}

// Pass through payloads that are already wrapped in the json_schema envelope.
$isWrappedEnvelope = isset($outputSchema['name'])
&& isset($outputSchema['schema'])
&& is_array($outputSchema['schema']);
if ($isWrappedEnvelope) {
return [
'type' => 'json_schema',
'json_schema' => $outputSchema,
];
}

return [
'type' => 'json_object',
'type' => 'json_schema',
'json_schema' => [
'name' => 'response_schema',
'schema' => $outputSchema,
],
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,16 @@ public function testPrepareGenerateTextParamsWithJsonOutputSchema(): void
$params = $model->exposePrepareGenerateTextParams($prompt);

$this->assertArrayHasKey('response_format', $params);
$this->assertEquals(['type' => 'json_schema', 'json_schema' => $schema], $params['response_format']);
$this->assertEquals(
[
'type' => 'json_schema',
'json_schema' => [
'name' => 'response_schema',
'schema' => $schema,
],
],
$params['response_format']
);
}

/**
Expand Down Expand Up @@ -950,7 +959,71 @@ public function testPrepareResponseFormatParamWithSchema(): void
$model = $this->createModel();
$format = $model->exposePrepareResponseFormatParam($schema);

$this->assertEquals(['type' => 'json_schema', 'json_schema' => $schema], $format);
$this->assertEquals(
[
'type' => 'json_schema',
'json_schema' => [
'name' => 'response_schema',
'schema' => $schema,
],
],
$format
);
}

/**
* Tests prepareResponseFormatParam() ignores the schema title when naming the envelope.
*
* The OpenAI API requires the json_schema name to match ^[a-zA-Z0-9_-]{1,64}$, so a
* user-supplied title (which may contain spaces or other invalid characters) must not be
* used as the name. A fixed, valid identifier is used instead.
*
* @return void
*/
public function testPrepareResponseFormatParamIgnoresSchemaTitle(): void
{
$schema = [
'title' => 'Review Notes!',
'type' => 'object',
'properties' => ['key' => ['type' => 'string']],
];
$model = $this->createModel();
$format = $model->exposePrepareResponseFormatParam($schema);

$this->assertEquals(
[
'type' => 'json_schema',
'json_schema' => [
'name' => 'response_schema',
'schema' => $schema,
],
],
$format
);
}

/**
* Tests prepareResponseFormatParam() passes through an already-wrapped envelope.
*
* @return void
*/
public function testPrepareResponseFormatParamPassesThroughWrappedEnvelope(): void
{
$envelope = [
'name' => 'classification',
'strict' => true,
'schema' => ['type' => 'object', 'properties' => ['key' => ['type' => 'string']]],
];
$model = $this->createModel();
$format = $model->exposePrepareResponseFormatParam($envelope);

$this->assertEquals(
[
'type' => 'json_schema',
'json_schema' => $envelope,
],
$format
);
}

/**
Expand Down
Loading