Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/phpaisdk/openai-compatible/llms.txt

Use this file to discover all available pages before exploring further.

ChatResponseParser is a stateless, final utility class in the aisdk/openai-compatible package responsible for converting a raw decoded /chat/completions response payload — an array<string, mixed> obtained by JSON-decoding the HTTP response body — into a fully typed TextModelResponse. It extracts text content, tool-call descriptors, token usage, and provider-specific metadata, normalizing them all into the portable AiSdk response model so that application code never has to inspect raw OpenAI JSON.

Namespace

AiSdk\OpenAICompatible\ChatResponseParser

Method: parse()

public static function parse(array $payload, string $providerName): TextModelResponse
Deserializes a single /chat/completions response object into a TextModelResponse. Only choices[0] is examined; additional choices are ignored.

Parameters

payload
array<string, mixed>
required
The fully decoded response array from the /chat/completions endpoint. This is the value you get from json_decode($responseBody, true). The parser reads the following keys:
Key pathUsed for
choices[0].message.contentTextPart
choices[0].message.tool_calls[]ToolCallPart list
choices[0].finish_reasonFinishReason mapping
choices[0].indexproviderMetadata.choice_index
usage.prompt_tokensusage.inputTokens
usage.completion_tokensusage.outputTokens
usage.total_tokensusage.totalTokens
usage.completion_tokens_details.reasoning_tokensusage.reasoningTokens
usage.prompt_tokens_details.cached_tokensusage.cachedInputTokens
id, object, created, model, system_fingerprint, service_tierproviderMetadata
providerName
string
required
The provider namespace string, e.g. "openai". This becomes the key under which provider-specific metadata is nested in TextModelResponse::$providerMetadata.

Return value: TextModelResponse

parts
array<TextPart|ToolCallPart>
An ordered array of typed response parts. TextPart appears first (when present), followed by one ToolCallPart per entry in choices[0].message.tool_calls.
finishReason
FinishReason
A FinishReason enum value mapped from choices[0].finish_reason using MapsFinishReason::map(). The mapping is:
Raw stringFinishReason
"stop", "end_turn"FinishReason::Stop
"length", "max_tokens"FinishReason::Length
"tool_calls", "function_call"FinishReason::ToolCalls
"content_filter"FinishReason::ContentFilter
null / missingFinishReason::Stop
anything elseFinishReason::Unknown
usage
Usage
Token consumption figures. Falls back to Usage::empty() when the usage key is absent from the payload.
Usage propertySource field
inputTokensusage.prompt_tokens
outputTokensusage.completion_tokens
totalTokensusage.total_tokens (nullable)
reasoningTokensusage.completion_tokens_details.reasoning_tokens (nullable)
cachedInputTokensusage.prompt_tokens_details.cached_tokens (nullable)
rawResponse
array<string, mixed>
The original $payload array passed to parse(), stored verbatim for debugging or low-level access.
providerMetadata
array<string, array<string, mixed>>
Provider-specific metadata keyed by $providerName. The inner array contains response-level and choice-level fields:
KeySource
id$payload['id']
object$payload['object']
created$payload['created']
model$payload['model']
system_fingerprint$payload['system_fingerprint']
service_tier$payload['service_tier']
choice_indexchoices[0]['index']
choice_finish_reasonchoices[0]['finish_reason']
Only keys that are present in the payload are included; absent keys are not set to null.

Part types

TextPart

Created when choices[0].message.content is a non-empty string. The content string is stored verbatim; no trimming or transformation is applied.

ToolCallPart

Created once per entry in choices[0].message.tool_calls. Each ToolCallPart has:
PropertySource
idtool_calls[n].id
nametool_calls[n].function.name
argumentsJSON-decoded tool_calls[n].function.arguments (always an array)
arguments is always decoded from the JSON string in the payload. If the arguments string is empty, it is treated as {} and decoded to an empty array.

Usage example

The example below uses the exact payload from the ChatWireFormatTest suite:
use AiSdk\OpenAICompatible\ChatResponseParser;

$payload = [
    'id'               => 'chatcmpl_123',
    'object'           => 'chat.completion',
    'created'          => 1710000000,
    'model'            => 'gpt-4o',
    'system_fingerprint' => 'fp_abc',
    'choices' => [[
        'index'   => 0,
        'message' => [
            'content'    => 'hello',
            'tool_calls' => [[
                'id'       => 'call_1',
                'function' => [
                    'name'      => 'weather',
                    'arguments' => '{"city":"Lahore"}',
                ],
            ]],
        ],
        'finish_reason' => 'tool_calls',
    ]],
    'usage' => [
        'prompt_tokens'     => 10,
        'completion_tokens' => 4,
    ],
];

$response = ChatResponseParser::parse($payload, 'openai');

// Text content
echo $response->text();              // 'hello'

// Tool calls
$calls = $response->toolCalls();     // array of ToolCallPart
echo $calls[0]->name;                // 'weather'
echo $calls[0]->id;                  // 'call_1'
print_r($calls[0]->arguments);       // ['city' => 'Lahore']

// Token usage
echo $response->usage->inputTokens;  // 10
echo $response->usage->outputTokens; // 4

// Finish reason
echo $response->finishReason->name;  // 'ToolCalls'

// Provider metadata
$meta = $response->providerMetadata['openai'];
echo $meta['id'];                    // 'chatcmpl_123'
echo $meta['model'];                 // 'gpt-4o'
echo $meta['system_fingerprint'];    // 'fp_abc'
echo $meta['choice_index'];          // 0
echo $meta['choice_finish_reason'];  // 'tool_calls'
You can also access the original decoded payload at any time via $response->rawResponse — useful when a provider sends non-standard fields that providerMetadata does not capture.

Build docs developers (and LLMs) love