Skip to content

feat: Add Code Interpreter support for Responses API #612

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

Closed
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
22 changes: 14 additions & 8 deletions src/Responses/Responses/CreateResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use OpenAI\Responses\Concerns\ArrayAccessible;
use OpenAI\Responses\Concerns\HasMetaInformation;
use OpenAI\Responses\Meta\MetaInformation;
use OpenAI\Responses\Responses\Output\OutputCodeInterpreterToolCall;
use OpenAI\Responses\Responses\Output\OutputComputerToolCall;
use OpenAI\Responses\Responses\Output\OutputFileSearchToolCall;
use OpenAI\Responses\Responses\Output\OutputFunctionToolCall;
Expand All @@ -20,6 +21,7 @@
use OpenAI\Responses\Responses\Output\OutputMessageContentOutputText;
use OpenAI\Responses\Responses\Output\OutputReasoning;
use OpenAI\Responses\Responses\Output\OutputWebSearchToolCall;
use OpenAI\Responses\Responses\Tool\CodeInterpreterTool;
use OpenAI\Responses\Responses\Tool\ComputerUseTool;
use OpenAI\Responses\Responses\Tool\FileSearchTool;
use OpenAI\Responses\Responses\Tool\FunctionTool;
Expand All @@ -32,6 +34,7 @@

/**
* @phpstan-import-type ResponseFormatType from CreateResponseFormat
* @phpstan-import-type OutputCodeInterpreterToolCallType from OutputCodeInterpreterToolCall
* @phpstan-import-type OutputComputerToolCallType from OutputComputerToolCall
* @phpstan-import-type OutputFileSearchToolCallType from OutputFileSearchToolCall
* @phpstan-import-type OutputFunctionToolCallType from OutputFunctionToolCall
Expand All @@ -42,6 +45,7 @@
* @phpstan-import-type OutputMcpApprovalRequestType from OutputMcpApprovalRequest
* @phpstan-import-type OutputMcpCallType from OutputMcpCall
* @phpstan-import-type OutputImageGenerationToolCallType from OutputImageGenerationToolCall
* @phpstan-import-type CodeInterpreterToolType from CodeInterpreterTool
* @phpstan-import-type ComputerUseToolType from ComputerUseTool
* @phpstan-import-type FileSearchToolType from FileSearchTool
* @phpstan-import-type ImageGenerationToolType from ImageGenerationTool
Expand All @@ -56,8 +60,8 @@
* @phpstan-import-type ReasoningType from CreateResponseReasoning
*
* @phpstan-type ToolChoiceType 'none'|'auto'|'required'|FunctionToolChoiceType|HostedToolChoiceType
* @phpstan-type ToolsType array<int, ComputerUseToolType|FileSearchToolType|FunctionToolType|WebSearchToolType|ImageGenerationToolType|RemoteMcpToolType|ImageGenerationToolType>
* @phpstan-type OutputType array<int, OutputComputerToolCallType|OutputFileSearchToolCallType|OutputFunctionToolCallType|OutputMessageType|OutputReasoningType|OutputWebSearchToolCallType|OutputMcpListToolsType|OutputMcpApprovalRequestType|OutputMcpCallType|OutputImageGenerationToolCallType>
* @phpstan-type ToolsType array<int, CodeInterpreterToolType|ComputerUseToolType|FileSearchToolType|FunctionToolType|WebSearchToolType|ImageGenerationToolType|RemoteMcpToolType>
* @phpstan-type OutputType array<int, OutputCodeInterpreterToolCallType|OutputComputerToolCallType|OutputFileSearchToolCallType|OutputFunctionToolCallType|OutputMessageType|OutputReasoningType|OutputWebSearchToolCallType|OutputMcpListToolsType|OutputMcpApprovalRequestType|OutputMcpCallType|OutputImageGenerationToolCallType>
* @phpstan-type CreateResponseType array{id: string, object: 'response', created_at: int, status: 'completed'|'failed'|'in_progress'|'incomplete', error: ErrorType|null, incomplete_details: IncompleteDetailsType|null, instructions: string|null, max_output_tokens: int|null, model: string, output: OutputType, output_text: string|null, parallel_tool_calls: bool, previous_response_id: string|null, reasoning: ReasoningType|null, store: bool, temperature: float|null, text: ResponseFormatType, tool_choice: ToolChoiceType, tools: ToolsType, top_p: float|null, truncation: 'auto'|'disabled'|null, usage: UsageType|null, user: string|null, metadata: array<string, string>|null}
*
* @implements ResponseContract<CreateResponseType>
Expand All @@ -75,8 +79,8 @@ final class CreateResponse implements ResponseContract, ResponseHasMetaInformati
/**
* @param 'response' $object
* @param 'completed'|'failed'|'in_progress'|'incomplete' $status
* @param array<int, OutputMessage|OutputComputerToolCall|OutputFileSearchToolCall|OutputWebSearchToolCall|OutputFunctionToolCall|OutputReasoning|OutputMcpListTools|OutputMcpApprovalRequest|OutputMcpCall|OutputImageGenerationToolCall> $output
* @param array<int, ComputerUseTool|FileSearchTool|FunctionTool|WebSearchTool|ImageGenerationTool|RemoteMcpTool|ImageGenerationTool> $tools
* @param array<int, OutputMessage|OutputCodeInterpreterToolCall|OutputComputerToolCall|OutputFileSearchToolCall|OutputWebSearchToolCall|OutputFunctionToolCall|OutputReasoning|OutputMcpListTools|OutputMcpApprovalRequest|OutputMcpCall|OutputImageGenerationToolCall> $output
* @param array<int, CodeInterpreterTool|ComputerUseTool|FileSearchTool|FunctionTool|WebSearchTool|ImageGenerationTool|RemoteMcpTool> $tools
* @param 'auto'|'disabled'|null $truncation
* @param array<string, string> $metadata
*/
Expand Down Expand Up @@ -114,7 +118,7 @@ private function __construct(
public static function from(array $attributes, MetaInformation $meta): self
{
$output = array_map(
fn (array $output): OutputMessage|OutputComputerToolCall|OutputFileSearchToolCall|OutputWebSearchToolCall|OutputFunctionToolCall|OutputReasoning|OutputMcpListTools|OutputMcpApprovalRequest|OutputMcpCall|OutputImageGenerationToolCall => match ($output['type']) {
fn (array $output): OutputMessage|OutputCodeInterpreterToolCall|OutputComputerToolCall|OutputFileSearchToolCall|OutputWebSearchToolCall|OutputFunctionToolCall|OutputReasoning|OutputMcpListTools|OutputMcpApprovalRequest|OutputMcpCall|OutputImageGenerationToolCall => match ($output['type']) {
'message' => OutputMessage::from($output),
'file_search_call' => OutputFileSearchToolCall::from($output),
'function_call' => OutputFunctionToolCall::from($output),
Expand All @@ -125,6 +129,7 @@ public static function from(array $attributes, MetaInformation $meta): self
'mcp_approval_request' => OutputMcpApprovalRequest::from($output),
'mcp_call' => OutputMcpCall::from($output),
'image_generation_call' => OutputImageGenerationToolCall::from($output),
'code_interpreter_call' => OutputCodeInterpreterToolCall::from($output),
},
$attributes['output'],
);
Expand All @@ -137,13 +142,14 @@ public static function from(array $attributes, MetaInformation $meta): self
: $attributes['tool_choice'];

$tools = array_map(
fn (array $tool): ComputerUseTool|FileSearchTool|FunctionTool|WebSearchTool|ImageGenerationTool|RemoteMcpTool => match ($tool['type']) {
fn (array $tool): ComputerUseTool|FileSearchTool|FunctionTool|WebSearchTool|ImageGenerationTool|RemoteMcpTool|CodeInterpreterTool => match ($tool['type']) {
'file_search' => FileSearchTool::from($tool),
'web_search_preview', 'web_search_preview_2025_03_11' => WebSearchTool::from($tool),
'function' => FunctionTool::from($tool),
'computer_use_preview' => ComputerUseTool::from($tool),
'image_generation' => ImageGenerationTool::from($tool),
'mcp' => RemoteMcpTool::from($tool),
'code_interpreter' => CodeInterpreterTool::from($tool),
},
$attributes['tools'],
);
Expand Down Expand Up @@ -216,7 +222,7 @@ public function toArray(): array
'metadata' => $this->metadata ?? [],
'model' => $this->model,
'output' => array_map(
fn (OutputMessage|OutputComputerToolCall|OutputFileSearchToolCall|OutputWebSearchToolCall|OutputFunctionToolCall|OutputReasoning|OutputMcpListTools|OutputMcpApprovalRequest|OutputMcpCall|OutputImageGenerationToolCall $output): array => $output->toArray(),
fn (OutputMessage|OutputCodeInterpreterToolCall|OutputComputerToolCall|OutputFileSearchToolCall|OutputWebSearchToolCall|OutputFunctionToolCall|OutputReasoning|OutputMcpListTools|OutputMcpApprovalRequest|OutputMcpCall|OutputImageGenerationToolCall $output): array => $output->toArray(),
$this->output
),
'parallel_tool_calls' => $this->parallelToolCalls,
Expand All @@ -229,7 +235,7 @@ public function toArray(): array
? $this->toolChoice
: $this->toolChoice->toArray(),
'tools' => array_map(
fn (ComputerUseTool|FileSearchTool|FunctionTool|WebSearchTool|ImageGenerationTool|RemoteMcpTool $tool): array => $tool->toArray(),
fn (CodeInterpreterTool|ComputerUseTool|FileSearchTool|FunctionTool|WebSearchTool|ImageGenerationTool|RemoteMcpTool $tool): array => $tool->toArray(),
$this->tools
),
'top_p' => $this->topP,
Expand Down
11 changes: 10 additions & 1 deletion src/Responses/Responses/CreateStreamedResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
use OpenAI\Contracts\ResponseContract;
use OpenAI\Exceptions\UnknownEventException;
use OpenAI\Responses\Concerns\ArrayAccessible;
use OpenAI\Responses\Responses\Streaming\CodeInterpreterCall;
use OpenAI\Responses\Responses\Streaming\CodeInterpreterCodeDelta;
use OpenAI\Responses\Responses\Streaming\CodeInterpreterCodeDone;
use OpenAI\Responses\Responses\Streaming\ContentPart;
use OpenAI\Responses\Responses\Streaming\Error;
use OpenAI\Responses\Responses\Streaming\FileSearchCall;
Expand Down Expand Up @@ -47,7 +50,7 @@ final class CreateStreamedResponse implements ResponseContract

private function __construct(
public readonly string $event,
public readonly CreateResponse|OutputItem|ContentPart|OutputTextDelta|OutputTextAnnotationAdded|OutputTextDone|RefusalDelta|RefusalDone|FunctionCallArgumentsDelta|FunctionCallArgumentsDone|FileSearchCall|WebSearchCall|ReasoningSummaryPart|ReasoningSummaryTextDelta|ReasoningSummaryTextDone|McpListTools|McpListToolsInProgress|McpCall|McpCallArgumentsDelta|McpCallArgumentsDone|ImageGenerationPart|ImageGenerationPartialImage|Error $response,
public readonly CreateResponse|OutputItem|ContentPart|OutputTextDelta|OutputTextAnnotationAdded|OutputTextDone|RefusalDelta|RefusalDone|FunctionCallArgumentsDelta|FunctionCallArgumentsDone|FileSearchCall|WebSearchCall|CodeInterpreterCall|CodeInterpreterCodeDelta|CodeInterpreterCodeDone|ReasoningSummaryPart|ReasoningSummaryTextDelta|ReasoningSummaryTextDone|McpListTools|McpListToolsInProgress|McpCall|McpCallArgumentsDelta|McpCallArgumentsDone|ImageGenerationPart|ImageGenerationPartialImage|Error $response,
) {}

/**
Expand Down Expand Up @@ -82,6 +85,12 @@ public static function from(array $attributes): self
'response.web_search_call.in_progress',
'response.web_search_call.searching',
'response.web_search_call.completed' => WebSearchCall::from($attributes, $meta), // @phpstan-ignore-line
'response.code_interpreter_call.in_progress',
'response.code_interpreter_call.running',
'response.code_interpreter_call.interpreting',
'response.code_interpreter_call.completed' => CodeInterpreterCall::from($attributes, $meta), // @phpstan-ignore-line
'response.code_interpreter_call_code.delta' => CodeInterpreterCodeDelta::from($attributes, $meta), // @phpstan-ignore-line
'response.code_interpreter_call_code.done' => CodeInterpreterCodeDone::from($attributes, $meta), // @phpstan-ignore-line
'response.reasoning_summary_part.added',
'response.reasoning_summary_part.done' => ReasoningSummaryPart::from($attributes, $meta), // @phpstan-ignore-line
'response.reasoning_summary_text.delta' => ReasoningSummaryTextDelta::from($attributes, $meta), // @phpstan-ignore-line
Expand Down
57 changes: 57 additions & 0 deletions src/Responses/Responses/Output/OutputCodeInterpreterToolCall.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace OpenAI\Responses\Responses\Output;

use OpenAI\Contracts\ResponseContract;
use OpenAI\Responses\Concerns\ArrayAccessible;
use OpenAI\Testing\Responses\Concerns\Fakeable;

/**
* @phpstan-type OutputCodeInterpreterToolCallType array{id: string, status: string, type: 'code_interpreter_call'}
*
* @implements ResponseContract<OutputCodeInterpreterToolCallType>
*/
final class OutputCodeInterpreterToolCall implements ResponseContract
{
/**
* @use ArrayAccessible<OutputCodeInterpreterToolCallType>
*/
use ArrayAccessible;

use Fakeable;

/**
* @param 'code_interpreter_call' $type
*/
private function __construct(
public readonly string $id,
public readonly string $status,
public readonly string $type,
) {}

/**
* @param OutputCodeInterpreterToolCallType $attributes
*/
public static function from(array $attributes): self
{
return new self(
id: $attributes['id'],
status: $attributes['status'],
type: $attributes['type'],
);
}

/**
* {@inheritDoc}
*/
public function toArray(): array
{
return [
'id' => $this->id,
'status' => $this->status,
'type' => $this->type,
];
}
}
38 changes: 31 additions & 7 deletions src/Responses/Responses/Output/OutputMessageContentOutputText.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@

use OpenAI\Contracts\ResponseContract;
use OpenAI\Responses\Concerns\ArrayAccessible;
use OpenAI\Responses\Responses\Output\OutputMessageContentOutputTextAnnotationsContainerFile as AnnotationContainerFile;
use OpenAI\Responses\Responses\Output\OutputMessageContentOutputTextAnnotationsFileCitation as AnnotationFileCitation;
use OpenAI\Responses\Responses\Output\OutputMessageContentOutputTextAnnotationsFilePath as AnnotationFilePath;
use OpenAI\Responses\Responses\Output\OutputMessageContentOutputTextAnnotationsUrlCitation as AnnotationUrlCitation;
use OpenAI\Testing\Responses\Concerns\Fakeable;

/**
* @phpstan-import-type ContainerFileType from OutputMessageContentOutputTextAnnotationsContainerFile
* @phpstan-import-type FileCitationType from OutputMessageContentOutputTextAnnotationsFileCitation
* @phpstan-import-type FilePathType from OutputMessageContentOutputTextAnnotationsFilePath
* @phpstan-import-type UrlCitationType from OutputMessageContentOutputTextAnnotationsUrlCitation
*
* @phpstan-type OutputTextType array{annotations: array<int, FileCitationType|FilePathType|UrlCitationType>, text: string, type: 'output_text'}
* @phpstan-type OutputTextType array{annotations: array<int, ContainerFileType|FileCitationType|FilePathType|UrlCitationType>, text: string, type: 'output_text'}
*
* @implements ResponseContract<OutputTextType>
*/
Expand All @@ -30,7 +32,7 @@ final class OutputMessageContentOutputText implements ResponseContract
use Fakeable;

/**
* @param array<int, AnnotationFileCitation|AnnotationFilePath|AnnotationUrlCitation> $annotations
* @param array<int, AnnotationContainerFile|AnnotationFileCitation|AnnotationFilePath|AnnotationUrlCitation> $annotations
* @param 'output_text' $type
*/
private function __construct(
Expand All @@ -45,10 +47,30 @@ private function __construct(
public static function from(array $attributes): self
{
$annotations = array_map(
fn (array $annotation): AnnotationFileCitation|AnnotationFilePath|AnnotationUrlCitation => match ($annotation['type']) {
'file_citation' => AnnotationFileCitation::from($annotation),
'file_path' => AnnotationFilePath::from($annotation),
'url_citation' => AnnotationUrlCitation::from($annotation),
function (array $annotation): AnnotationContainerFile|AnnotationFileCitation|AnnotationFilePath|AnnotationUrlCitation {
$annotationType = $annotation['type'];

// Handle container_file types with any suffix
if (str_starts_with($annotationType, 'container_file')) {
/** @var ContainerFileType $annotation */
return AnnotationContainerFile::from($annotation);
}

return match ($annotationType) {
'file_citation' => (static function (array $annotation) {
/** @var FileCitationType $annotation */
return AnnotationFileCitation::from($annotation);
})($annotation),
'file_path' => (static function (array $annotation) {
/** @var FilePathType $annotation */
return AnnotationFilePath::from($annotation);
})($annotation),
'url_citation' => (static function (array $annotation) {
/** @var UrlCitationType $annotation */
return AnnotationUrlCitation::from($annotation);
})($annotation),
default => throw new \UnhandledMatchError("Unhandled annotation type: {$annotationType}")
};
},
$attributes['annotations'],
);
Expand All @@ -67,7 +89,9 @@ public function toArray(): array
{
return [
'annotations' => array_map(
fn (AnnotationFileCitation|AnnotationFilePath|AnnotationUrlCitation $annotation): array => $annotation->toArray(),
static function (AnnotationContainerFile|AnnotationFileCitation|AnnotationFilePath|AnnotationUrlCitation $annotation): array {
return $annotation->toArray();
},
$this->annotations,
),
'text' => $this->text,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

declare(strict_types=1);

namespace OpenAI\Responses\Responses\Output;

use OpenAI\Contracts\ResponseContract;
use OpenAI\Responses\Concerns\ArrayAccessible;
use OpenAI\Testing\Responses\Concerns\Fakeable;

/**
* @phpstan-type ContainerFileType array{file_id: string, type: string, text?: string, start_index?: int, end_index?: int}
*
* @implements ResponseContract<ContainerFileType>
*/
final class OutputMessageContentOutputTextAnnotationsContainerFile implements ResponseContract
{
/**
* @use ArrayAccessible<ContainerFileType>
*/
use ArrayAccessible;

use Fakeable;

private function __construct(
public readonly string $fileId,
public readonly string $type,
public readonly ?string $text,
public readonly ?int $startIndex,
public readonly ?int $endIndex,
) {}

/**
* @param ContainerFileType $attributes
*/
public static function from(array $attributes): self
{
return new self(
fileId: $attributes['file_id'],
type: $attributes['type'],
text: $attributes['text'] ?? null,
startIndex: $attributes['start_index'] ?? null,
endIndex: $attributes['end_index'] ?? null,
);
}

/**
* {@inheritDoc}
*/
public function toArray(): array
{
$result = [
'file_id' => $this->fileId,
'type' => $this->type,
];

if ($this->text !== null) {
$result['text'] = $this->text;
}

if ($this->startIndex !== null) {
$result['start_index'] = $this->startIndex;
}

if ($this->endIndex !== null) {
$result['end_index'] = $this->endIndex;
}

return $result;
}
}
Loading