diff --git a/demo/src/Audio/Chat.php b/demo/src/Audio/Chat.php index b6caee85..d1fed95c 100644 --- a/demo/src/Audio/Chat.php +++ b/demo/src/Audio/Chat.php @@ -17,7 +17,7 @@ use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; use Symfony\AI\Platform\PlatformInterface; -use Symfony\AI\Platform\Response\TextResponse; +use Symfony\AI\Platform\Result\TextResult; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\HttpFoundation\RequestStack; @@ -39,9 +39,9 @@ public function say(string $base64audio): void $path = tempnam(sys_get_temp_dir(), 'audio-').'.wav'; file_put_contents($path, base64_decode($base64audio)); - $response = $this->platform->request(new Whisper(), Audio::fromFile($path)); + $result = $this->platform->invoke(new Whisper(), Audio::fromFile($path)); - $this->submitMessage($response->asText()); + $this->submitMessage($result->asText()); } public function loadMessages(): MessageBag @@ -54,11 +54,11 @@ public function submitMessage(string $message): void $messages = $this->loadMessages(); $messages->add(Message::ofUser($message)); - $response = $this->agent->call($messages); + $result = $this->agent->call($messages); - \assert($response instanceof TextResponse); + \assert($result instanceof TextResult); - $messages->add(Message::ofAssistant($response->getContent())); + $messages->add(Message::ofAssistant($result->getContent())); $this->saveMessages($messages); } diff --git a/demo/src/Blog/Chat.php b/demo/src/Blog/Chat.php index 559b404b..fd0adf29 100644 --- a/demo/src/Blog/Chat.php +++ b/demo/src/Blog/Chat.php @@ -14,7 +14,7 @@ use Symfony\AI\Agent\AgentInterface; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; -use Symfony\AI\Platform\Response\TextResponse; +use Symfony\AI\Platform\Result\TextResult; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\HttpFoundation\RequestStack; @@ -49,11 +49,11 @@ public function submitMessage(string $message): void $messages = $this->loadMessages(); $messages->add(Message::ofUser($message)); - $response = $this->agent->call($messages); + $result = $this->agent->call($messages); - \assert($response instanceof TextResponse); + \assert($result instanceof TextResult); - $messages->add(Message::ofAssistant($response->getContent())); + $messages->add(Message::ofAssistant($result->getContent())); $this->saveMessages($messages); } diff --git a/demo/src/Blog/Command/QueryCommand.php b/demo/src/Blog/Command/QueryCommand.php index db3d59dc..096dce0a 100644 --- a/demo/src/Blog/Command/QueryCommand.php +++ b/demo/src/Blog/Command/QueryCommand.php @@ -48,7 +48,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $io->comment(\sprintf('Converting "%s" to vector & searching in Chroma DB ...', $search)); $io->comment('Results are limited to 4 most similar documents.'); - $platformResponse = $this->platform->request(new Embeddings(), $search); + $platformResponse = $this->platform->invoke(new Embeddings(), $search); $queryResponse = $collection->query( queryEmbeddings: [$platformResponse->asVectors()[0]->getData()], nResults: 4, diff --git a/demo/src/Blog/FeedLoader.php b/demo/src/Blog/FeedLoader.php index b82d95a4..d02eb058 100644 --- a/demo/src/Blog/FeedLoader.php +++ b/demo/src/Blog/FeedLoader.php @@ -27,10 +27,10 @@ public function __construct( */ public function load(): array { - $response = $this->httpClient->request('GET', 'https://feeds.feedburner.com/symfony/blog'); + $result = $this->httpClient->request('GET', 'https://feeds.feedburner.com/symfony/blog'); $posts = []; - $crawler = new Crawler($response->getContent()); + $crawler = new Crawler($result->getContent()); $crawler->filter('item')->each(function (Crawler $node) use (&$posts) { $title = $node->filter('title')->text(); $posts[] = new Post( diff --git a/demo/src/Video/TwigComponent.php b/demo/src/Video/TwigComponent.php index 30ca7341..009f236a 100644 --- a/demo/src/Video/TwigComponent.php +++ b/demo/src/Video/TwigComponent.php @@ -47,10 +47,10 @@ public function submit(#[LiveArg] string $instruction, #[LiveArg] string $image) Message::ofUser($instruction, Image::fromDataUrl($image)) ); - $response = $this->platform->request(new GPT(GPT::GPT_4O_MINI), $messageBag, [ + $result = $this->platform->invoke(new GPT(GPT::GPT_4O_MINI), $messageBag, [ 'max_tokens' => 100, ]); - $this->caption = $response->asText(); + $this->caption = $result->asText(); } } diff --git a/demo/src/Wikipedia/Chat.php b/demo/src/Wikipedia/Chat.php index 28da86d3..cd9736f7 100644 --- a/demo/src/Wikipedia/Chat.php +++ b/demo/src/Wikipedia/Chat.php @@ -14,7 +14,7 @@ use Symfony\AI\Agent\AgentInterface; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; -use Symfony\AI\Platform\Response\TextResponse; +use Symfony\AI\Platform\Result\TextResult; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\HttpFoundation\RequestStack; @@ -39,11 +39,11 @@ public function submitMessage(string $message): void $messages = $this->loadMessages(); $messages->add(Message::ofUser($message)); - $response = $this->agent->call($messages); + $result = $this->agent->call($messages); - \assert($response instanceof TextResponse); + \assert($result instanceof TextResult); - $messages->add(Message::ofAssistant($response->getContent())); + $messages->add(Message::ofAssistant($result->getContent())); $this->saveMessages($messages); } diff --git a/demo/src/YouTube/Chat.php b/demo/src/YouTube/Chat.php index 7527ddce..515da3ff 100644 --- a/demo/src/YouTube/Chat.php +++ b/demo/src/YouTube/Chat.php @@ -14,7 +14,7 @@ use Symfony\AI\Agent\AgentInterface; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; -use Symfony\AI\Platform\Response\TextResponse; +use Symfony\AI\Platform\Result\TextResult; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\HttpFoundation\RequestStack; @@ -61,11 +61,11 @@ public function submitMessage(string $message): void $messages = $this->loadMessages(); $messages->add(Message::ofUser($message)); - $response = $this->agent->call($messages); + $result = $this->agent->call($messages); - \assert($response instanceof TextResponse); + \assert($result instanceof TextResult); - $messages->add(Message::ofAssistant($response->getContent())); + $messages->add(Message::ofAssistant($result->getContent())); $this->saveMessages($messages); } diff --git a/examples/albert/chat.php b/examples/albert/chat.php index d4425cb5..79ef5955 100644 --- a/examples/albert/chat.php +++ b/examples/albert/chat.php @@ -44,6 +44,6 @@ Message::ofUser('What are the main objectives of France\'s AI strategy?'), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/anthropic/chat.php b/examples/anthropic/chat.php index 5f6bd009..d2c0ed86 100644 --- a/examples/anthropic/chat.php +++ b/examples/anthropic/chat.php @@ -25,6 +25,6 @@ Message::forSystem('You are a pirate and you write funny.'), Message::ofUser('What is the Symfony framework?'), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/anthropic/image-input-binary.php b/examples/anthropic/image-input-binary.php index f65db140..d2e8fe9b 100644 --- a/examples/anthropic/image-input-binary.php +++ b/examples/anthropic/image-input-binary.php @@ -29,6 +29,6 @@ 'Describe this image.', ), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/anthropic/image-input-url.php b/examples/anthropic/image-input-url.php index fb671775..089eb927 100644 --- a/examples/anthropic/image-input-url.php +++ b/examples/anthropic/image-input-url.php @@ -29,6 +29,6 @@ 'Describe this image.', ), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/anthropic/pdf-input-binary.php b/examples/anthropic/pdf-input-binary.php index 82296bf0..79cc9f64 100644 --- a/examples/anthropic/pdf-input-binary.php +++ b/examples/anthropic/pdf-input-binary.php @@ -28,6 +28,6 @@ 'What is this document about?', ), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/anthropic/pdf-input-url.php b/examples/anthropic/pdf-input-url.php index f1da14cf..4f3d4f88 100644 --- a/examples/anthropic/pdf-input-url.php +++ b/examples/anthropic/pdf-input-url.php @@ -28,6 +28,6 @@ 'What is this document about?', ), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/anthropic/stream.php b/examples/anthropic/stream.php index 9f8da137..69373d53 100644 --- a/examples/anthropic/stream.php +++ b/examples/anthropic/stream.php @@ -25,11 +25,11 @@ Message::forSystem('You are a thoughtful philosopher.'), Message::ofUser('What is the purpose of an ant?'), ); -$response = $agent->call($messages, [ +$result = $agent->call($messages, [ 'stream' => true, // enable streaming of response text ]); -foreach ($response->getContent() as $word) { +foreach ($result->getContent() as $word) { echo $word; } echo \PHP_EOL; diff --git a/examples/anthropic/toolcall.php b/examples/anthropic/toolcall.php index be35daad..926c0576 100644 --- a/examples/anthropic/toolcall.php +++ b/examples/anthropic/toolcall.php @@ -29,6 +29,6 @@ $agent = new Agent($platform, $model, [$processor], [$processor], logger()); $messages = new MessageBag(Message::ofUser('Who is the current chancellor of Germany?')); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/azure/audio-transcript.php b/examples/azure/audio-transcript.php index eede7b38..ab986675 100644 --- a/examples/azure/audio-transcript.php +++ b/examples/azure/audio-transcript.php @@ -25,6 +25,6 @@ $model = new Whisper(); $file = Audio::fromFile(dirname(__DIR__, 2).'/fixtures/audio.mp3'); -$response = $platform->request($model, $file); +$result = $platform->invoke($model, $file); -echo $response->asText().\PHP_EOL; +echo $result->asText().\PHP_EOL; diff --git a/examples/azure/chat-gpt.php b/examples/azure/chat-gpt.php index 4acc66c5..a0a1ed35 100644 --- a/examples/azure/chat-gpt.php +++ b/examples/azure/chat-gpt.php @@ -31,6 +31,6 @@ Message::forSystem('You are a pirate and you write funny.'), Message::ofUser('What is the Symfony framework?'), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/azure/chat-llama.php b/examples/azure/chat-llama.php index 8690cc1b..011abdbc 100644 --- a/examples/azure/chat-llama.php +++ b/examples/azure/chat-llama.php @@ -22,7 +22,7 @@ $agent = new Agent($platform, $model, logger: logger()); $messages = new MessageBag(Message::ofUser('I am going to Paris, what should I see?')); -$response = $agent->call($messages, [ +$result = $agent->call($messages, [ 'max_tokens' => 2048, 'temperature' => 0.8, 'top_p' => 0.1, @@ -30,4 +30,4 @@ 'frequency_penalty' => 0, ]); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/azure/embeddings.php b/examples/azure/embeddings.php index 126c17c0..1fd1d5b8 100644 --- a/examples/azure/embeddings.php +++ b/examples/azure/embeddings.php @@ -23,10 +23,10 @@ ); $embeddings = new Embeddings(); -$response = $platform->request($embeddings, <<invoke($embeddings, <<asVectors()[0]->getDimensions().\PHP_EOL; +echo 'Dimensions: '.$result->asVectors()[0]->getDimensions().\PHP_EOL; diff --git a/examples/bedrock/chat-claude.php b/examples/bedrock/chat-claude.php index 8f513353..3671df6d 100644 --- a/examples/bedrock/chat-claude.php +++ b/examples/bedrock/chat-claude.php @@ -31,6 +31,6 @@ Message::forSystem('You answer questions in short and concise manner.'), Message::ofUser('What is the Symfony framework?'), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/bedrock/chat-llama.php b/examples/bedrock/chat-llama.php index b0d278f5..9ff4e602 100644 --- a/examples/bedrock/chat-llama.php +++ b/examples/bedrock/chat-llama.php @@ -31,6 +31,6 @@ Message::forSystem('You are a pirate and you write funny.'), Message::ofUser('What is the Symfony framework?'), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/bedrock/chat-nova.php b/examples/bedrock/chat-nova.php index a79c205b..9a7b39a8 100644 --- a/examples/bedrock/chat-nova.php +++ b/examples/bedrock/chat-nova.php @@ -31,6 +31,6 @@ Message::forSystem('You are a pirate and you write funny.'), Message::ofUser('What is the Symfony framework?'), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/bedrock/image-claude-binary.php b/examples/bedrock/image-claude-binary.php index 36dcde68..85a4aa8f 100644 --- a/examples/bedrock/image-claude-binary.php +++ b/examples/bedrock/image-claude-binary.php @@ -35,6 +35,6 @@ Image::fromFile(dirname(__DIR__, 2).'/fixtures/image.jpg'), ), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/bedrock/image-nova.php b/examples/bedrock/image-nova.php index b576e287..c1414689 100644 --- a/examples/bedrock/image-nova.php +++ b/examples/bedrock/image-nova.php @@ -35,6 +35,6 @@ Image::fromFile(dirname(__DIR__, 2).'/fixtures/image.jpg'), ), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/bedrock/toolcall-claude.php b/examples/bedrock/toolcall-claude.php index 9a643a00..6914151f 100644 --- a/examples/bedrock/toolcall-claude.php +++ b/examples/bedrock/toolcall-claude.php @@ -35,6 +35,6 @@ $agent = new Agent($platform, $model, [$processor], [$processor], logger()); $messages = new MessageBag(Message::ofUser('Who is the current chancellor of Germany?')); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/bedrock/toolcall-nova.php b/examples/bedrock/toolcall-nova.php index 3d0cb549..1f1f7e7c 100644 --- a/examples/bedrock/toolcall-nova.php +++ b/examples/bedrock/toolcall-nova.php @@ -37,6 +37,6 @@ $messages = new MessageBag( Message::ofUser('Who is the current chancellor of Germany? Use Wikipedia to find the answer.') ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/google/audio-input.php b/examples/google/audio-input.php index 35ab6ac2..1674310b 100644 --- a/examples/google/audio-input.php +++ b/examples/google/audio-input.php @@ -28,6 +28,6 @@ Audio::fromFile(dirname(__DIR__, 2).'/fixtures/audio.mp3'), ), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/google/chat.php b/examples/google/chat.php index 5469f877..8e3560ba 100644 --- a/examples/google/chat.php +++ b/examples/google/chat.php @@ -25,6 +25,6 @@ Message::forSystem('You are a pirate and you write funny.'), Message::ofUser('What is the Symfony framework?'), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/google/embeddings.php b/examples/google/embeddings.php index 7af5ef88..926904fe 100644 --- a/examples/google/embeddings.php +++ b/examples/google/embeddings.php @@ -17,10 +17,10 @@ $platform = PlatformFactory::create(env('GEMINI_API_KEY'), http_client()); $embeddings = new Embeddings(); -$response = $platform->request($embeddings, <<invoke($embeddings, <<asVectors()[0]->getDimensions().\PHP_EOL; +echo 'Dimensions: '.$result->asVectors()[0]->getDimensions().\PHP_EOL; diff --git a/examples/google/image-input.php b/examples/google/image-input.php index 37cd0480..5f5821d9 100644 --- a/examples/google/image-input.php +++ b/examples/google/image-input.php @@ -29,6 +29,6 @@ Image::fromFile(dirname(__DIR__, 2).'/fixtures/image.jpg'), ), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/google/pdf-input-binary.php b/examples/google/pdf-input-binary.php index b8334f3d..e7625bd0 100644 --- a/examples/google/pdf-input-binary.php +++ b/examples/google/pdf-input-binary.php @@ -28,6 +28,6 @@ 'What is this document about?', ), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/google/server-tools.php b/examples/google/server-tools.php index 4c158e86..826a6f90 100644 --- a/examples/google/server-tools.php +++ b/examples/google/server-tools.php @@ -37,6 +37,6 @@ ), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/google/stream.php b/examples/google/stream.php index 8a213111..6e8f5b52 100644 --- a/examples/google/stream.php +++ b/examples/google/stream.php @@ -25,11 +25,11 @@ Message::forSystem('You are a funny clown that entertains people.'), Message::ofUser('What is the purpose of an ant?'), ); -$response = $agent->call($messages, [ +$result = $agent->call($messages, [ 'stream' => true, // enable streaming of response text ]); -foreach ($response->getContent() as $word) { +foreach ($result->getContent() as $word) { echo $word; } echo \PHP_EOL; diff --git a/examples/google/structured-output-clock.php b/examples/google/structured-output-clock.php index 49d90385..d4caf8b0 100644 --- a/examples/google/structured-output-clock.php +++ b/examples/google/structured-output-clock.php @@ -32,7 +32,7 @@ $agent = new Agent($platform, $model, [$toolProcessor, $structuredOutputProcessor], [$toolProcessor, $structuredOutputProcessor], logger()); $messages = new MessageBag(Message::ofUser('What date and time is it?')); -$response = $agent->call($messages, ['response_format' => [ +$result = $agent->call($messages, ['response_format' => [ 'type' => 'json_schema', 'json_schema' => [ 'name' => 'clock', @@ -49,4 +49,4 @@ ], ]]); -dump($response->getContent()); +dump($result->getContent()); diff --git a/examples/google/structured-output-math.php b/examples/google/structured-output-math.php index 7ba82e9c..0cf4295c 100644 --- a/examples/google/structured-output-math.php +++ b/examples/google/structured-output-math.php @@ -28,6 +28,6 @@ Message::forSystem('You are a helpful math tutor. Guide the user through the solution step by step.'), Message::ofUser('how can I solve 8x + 7 = -23'), ); -$response = $agent->call($messages, ['output_structure' => MathReasoning::class]); +$result = $agent->call($messages, ['output_structure' => MathReasoning::class]); -dump($response->getContent()); +dump($result->getContent()); diff --git a/examples/google/toolcall.php b/examples/google/toolcall.php index fc9c4f46..0744ff1e 100644 --- a/examples/google/toolcall.php +++ b/examples/google/toolcall.php @@ -28,6 +28,6 @@ $agent = new Agent($platform, $llm, [$processor], [$processor], logger()); $messages = new MessageBag(Message::ofUser('What time is it?')); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/huggingface/audio-classification.php b/examples/huggingface/audio-classification.php index 7f291f5a..bdbf3d93 100644 --- a/examples/huggingface/audio-classification.php +++ b/examples/huggingface/audio-classification.php @@ -20,8 +20,8 @@ $model = new Model('MIT/ast-finetuned-audioset-10-10-0.4593'); $audio = Audio::fromFile(dirname(__DIR__, 2).'/fixtures/audio.mp3'); -$response = $platform->request($model, $audio, [ +$result = $platform->invoke($model, $audio, [ 'task' => Task::AUDIO_CLASSIFICATION, ]); -dump($response->asObject()); +dump($result->asObject()); diff --git a/examples/huggingface/automatic-speech-recognition.php b/examples/huggingface/automatic-speech-recognition.php index 99372103..73e03a0c 100644 --- a/examples/huggingface/automatic-speech-recognition.php +++ b/examples/huggingface/automatic-speech-recognition.php @@ -20,8 +20,8 @@ $model = new Model('openai/whisper-large-v3'); $audio = Audio::fromFile(dirname(__DIR__, 2).'/fixtures/audio.mp3'); -$response = $platform->request($model, $audio, [ +$result = $platform->invoke($model, $audio, [ 'task' => Task::AUTOMATIC_SPEECH_RECOGNITION, ]); -echo $response->asText().\PHP_EOL; +echo $result->asText().\PHP_EOL; diff --git a/examples/huggingface/chat-completion.php b/examples/huggingface/chat-completion.php index 766a8b68..bfeb263e 100644 --- a/examples/huggingface/chat-completion.php +++ b/examples/huggingface/chat-completion.php @@ -21,8 +21,8 @@ $model = new Model('HuggingFaceH4/zephyr-7b-beta'); $messages = new MessageBag(Message::ofUser('Hello, how are you doing today?')); -$response = $platform->request($model, $messages, [ +$result = $platform->invoke($model, $messages, [ 'task' => Task::CHAT_COMPLETION, ]); -echo $response->asText().\PHP_EOL; +echo $result->asText().\PHP_EOL; diff --git a/examples/huggingface/feature-extraction.php b/examples/huggingface/feature-extraction.php index 92ef1958..a8e98ad8 100644 --- a/examples/huggingface/feature-extraction.php +++ b/examples/huggingface/feature-extraction.php @@ -18,8 +18,8 @@ $platform = PlatformFactory::create(env('HUGGINGFACE_KEY'), httpClient: http_client()); $model = new Model('thenlper/gte-large'); -$response = $platform->request($model, 'Today is a sunny day and I will get some ice cream.', [ +$result = $platform->invoke($model, 'Today is a sunny day and I will get some ice cream.', [ 'task' => Task::FEATURE_EXTRACTION, ]); -echo 'Dimensions: '.$response->asVectors()[0]->getDimensions().\PHP_EOL; +echo 'Dimensions: '.$result->asVectors()[0]->getDimensions().\PHP_EOL; diff --git a/examples/huggingface/fill-mask.php b/examples/huggingface/fill-mask.php index 9db81b72..2e101c75 100644 --- a/examples/huggingface/fill-mask.php +++ b/examples/huggingface/fill-mask.php @@ -18,8 +18,8 @@ $platform = PlatformFactory::create(env('HUGGINGFACE_KEY'), httpClient: http_client()); $model = new Model('FacebookAI/xlm-roberta-base'); -$response = $platform->request($model, 'Hello I\'m a model.', [ +$result = $platform->invoke($model, 'Hello I\'m a model.', [ 'task' => Task::FILL_MASK, ]); -dump($response->asObject()); +dump($result->asObject()); diff --git a/examples/huggingface/image-classification.php b/examples/huggingface/image-classification.php index b49b6fd7..bb15ebf5 100644 --- a/examples/huggingface/image-classification.php +++ b/examples/huggingface/image-classification.php @@ -20,8 +20,8 @@ $model = new Model('google/vit-base-patch16-224'); $image = Image::fromFile(dirname(__DIR__, 2).'/fixtures/image.jpg'); -$response = $platform->request($model, $image, [ +$result = $platform->invoke($model, $image, [ 'task' => Task::IMAGE_CLASSIFICATION, ]); -dump($response->asObject()); +dump($result->asObject()); diff --git a/examples/huggingface/image-segmentation.php b/examples/huggingface/image-segmentation.php index 32ff2d20..5c17f291 100644 --- a/examples/huggingface/image-segmentation.php +++ b/examples/huggingface/image-segmentation.php @@ -20,8 +20,8 @@ $model = new Model('nvidia/segformer-b0-finetuned-ade-512-512'); $image = Image::fromFile(dirname(__DIR__, 2).'/fixtures/image.jpg'); -$response = $platform->request($model, $image, [ +$result = $platform->invoke($model, $image, [ 'task' => Task::IMAGE_SEGMENTATION, ]); -dump($response->asObject()); +dump($result->asObject()); diff --git a/examples/huggingface/image-to-text.php b/examples/huggingface/image-to-text.php index 48a6f34b..ec3f9763 100644 --- a/examples/huggingface/image-to-text.php +++ b/examples/huggingface/image-to-text.php @@ -20,8 +20,8 @@ $model = new Model('Salesforce/blip-image-captioning-base'); $image = Image::fromFile(dirname(__DIR__, 2).'/fixtures/image.jpg'); -$response = $platform->request($model, $image, [ +$result = $platform->invoke($model, $image, [ 'task' => Task::IMAGE_TO_TEXT, ]); -echo $response->asText().\PHP_EOL; +echo $result->asText().\PHP_EOL; diff --git a/examples/huggingface/object-detection.php b/examples/huggingface/object-detection.php index 8275fbc8..d0b367e6 100644 --- a/examples/huggingface/object-detection.php +++ b/examples/huggingface/object-detection.php @@ -20,8 +20,8 @@ $model = new Model('facebook/detr-resnet-50'); $image = Image::fromFile(dirname(__DIR__, 2).'/fixtures/image.jpg'); -$response = $platform->request($model, $image, [ +$result = $platform->invoke($model, $image, [ 'task' => Task::OBJECT_DETECTION, ]); -dump($response->asObject()); +dump($result->asObject()); diff --git a/examples/huggingface/question-answering.php b/examples/huggingface/question-answering.php index f3214672..15a92f34 100644 --- a/examples/huggingface/question-answering.php +++ b/examples/huggingface/question-answering.php @@ -23,8 +23,8 @@ 'context' => 'Paris is the capital and most populous city of France, with an estimated population of 2,175,601 residents as of 2018, in an area of more than 105 square kilometres.', ]; -$response = $platform->request($model, $input, [ +$result = $platform->invoke($model, $input, [ 'task' => Task::QUESTION_ANSWERING, ]); -dump($response->asObject()); +dump($result->asObject()); diff --git a/examples/huggingface/sentence-similarity.php b/examples/huggingface/sentence-similarity.php index 89d92199..6c5cb1fa 100644 --- a/examples/huggingface/sentence-similarity.php +++ b/examples/huggingface/sentence-similarity.php @@ -27,8 +27,8 @@ ], ]; -$response = $platform->request($model, $input, [ +$result = $platform->invoke($model, $input, [ 'task' => Task::SENTENCE_SIMILARITY, ]); -dump($response->asObject()); +dump($result->asObject()); diff --git a/examples/huggingface/summarization.php b/examples/huggingface/summarization.php index 9931474a..5d6d6b0c 100644 --- a/examples/huggingface/summarization.php +++ b/examples/huggingface/summarization.php @@ -28,8 +28,8 @@ free-standing structure in France after the Millau Viaduct. TEXT; -$response = $platform->request($model, $longText, [ +$result = $platform->invoke($model, $longText, [ 'task' => Task::SUMMARIZATION, ]); -echo $response->asText().\PHP_EOL; +echo $result->asText().\PHP_EOL; diff --git a/examples/huggingface/table-question-answering.php b/examples/huggingface/table-question-answering.php index 699a0216..32dae0db 100644 --- a/examples/huggingface/table-question-answering.php +++ b/examples/huggingface/table-question-answering.php @@ -26,8 +26,8 @@ ], ]; -$response = $platform->request($model, $input, [ +$result = $platform->invoke($model, $input, [ 'task' => Task::TABLE_QUESTION_ANSWERING, ]); -dump($response->asObject()); +dump($result->asObject()); diff --git a/examples/huggingface/text-classification.php b/examples/huggingface/text-classification.php index 39a00ee7..eac749f1 100644 --- a/examples/huggingface/text-classification.php +++ b/examples/huggingface/text-classification.php @@ -18,8 +18,8 @@ $platform = PlatformFactory::create(env('HUGGINGFACE_KEY'), httpClient: http_client()); $model = new Model('ProsusAI/finbert'); -$response = $platform->request($model, 'I like you. I love you.', [ +$result = $platform->invoke($model, 'I like you. I love you.', [ 'task' => Task::TEXT_CLASSIFICATION, ]); -dump($response->asObject()); +dump($result->asObject()); diff --git a/examples/huggingface/text-generation.php b/examples/huggingface/text-generation.php index 56923dca..2af06214 100644 --- a/examples/huggingface/text-generation.php +++ b/examples/huggingface/text-generation.php @@ -18,8 +18,8 @@ $platform = PlatformFactory::create(env('HUGGINGFACE_KEY'), httpClient: http_client()); $model = new Model('gpt2'); -$response = $platform->request($model, 'The quick brown fox jumps over the lazy', [ +$result = $platform->invoke($model, 'The quick brown fox jumps over the lazy', [ 'task' => Task::TEXT_GENERATION, ]); -echo $response->asText().\PHP_EOL; +echo $result->asText().\PHP_EOL; diff --git a/examples/huggingface/text-to-image.php b/examples/huggingface/text-to-image.php index af2f2f62..399f7511 100644 --- a/examples/huggingface/text-to-image.php +++ b/examples/huggingface/text-to-image.php @@ -18,8 +18,8 @@ $platform = PlatformFactory::create(env('HUGGINGFACE_KEY'), httpClient: http_client()); $model = new Model('black-forest-labs/FLUX.1-dev'); -$response = $platform->request($model, 'Astronaut riding a horse', [ +$result = $platform->invoke($model, 'Astronaut riding a horse', [ 'task' => Task::TEXT_TO_IMAGE, ]); -echo $response->asBase64().\PHP_EOL; +echo $result->asBase64().\PHP_EOL; diff --git a/examples/huggingface/token-classification.php b/examples/huggingface/token-classification.php index ca69cc95..19d93b80 100644 --- a/examples/huggingface/token-classification.php +++ b/examples/huggingface/token-classification.php @@ -18,8 +18,8 @@ $platform = PlatformFactory::create(env('HUGGINGFACE_KEY'), httpClient: http_client()); $model = new Model('dbmdz/bert-large-cased-finetuned-conll03-english'); -$response = $platform->request($model, 'John Smith works at Microsoft in London.', [ +$result = $platform->invoke($model, 'John Smith works at Microsoft in London.', [ 'task' => Task::TOKEN_CLASSIFICATION, ]); -dump($response->asObject()); +dump($result->asObject()); diff --git a/examples/huggingface/translation.php b/examples/huggingface/translation.php index d9c4127f..d2bc2971 100644 --- a/examples/huggingface/translation.php +++ b/examples/huggingface/translation.php @@ -18,10 +18,10 @@ $platform = PlatformFactory::create(env('HUGGINGFACE_KEY'), httpClient: http_client()); $model = new Model('facebook/mbart-large-50-many-to-many-mmt'); -$response = $platform->request($model, 'Меня зовут Вольфганг и я живу в Берлине', [ +$result = $platform->invoke($model, 'Меня зовут Вольфганг и я живу в Берлине', [ 'task' => Task::TRANSLATION, 'src_lang' => 'ru', 'tgt_lang' => 'en', ]); -echo $response->asText().\PHP_EOL; +echo $result->asText().\PHP_EOL; diff --git a/examples/huggingface/zero-shot-classification.php b/examples/huggingface/zero-shot-classification.php index 8db1e920..69eb530e 100644 --- a/examples/huggingface/zero-shot-classification.php +++ b/examples/huggingface/zero-shot-classification.php @@ -19,9 +19,9 @@ $model = new Model('facebook/bart-large-mnli'); $text = 'Hi, I recently bought a device from your company but it is not working as advertised and I would like to get reimbursed!'; -$response = $platform->request($model, $text, [ +$result = $platform->invoke($model, $text, [ 'task' => Task::ZERO_SHOT_CLASSIFICATION, 'candidate_labels' => ['refund', 'legal', 'faq'], ]); -dump($response->asObject()); +dump($result->asObject()); diff --git a/examples/lmstudio/chat.php b/examples/lmstudio/chat.php index c091eae6..24339c3c 100644 --- a/examples/lmstudio/chat.php +++ b/examples/lmstudio/chat.php @@ -25,8 +25,8 @@ Message::forSystem('You are a pirate and you write funny.'), Message::ofUser('What is the Symfony framework?'), ); -$response = $agent->call($messages, [ +$result = $agent->call($messages, [ 'max_tokens' => 500, // specific options just for this call ]); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/lmstudio/image-input-binary.php b/examples/lmstudio/image-input-binary.php index 261dd3e9..c8ea2d39 100644 --- a/examples/lmstudio/image-input-binary.php +++ b/examples/lmstudio/image-input-binary.php @@ -33,6 +33,6 @@ Image::fromFile(dirname(__DIR__, 2).'/fixtures/image.jpg'), ), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/misc/chat-system-prompt.php b/examples/misc/chat-system-prompt.php index bbed1702..b21cb457 100644 --- a/examples/misc/chat-system-prompt.php +++ b/examples/misc/chat-system-prompt.php @@ -25,6 +25,6 @@ $agent = new Agent($platform, $model, [$processor], logger: logger()); $messages = new MessageBag(Message::ofUser('What is the meaning of life?')); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/misc/chat-with-memory.php b/examples/misc/chat-with-memory.php index 5cf5fdc4..4ec91f8e 100644 --- a/examples/misc/chat-with-memory.php +++ b/examples/misc/chat-with-memory.php @@ -34,6 +34,6 @@ $chain = new Agent($platform, $model, [$systemPromptProcessor, $memoryProcessor], logger: logger()); $messages = new MessageBag(Message::ofUser('What do we do today?')); -$response = $chain->call($messages); +$result = $chain->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/misc/parallel-chat-gpt.php b/examples/misc/parallel-chat-gpt.php index 86056f3b..29d59c33 100644 --- a/examples/misc/parallel-chat-gpt.php +++ b/examples/misc/parallel-chat-gpt.php @@ -26,13 +26,13 @@ ); echo 'Initiating parallel calls to GPT on platform ...'.\PHP_EOL; -$responses = []; +$results = []; foreach (range('A', 'D') as $letter) { echo ' - Request for the letter '.$letter.' initiated.'.\PHP_EOL; - $responses[] = $platform->request($model, $messages->with(Message::ofUser($letter))); + $results[] = $platform->invoke($model, $messages->with(Message::ofUser($letter))); } echo 'Waiting for the responses ...'.\PHP_EOL; -foreach ($responses as $response) { - echo 'Next Letter: '.$response->asText().\PHP_EOL; +foreach ($results as $result) { + echo 'Next Letter: '.$result->asText().\PHP_EOL; } diff --git a/examples/misc/parallel-embeddings.php b/examples/misc/parallel-embeddings.php index 9f667bbb..40bfdce1 100644 --- a/examples/misc/parallel-embeddings.php +++ b/examples/misc/parallel-embeddings.php @@ -20,13 +20,13 @@ $large = new Embeddings(Embeddings::TEXT_3_LARGE); echo 'Initiating parallel embeddings calls to platform ...'.\PHP_EOL; -$responses = []; +$results = []; foreach (['ADA' => $ada, 'Small' => $small, 'Large' => $large] as $name => $model) { echo ' - Request for model '.$name.' initiated.'.\PHP_EOL; - $responses[] = $platform->request($model, 'Hello, world!'); + $results[] = $platform->invoke($model, 'Hello, world!'); } echo 'Waiting for the responses ...'.\PHP_EOL; -foreach ($responses as $response) { - echo 'Dimensions: '.$response->asVectors()[0]->getDimensions().\PHP_EOL; +foreach ($results as $result) { + echo 'Dimensions: '.$result->asVectors()[0]->getDimensions().\PHP_EOL; } diff --git a/examples/mistral/chat.php b/examples/mistral/chat.php index 3482f2dc..cf11f10d 100644 --- a/examples/mistral/chat.php +++ b/examples/mistral/chat.php @@ -22,8 +22,8 @@ $agent = new Agent($platform, $model, logger: logger()); $messages = new MessageBag(Message::ofUser('What is the best French cheese?')); -$response = $agent->call($messages, [ +$result = $agent->call($messages, [ 'temperature' => 0.7, ]); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/mistral/embeddings.php b/examples/mistral/embeddings.php index c0246fdf..2e820743 100644 --- a/examples/mistral/embeddings.php +++ b/examples/mistral/embeddings.php @@ -17,11 +17,11 @@ $platform = PlatformFactory::create(env('MISTRAL_API_KEY'), http_client()); $model = new Embeddings(); -$response = $platform->request($model, <<invoke($model, <<asVectors()[0]->getDimensions().\PHP_EOL; +echo 'Dimensions: '.$result->asVectors()[0]->getDimensions().\PHP_EOL; diff --git a/examples/mistral/image.php b/examples/mistral/image.php index be1986e6..f7e682c9 100644 --- a/examples/mistral/image.php +++ b/examples/mistral/image.php @@ -29,6 +29,6 @@ Image::fromFile(dirname(__DIR__, 2).'/fixtures/image.jpg'), ), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/mistral/stream.php b/examples/mistral/stream.php index 1aa5c36e..85982237 100644 --- a/examples/mistral/stream.php +++ b/examples/mistral/stream.php @@ -22,11 +22,11 @@ $agent = new Agent($platform, $model, logger: logger()); $messages = new MessageBag(Message::ofUser('What is the eighth prime number?')); -$response = $agent->call($messages, [ +$result = $agent->call($messages, [ 'stream' => true, ]); -foreach ($response->getContent() as $word) { +foreach ($result->getContent() as $word) { echo $word; } echo \PHP_EOL; diff --git a/examples/mistral/structured-output-math.php b/examples/mistral/structured-output-math.php index b6657362..65b054d6 100644 --- a/examples/mistral/structured-output-math.php +++ b/examples/mistral/structured-output-math.php @@ -33,6 +33,6 @@ Message::forSystem('You are a helpful math tutor. Guide the user through the solution step by step.'), Message::ofUser('how can I solve 8x + 7 = -23'), ); -$response = $agent->call($messages, ['output_structure' => MathReasoning::class]); +$result = $agent->call($messages, ['output_structure' => MathReasoning::class]); -dump($response->getContent()); +dump($result->getContent()); diff --git a/examples/mistral/toolcall-stream.php b/examples/mistral/toolcall-stream.php index 2b9ab508..475cc822 100644 --- a/examples/mistral/toolcall-stream.php +++ b/examples/mistral/toolcall-stream.php @@ -29,11 +29,11 @@ $agent = new Agent($platform, $model, [$processor], [$processor], logger()); $messages = new MessageBag(Message::ofUser('Please summarize this video for me: https://www.youtube.com/watch?v=6uXW-ulpj0s')); -$response = $agent->call($messages, [ +$result = $agent->call($messages, [ 'stream' => true, ]); -foreach ($response->getContent() as $word) { +foreach ($result->getContent() as $word) { echo $word; } echo \PHP_EOL; diff --git a/examples/mistral/toolcall.php b/examples/mistral/toolcall.php index 30bc6d96..7ab6b7a0 100644 --- a/examples/mistral/toolcall.php +++ b/examples/mistral/toolcall.php @@ -28,6 +28,6 @@ $agent = new Agent($platform, $model, [$processor], [$processor], logger()); $messages = new MessageBag(Message::ofUser('What time is it?')); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/ollama/chat-llama.php b/examples/ollama/chat-llama.php index 6b94892d..f7422715 100644 --- a/examples/ollama/chat-llama.php +++ b/examples/ollama/chat-llama.php @@ -25,6 +25,6 @@ Message::forSystem('You are a helpful assistant.'), Message::ofUser('Tina has one brother and one sister. How many sisters do Tina\'s siblings have?'), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/openai/audio-input.php b/examples/openai/audio-input.php index cd4df9ba..1fa67c1a 100644 --- a/examples/openai/audio-input.php +++ b/examples/openai/audio-input.php @@ -28,6 +28,6 @@ Audio::fromFile(dirname(__DIR__, 2).'/fixtures/audio.mp3'), ), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/openai/audio-transcript.php b/examples/openai/audio-transcript.php index a0813a0e..8ce44d3d 100644 --- a/examples/openai/audio-transcript.php +++ b/examples/openai/audio-transcript.php @@ -19,6 +19,6 @@ $model = new Whisper(); $file = Audio::fromFile(dirname(__DIR__, 2).'/fixtures/audio.mp3'); -$response = $platform->request($model, $file); +$result = $platform->invoke($model, $file); -echo $response->asText().\PHP_EOL; +echo $result->asText().\PHP_EOL; diff --git a/examples/openai/chat-o1.php b/examples/openai/chat-o1.php index 3fb6ac84..e88ce4c0 100644 --- a/examples/openai/chat-o1.php +++ b/examples/openai/chat-o1.php @@ -35,6 +35,6 @@ PROMPT; $agent = new Agent($platform, $model, logger: logger()); -$response = $agent->call(new MessageBag(Message::ofUser($prompt))); +$result = $agent->call(new MessageBag(Message::ofUser($prompt))); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/openai/chat.php b/examples/openai/chat.php index 39cc79c8..1ff4d995 100644 --- a/examples/openai/chat.php +++ b/examples/openai/chat.php @@ -27,8 +27,8 @@ Message::forSystem('You are a pirate and you write funny.'), Message::ofUser('What is the Symfony framework?'), ); -$response = $agent->call($messages, [ +$result = $agent->call($messages, [ 'max_tokens' => 500, // specific options just for this call ]); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/openai/embeddings.php b/examples/openai/embeddings.php index 4aee3354..8f778e0a 100644 --- a/examples/openai/embeddings.php +++ b/examples/openai/embeddings.php @@ -17,10 +17,10 @@ $platform = PlatformFactory::create(env('OPENAI_API_KEY'), http_client()); $embeddings = new Embeddings(); -$response = $platform->request($embeddings, <<invoke($embeddings, <<asVectors()[0]->getDimensions().\PHP_EOL; +echo 'Dimensions: '.$result->asVectors()[0]->getDimensions().\PHP_EOL; diff --git a/examples/openai/image-input-binary.php b/examples/openai/image-input-binary.php index af32d9a1..94d58bc7 100644 --- a/examples/openai/image-input-binary.php +++ b/examples/openai/image-input-binary.php @@ -29,6 +29,6 @@ Image::fromFile(dirname(__DIR__, 2).'/fixtures/image.jpg'), ), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/openai/image-input-url.php b/examples/openai/image-input-url.php index 1bff561e..e3f860c6 100644 --- a/examples/openai/image-input-url.php +++ b/examples/openai/image-input-url.php @@ -29,6 +29,6 @@ new ImageUrl('https://upload.wikimedia.org/wikipedia/commons/thumb/3/31/Webysther_20160423_-_Elephpant.svg/350px-Webysther_20160423_-_Elephpant.svg.png'), ), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/openai/image-output-dall-e-2.php b/examples/openai/image-output-dall-e-2.php index d2c1a593..1a3fa085 100644 --- a/examples/openai/image-output-dall-e-2.php +++ b/examples/openai/image-output-dall-e-2.php @@ -16,7 +16,7 @@ $platform = PlatformFactory::create(env('OPENAI_API_KEY'), http_client()); -$response = $platform->request( +$result = $platform->invoke( model: new DallE(), // Utilize Dall-E 2 version in default input: 'A cartoon-style elephant with a long trunk and large ears.', options: [ @@ -25,6 +25,6 @@ ], ); -foreach ($response->getResponse()->getContent() as $index => $image) { +foreach ($result->getResult()->getContent() as $index => $image) { echo 'Image '.$index.': '.$image->url.\PHP_EOL; } diff --git a/examples/openai/image-output-dall-e-3.php b/examples/openai/image-output-dall-e-3.php index 4e2fa887..2a053a7c 100644 --- a/examples/openai/image-output-dall-e-3.php +++ b/examples/openai/image-output-dall-e-3.php @@ -10,25 +10,25 @@ */ use Symfony\AI\Platform\Bridge\OpenAI\DallE; -use Symfony\AI\Platform\Bridge\OpenAI\DallE\ImageResponse; +use Symfony\AI\Platform\Bridge\OpenAI\DallE\ImageResult; use Symfony\AI\Platform\Bridge\OpenAI\PlatformFactory; require_once dirname(__DIR__).'/bootstrap.php'; $platform = PlatformFactory::create(env('OPENAI_API_KEY'), http_client()); -$response = $platform->request( +$result = $platform->invoke( model: new DallE(name: DallE::DALL_E_3), input: 'A cartoon-style elephant with a long trunk and large ears.', options: [ 'response_format' => 'url', // Generate response as URL ], -)->getResponse(); +)->getResult(); -assert($response instanceof ImageResponse); +assert($result instanceof ImageResult); -echo 'Revised Prompt: '.$response->revisedPrompt.\PHP_EOL.\PHP_EOL; +echo 'Revised Prompt: '.$result->revisedPrompt.\PHP_EOL.\PHP_EOL; -foreach ($response->getContent() as $index => $image) { +foreach ($result->getContent() as $index => $image) { echo 'Image '.$index.': '.$image->url.\PHP_EOL; } diff --git a/examples/openai/stream.php b/examples/openai/stream.php index 3a0e52ef..2c164697 100644 --- a/examples/openai/stream.php +++ b/examples/openai/stream.php @@ -25,11 +25,11 @@ Message::forSystem('You are a thoughtful philosopher.'), Message::ofUser('What is the purpose of an ant?'), ); -$response = $agent->call($messages, [ +$result = $agent->call($messages, [ 'stream' => true, // enable streaming of response text ]); -foreach ($response->getContent() as $word) { +foreach ($result->getContent() as $word) { echo $word; } echo \PHP_EOL; diff --git a/examples/openai/structured-output-clock.php b/examples/openai/structured-output-clock.php index 7ea09dc7..25fc516b 100644 --- a/examples/openai/structured-output-clock.php +++ b/examples/openai/structured-output-clock.php @@ -32,7 +32,7 @@ $agent = new Agent($platform, $model, [$toolProcessor, $structuredOutputProcessor], [$toolProcessor, $structuredOutputProcessor]); $messages = new MessageBag(Message::ofUser('What date and time is it?')); -$response = $agent->call($messages, ['response_format' => [ +$result = $agent->call($messages, ['response_format' => [ 'type' => 'json_schema', 'json_schema' => [ 'name' => 'clock', @@ -49,4 +49,4 @@ ], ]]); -dump($response->getContent()); +dump($result->getContent()); diff --git a/examples/openai/structured-output-math.php b/examples/openai/structured-output-math.php index e6b7b9f8..d5f34b59 100644 --- a/examples/openai/structured-output-math.php +++ b/examples/openai/structured-output-math.php @@ -28,6 +28,6 @@ Message::forSystem('You are a helpful math tutor. Guide the user through the solution step by step.'), Message::ofUser('how can I solve 8x + 7 = -23'), ); -$response = $agent->call($messages, ['output_structure' => MathReasoning::class]); +$result = $agent->call($messages, ['output_structure' => MathReasoning::class]); -dump($response->getContent()); +dump($result->getContent()); diff --git a/examples/openai/token-metadata.php b/examples/openai/token-metadata.php index 74f2034a..6b9d3f8f 100644 --- a/examples/openai/token-metadata.php +++ b/examples/openai/token-metadata.php @@ -28,11 +28,11 @@ Message::forSystem('You are a pirate and you write funny.'), Message::ofUser('What is the Symfony framework?'), ); -$response = $agent->call($messages, [ +$result = $agent->call($messages, [ 'max_tokens' => 500, // specific options just for this call ]); -$metadata = $response->getMetadata(); +$metadata = $result->getMetadata(); echo 'Utilized Tokens: '.$metadata['total_tokens'].\PHP_EOL; echo '-- Prompt Tokens: '.$metadata['prompt_tokens'].\PHP_EOL; diff --git a/examples/openai/toolcall-stream.php b/examples/openai/toolcall-stream.php index ce977e9e..d03c0291 100644 --- a/examples/openai/toolcall-stream.php +++ b/examples/openai/toolcall-stream.php @@ -32,11 +32,11 @@ Then lookup at Wikipedia what the irish history looks like in 2 sentences. Please tell me before you call tools. TXT)); -$response = $agent->call($messages, [ +$result = $agent->call($messages, [ 'stream' => true, // enable streaming of response text ]); -foreach ($response->getContent() as $word) { +foreach ($result->getContent() as $word) { echo $word; } diff --git a/examples/openai/toolcall.php b/examples/openai/toolcall.php index 54d67438..19da2abe 100644 --- a/examples/openai/toolcall.php +++ b/examples/openai/toolcall.php @@ -29,6 +29,6 @@ $agent = new Agent($platform, $model, [$processor], [$processor], logger()); $messages = new MessageBag(Message::ofUser('Please summarize this video for me: https://www.youtube.com/watch?v=6uXW-ulpj0s')); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/openrouter/chat-gemini.php b/examples/openrouter/chat-gemini.php index e0c33fc1..c30fe5e8 100644 --- a/examples/openrouter/chat-gemini.php +++ b/examples/openrouter/chat-gemini.php @@ -27,6 +27,6 @@ Message::forSystem('You are a helpful assistant.'), Message::ofUser('Tina has one brother and one sister. How many sisters do Tina\'s siblings have?'), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/replicate/chat-llama.php b/examples/replicate/chat-llama.php index f06b7b95..e1a3aaac 100644 --- a/examples/replicate/chat-llama.php +++ b/examples/replicate/chat-llama.php @@ -25,6 +25,6 @@ Message::forSystem('You are a helpful assistant.'), Message::ofUser('Tina has one brother and one sister. How many sisters do Tina\'s siblings have?'), ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/store/mariadb-chat-memory.php b/examples/store/mariadb-chat-memory.php index 9d18c108..3900286d 100644 --- a/examples/store/mariadb-chat-memory.php +++ b/examples/store/mariadb-chat-memory.php @@ -68,6 +68,6 @@ $agent = new Agent($platform, new GPT(GPT::GPT_4O_MINI), [$memoryProcessor], logger: logger()); $messages = new MessageBag(Message::ofUser('Have we discussed about my friend John in the past? If yes, what did we talk about?')); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/store/mariadb-similarity-search-gemini.php b/examples/store/mariadb-similarity-search-gemini.php index 4d467053..d467b36c 100644 --- a/examples/store/mariadb-similarity-search-gemini.php +++ b/examples/store/mariadb-similarity-search-gemini.php @@ -68,6 +68,6 @@ Message::forSystem('Please answer all user questions only using SimilaritySearch function.'), Message::ofUser('Which movie fits the theme of the mafia?') ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/store/mariadb-similarity-search.php b/examples/store/mariadb-similarity-search.php index 2e552c8f..9605792a 100644 --- a/examples/store/mariadb-similarity-search.php +++ b/examples/store/mariadb-similarity-search.php @@ -66,6 +66,6 @@ Message::forSystem('Please answer all user questions only using SimilaritySearch function.'), Message::ofUser('Which movie fits the theme of the mafia?') ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/store/meilisearch-similarity-search.php b/examples/store/meilisearch-similarity-search.php index 06c8db1f..f998675d 100644 --- a/examples/store/meilisearch-similarity-search.php +++ b/examples/store/meilisearch-similarity-search.php @@ -67,6 +67,6 @@ Message::forSystem('Please answer all user questions only using SimilaritySearch function.'), Message::ofUser('Which movie fits the theme of technology?') ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/store/memory-similarity-search.php b/examples/store/memory-similarity-search.php index ea2da49b..041e6170 100644 --- a/examples/store/memory-similarity-search.php +++ b/examples/store/memory-similarity-search.php @@ -57,6 +57,6 @@ Message::forSystem('Please answer all user questions only using SimilaritySearch function.'), Message::ofUser('Which movie fits the theme of the mafia?') ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/store/mongodb-similarity-search.php b/examples/store/mongodb-similarity-search.php index f0d05609..9a7cbf6d 100644 --- a/examples/store/mongodb-similarity-search.php +++ b/examples/store/mongodb-similarity-search.php @@ -67,6 +67,6 @@ Message::forSystem('Please answer all user questions only using SimilaritySearch function.'), Message::ofUser('Which movie fits the theme of the mafia?') ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/store/pinecone-similarity-search.php b/examples/store/pinecone-similarity-search.php index b8624d15..f7455451 100644 --- a/examples/store/pinecone-similarity-search.php +++ b/examples/store/pinecone-similarity-search.php @@ -58,6 +58,6 @@ Message::forSystem('Please answer all user questions only using SimilaritySearch function.'), Message::ofUser('Which movie fits the theme of the mafia?') ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/store/postgres-similarity-search.php b/examples/store/postgres-similarity-search.php index c2a0b798..14213694 100644 --- a/examples/store/postgres-similarity-search.php +++ b/examples/store/postgres-similarity-search.php @@ -66,6 +66,6 @@ Message::forSystem('Please answer all user questions only using SimilaritySearch function.'), Message::ofUser('Which movie fits the theme of technology?') ); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/toolbox/brave.php b/examples/toolbox/brave.php index 63562110..1f672475 100644 --- a/examples/toolbox/brave.php +++ b/examples/toolbox/brave.php @@ -31,6 +31,6 @@ $agent = new Agent($platform, $model, [$processor], [$processor], logger()); $messages = new MessageBag(Message::ofUser('What was the latest game result of Dallas Cowboys?')); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/toolbox/clock.php b/examples/toolbox/clock.php index 9b2c5464..d351f5ec 100644 --- a/examples/toolbox/clock.php +++ b/examples/toolbox/clock.php @@ -31,6 +31,6 @@ $agent = new Agent($platform, $model, [$processor], [$processor], logger()); $messages = new MessageBag(Message::ofUser('What date and time is it?')); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/toolbox/serpapi.php b/examples/toolbox/serpapi.php index cc1f6dd2..f816391c 100644 --- a/examples/toolbox/serpapi.php +++ b/examples/toolbox/serpapi.php @@ -29,6 +29,6 @@ $agent = new Agent($platform, $model, [$processor], [$processor], logger()); $messages = new MessageBag(Message::ofUser('Who is the current chancellor of Germany?')); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/toolbox/tavily.php b/examples/toolbox/tavily.php index 7953ec94..f0741f27 100644 --- a/examples/toolbox/tavily.php +++ b/examples/toolbox/tavily.php @@ -29,6 +29,6 @@ $agent = new Agent($platform, $model, [$processor], [$processor], logger()); $messages = new MessageBag(Message::ofUser('What was the latest game result of Dallas Cowboys?')); -$response = $agent->call($messages); +$result = $agent->call($messages); -echo $response->getContent().\PHP_EOL; +echo $result->getContent().\PHP_EOL; diff --git a/examples/toolbox/weather-event.php b/examples/toolbox/weather-event.php index 7a7db0c6..15b027ae 100644 --- a/examples/toolbox/weather-event.php +++ b/examples/toolbox/weather-event.php @@ -18,7 +18,7 @@ use Symfony\AI\Platform\Bridge\OpenAI\PlatformFactory; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; -use Symfony\AI\Platform\Response\ObjectResponse; +use Symfony\AI\Platform\Result\ObjectResult; use Symfony\Component\EventDispatcher\EventDispatcher; require_once dirname(__DIR__).'/bootstrap.php'; @@ -34,14 +34,14 @@ // Add tool call result listener to enforce chain exits direct with structured response for weather tools $eventDispatcher->addListener(ToolCallsExecuted::class, function (ToolCallsExecuted $event): void { - foreach ($event->toolCallResults as $toolCallResult) { + foreach ($event->toolResults as $toolCallResult) { if (str_starts_with($toolCallResult->toolCall->name, 'weather_')) { - $event->response = new ObjectResponse($toolCallResult->result); + $event->result = new ObjectResult($toolCallResult->result); } } }); $messages = new MessageBag(Message::ofUser('How is the weather currently in Berlin?')); -$response = $agent->call($messages); +$result = $agent->call($messages); -dump($response->getContent()); +dump($result->getContent()); diff --git a/examples/transformers/text-generation.php b/examples/transformers/text-generation.php index d7c85cca..89a0d8c5 100644 --- a/examples/transformers/text-generation.php +++ b/examples/transformers/text-generation.php @@ -28,8 +28,8 @@ $platform = PlatformFactory::create(); $model = new Model('Xenova/LaMini-Flan-T5-783M'); -$response = $platform->request($model, 'How many continents are there in the world?', [ +$result = $platform->invoke($model, 'How many continents are there in the world?', [ 'task' => Task::Text2TextGeneration, ]); -echo $response->asText().\PHP_EOL; +echo $result->asText().\PHP_EOL; diff --git a/examples/voyage/embeddings.php b/examples/voyage/embeddings.php index 20139c79..d5720bf9 100644 --- a/examples/voyage/embeddings.php +++ b/examples/voyage/embeddings.php @@ -17,10 +17,10 @@ $platform = PlatformFactory::create(env('VOYAGE_API_KEY'), http_client()); $embeddings = new Voyage(); -$response = $platform->request($embeddings, <<invoke($embeddings, <<asVectors()[0]->getDimensions().\PHP_EOL; +echo 'Dimensions: '.$result->asVectors()[0]->getDimensions().\PHP_EOL; diff --git a/src/agent/doc/index.rst b/src/agent/doc/index.rst index dbf75b68..3f9be0d4 100644 --- a/src/agent/doc/index.rst +++ b/src/agent/doc/index.rst @@ -42,9 +42,9 @@ array of options:: Message::forSystem('You are a helpful chatbot answering questions about LLM agent.'), Message::ofUser('Hello, how are you?'), ); - $response = $agent->call($messages); + $result = $agent->call($messages); - echo $response->getContent(); // "I'm fine, thank you. How can I help you today?" + echo $result->getContent(); // "I'm fine, thank you. How can I help you today?" The structure of the input message bag is flexible, see `Platform Component`_ for more details on how to use it. @@ -90,7 +90,7 @@ Custom tools can basically be any class, but must configure by the ``#[AsTool]`` **Tool Return Value** -In the end, the tool's response needs to be a string, but Symfony AI converts arrays and objects, that implement the +In the end, the tool's result needs to be a string, but Symfony AI converts arrays and objects, that implement the JsonSerializable interface, to JSON strings for you. So you can return arrays or objects directly from your tool. **Tool Methods** @@ -234,12 +234,12 @@ tools option with a list of tool names:: To react to the result of a tool, you can implement an EventListener or EventSubscriber, that listens to the ``ToolCallsExecuted`` event. This event is dispatched after the Toolbox executed all current tool calls and enables you -to skip the next LLM call by setting a response yourself:: +to skip the next LLM call by setting a result yourself:: $eventDispatcher->addListener(ToolCallsExecuted::class, function (ToolCallsExecuted $event): void { foreach ($event->toolCallResults as $toolCallResult) { if (str_starts_with($toolCallResult->toolCall->name, 'weather_')) { - $event->response = new StructuredResponse($toolCallResult->result); + $event->result = new ObjectResult($toolCallResult->result); } } }); @@ -247,7 +247,7 @@ to skip the next LLM call by setting a response yourself:: **Keeping Tool Messages** Sometimes you might wish to keep the tool messages (AssistantMessage containing the toolCalls and ToolCallMessage -containing the response) in the context. Enable the keepToolMessages flag of the toolbox' AgentProcessor to ensure those +containing the result) in the context. Enable the keepToolMessages flag of the toolbox' AgentProcessor to ensure those messages will be added to your MessageBag:: use Symfony\AI\Agent\Toolbox\AgentProcessor; @@ -268,7 +268,7 @@ messages will be added to your MessageBag:: $toolProcessor = new AgentProcessor($toolbox, keepToolMessages: true); $agent = new Agent($platform, $model, inputProcessor: [$toolProcessor], outputProcessor: [$toolProcessor]); - $response = $agent->call($messages); + $result = $agent->call($messages); // $messages will now include the tool messages **Code Examples (with built-in tools)** @@ -287,7 +287,7 @@ Retrieval Augmented Generation (RAG) In combination with the `Store Component`_, the Agent component can be used to build agents that perform Retrieval Augmented Generation (RAG). This allows the agent to retrieve relevant documents from a store and use them to generate -more accurate and context-aware responses. Therefore, the component provides a built-in tool called +more accurate and context-aware results. Therefore, the component provides a built-in tool called ``Symfony\AI\Agent\Toolbox\Tool\SimilaritySearch``:: use Symfony\AI\Agent\Agent; @@ -311,7 +311,7 @@ more accurate and context-aware responses. Therefore, the component provides a b PROMPT), Message::ofUser('...') // The user's question. ); - $response = $agent->call($messages); + $result = $agent->call($messages); **Code Examples** @@ -327,7 +327,7 @@ by features like **Structured Output** or providing a **Response Format**. **PHP Classes as Output** Symfony AI supports that use-case by abstracting the hustle of defining and providing schemas to the LLM and converting -the response back to PHP objects. +the result back to PHP objects. To achieve this, a specific agent processor needs to be registered:: @@ -351,9 +351,9 @@ To achieve this, a specific agent processor needs to be registered:: Message::forSystem('You are a helpful math tutor. Guide the user through the solution step by step.'), Message::ofUser('how can I solve 8x + 7 = -23'), ); - $response = $agent->call($messages, ['output_structure' => MathReasoning::class]); + $result = $agent->call($messages, ['output_structure' => MathReasoning::class]); - dump($response->getContent()); // returns an instance of `MathReasoning` class + dump($result->getContent()); // returns an instance of `MathReasoning` class **Array Structures as Output** @@ -365,7 +365,7 @@ Also PHP array structures as response_format are supported, which also requires // Initialize Platform, LLM and agent with processors and Clock tool $messages = new MessageBag(Message::ofUser('What date and time is it?')); - $response = $agent->call($messages, ['response_format' => [ + $result = $agent->call($messages, ['response_format' => [ 'type' => 'json_schema', 'json_schema' => [ 'name' => 'clock', @@ -382,7 +382,7 @@ Also PHP array structures as response_format are supported, which also requires ], ]]); - dump($response->getContent()); // returns an array + dump($result->getContent()); // returns an array **Code Examples** @@ -426,19 +426,19 @@ and are able to mutate both on top of the Input instance provided:: **OutputProcessor** -OutputProcessor instances are called after the LLM provided a response and can - on top of options and messages - mutate -or replace the given response:: +OutputProcessor instances are called after the model provided a result and can - on top of options and messages - mutate +or replace the given result:: use Symfony\AI\Agent\Output; use Symfony\AI\Agent\OutputProcessorInterface; final class MyProcessor implements OutputProcessorInterface { - public function processOutput(Output $out): void + public function processOutput(Output $output): void { - // mutate response - if (str_contains($output->response->getContent, self::STOP_WORD)) { - $output->reponse = new TextReponse('Sorry, we were unable to find relevant information.') + // mutate result + if (str_contains($output->result->getContent(), self::STOP_WORD)) { + $output->result = new TextResult('Sorry, we were unable to find relevant information.') } } } @@ -461,7 +461,7 @@ AgentAwareTrait:: public function processOutput(Output $out): void { // additional agent interaction - $response = $this->agent->call(...); + $result = $this->agent->call(...); } } @@ -494,7 +494,7 @@ Memory integration is handled through the ``MemoryInputProcessor`` and one or mo $agent = new Agent($platform, $model, [$memoryProcessor]); $messages = new MessageBag(Message::ofUser('What do we do today?')); - $response = $agent->call($messages); + $result = $agent->call($messages); Memory Providers ~~~~~~~~~~~~~~~~ @@ -532,7 +532,7 @@ Dynamic Memory Control Memory is globally configured for the agent, but you can selectively disable it for specific calls when needed. This is useful when certain interactions shouldn't be influenced by the memory context:: - $response = $agent->call($messages, [ + $result = $agent->call($messages, [ 'use_memory' => false, // Disable memory for this specific call ]); diff --git a/src/agent/src/Agent.php b/src/agent/src/Agent.php index a0703963..c40b9d0e 100644 --- a/src/agent/src/Agent.php +++ b/src/agent/src/Agent.php @@ -20,7 +20,7 @@ use Symfony\AI\Platform\Message\MessageBagInterface; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\PlatformInterface; -use Symfony\AI\Platform\Response\ResponseInterface; +use Symfony\AI\Platform\Result\ResultInterface; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface; @@ -57,7 +57,7 @@ public function __construct( /** * @param array $options */ - public function call(MessageBagInterface $messages, array $options = []): ResponseInterface + public function call(MessageBagInterface $messages, array $options = []): ResultInterface { $input = new Input($this->model, $messages, $options); array_map(fn (InputProcessorInterface $processor) => $processor->processInput($input), $this->inputProcessors); @@ -75,7 +75,7 @@ public function call(MessageBagInterface $messages, array $options = []): Respon } try { - $response = $this->platform->request($model, $messages, $options)->getResponse(); + $result = $this->platform->invoke($model, $messages, $options)->getResult(); } catch (ClientExceptionInterface $e) { $message = $e->getMessage(); $content = $e->getResponse()->toArray(false); @@ -87,10 +87,10 @@ public function call(MessageBagInterface $messages, array $options = []): Respon throw new RuntimeException('Failed to request model', previous: $e); } - $output = new Output($model, $response, $messages, $options); + $output = new Output($model, $result, $messages, $options); array_map(fn (OutputProcessorInterface $processor) => $processor->processOutput($output), $this->outputProcessors); - return $output->response; + return $output->result; } /** diff --git a/src/agent/src/AgentInterface.php b/src/agent/src/AgentInterface.php index d205836d..6117757a 100644 --- a/src/agent/src/AgentInterface.php +++ b/src/agent/src/AgentInterface.php @@ -12,7 +12,7 @@ namespace Symfony\AI\Agent; use Symfony\AI\Platform\Message\MessageBagInterface; -use Symfony\AI\Platform\Response\ResponseInterface; +use Symfony\AI\Platform\Result\ResultInterface; /** * @author Denis Zunke @@ -22,5 +22,5 @@ interface AgentInterface /** * @param array $options */ - public function call(MessageBagInterface $messages, array $options = []): ResponseInterface; + public function call(MessageBagInterface $messages, array $options = []): ResultInterface; } diff --git a/src/agent/src/Chat.php b/src/agent/src/Chat.php index 64b1c029..4c7ae521 100644 --- a/src/agent/src/Chat.php +++ b/src/agent/src/Chat.php @@ -16,7 +16,7 @@ use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBagInterface; use Symfony\AI\Platform\Message\UserMessage; -use Symfony\AI\Platform\Response\TextResponse; +use Symfony\AI\Platform\Result\TextResult; final readonly class Chat implements ChatInterface { @@ -37,11 +37,11 @@ public function submit(UserMessage $message): AssistantMessage $messages = $this->store->load(); $messages->add($message); - $response = $this->agent->call($messages); + $result = $this->agent->call($messages); - \assert($response instanceof TextResponse); + \assert($result instanceof TextResult); - $assistantMessage = Message::ofAssistant($response->getContent()); + $assistantMessage = Message::ofAssistant($result->getContent()); $messages->add($assistantMessage); $this->store->save($messages); diff --git a/src/agent/src/Memory/EmbeddingProvider.php b/src/agent/src/Memory/EmbeddingProvider.php index abeee34f..1dd25c71 100644 --- a/src/agent/src/Memory/EmbeddingProvider.php +++ b/src/agent/src/Memory/EmbeddingProvider.php @@ -53,7 +53,7 @@ public function loadMemory(Input $input): array $userMessageTextContent = array_shift($userMessageTextContent); - $vectors = $this->platform->request($this->model, $userMessageTextContent->text)->asVectors(); + $vectors = $this->platform->invoke($this->model, $userMessageTextContent->text)->asVectors(); $foundEmbeddingContent = $this->vectorStore->query($vectors[0]); if (0 === \count($foundEmbeddingContent)) { return []; diff --git a/src/agent/src/Output.php b/src/agent/src/Output.php index dffd7381..2b01390c 100644 --- a/src/agent/src/Output.php +++ b/src/agent/src/Output.php @@ -13,7 +13,7 @@ use Symfony\AI\Platform\Message\MessageBagInterface; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\ResponseInterface; +use Symfony\AI\Platform\Result\ResultInterface; /** * @author Christopher Hertel @@ -25,7 +25,7 @@ final class Output */ public function __construct( public readonly Model $model, - public ResponseInterface $response, + public ResultInterface $result, public readonly MessageBagInterface $messages, public readonly array $options, ) { diff --git a/src/agent/src/StructuredOutput/AgentProcessor.php b/src/agent/src/StructuredOutput/AgentProcessor.php index 50a95a29..4488f820 100644 --- a/src/agent/src/StructuredOutput/AgentProcessor.php +++ b/src/agent/src/StructuredOutput/AgentProcessor.php @@ -18,7 +18,7 @@ use Symfony\AI\Agent\Output; use Symfony\AI\Agent\OutputProcessorInterface; use Symfony\AI\Platform\Capability; -use Symfony\AI\Platform\Response\ObjectResponse; +use Symfony\AI\Platform\Result\ObjectResult; use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\PropertyInfoExtractor; use Symfony\Component\Serializer\Encoder\JsonEncoder; @@ -73,7 +73,7 @@ public function processOutput(Output $output): void { $options = $output->options; - if ($output->response instanceof ObjectResponse) { + if ($output->result instanceof ObjectResult) { return; } @@ -82,13 +82,13 @@ public function processOutput(Output $output): void } if (!isset($this->outputStructure)) { - $output->response = new ObjectResponse(json_decode($output->response->getContent(), true)); + $output->result = new ObjectResult(json_decode($output->result->getContent(), true)); return; } - $output->response = new ObjectResponse( - $this->serializer->deserialize($output->response->getContent(), $this->outputStructure, 'json') + $output->result = new ObjectResult( + $this->serializer->deserialize($output->result->getContent(), $this->outputStructure, 'json') ); } } diff --git a/src/agent/src/Toolbox/AgentProcessor.php b/src/agent/src/Toolbox/AgentProcessor.php index 9f7c0685..366fb068 100644 --- a/src/agent/src/Toolbox/AgentProcessor.php +++ b/src/agent/src/Toolbox/AgentProcessor.php @@ -19,13 +19,13 @@ use Symfony\AI\Agent\Output; use Symfony\AI\Agent\OutputProcessorInterface; use Symfony\AI\Agent\Toolbox\Event\ToolCallsExecuted; -use Symfony\AI\Agent\Toolbox\StreamResponse as ToolboxStreamResponse; +use Symfony\AI\Agent\Toolbox\StreamResult as ToolboxStreamResponse; use Symfony\AI\Platform\Capability; use Symfony\AI\Platform\Message\AssistantMessage; use Symfony\AI\Platform\Message\Message; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\Response\StreamResponse as GenericStreamResponse; -use Symfony\AI\Platform\Response\ToolCallResponse; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\Result\StreamResult as GenericStreamResponse; +use Symfony\AI\Platform\Result\ToolCallResult; use Symfony\AI\Platform\Tool\Tool; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; @@ -67,20 +67,20 @@ public function processInput(Input $input): void public function processOutput(Output $output): void { - if ($output->response instanceof GenericStreamResponse) { - $output->response = new ToolboxStreamResponse( - $output->response->getContent(), + if ($output->result instanceof GenericStreamResponse) { + $output->result = new ToolboxStreamResponse( + $output->result->getContent(), $this->handleToolCallsCallback($output), ); return; } - if (!$output->response instanceof ToolCallResponse) { + if (!$output->result instanceof ToolCallResult) { return; } - $output->response = $this->handleToolCallsCallback($output)($output->response); + $output->result = $this->handleToolCallsCallback($output)($output->result); } /** @@ -93,7 +93,7 @@ private function isFlatStringArray(array $tools): bool private function handleToolCallsCallback(Output $output): \Closure { - return function (ToolCallResponse $response, ?AssistantMessage $streamedAssistantResponse = null) use ($output): ResponseInterface { + return function (ToolCallResult $result, ?AssistantMessage $streamedAssistantResponse = null) use ($output): ResultInterface { $messages = $this->keepToolMessages ? $output->messages : clone $output->messages; if (null !== $streamedAssistantResponse && '' !== $streamedAssistantResponse->content) { @@ -101,23 +101,23 @@ private function handleToolCallsCallback(Output $output): \Closure } do { - $toolCalls = $response->getContent(); + $toolCalls = $result->getContent(); $messages->add(Message::ofAssistant(toolCalls: $toolCalls)); $results = []; foreach ($toolCalls as $toolCall) { $result = $this->toolbox->execute($toolCall); - $results[] = new ToolCallResult($toolCall, $result); + $results[] = new ToolResult($toolCall, $result); $messages->add(Message::ofToolCall($toolCall, $this->resultConverter->convert($result))); } $event = new ToolCallsExecuted(...$results); $this->eventDispatcher?->dispatch($event); - $response = $event->hasResponse() ? $event->response : $this->agent->call($messages, $output->options); - } while ($response instanceof ToolCallResponse); + $result = $event->hasResponse() ? $event->result : $this->agent->call($messages, $output->options); + } while ($result instanceof ToolCallResult); - return $response; + return $result; }; } } diff --git a/src/agent/src/Toolbox/Event/ToolCallsExecuted.php b/src/agent/src/Toolbox/Event/ToolCallsExecuted.php index 4101b8d0..8fb975af 100644 --- a/src/agent/src/Toolbox/Event/ToolCallsExecuted.php +++ b/src/agent/src/Toolbox/Event/ToolCallsExecuted.php @@ -11,8 +11,8 @@ namespace Symfony\AI\Agent\Toolbox\Event; -use Symfony\AI\Agent\Toolbox\ToolCallResult; -use Symfony\AI\Platform\Response\ResponseInterface; +use Symfony\AI\Agent\Toolbox\ToolResult; +use Symfony\AI\Platform\Result\ResultInterface; /** * @author Christopher Hertel @@ -20,18 +20,18 @@ final class ToolCallsExecuted { /** - * @var ToolCallResult[] + * @var ToolResult[] */ - public readonly array $toolCallResults; - public ResponseInterface $response; + public readonly array $toolResults; + public ResultInterface $result; - public function __construct(ToolCallResult ...$toolCallResults) + public function __construct(ToolResult ...$toolResults) { - $this->toolCallResults = $toolCallResults; + $this->toolResults = $toolResults; } public function hasResponse(): bool { - return isset($this->response); + return isset($this->result); } } diff --git a/src/agent/src/Toolbox/Exception/ToolExecutionException.php b/src/agent/src/Toolbox/Exception/ToolExecutionException.php index 3577020b..933a09ec 100644 --- a/src/agent/src/Toolbox/Exception/ToolExecutionException.php +++ b/src/agent/src/Toolbox/Exception/ToolExecutionException.php @@ -11,7 +11,7 @@ namespace Symfony\AI\Agent\Toolbox\Exception; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; /** * @author Christopher Hertel diff --git a/src/agent/src/Toolbox/Exception/ToolNotFoundException.php b/src/agent/src/Toolbox/Exception/ToolNotFoundException.php index 8e1fb900..b5231d0e 100644 --- a/src/agent/src/Toolbox/Exception/ToolNotFoundException.php +++ b/src/agent/src/Toolbox/Exception/ToolNotFoundException.php @@ -11,7 +11,7 @@ namespace Symfony\AI\Agent\Toolbox\Exception; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\AI\Platform\Tool\ExecutionReference; /** diff --git a/src/agent/src/Toolbox/FaultTolerantToolbox.php b/src/agent/src/Toolbox/FaultTolerantToolbox.php index f372ab1e..a235c400 100644 --- a/src/agent/src/Toolbox/FaultTolerantToolbox.php +++ b/src/agent/src/Toolbox/FaultTolerantToolbox.php @@ -13,7 +13,7 @@ use Symfony\AI\Agent\Toolbox\Exception\ToolExecutionException; use Symfony\AI\Agent\Toolbox\Exception\ToolNotFoundException; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\AI\Platform\Tool\Tool; /** diff --git a/src/agent/src/Toolbox/StreamResponse.php b/src/agent/src/Toolbox/StreamResult.php similarity index 69% rename from src/agent/src/Toolbox/StreamResponse.php rename to src/agent/src/Toolbox/StreamResult.php index 475dbb60..63efcaa9 100644 --- a/src/agent/src/Toolbox/StreamResponse.php +++ b/src/agent/src/Toolbox/StreamResult.php @@ -12,13 +12,13 @@ namespace Symfony\AI\Agent\Toolbox; use Symfony\AI\Platform\Message\Message; -use Symfony\AI\Platform\Response\BaseResponse; -use Symfony\AI\Platform\Response\ToolCallResponse; +use Symfony\AI\Platform\Result\BaseResult; +use Symfony\AI\Platform\Result\ToolCallResult; /** * @author Denis Zunke */ -final class StreamResponse extends BaseResponse +final class StreamResult extends BaseResult { public function __construct( private readonly \Generator $generator, @@ -28,15 +28,16 @@ public function __construct( public function getContent(): \Generator { - $streamedResponse = ''; + $streamedResult = ''; foreach ($this->generator as $value) { - if ($value instanceof ToolCallResponse) { - yield from ($this->handleToolCallsCallback)($value, Message::ofAssistant($streamedResponse))->getContent(); + if ($value instanceof ToolCallResult) { + yield from ($this->handleToolCallsCallback)($value, Message::ofAssistant($streamedResult))->getContent(); break; } - $streamedResponse .= $value; + $streamedResult .= $value; + yield $value; } } diff --git a/src/agent/src/Toolbox/Tool/Agent.php b/src/agent/src/Toolbox/Tool/Agent.php index 1e3ca7a6..cba0f85b 100644 --- a/src/agent/src/Toolbox/Tool/Agent.php +++ b/src/agent/src/Toolbox/Tool/Agent.php @@ -14,7 +14,7 @@ use Symfony\AI\Agent\AgentInterface; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; -use Symfony\AI\Platform\Response\TextResponse; +use Symfony\AI\Platform\Result\TextResult; /** * @author Christopher Hertel @@ -31,10 +31,10 @@ public function __construct( */ public function __invoke(string $message): string { - $response = $this->agent->call(new MessageBag(Message::ofUser($message))); + $result = $this->agent->call(new MessageBag(Message::ofUser($message))); - \assert($response instanceof TextResponse); + \assert($result instanceof TextResult); - return $response->getContent(); + return $result->getContent(); } } diff --git a/src/agent/src/Toolbox/Tool/Brave.php b/src/agent/src/Toolbox/Tool/Brave.php index 4a25d300..a031773a 100644 --- a/src/agent/src/Toolbox/Tool/Brave.php +++ b/src/agent/src/Toolbox/Tool/Brave.php @@ -52,7 +52,7 @@ public function __invoke( #[With(minimum: 0, maximum: 9)] int $offset = 0, ): array { - $response = $this->httpClient->request('GET', 'https://api.search.brave.com/res/v1/web/search', [ + $result = $this->httpClient->request('GET', 'https://api.search.brave.com/res/v1/web/search', [ 'headers' => ['X-Subscription-Token' => $this->apiKey], 'query' => array_merge($this->options, [ 'q' => $query, @@ -61,7 +61,7 @@ public function __invoke( ]), ]); - $data = $response->toArray(); + $data = $result->toArray(); return array_map(static function (array $result) { return ['title' => $result['title'], 'description' => $result['description'], 'url' => $result['url']]; diff --git a/src/agent/src/Toolbox/Tool/Crawler.php b/src/agent/src/Toolbox/Tool/Crawler.php index 9bb4f636..364dc6ea 100644 --- a/src/agent/src/Toolbox/Tool/Crawler.php +++ b/src/agent/src/Toolbox/Tool/Crawler.php @@ -35,8 +35,8 @@ public function __construct( */ public function __invoke(string $url): string { - $response = $this->httpClient->request('GET', $url); + $result = $this->httpClient->request('GET', $url); - return (new DomCrawler($response->getContent()))->filter('body')->text(); + return (new DomCrawler($result->getContent()))->filter('body')->text(); } } diff --git a/src/agent/src/Toolbox/Tool/OpenMeteo.php b/src/agent/src/Toolbox/Tool/OpenMeteo.php index 7e0adef8..6283614a 100644 --- a/src/agent/src/Toolbox/Tool/OpenMeteo.php +++ b/src/agent/src/Toolbox/Tool/OpenMeteo.php @@ -71,7 +71,7 @@ public function __construct( */ public function current(float $latitude, float $longitude): array { - $response = $this->httpClient->request('GET', 'https://api.open-meteo.com/v1/forecast', [ + $result = $this->httpClient->request('GET', 'https://api.open-meteo.com/v1/forecast', [ 'query' => [ 'latitude' => $latitude, 'longitude' => $longitude, @@ -79,7 +79,7 @@ public function current(float $latitude, float $longitude): array ], ]); - $data = $response->toArray(); + $data = $result->toArray(); return [ 'weather' => self::WMO_CODES[$data['current']['weather_code']] ?? 'Unknown', @@ -107,7 +107,7 @@ public function forecast( #[With(minimum: 1, maximum: 16)] int $days = 7, ): array { - $response = $this->httpClient->request('GET', 'https://api.open-meteo.com/v1/forecast', [ + $result = $this->httpClient->request('GET', 'https://api.open-meteo.com/v1/forecast', [ 'query' => [ 'latitude' => $latitude, 'longitude' => $longitude, @@ -116,7 +116,7 @@ public function forecast( ], ]); - $data = $response->toArray(); + $data = $result->toArray(); $forecast = []; for ($i = 0; $i < $days; ++$i) { $forecast[] = [ diff --git a/src/agent/src/Toolbox/Tool/SerpApi.php b/src/agent/src/Toolbox/Tool/SerpApi.php index 782cd97c..aa04e442 100644 --- a/src/agent/src/Toolbox/Tool/SerpApi.php +++ b/src/agent/src/Toolbox/Tool/SerpApi.php @@ -31,14 +31,14 @@ public function __construct( */ public function __invoke(string $query): string { - $response = $this->httpClient->request('GET', 'https://serpapi.com/search', [ + $result = $this->httpClient->request('GET', 'https://serpapi.com/search', [ 'query' => [ 'q' => $query, 'api_key' => $this->apiKey, ], ]); - return \sprintf('Results for "%s" are "%s".', $query, $this->extractBestResponse($response->toArray())); + return \sprintf('Results for "%s" are "%s".', $query, $this->extractBestResponse($result->toArray())); } /** diff --git a/src/agent/src/Toolbox/Tool/SimilaritySearch.php b/src/agent/src/Toolbox/Tool/SimilaritySearch.php index 1a1b1d3d..812e6220 100644 --- a/src/agent/src/Toolbox/Tool/SimilaritySearch.php +++ b/src/agent/src/Toolbox/Tool/SimilaritySearch.php @@ -40,7 +40,7 @@ public function __construct( */ public function __invoke(string $searchTerm): string { - $vectors = $this->platform->request($this->model, $searchTerm)->asVectors(); + $vectors = $this->platform->invoke($this->model, $searchTerm)->asVectors(); $this->usedDocuments = $this->vectorStore->query($vectors[0]); if ([] === $this->usedDocuments) { diff --git a/src/agent/src/Toolbox/Tool/Tavily.php b/src/agent/src/Toolbox/Tool/Tavily.php index f84848d7..36405b42 100644 --- a/src/agent/src/Toolbox/Tool/Tavily.php +++ b/src/agent/src/Toolbox/Tool/Tavily.php @@ -38,14 +38,14 @@ public function __construct( */ public function search(string $query): string { - $response = $this->httpClient->request('POST', 'https://api.tavily.com/search', [ + $result = $this->httpClient->request('POST', 'https://api.tavily.com/search', [ 'json' => array_merge($this->options, [ 'query' => $query, 'api_key' => $this->apiKey, ]), ]); - return $response->getContent(); + return $result->getContent(); } /** @@ -53,13 +53,13 @@ public function search(string $query): string */ public function extract(array $urls): string { - $response = $this->httpClient->request('POST', 'https://api.tavily.com/extract', [ + $result = $this->httpClient->request('POST', 'https://api.tavily.com/extract', [ 'json' => [ 'urls' => $urls, 'api_key' => $this->apiKey, ], ]); - return $response->getContent(); + return $result->getContent(); } } diff --git a/src/agent/src/Toolbox/Tool/Wikipedia.php b/src/agent/src/Toolbox/Tool/Wikipedia.php index 98a85766..8cf85e4a 100644 --- a/src/agent/src/Toolbox/Tool/Wikipedia.php +++ b/src/agent/src/Toolbox/Tool/Wikipedia.php @@ -45,12 +45,12 @@ public function search(string $query): string return 'No articles were found on Wikipedia.'; } - $response = 'Articles with the following titles were found on Wikipedia:'.\PHP_EOL; + $result = 'Articles with the following titles were found on Wikipedia:'.\PHP_EOL; foreach ($titles as $title) { - $response .= ' - '.$title.\PHP_EOL; + $result .= ' - '.$title.\PHP_EOL; } - return $response.\PHP_EOL.'Use the title of the article with tool "wikipedia_article" to load the content.'; + return $result.\PHP_EOL.'Use the title of the article with tool "wikipedia_article" to load the content.'; } /** @@ -58,7 +58,7 @@ public function search(string $query): string */ public function article(string $title): string { - $result = $this->execute([ + $response = $this->execute([ 'action' => 'query', 'format' => 'json', 'prop' => 'extracts|info|pageimages', @@ -67,21 +67,21 @@ public function article(string $title): string 'redirects' => true, ], $this->locale); - $article = current($result['query']['pages']); + $article = current($response['query']['pages']); if (\array_key_exists('missing', $article)) { return \sprintf('No article with title "%s" was found on Wikipedia.', $title); } - $response = ''; - if (\array_key_exists('redirects', $result['query'])) { - foreach ($result['query']['redirects'] as $redirect) { - $response .= \sprintf('The article "%s" redirects to article "%s".', $redirect['from'], $redirect['to']).\PHP_EOL; + $result = ''; + if (\array_key_exists('redirects', $response['query'])) { + foreach ($response['query']['redirects'] as $redirect) { + $result .= \sprintf('The article "%s" redirects to article "%s".', $redirect['from'], $redirect['to']).\PHP_EOL; } - $response .= \PHP_EOL; + $result .= \PHP_EOL; } - return $response.'This is the content of article "'.$article['title'].'":'.\PHP_EOL.$article['extract']; + return $result.'This is the content of article "'.$article['title'].'":'.\PHP_EOL.$article['extract']; } /** diff --git a/src/agent/src/Toolbox/ToolCallArgumentResolver.php b/src/agent/src/Toolbox/ToolCallArgumentResolver.php index 1cf19e1a..456c1ade 100644 --- a/src/agent/src/Toolbox/ToolCallArgumentResolver.php +++ b/src/agent/src/Toolbox/ToolCallArgumentResolver.php @@ -11,7 +11,7 @@ namespace Symfony\AI\Agent\Toolbox; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\AI\Platform\Tool\Tool; use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; diff --git a/src/agent/src/Toolbox/ToolCallArgumentResolverInterface.php b/src/agent/src/Toolbox/ToolCallArgumentResolverInterface.php index e0780c84..13f82e79 100644 --- a/src/agent/src/Toolbox/ToolCallArgumentResolverInterface.php +++ b/src/agent/src/Toolbox/ToolCallArgumentResolverInterface.php @@ -11,7 +11,7 @@ namespace Symfony\AI\Agent\Toolbox; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\AI\Platform\Tool\Tool; /** diff --git a/src/agent/src/Toolbox/ToolCallResult.php b/src/agent/src/Toolbox/ToolResult.php similarity index 85% rename from src/agent/src/Toolbox/ToolCallResult.php rename to src/agent/src/Toolbox/ToolResult.php index 153631c2..de4b0246 100644 --- a/src/agent/src/Toolbox/ToolCallResult.php +++ b/src/agent/src/Toolbox/ToolResult.php @@ -11,12 +11,12 @@ namespace Symfony\AI\Agent\Toolbox; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; /** * @author Christopher Hertel */ -final readonly class ToolCallResult +final readonly class ToolResult { public function __construct( public ToolCall $toolCall, diff --git a/src/agent/src/Toolbox/Toolbox.php b/src/agent/src/Toolbox/Toolbox.php index ee995246..fff53183 100644 --- a/src/agent/src/Toolbox/Toolbox.php +++ b/src/agent/src/Toolbox/Toolbox.php @@ -17,7 +17,7 @@ use Symfony\AI\Agent\Toolbox\Exception\ToolExecutionException; use Symfony\AI\Agent\Toolbox\Exception\ToolNotFoundException; use Symfony\AI\Agent\Toolbox\ToolFactory\ReflectionToolFactory; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\AI\Platform\Tool\Tool; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; diff --git a/src/agent/src/Toolbox/ToolboxInterface.php b/src/agent/src/Toolbox/ToolboxInterface.php index 15478644..e3040504 100644 --- a/src/agent/src/Toolbox/ToolboxInterface.php +++ b/src/agent/src/Toolbox/ToolboxInterface.php @@ -13,7 +13,7 @@ use Symfony\AI\Agent\Toolbox\Exception\ToolExecutionException; use Symfony\AI\Agent\Toolbox\Exception\ToolNotFoundException; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\AI\Platform\Tool\Tool; /** diff --git a/src/agent/tests/InputProcessor/SystemPromptInputProcessorTest.php b/src/agent/tests/InputProcessor/SystemPromptInputProcessorTest.php index c0ab486f..1f9b5b2e 100644 --- a/src/agent/tests/InputProcessor/SystemPromptInputProcessorTest.php +++ b/src/agent/tests/InputProcessor/SystemPromptInputProcessorTest.php @@ -27,7 +27,7 @@ use Symfony\AI\Platform\Message\MessageBag; use Symfony\AI\Platform\Message\SystemMessage; use Symfony\AI\Platform\Message\UserMessage; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\AI\Platform\Tool\ExecutionReference; use Symfony\AI\Platform\Tool\Tool; diff --git a/src/agent/tests/Memory/EmbeddingProviderTest.php b/src/agent/tests/Memory/EmbeddingProviderTest.php index 9993ac8b..4bda203b 100644 --- a/src/agent/tests/Memory/EmbeddingProviderTest.php +++ b/src/agent/tests/Memory/EmbeddingProviderTest.php @@ -24,9 +24,9 @@ use Symfony\AI\Platform\Message\MessageBag; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\PlatformInterface; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponsePromise; -use Symfony\AI\Platform\Response\VectorResponse; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultPromise; +use Symfony\AI\Platform\Result\VectorResult; use Symfony\AI\Platform\Vector\Vector; use Symfony\AI\Store\VectorStoreInterface; @@ -46,7 +46,7 @@ final class EmbeddingProviderTest extends TestCase public function itIsDoingNothingWithEmptyMessageBag(): void { $platform = $this->createMock(PlatformInterface::class); - $platform->expects($this->never())->method('request'); + $platform->expects($this->never())->method('invoke'); $vectorStore = $this->createMock(VectorStoreInterface::class); $vectorStore->expects($this->never())->method('query'); @@ -68,7 +68,7 @@ public function itIsDoingNothingWithEmptyMessageBag(): void public function itIsDoingNothingWithoutUserMessageInBag(): void { $platform = $this->createMock(PlatformInterface::class); - $platform->expects($this->never())->method('request'); + $platform->expects($this->never())->method('invoke'); $vectorStore = $this->createMock(VectorStoreInterface::class); $vectorStore->expects($this->never())->method('query'); @@ -90,7 +90,7 @@ public function itIsDoingNothingWithoutUserMessageInBag(): void public function itIsDoingNothingWhenUserMessageHasNoTextContent(): void { $platform = $this->createMock(PlatformInterface::class); - $platform->expects($this->never())->method('request'); + $platform->expects($this->never())->method('invoke'); $vectorStore = $this->createMock(VectorStoreInterface::class); $vectorStore->expects($this->never())->method('query'); @@ -111,16 +111,16 @@ public function itIsDoingNothingWhenUserMessageHasNoTextContent(): void #[Test] public function itIsNotCreatingMemoryWhenNoVectorsFound(): void { - $vectorResponse = new VectorResponse($vector = new Vector([0.1, 0.2], 2)); - $responsePromise = new ResponsePromise( - static fn () => $vectorResponse, - self::createStub(RawResponseInterface::class), + $vectorResult = new VectorResult($vector = new Vector([0.1, 0.2], 2)); + $resultPromise = new ResultPromise( + static fn () => $vectorResult, + self::createStub(RawResultInterface::class), ); $platform = $this->createMock(PlatformInterface::class); $platform->expects($this->once()) - ->method('request') - ->willReturn($responsePromise); + ->method('invoke') + ->willReturn($resultPromise); $vectorStore = $this->createMock(VectorStoreInterface::class); $vectorStore->expects($this->once()) @@ -146,16 +146,16 @@ public function itIsNotCreatingMemoryWhenNoVectorsFound(): void #[Test] public function itIsCreatingMemoryWithFoundVectors(): void { - $vectorResponse = new VectorResponse($vector = new Vector([0.1, 0.2], 2)); - $responsePromise = new ResponsePromise( - static fn () => $vectorResponse, - self::createStub(RawResponseInterface::class), + $vectorResult = new VectorResult($vector = new Vector([0.1, 0.2], 2)); + $resultPromise = new ResultPromise( + static fn () => $vectorResult, + self::createStub(RawResultInterface::class), ); $platform = $this->createMock(PlatformInterface::class); $platform->expects($this->once()) - ->method('request') - ->willReturn($responsePromise); + ->method('invoke') + ->willReturn($resultPromise); $vectorStore = $this->createMock(VectorStoreInterface::class); $vectorStore->expects($this->once()) diff --git a/src/agent/tests/StructuredOutput/AgentProcessorTest.php b/src/agent/tests/StructuredOutput/AgentProcessorTest.php index 85039f9c..d97cd345 100644 --- a/src/agent/tests/StructuredOutput/AgentProcessorTest.php +++ b/src/agent/tests/StructuredOutput/AgentProcessorTest.php @@ -25,9 +25,9 @@ use Symfony\AI\Platform\Capability; use Symfony\AI\Platform\Message\MessageBag; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\Choice; -use Symfony\AI\Platform\Response\ObjectResponse; -use Symfony\AI\Platform\Response\TextResponse; +use Symfony\AI\Platform\Result\Choice; +use Symfony\AI\Platform\Result\ObjectResult; +use Symfony\AI\Platform\Result\TextResult; use Symfony\Component\Serializer\SerializerInterface; #[CoversClass(AgentProcessor::class)] @@ -36,8 +36,8 @@ #[UsesClass(MessageBag::class)] #[UsesClass(Choice::class)] #[UsesClass(MissingModelSupportException::class)] -#[UsesClass(TextResponse::class)] -#[UsesClass(ObjectResponse::class)] +#[UsesClass(TextResult::class)] +#[UsesClass(ObjectResult::class)] #[UsesClass(Model::class)] final class AgentProcessorTest extends TestCase { @@ -90,15 +90,15 @@ public function processOutputWithResponseFormat(): void $input = new Input($model, new MessageBag(), $options); $processor->processInput($input); - $response = new TextResponse('{"some": "data"}'); + $result = new TextResult('{"some": "data"}'); - $output = new Output($model, $response, new MessageBag(), $input->getOptions()); + $output = new Output($model, $result, new MessageBag(), $input->getOptions()); $processor->processOutput($output); - self::assertInstanceOf(ObjectResponse::class, $output->response); - self::assertInstanceOf(SomeStructure::class, $output->response->getContent()); - self::assertSame('data', $output->response->getContent()->some); + self::assertInstanceOf(ObjectResult::class, $output->result); + self::assertInstanceOf(SomeStructure::class, $output->result->getContent()); + self::assertSame('data', $output->result->getContent()->some); } #[Test] @@ -111,7 +111,7 @@ public function processOutputWithComplexResponseFormat(): void $input = new Input($model, new MessageBag(), $options); $processor->processInput($input); - $response = new TextResponse(<<getOptions()); + $output = new Output($model, $result, new MessageBag(), $input->getOptions()); $processor->processOutput($output); - self::assertInstanceOf(ObjectResponse::class, $output->response); - self::assertInstanceOf(MathReasoning::class, $structure = $output->response->getContent()); + self::assertInstanceOf(ObjectResult::class, $output->result); + self::assertInstanceOf(MathReasoning::class, $structure = $output->result->getContent()); self::assertCount(5, $structure->steps); self::assertInstanceOf(Step::class, $structure->steps[0]); self::assertInstanceOf(Step::class, $structure->steps[1]); @@ -157,17 +157,17 @@ public function processOutputWithComplexResponseFormat(): void #[Test] public function processOutputWithoutResponseFormat(): void { - $responseFormatFactory = new ConfigurableResponseFormatFactory(); + $resultFormatFactory = new ConfigurableResponseFormatFactory(); $serializer = self::createMock(SerializerInterface::class); - $processor = new AgentProcessor($responseFormatFactory, $serializer); + $processor = new AgentProcessor($resultFormatFactory, $serializer); $model = self::createMock(Model::class); - $response = new TextResponse(''); + $result = new TextResult(''); - $output = new Output($model, $response, new MessageBag(), []); + $output = new Output($model, $result, new MessageBag(), []); $processor->processOutput($output); - self::assertSame($response, $output->response); + self::assertSame($result, $output->result); } } diff --git a/src/agent/tests/Toolbox/AgentProcessorTest.php b/src/agent/tests/Toolbox/AgentProcessorTest.php index 78699067..4766ba03 100644 --- a/src/agent/tests/Toolbox/AgentProcessorTest.php +++ b/src/agent/tests/Toolbox/AgentProcessorTest.php @@ -26,8 +26,8 @@ use Symfony\AI\Platform\Message\MessageBag; use Symfony\AI\Platform\Message\ToolCallMessage; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\ToolCall; -use Symfony\AI\Platform\Response\ToolCallResponse; +use Symfony\AI\Platform\Result\ToolCall; +use Symfony\AI\Platform\Result\ToolCallResult; use Symfony\AI\Platform\Tool\ExecutionReference; use Symfony\AI\Platform\Tool\Tool; @@ -36,7 +36,7 @@ #[UsesClass(Output::class)] #[UsesClass(Tool::class)] #[UsesClass(ToolCall::class)] -#[UsesClass(ToolCallResponse::class)] +#[UsesClass(ToolCallResult::class)] #[UsesClass(ExecutionReference::class)] #[UsesClass(MessageBag::class)] #[UsesClass(MissingModelSupportException::class)] @@ -114,14 +114,14 @@ public function processOutputWithToolCallResponseKeepingMessages(): void $messageBag = new MessageBag(); - $response = new ToolCallResponse(new ToolCall('id1', 'tool1', ['arg1' => 'value1'])); + $result = new ToolCallResult(new ToolCall('id1', 'tool1', ['arg1' => 'value1'])); $agent = $this->createStub(AgentInterface::class); $processor = new AgentProcessor($toolbox, keepToolMessages: true); $processor->setAgent($agent); - $output = new Output($model, $response, $messageBag, []); + $output = new Output($model, $result, $messageBag, []); $processor->processOutput($output); @@ -140,14 +140,14 @@ public function processOutputWithToolCallResponseForgettingMessages(): void $messageBag = new MessageBag(); - $response = new ToolCallResponse(new ToolCall('id1', 'tool1', ['arg1' => 'value1'])); + $result = new ToolCallResult(new ToolCall('id1', 'tool1', ['arg1' => 'value1'])); $agent = $this->createStub(AgentInterface::class); $processor = new AgentProcessor($toolbox, keepToolMessages: false); $processor->setAgent($agent); - $output = new Output($model, $response, $messageBag, []); + $output = new Output($model, $result, $messageBag, []); $processor->processOutput($output); diff --git a/src/agent/tests/Toolbox/FaultTolerantToolboxTest.php b/src/agent/tests/Toolbox/FaultTolerantToolboxTest.php index 6df4e748..b4fd1463 100644 --- a/src/agent/tests/Toolbox/FaultTolerantToolboxTest.php +++ b/src/agent/tests/Toolbox/FaultTolerantToolboxTest.php @@ -21,7 +21,7 @@ use Symfony\AI\Agent\Toolbox\ToolboxInterface; use Symfony\AI\Fixtures\Tool\ToolNoParams; use Symfony\AI\Fixtures\Tool\ToolRequiredParams; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\AI\Platform\Tool\ExecutionReference; use Symfony\AI\Platform\Tool\Tool; diff --git a/src/agent/tests/Toolbox/Tool/BraveTest.php b/src/agent/tests/Toolbox/Tool/BraveTest.php index 730fbe2e..0a0b1302 100644 --- a/src/agent/tests/Toolbox/Tool/BraveTest.php +++ b/src/agent/tests/Toolbox/Tool/BraveTest.php @@ -25,8 +25,8 @@ final class BraveTest extends TestCase #[Test] public function returnsSearchResults(): void { - $response = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/brave.json'); - $httpClient = new MockHttpClient($response); + $result = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/brave.json'); + $httpClient = new MockHttpClient($result); $brave = new Brave($httpClient, 'test-api-key'); $results = $brave('latest Dallas Cowboys game result'); @@ -43,19 +43,19 @@ public function returnsSearchResults(): void #[Test] public function passesCorrectParametersToApi(): void { - $response = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/brave.json'); - $httpClient = new MockHttpClient($response); + $result = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/brave.json'); + $httpClient = new MockHttpClient($result); $brave = new Brave($httpClient, 'test-api-key', ['extra' => 'option']); $brave('test query', 10, 5); - $request = $response->getRequestUrl(); + $request = $result->getRequestUrl(); self::assertStringContainsString('q=test%20query', $request); self::assertStringContainsString('count=10', $request); self::assertStringContainsString('offset=5', $request); self::assertStringContainsString('extra=option', $request); - $requestOptions = $response->getRequestOptions(); + $requestOptions = $result->getRequestOptions(); self::assertArrayHasKey('headers', $requestOptions); self::assertContains('X-Subscription-Token: test-api-key', $requestOptions['headers']); } @@ -63,8 +63,8 @@ public function passesCorrectParametersToApi(): void #[Test] public function handlesEmptyResults(): void { - $response = new MockResponse(json_encode(['web' => ['results' => []]])); - $httpClient = new MockHttpClient($response); + $result = new MockResponse(json_encode(['web' => ['results' => []]])); + $httpClient = new MockHttpClient($result); $brave = new Brave($httpClient, 'test-api-key'); $results = $brave('this should return nothing'); diff --git a/src/agent/tests/Toolbox/Tool/OpenMeteoTest.php b/src/agent/tests/Toolbox/Tool/OpenMeteoTest.php index 6a9050b1..d2d43441 100644 --- a/src/agent/tests/Toolbox/Tool/OpenMeteoTest.php +++ b/src/agent/tests/Toolbox/Tool/OpenMeteoTest.php @@ -24,8 +24,8 @@ final class OpenMeteoTest extends TestCase #[Test] public function current(): void { - $response = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/openmeteo-current.json'); - $httpClient = new MockHttpClient($response); + $result = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/openmeteo-current.json'); + $httpClient = new MockHttpClient($result); $openMeteo = new OpenMeteo($httpClient); @@ -43,8 +43,8 @@ public function current(): void #[Test] public function forecast(): void { - $response = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/openmeteo-forecast.json'); - $httpClient = new MockHttpClient($response); + $result = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/openmeteo-forecast.json'); + $httpClient = new MockHttpClient($result); $openMeteo = new OpenMeteo($httpClient); diff --git a/src/agent/tests/Toolbox/Tool/WikipediaTest.php b/src/agent/tests/Toolbox/Tool/WikipediaTest.php index 1547eb93..cb538702 100644 --- a/src/agent/tests/Toolbox/Tool/WikipediaTest.php +++ b/src/agent/tests/Toolbox/Tool/WikipediaTest.php @@ -24,8 +24,8 @@ final class WikipediaTest extends TestCase #[Test] public function searchWithResults(): void { - $response = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/wikipedia-search-result.json'); - $httpClient = new MockHttpClient($response); + $result = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/wikipedia-search-result.json'); + $httpClient = new MockHttpClient($result); $wikipedia = new Wikipedia($httpClient); @@ -52,8 +52,8 @@ public function searchWithResults(): void #[Test] public function searchWithoutResults(): void { - $response = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/wikipedia-search-empty.json'); - $httpClient = new MockHttpClient($response); + $result = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/wikipedia-search-empty.json'); + $httpClient = new MockHttpClient($result); $wikipedia = new Wikipedia($httpClient); @@ -66,8 +66,8 @@ public function searchWithoutResults(): void #[Test] public function articleWithResult(): void { - $response = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/wikipedia-article.json'); - $httpClient = new MockHttpClient($response); + $result = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/wikipedia-article.json'); + $httpClient = new MockHttpClient($result); $wikipedia = new Wikipedia($httpClient); @@ -83,8 +83,8 @@ public function articleWithResult(): void #[Test] public function articleWithRedirect(): void { - $response = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/wikipedia-article-redirect.json'); - $httpClient = new MockHttpClient($response); + $result = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/wikipedia-article-redirect.json'); + $httpClient = new MockHttpClient($result); $wikipedia = new Wikipedia($httpClient); @@ -102,8 +102,8 @@ public function articleWithRedirect(): void #[Test] public function articleMissing(): void { - $response = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/wikipedia-article-missing.json'); - $httpClient = new MockHttpClient($response); + $result = $this->jsonMockResponseFromFile(__DIR__.'/fixtures/wikipedia-article-missing.json'); + $httpClient = new MockHttpClient($result); $wikipedia = new Wikipedia($httpClient); diff --git a/src/agent/tests/Toolbox/ToolCallArgumentResolverTest.php b/src/agent/tests/Toolbox/ToolCallArgumentResolverTest.php index 423c2bc7..b73bbb12 100644 --- a/src/agent/tests/Toolbox/ToolCallArgumentResolverTest.php +++ b/src/agent/tests/Toolbox/ToolCallArgumentResolverTest.php @@ -18,7 +18,7 @@ use Symfony\AI\Agent\Toolbox\ToolCallArgumentResolver; use Symfony\AI\Fixtures\Tool\ToolArray; use Symfony\AI\Fixtures\Tool\ToolDate; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\AI\Platform\Tool\ExecutionReference; use Symfony\AI\Platform\Tool\Tool; diff --git a/src/agent/tests/Toolbox/ToolboxTest.php b/src/agent/tests/Toolbox/ToolboxTest.php index 27834890..63c1012d 100644 --- a/src/agent/tests/Toolbox/ToolboxTest.php +++ b/src/agent/tests/Toolbox/ToolboxTest.php @@ -33,7 +33,7 @@ use Symfony\AI\Fixtures\Tool\ToolRequiredParams; use Symfony\AI\Platform\Contract\JsonSchema\DescriptionParser; use Symfony\AI\Platform\Contract\JsonSchema\Factory; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\AI\Platform\Tool\ExecutionReference; use Symfony\AI\Platform\Tool\Tool; @@ -250,9 +250,9 @@ public function toolboxExecutionWithMemoryFactory(): void ->addTool(ToolNoAttribute1::class, 'happy_birthday', 'Generates birthday message'); $toolbox = new Toolbox([new ToolNoAttribute1()], $memoryFactory); - $response = $toolbox->execute(new ToolCall('call_1234', 'happy_birthday', ['name' => 'John', 'years' => 30])); + $result = $toolbox->execute(new ToolCall('call_1234', 'happy_birthday', ['name' => 'John', 'years' => 30])); - self::assertSame('Happy Birthday, John! You are 30 years old.', $response); + self::assertSame('Happy Birthday, John! You are 30 years old.', $result); } #[Test] diff --git a/src/ai-bundle/src/AIBundle.php b/src/ai-bundle/src/AIBundle.php index f964b334..34306ee6 100644 --- a/src/ai-bundle/src/AIBundle.php +++ b/src/ai-bundle/src/AIBundle.php @@ -40,7 +40,7 @@ use Symfony\AI\Platform\ModelClientInterface; use Symfony\AI\Platform\Platform; use Symfony\AI\Platform\PlatformInterface; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\ResultConverterInterface; use Symfony\AI\Store\Bridge\Azure\SearchStore as AzureSearchStore; use Symfony\AI\Store\Bridge\ChromaDB\Store as ChromaDBStore; use Symfony\AI\Store\Bridge\MongoDB\Store as MongoDBStore; @@ -132,8 +132,8 @@ public function loadExtension(array $config, ContainerConfigurator $container, C ->addTag('ai.agent.output_processor'); $builder->registerForAutoconfiguration(ModelClientInterface::class) ->addTag('ai.platform.model_client'); - $builder->registerForAutoconfiguration(ResponseConverterInterface::class) - ->addTag('ai.platform.response_converter'); + $builder->registerForAutoconfiguration(ResultConverterInterface::class) + ->addTag('ai.platform.result_converter'); if (!ContainerBuilder::willBeAvailable('symfony/security-core', AuthorizationCheckerInterface::class, ['symfony/ai-bundle'])) { $builder->removeDefinition('ai.security.is_granted_attribute_listener'); diff --git a/src/ai-bundle/src/Profiler/DataCollector.php b/src/ai-bundle/src/Profiler/DataCollector.php index da5cc89c..4eb066bb 100644 --- a/src/ai-bundle/src/Profiler/DataCollector.php +++ b/src/ai-bundle/src/Profiler/DataCollector.php @@ -95,14 +95,14 @@ public function getToolCalls(): array * model: Model, * input: array|string|object, * options: array, - * response: string|iterable|object|null + * result: string|iterable|object|null * }[] */ private function awaitCallResults(TraceablePlatform $platform): array { $calls = $platform->calls; foreach ($calls as $key => $call) { - $call['response'] = $call['response']->await()->getContent(); + $call['result'] = $call['result']->await()->getContent(); $calls[$key] = $call; } diff --git a/src/ai-bundle/src/Profiler/TraceablePlatform.php b/src/ai-bundle/src/Profiler/TraceablePlatform.php index f8315566..7ea91abf 100644 --- a/src/ai-bundle/src/Profiler/TraceablePlatform.php +++ b/src/ai-bundle/src/Profiler/TraceablePlatform.php @@ -14,7 +14,7 @@ use Symfony\AI\Platform\Message\Content\File; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\PlatformInterface; -use Symfony\AI\Platform\Response\ResponsePromise; +use Symfony\AI\Platform\Result\ResultPromise; /** * @author Christopher Hertel @@ -23,7 +23,7 @@ * model: Model, * input: array|string|object, * options: array, - * response: ResponsePromise, + * result: ResultPromise, * } */ final class TraceablePlatform implements PlatformInterface @@ -38,9 +38,9 @@ public function __construct( ) { } - public function request(Model $model, array|string|object $input, array $options = []): ResponsePromise + public function invoke(Model $model, array|string|object $input, array $options = []): ResultPromise { - $response = $this->platform->request($model, $input, $options); + $result = $this->platform->invoke($model, $input, $options); if ($input instanceof File) { $input = $input::class.': '.$input->getFormat(); @@ -50,9 +50,9 @@ public function request(Model $model, array|string|object $input, array $options 'model' => $model, 'input' => \is_object($input) ? clone $input : $input, 'options' => $options, - 'response' => $response, + 'result' => $result, ]; - return $response; + return $result; } } diff --git a/src/ai-bundle/src/Profiler/TraceableToolbox.php b/src/ai-bundle/src/Profiler/TraceableToolbox.php index a3d070ac..d514878a 100644 --- a/src/ai-bundle/src/Profiler/TraceableToolbox.php +++ b/src/ai-bundle/src/Profiler/TraceableToolbox.php @@ -12,7 +12,7 @@ namespace Symfony\AI\AIBundle\Profiler; use Symfony\AI\Agent\Toolbox\ToolboxInterface; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; /** * @author Christopher Hertel diff --git a/src/ai-bundle/templates/data_collector.html.twig b/src/ai-bundle/templates/data_collector.html.twig index 6193669a..93552376 100644 --- a/src/ai-bundle/templates/data_collector.html.twig +++ b/src/ai-bundle/templates/data_collector.html.twig @@ -151,18 +151,18 @@ - Response + Result - {% if call.input.messages is defined and call.response is iterable %}{# expect array of ToolCall #} - {{ _self.tool_calls(call.response) }} - {% elseif call.response is iterable %}{# expect array of Vectors #} + {% if call.input.messages is defined and call.result is iterable %}{# expect array of ToolCall #} + {{ _self.tool_calls(call.result) }} + {% elseif call.result is iterable %}{# expect array of Vectors #}
    - {% for vector in call.response %} + {% for vector in call.result %}
  1. Vector with {{ vector.dimensions }} dimensions
  2. {% endfor %}
{% else %} - {{ call.response }} + {{ call.result }} {% endif %} @@ -238,7 +238,7 @@ {{ dump(call.call.arguments) }} - Response + Result {{ call.result|nl2br }} diff --git a/src/ai-bundle/tests/Profiler/TraceableToolboxTest.php b/src/ai-bundle/tests/Profiler/TraceableToolboxTest.php index 6990ca89..df4a9225 100644 --- a/src/ai-bundle/tests/Profiler/TraceableToolboxTest.php +++ b/src/ai-bundle/tests/Profiler/TraceableToolboxTest.php @@ -17,7 +17,7 @@ use PHPUnit\Framework\TestCase; use Symfony\AI\Agent\Toolbox\ToolboxInterface; use Symfony\AI\AIBundle\Profiler\TraceableToolbox; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\AI\Platform\Tool\ExecutionReference; use Symfony\AI\Platform\Tool\Tool; diff --git a/src/platform/doc/google-gemini-server-tools.rst b/src/platform/doc/google-gemini-server-tools.rst index a519c473..179a4967 100644 --- a/src/platform/doc/google-gemini-server-tools.rst +++ b/src/platform/doc/google-gemini-server-tools.rst @@ -35,12 +35,12 @@ The URL Context tool allows Gemini to fetch and analyze content from web pages. Message::ofUser('What was the 12 month Euribor rate a week ago based on https://www.euribor-rates.eu/en/current-euribor-rates/4/euribor-rate-12-months/') ); - $response = $platform->request($model, $messages); + $result = $platform->invoke($model, $messages); **Google Search** -The Google Search tool enables the model to search the web and incorporate search results into its responses:: +The Google Search tool enables the model to search the web and incorporate search results into its results:: $model = new Gemini('gemini-2.5-pro-preview-03-25', [ 'server_tools' => [ @@ -52,7 +52,7 @@ The Google Search tool enables the model to search the web and incorporate searc Message::ofUser('What are the latest developments in quantum computing?') ); - $response = $platform->request($model, $messages); + $result = $platform->invoke($model, $messages); **Code Execution** @@ -68,7 +68,7 @@ The Code Execution tool provides a sandboxed environment for running code:: Message::ofUser('Calculate the factorial of 20 and show me the code') ); - $response = $platform->request($model, $messages); + $result = $platform->invoke($model, $messages); ## Using Multiple Server Tools diff --git a/src/platform/doc/index.rst b/src/platform/doc/index.rst index 32794562..b0e3e957 100644 --- a/src/platform/doc/index.rst +++ b/src/platform/doc/index.rst @@ -44,11 +44,11 @@ For example, to use the OpenAI provider, you would typically do something like t And with a ``Symfony\AI\Platform\PlatformInterface`` instance, and a ``Symfony\AI\Platform\Model`` instance, you can now use the platform to interact with the AI model:: - // Generate a vector embedding for a text, returns a Symfony\AI\Platform\Response\VectorResponse - $response = $platform->request($embeddings, 'What is the capital of France?'); + // Generate a vector embedding for a text, returns a Symfony\AI\Platform\Result\VectorResult + $result = $platform->invoke($embeddings, 'What is the capital of France?'); - // Generate a text completion with GPT, returns a Symfony\AI\Platform\Response\TextResponse - $embeddingsResult = $platform->request($model, new MessageBag(Message::ofUser('What is the capital of France?'))); + // Generate a text completion with GPT, returns a Symfony\AI\Platform\Result\TextResult + $embeddingsResult = $platform->invoke($model, new MessageBag(Message::ofUser('What is the capital of France?'))); Depending on the model and its capabilities, different types of inputs and outputs are supported, which results in a very flexible and powerful interface for working with AI models. @@ -95,10 +95,10 @@ See `GitHub`_ for planned support of other models and platforms. Options ------- -The third parameter of the ``request`` method is an array of options, which basically wraps the options of the +The third parameter of the ``invoke`` method is an array of options, which basically wraps the options of the corresponding model and platform, like ``temperature`` or ``stream``:: - $response = $platform->request($model, $input, [ + $result = $platform->invoke($model, $input, [ 'temperature' => 0.7, 'max_tokens' => 100, ]); @@ -152,11 +152,11 @@ This provides several benefits: // Get string representation echo $id->toRfc4122(); // e.g., "01928d1f-6f2e-7123-a456-123456789abc" -Response Streaming ------------------- +Result Streaming +---------------- -Since LLMs usually generate a response word by word, most of them also support streaming the response using Server Side -Events. Symfony AI supports that by abstracting the conversion and returning a ``Generator`` as content of the response:: +Since LLMs usually generate a result word by word, most of them also support streaming the result using Server Side +Events. Symfony AI supports that by abstracting the conversion and returning a ``Generator`` as content of the result:: use Symfony\AI\Agent\Agent; use Symfony\AI\Message\Message; @@ -169,11 +169,11 @@ Events. Symfony AI supports that by abstracting the conversion and returning a ` Message::forSystem('You are a thoughtful philosopher.'), Message::ofUser('What is the purpose of an ant?'), ); - $response = $agent->call($messages, [ + $result = $agent->call($messages, [ 'stream' => true, // enable streaming of response text ]); - foreach ($response->getContent() as $word) { + foreach ($result->getContent() as $word) { echo $word; } @@ -205,7 +205,7 @@ Some LLMs also support images as input, which Symfony AI supports as content typ new ImageUrl('https://foo.com/bar.png'), // URL to an image ), ); - $response = $agent->call($messages); + $result = $agent->call($messages); **Code Examples** * `Binary Image Input with GPT`_ @@ -229,7 +229,7 @@ Similar to images, some LLMs also support audio as input, which is just another Audio::fromFile('/path/audio.mp3'), // Path to an audio file ), ); - $response = $agent->call($messages); + $result = $agent->call($messages); **Code Examples** @@ -248,7 +248,7 @@ The standalone usage results in an ``Vector`` instance:: $embeddings = new Embeddings($platform, Embeddings::TEXT_3_SMALL); - $vectors = $platform->request($embeddings, $textInput)->asVectors(); + $vectors = $platform->invoke($embeddings, $textInput)->asVectors(); dump($vectors[0]->getData()); // returns something like: [0.123, -0.456, 0.789, ...] @@ -274,11 +274,11 @@ which can be useful to speed up the processing:: // Initialize Platform & Model foreach ($inputs as $input) { - $responses[] = $platform->request($model, $input); + $results[] = $platform->invoke($model, $input); } - foreach ($responses as $response) { - echo $response->asText().PHP_EOL; + foreach ($results as $result) { + echo $result->asText().PHP_EOL; } .. note:: diff --git a/src/platform/src/Bridge/Albert/EmbeddingsModelClient.php b/src/platform/src/Bridge/Albert/EmbeddingsModelClient.php index a8be7202..6ff3b77e 100644 --- a/src/platform/src/Bridge/Albert/EmbeddingsModelClient.php +++ b/src/platform/src/Bridge/Albert/EmbeddingsModelClient.php @@ -15,8 +15,8 @@ use Symfony\AI\Platform\Exception\InvalidArgumentException; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\RawResponseInterface; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\RawResultInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; /** @@ -38,9 +38,9 @@ public function supports(Model $model): bool return $model instanceof Embeddings; } - public function request(Model $model, array|string $payload, array $options = []): RawResponseInterface + public function request(Model $model, array|string $payload, array $options = []): RawResultInterface { - return new RawHttpResponse($this->httpClient->request('POST', \sprintf('%s/embeddings', $this->baseUrl), [ + return new RawHttpResult($this->httpClient->request('POST', \sprintf('%s/embeddings', $this->baseUrl), [ 'auth_bearer' => $this->apiKey, 'json' => \is_array($payload) ? array_merge($payload, $options) : $payload, ])); diff --git a/src/platform/src/Bridge/Albert/GPTModelClient.php b/src/platform/src/Bridge/Albert/GPTModelClient.php index 0efebc6f..68a2c903 100644 --- a/src/platform/src/Bridge/Albert/GPTModelClient.php +++ b/src/platform/src/Bridge/Albert/GPTModelClient.php @@ -15,8 +15,8 @@ use Symfony\AI\Platform\Exception\InvalidArgumentException; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\RawResponseInterface; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\RawResultInterface; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -43,9 +43,9 @@ public function supports(Model $model): bool return $model instanceof GPT; } - public function request(Model $model, array|string $payload, array $options = []): RawResponseInterface + public function request(Model $model, array|string $payload, array $options = []): RawResultInterface { - return new RawHttpResponse($this->httpClient->request('POST', \sprintf('%s/chat/completions', $this->baseUrl), [ + return new RawHttpResult($this->httpClient->request('POST', \sprintf('%s/chat/completions', $this->baseUrl), [ 'auth_bearer' => $this->apiKey, 'json' => \is_array($payload) ? array_merge($payload, $options) : $payload, ])); diff --git a/src/platform/src/Bridge/Albert/PlatformFactory.php b/src/platform/src/Bridge/Albert/PlatformFactory.php index b43062e0..0146714e 100644 --- a/src/platform/src/Bridge/Albert/PlatformFactory.php +++ b/src/platform/src/Bridge/Albert/PlatformFactory.php @@ -11,8 +11,8 @@ namespace Symfony\AI\Platform\Bridge\Albert; -use Symfony\AI\Platform\Bridge\OpenAI\Embeddings\ResponseConverter as EmbeddingsResponseConverter; -use Symfony\AI\Platform\Bridge\OpenAI\GPT\ResponseConverter as GPTResponseConverter; +use Symfony\AI\Platform\Bridge\OpenAI\Embeddings; +use Symfony\AI\Platform\Bridge\OpenAI\GPT; use Symfony\AI\Platform\Contract; use Symfony\AI\Platform\Exception\InvalidArgumentException; use Symfony\AI\Platform\Platform; @@ -40,7 +40,7 @@ public static function create( new GPTModelClient($httpClient, $apiKey, $baseUrl), new EmbeddingsModelClient($httpClient, $apiKey, $baseUrl), ], - [new GPTResponseConverter(), new EmbeddingsResponseConverter()], + [new GPT\ResultConverter(), new Embeddings\ResultConverter()], Contract::create(), ); } diff --git a/src/platform/src/Bridge/Anthropic/Contract/AssistantMessageNormalizer.php b/src/platform/src/Bridge/Anthropic/Contract/AssistantMessageNormalizer.php index 65698990..c03e034e 100644 --- a/src/platform/src/Bridge/Anthropic/Contract/AssistantMessageNormalizer.php +++ b/src/platform/src/Bridge/Anthropic/Contract/AssistantMessageNormalizer.php @@ -15,7 +15,7 @@ use Symfony\AI\Platform\Contract\Normalizer\ModelContractNormalizer; use Symfony\AI\Platform\Message\AssistantMessage; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; diff --git a/src/platform/src/Bridge/Anthropic/ModelClient.php b/src/platform/src/Bridge/Anthropic/ModelClient.php index a8b55c46..978887b3 100644 --- a/src/platform/src/Bridge/Anthropic/ModelClient.php +++ b/src/platform/src/Bridge/Anthropic/ModelClient.php @@ -13,7 +13,7 @@ use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -37,13 +37,13 @@ public function supports(Model $model): bool return $model instanceof Claude; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { if (isset($options['tools'])) { $options['tool_choice'] = ['type' => 'auto']; } - return new RawHttpResponse($this->httpClient->request('POST', 'https://api.anthropic.com/v1/messages', [ + return new RawHttpResult($this->httpClient->request('POST', 'https://api.anthropic.com/v1/messages', [ 'headers' => [ 'x-api-key' => $this->apiKey, 'anthropic-version' => $this->version, diff --git a/src/platform/src/Bridge/Anthropic/PlatformFactory.php b/src/platform/src/Bridge/Anthropic/PlatformFactory.php index 428949fe..45f8b4c8 100644 --- a/src/platform/src/Bridge/Anthropic/PlatformFactory.php +++ b/src/platform/src/Bridge/Anthropic/PlatformFactory.php @@ -33,7 +33,7 @@ public static function create( return new Platform( [new ModelClient($httpClient, $apiKey, $version)], - [new ResponseConverter()], + [new ResultConverter()], $contract ?? AnthropicContract::create(), ); } diff --git a/src/platform/src/Bridge/Anthropic/ResponseConverter.php b/src/platform/src/Bridge/Anthropic/ResultConverter.php similarity index 67% rename from src/platform/src/Bridge/Anthropic/ResponseConverter.php rename to src/platform/src/Bridge/Anthropic/ResultConverter.php index ab2539e2..0ced3f0e 100644 --- a/src/platform/src/Bridge/Anthropic/ResponseConverter.php +++ b/src/platform/src/Bridge/Anthropic/ResultConverter.php @@ -13,14 +13,14 @@ use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\Response\StreamResponse; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\Response\ToolCall; -use Symfony\AI\Platform\Response\ToolCallResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\Result\StreamResult; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\Result\ToolCall; +use Symfony\AI\Platform\Result\ToolCallResult; +use Symfony\AI\Platform\ResultConverterInterface; use Symfony\Component\HttpClient\Chunk\ServerSentEvent; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Component\HttpClient\Exception\JsonException; @@ -29,20 +29,20 @@ /** * @author Christopher Hertel */ -class ResponseConverter implements ResponseConverterInterface +class ResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return $model instanceof Claude; } - public function convert(RawHttpResponse|RawResponseInterface $response, array $options = []): ResponseInterface + public function convert(RawHttpResult|RawResultInterface $result, array $options = []): ResultInterface { if ($options['stream'] ?? false) { - return new StreamResponse($this->convertStream($response->getRawObject())); + return new StreamResult($this->convertStream($result->getObject())); } - $data = $response->getRawData(); + $data = $result->getData(); if (!isset($data['content']) || [] === $data['content']) { throw new RuntimeException('Response does not contain any content'); @@ -60,15 +60,15 @@ public function convert(RawHttpResponse|RawResponseInterface $response, array $o } if ([] !== $toolCalls) { - return new ToolCallResponse(...$toolCalls); + return new ToolCallResult(...$toolCalls); } - return new TextResponse($data['content'][0]['text']); + return new TextResult($data['content'][0]['text']); } - private function convertStream(HttpResponse $response): \Generator + private function convertStream(HttpResponse $result): \Generator { - foreach ((new EventSourceHttpClient())->stream($response) as $chunk) { + foreach ((new EventSourceHttpClient())->stream($result) as $chunk) { if (!$chunk instanceof ServerSentEvent || '[DONE]' === $chunk->getData()) { continue; } diff --git a/src/platform/src/Bridge/Azure/Meta/LlamaModelClient.php b/src/platform/src/Bridge/Azure/Meta/LlamaModelClient.php index b31d52ec..b5f1b7eb 100644 --- a/src/platform/src/Bridge/Azure/Meta/LlamaModelClient.php +++ b/src/platform/src/Bridge/Azure/Meta/LlamaModelClient.php @@ -14,7 +14,7 @@ use Symfony\AI\Platform\Bridge\Meta\Llama; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Contracts\HttpClient\HttpClientInterface; /** @@ -34,11 +34,11 @@ public function supports(Model $model): bool return $model instanceof Llama; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { $url = \sprintf('https://%s/chat/completions', $this->baseUrl); - return new RawHttpResponse($this->httpClient->request('POST', $url, [ + return new RawHttpResult($this->httpClient->request('POST', $url, [ 'headers' => [ 'Content-Type' => 'application/json', 'Authorization' => $this->apiKey, diff --git a/src/platform/src/Bridge/Azure/Meta/LlamaResponseConverter.php b/src/platform/src/Bridge/Azure/Meta/LlamaResultConverter.php similarity index 62% rename from src/platform/src/Bridge/Azure/Meta/LlamaResponseConverter.php rename to src/platform/src/Bridge/Azure/Meta/LlamaResultConverter.php index 3b8e1275..677b8872 100644 --- a/src/platform/src/Bridge/Azure/Meta/LlamaResponseConverter.php +++ b/src/platform/src/Bridge/Azure/Meta/LlamaResultConverter.php @@ -14,28 +14,28 @@ use Symfony\AI\Platform\Bridge\Meta\Llama; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\ResultConverterInterface; /** * @author Christopher Hertel */ -final readonly class LlamaResponseConverter implements ResponseConverterInterface +final readonly class LlamaResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return $model instanceof Llama; } - public function convert(RawResponseInterface $response, array $options = []): TextResponse + public function convert(RawResultInterface $result, array $options = []): TextResult { - $data = $response->getRawData(); + $data = $result->getData(); if (!isset($data['choices'][0]['message']['content'])) { throw new RuntimeException('Response does not contain output'); } - return new TextResponse($data['choices'][0]['message']['content']); + return new TextResult($data['choices'][0]['message']['content']); } } diff --git a/src/platform/src/Bridge/Azure/Meta/PlatformFactory.php b/src/platform/src/Bridge/Azure/Meta/PlatformFactory.php index 17505fa0..b912d951 100644 --- a/src/platform/src/Bridge/Azure/Meta/PlatformFactory.php +++ b/src/platform/src/Bridge/Azure/Meta/PlatformFactory.php @@ -30,6 +30,6 @@ public static function create( ): Platform { $modelClient = new LlamaModelClient($httpClient ?? HttpClient::create(), $baseUrl, $apiKey); - return new Platform([$modelClient], [new LlamaResponseConverter()], $contract); + return new Platform([$modelClient], [new LlamaResultConverter()], $contract); } } diff --git a/src/platform/src/Bridge/Azure/OpenAI/EmbeddingsModelClient.php b/src/platform/src/Bridge/Azure/OpenAI/EmbeddingsModelClient.php index 811eac78..219a08d6 100644 --- a/src/platform/src/Bridge/Azure/OpenAI/EmbeddingsModelClient.php +++ b/src/platform/src/Bridge/Azure/OpenAI/EmbeddingsModelClient.php @@ -15,7 +15,7 @@ use Symfony\AI\Platform\Exception\InvalidArgumentException; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -46,11 +46,11 @@ public function supports(Model $model): bool return $model instanceof Embeddings; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { $url = \sprintf('https://%s/openai/deployments/%s/embeddings', $this->baseUrl, $this->deployment); - return new RawHttpResponse($this->httpClient->request('POST', $url, [ + return new RawHttpResult($this->httpClient->request('POST', $url, [ 'headers' => [ 'api-key' => $this->apiKey, ], diff --git a/src/platform/src/Bridge/Azure/OpenAI/GPTModelClient.php b/src/platform/src/Bridge/Azure/OpenAI/GPTModelClient.php index ddfd33e1..7772dee5 100644 --- a/src/platform/src/Bridge/Azure/OpenAI/GPTModelClient.php +++ b/src/platform/src/Bridge/Azure/OpenAI/GPTModelClient.php @@ -15,7 +15,7 @@ use Symfony\AI\Platform\Exception\InvalidArgumentException; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -46,11 +46,11 @@ public function supports(Model $model): bool return $model instanceof GPT; } - public function request(Model $model, object|array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, object|array|string $payload, array $options = []): RawHttpResult { $url = \sprintf('https://%s/openai/deployments/%s/chat/completions', $this->baseUrl, $this->deployment); - return new RawHttpResponse($this->httpClient->request('POST', $url, [ + return new RawHttpResult($this->httpClient->request('POST', $url, [ 'headers' => [ 'api-key' => $this->apiKey, ], diff --git a/src/platform/src/Bridge/Azure/OpenAI/PlatformFactory.php b/src/platform/src/Bridge/Azure/OpenAI/PlatformFactory.php index 9949803e..8b3299ba 100644 --- a/src/platform/src/Bridge/Azure/OpenAI/PlatformFactory.php +++ b/src/platform/src/Bridge/Azure/OpenAI/PlatformFactory.php @@ -12,7 +12,8 @@ namespace Symfony\AI\Platform\Bridge\Azure\OpenAI; use Symfony\AI\Platform\Bridge\OpenAI\Embeddings; -use Symfony\AI\Platform\Bridge\OpenAI\GPT\ResponseConverter; +use Symfony\AI\Platform\Bridge\OpenAI\GPT; +use Symfony\AI\Platform\Bridge\OpenAI\Whisper; use Symfony\AI\Platform\Bridge\OpenAI\Whisper\AudioNormalizer; use Symfony\AI\Platform\Contract; use Symfony\AI\Platform\Platform; @@ -34,13 +35,13 @@ public static function create( ?Contract $contract = null, ): Platform { $httpClient = $httpClient instanceof EventSourceHttpClient ? $httpClient : new EventSourceHttpClient($httpClient); - $embeddingsResponseFactory = new EmbeddingsModelClient($httpClient, $baseUrl, $deployment, $apiVersion, $apiKey); - $GPTResponseFactory = new GPTModelClient($httpClient, $baseUrl, $deployment, $apiVersion, $apiKey); - $whisperResponseFactory = new WhisperModelClient($httpClient, $baseUrl, $deployment, $apiVersion, $apiKey); + $embeddingsModelClient = new EmbeddingsModelClient($httpClient, $baseUrl, $deployment, $apiVersion, $apiKey); + $GPTModelClient = new GPTModelClient($httpClient, $baseUrl, $deployment, $apiVersion, $apiKey); + $whisperModelClient = new WhisperModelClient($httpClient, $baseUrl, $deployment, $apiVersion, $apiKey); return new Platform( - [$GPTResponseFactory, $embeddingsResponseFactory, $whisperResponseFactory], - [new ResponseConverter(), new Embeddings\ResponseConverter(), new \Symfony\AI\Platform\Bridge\OpenAI\Whisper\ResponseConverter()], + [$GPTModelClient, $embeddingsModelClient, $whisperModelClient], + [new GPT\ResultConverter(), new Embeddings\ResultConverter(), new Whisper\ResultConverter()], $contract ?? Contract::create(new AudioNormalizer()), ); } diff --git a/src/platform/src/Bridge/Azure/OpenAI/WhisperModelClient.php b/src/platform/src/Bridge/Azure/OpenAI/WhisperModelClient.php index f488ba1e..09827033 100644 --- a/src/platform/src/Bridge/Azure/OpenAI/WhisperModelClient.php +++ b/src/platform/src/Bridge/Azure/OpenAI/WhisperModelClient.php @@ -16,7 +16,7 @@ use Symfony\AI\Platform\Exception\InvalidArgumentException; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -47,7 +47,7 @@ public function supports(Model $model): bool return $model instanceof Whisper; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { $task = $options['task'] ?? Task::TRANSCRIPTION; $endpoint = Task::TRANSCRIPTION === $task ? 'transcriptions' : 'translations'; @@ -55,7 +55,7 @@ public function request(Model $model, array|string $payload, array $options = [] unset($options['task']); - return new RawHttpResponse($this->httpClient->request('POST', $url, [ + return new RawHttpResult($this->httpClient->request('POST', $url, [ 'headers' => [ 'api-key' => $this->apiKey, 'Content-Type' => 'multipart/form-data', diff --git a/src/platform/src/Bridge/Bedrock/Anthropic/ClaudeModelClient.php b/src/platform/src/Bridge/Bedrock/Anthropic/ClaudeModelClient.php index d7378eed..a8296017 100644 --- a/src/platform/src/Bridge/Bedrock/Anthropic/ClaudeModelClient.php +++ b/src/platform/src/Bridge/Bedrock/Anthropic/ClaudeModelClient.php @@ -15,13 +15,13 @@ use AsyncAws\BedrockRuntime\Input\InvokeModelRequest; use AsyncAws\BedrockRuntime\Result\InvokeModelResponse; use Symfony\AI\Platform\Bridge\Anthropic\Claude; -use Symfony\AI\Platform\Bridge\Bedrock\RawBedrockResponse; +use Symfony\AI\Platform\Bridge\Bedrock\RawBedrockResult; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\Response\ToolCall; -use Symfony\AI\Platform\Response\ToolCallResponse; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\Result\ToolCall; +use Symfony\AI\Platform\Result\ToolCallResult; /** * @author Björn Altmann @@ -39,7 +39,7 @@ public function supports(Model $model): bool return $model instanceof Claude; } - public function request(Model $model, array|string $payload, array $options = []): RawBedrockResponse + public function request(Model $model, array|string $payload, array $options = []): RawBedrockResult { unset($payload['model']); @@ -57,10 +57,10 @@ public function request(Model $model, array|string $payload, array $options = [] 'body' => json_encode(array_merge($options, $payload), \JSON_THROW_ON_ERROR), ]; - return new RawBedrockResponse($this->bedrockRuntimeClient->invokeModel(new InvokeModelRequest($request))); + return new RawBedrockResult($this->bedrockRuntimeClient->invokeModel(new InvokeModelRequest($request))); } - public function convert(InvokeModelResponse $bedrockResponse): ToolCallResponse|TextResponse + public function convert(InvokeModelResponse $bedrockResponse): ToolCallResult|TextResult { $data = json_decode($bedrockResponse->getBody(), true, 512, \JSON_THROW_ON_ERROR); @@ -79,10 +79,10 @@ public function convert(InvokeModelResponse $bedrockResponse): ToolCallResponse| } } if ([] !== $toolCalls) { - return new ToolCallResponse(...$toolCalls); + return new ToolCallResult(...$toolCalls); } - return new TextResponse($data['content'][0]['text']); + return new TextResult($data['content'][0]['text']); } private function getModelId(Model $model): string diff --git a/src/platform/src/Bridge/Bedrock/Anthropic/ClaudeResponseConverter.php b/src/platform/src/Bridge/Bedrock/Anthropic/ClaudeResultConverter.php similarity index 64% rename from src/platform/src/Bridge/Bedrock/Anthropic/ClaudeResponseConverter.php rename to src/platform/src/Bridge/Bedrock/Anthropic/ClaudeResultConverter.php index faf036e8..ab5a1d5c 100644 --- a/src/platform/src/Bridge/Bedrock/Anthropic/ClaudeResponseConverter.php +++ b/src/platform/src/Bridge/Bedrock/Anthropic/ClaudeResultConverter.php @@ -12,28 +12,28 @@ namespace Symfony\AI\Platform\Bridge\Bedrock\Anthropic; use Symfony\AI\Platform\Bridge\Anthropic\Claude; -use Symfony\AI\Platform\Bridge\Bedrock\RawBedrockResponse; +use Symfony\AI\Platform\Bridge\Bedrock\RawBedrockResult; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\Response\ToolCall; -use Symfony\AI\Platform\Response\ToolCallResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\Result\ToolCall; +use Symfony\AI\Platform\Result\ToolCallResult; +use Symfony\AI\Platform\ResultConverterInterface; /** * @author Björn Altmann */ -final readonly class ClaudeResponseConverter implements ResponseConverterInterface +final readonly class ClaudeResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return $model instanceof Claude; } - public function convert(RawResponseInterface|RawBedrockResponse $response, array $options = []): ToolCallResponse|TextResponse + public function convert(RawResultInterface|RawBedrockResult $result, array $options = []): ToolCallResult|TextResult { - $data = $response->getRawData(); + $data = $result->getData(); if (!isset($data['content']) || [] === $data['content']) { throw new RuntimeException('Response does not contain any content'); @@ -50,9 +50,9 @@ public function convert(RawResponseInterface|RawBedrockResponse $response, array } } if ([] !== $toolCalls) { - return new ToolCallResponse(...$toolCalls); + return new ToolCallResult(...$toolCalls); } - return new TextResponse($data['content'][0]['text']); + return new TextResult($data['content'][0]['text']); } } diff --git a/src/platform/src/Bridge/Bedrock/Meta/LlamaModelClient.php b/src/platform/src/Bridge/Bedrock/Meta/LlamaModelClient.php index c2253d38..2607b83e 100644 --- a/src/platform/src/Bridge/Bedrock/Meta/LlamaModelClient.php +++ b/src/platform/src/Bridge/Bedrock/Meta/LlamaModelClient.php @@ -13,7 +13,7 @@ use AsyncAws\BedrockRuntime\BedrockRuntimeClient; use AsyncAws\BedrockRuntime\Input\InvokeModelRequest; -use Symfony\AI\Platform\Bridge\Bedrock\RawBedrockResponse; +use Symfony\AI\Platform\Bridge\Bedrock\RawBedrockResult; use Symfony\AI\Platform\Bridge\Meta\Llama; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; @@ -33,9 +33,9 @@ public function supports(Model $model): bool return $model instanceof Llama; } - public function request(Model $model, array|string $payload, array $options = []): RawBedrockResponse + public function request(Model $model, array|string $payload, array $options = []): RawBedrockResult { - return new RawBedrockResponse($this->bedrockRuntimeClient->invokeModel(new InvokeModelRequest([ + return new RawBedrockResult($this->bedrockRuntimeClient->invokeModel(new InvokeModelRequest([ 'modelId' => $this->getModelId($model), 'contentType' => 'application/json', 'body' => json_encode($payload, \JSON_THROW_ON_ERROR), diff --git a/src/platform/src/Bridge/Bedrock/Meta/LlamaResponseConverter.php b/src/platform/src/Bridge/Bedrock/Meta/LlamaResultConverter.php similarity index 59% rename from src/platform/src/Bridge/Bedrock/Meta/LlamaResponseConverter.php rename to src/platform/src/Bridge/Bedrock/Meta/LlamaResultConverter.php index e9abf162..3f01e24a 100644 --- a/src/platform/src/Bridge/Bedrock/Meta/LlamaResponseConverter.php +++ b/src/platform/src/Bridge/Bedrock/Meta/LlamaResultConverter.php @@ -11,32 +11,32 @@ namespace Symfony\AI\Platform\Bridge\Bedrock\Meta; -use Symfony\AI\Platform\Bridge\Bedrock\RawBedrockResponse; +use Symfony\AI\Platform\Bridge\Bedrock\RawBedrockResult; use Symfony\AI\Platform\Bridge\Meta\Llama; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\ResultConverterInterface; /** * @author Björn Altmann */ -class LlamaResponseConverter implements ResponseConverterInterface +class LlamaResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return $model instanceof Llama; } - public function convert(RawResponseInterface|RawBedrockResponse $response, array $options = []): TextResponse + public function convert(RawResultInterface|RawBedrockResult $result, array $options = []): TextResult { - $data = $response->getRawData(); + $data = $result->getData(); if (!isset($data['generation'])) { throw new RuntimeException('Response does not contain any content'); } - return new TextResponse($data['generation']); + return new TextResult($data['generation']); } } diff --git a/src/platform/src/Bridge/Bedrock/Nova/Contract/AssistantMessageNormalizer.php b/src/platform/src/Bridge/Bedrock/Nova/Contract/AssistantMessageNormalizer.php index fce0b061..a7b20774 100644 --- a/src/platform/src/Bridge/Bedrock/Nova/Contract/AssistantMessageNormalizer.php +++ b/src/platform/src/Bridge/Bedrock/Nova/Contract/AssistantMessageNormalizer.php @@ -15,7 +15,7 @@ use Symfony\AI\Platform\Contract\Normalizer\ModelContractNormalizer; use Symfony\AI\Platform\Message\AssistantMessage; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; /** * @author Christopher Hertel diff --git a/src/platform/src/Bridge/Bedrock/Nova/NovaModelClient.php b/src/platform/src/Bridge/Bedrock/Nova/NovaModelClient.php index 9f6a9f0b..a1990da6 100644 --- a/src/platform/src/Bridge/Bedrock/Nova/NovaModelClient.php +++ b/src/platform/src/Bridge/Bedrock/Nova/NovaModelClient.php @@ -13,7 +13,7 @@ use AsyncAws\BedrockRuntime\BedrockRuntimeClient; use AsyncAws\BedrockRuntime\Input\InvokeModelRequest; -use Symfony\AI\Platform\Bridge\Bedrock\RawBedrockResponse; +use Symfony\AI\Platform\Bridge\Bedrock\RawBedrockResult; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; @@ -32,7 +32,7 @@ public function supports(Model $model): bool return $model instanceof Nova; } - public function request(Model $model, array|string $payload, array $options = []): RawBedrockResponse + public function request(Model $model, array|string $payload, array $options = []): RawBedrockResult { $modelOptions = []; if (isset($options['tools'])) { @@ -53,7 +53,7 @@ public function request(Model $model, array|string $payload, array $options = [] 'body' => json_encode(array_merge($payload, $modelOptions), \JSON_THROW_ON_ERROR), ]; - return new RawBedrockResponse($this->bedrockRuntimeClient->invokeModel(new InvokeModelRequest($request))); + return new RawBedrockResult($this->bedrockRuntimeClient->invokeModel(new InvokeModelRequest($request))); } private function getModelId(Model $model): string diff --git a/src/platform/src/Bridge/Bedrock/Nova/NovaResponseConverter.php b/src/platform/src/Bridge/Bedrock/Nova/NovaResultConverter.php similarity index 63% rename from src/platform/src/Bridge/Bedrock/Nova/NovaResponseConverter.php rename to src/platform/src/Bridge/Bedrock/Nova/NovaResultConverter.php index 9c276b71..438093b8 100644 --- a/src/platform/src/Bridge/Bedrock/Nova/NovaResponseConverter.php +++ b/src/platform/src/Bridge/Bedrock/Nova/NovaResultConverter.php @@ -11,28 +11,28 @@ namespace Symfony\AI\Platform\Bridge\Bedrock\Nova; -use Symfony\AI\Platform\Bridge\Bedrock\RawBedrockResponse; +use Symfony\AI\Platform\Bridge\Bedrock\RawBedrockResult; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\Response\ToolCall; -use Symfony\AI\Platform\Response\ToolCallResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\Result\ToolCall; +use Symfony\AI\Platform\Result\ToolCallResult; +use Symfony\AI\Platform\ResultConverterInterface; /** * @author Björn Altmann */ -class NovaResponseConverter implements ResponseConverterInterface +class NovaResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return $model instanceof Nova; } - public function convert(RawResponseInterface|RawBedrockResponse $response, array $options = []): ToolCallResponse|TextResponse + public function convert(RawResultInterface|RawBedrockResult $result, array $options = []): ToolCallResult|TextResult { - $data = $response->getRawData(); + $data = $result->getData(); if (!isset($data['output']) || [] === $data['output']) { throw new RuntimeException('Response does not contain any content'); @@ -49,9 +49,9 @@ public function convert(RawResponseInterface|RawBedrockResponse $response, array } } if ([] !== $toolCalls) { - return new ToolCallResponse(...$toolCalls); + return new ToolCallResult(...$toolCalls); } - return new TextResponse($data['output']['message']['content'][0]['text']); + return new TextResult($data['output']['message']['content'][0]['text']); } } diff --git a/src/platform/src/Bridge/Bedrock/PlatformFactory.php b/src/platform/src/Bridge/Bedrock/PlatformFactory.php index b53e6b74..3df89141 100644 --- a/src/platform/src/Bridge/Bedrock/PlatformFactory.php +++ b/src/platform/src/Bridge/Bedrock/PlatformFactory.php @@ -14,12 +14,12 @@ use AsyncAws\BedrockRuntime\BedrockRuntimeClient; use Symfony\AI\Platform\Bridge\Anthropic\Contract as AnthropicContract; use Symfony\AI\Platform\Bridge\Bedrock\Anthropic\ClaudeModelClient; -use Symfony\AI\Platform\Bridge\Bedrock\Anthropic\ClaudeResponseConverter; +use Symfony\AI\Platform\Bridge\Bedrock\Anthropic\ClaudeResultConverter; use Symfony\AI\Platform\Bridge\Bedrock\Meta\LlamaModelClient; -use Symfony\AI\Platform\Bridge\Bedrock\Meta\LlamaResponseConverter; +use Symfony\AI\Platform\Bridge\Bedrock\Meta\LlamaResultConverter; use Symfony\AI\Platform\Bridge\Bedrock\Nova\Contract as NovaContract; use Symfony\AI\Platform\Bridge\Bedrock\Nova\NovaModelClient; -use Symfony\AI\Platform\Bridge\Bedrock\Nova\NovaResponseConverter; +use Symfony\AI\Platform\Bridge\Bedrock\Nova\NovaResultConverter; use Symfony\AI\Platform\Bridge\Meta\Contract as LlamaContract; use Symfony\AI\Platform\Contract; use Symfony\AI\Platform\Exception\RuntimeException; @@ -45,9 +45,9 @@ public static function create( new NovaModelClient($bedrockRuntimeClient), ], [ - new ClaudeResponseConverter(), - new LlamaResponseConverter(), - new NovaResponseConverter(), + new ClaudeResultConverter(), + new LlamaResultConverter(), + new NovaResultConverter(), ], $contract ?? Contract::create( new AnthropicContract\AssistantMessageNormalizer(), diff --git a/src/platform/src/Bridge/Bedrock/RawBedrockResponse.php b/src/platform/src/Bridge/Bedrock/RawBedrockResult.php similarity index 75% rename from src/platform/src/Bridge/Bedrock/RawBedrockResponse.php rename to src/platform/src/Bridge/Bedrock/RawBedrockResult.php index b86b6a5f..7e3fad83 100644 --- a/src/platform/src/Bridge/Bedrock/RawBedrockResponse.php +++ b/src/platform/src/Bridge/Bedrock/RawBedrockResult.php @@ -12,24 +12,24 @@ namespace Symfony\AI\Platform\Bridge\Bedrock; use AsyncAws\BedrockRuntime\Result\InvokeModelResponse; -use Symfony\AI\Platform\Response\RawResponseInterface; +use Symfony\AI\Platform\Result\RawResultInterface; /** * @author Christopher Hertel */ -final readonly class RawBedrockResponse implements RawResponseInterface +final readonly class RawBedrockResult implements RawResultInterface { public function __construct( private InvokeModelResponse $invokeModelResponse, ) { } - public function getRawData(): array + public function getData(): array { return json_decode($this->invokeModelResponse->getBody(), true, 512, \JSON_THROW_ON_ERROR); } - public function getRawObject(): InvokeModelResponse + public function getObject(): InvokeModelResponse { return $this->invokeModelResponse; } diff --git a/src/platform/src/Bridge/Google/Contract/ToolCallMessageNormalizer.php b/src/platform/src/Bridge/Google/Contract/ToolCallMessageNormalizer.php index 1bb4d375..7056b62d 100644 --- a/src/platform/src/Bridge/Google/Contract/ToolCallMessageNormalizer.php +++ b/src/platform/src/Bridge/Google/Contract/ToolCallMessageNormalizer.php @@ -44,14 +44,14 @@ protected function supportsModel(Model $model): bool */ public function normalize(mixed $data, ?string $format = null, array $context = []): array { - $responseContent = json_validate($data->content) ? json_decode($data->content, true) : $data->content; + $resultContent = json_validate($data->content) ? json_decode($data->content, true) : $data->content; return [[ 'functionResponse' => array_filter([ 'id' => $data->toolCall->id, 'name' => $data->toolCall->name, - 'response' => \is_array($responseContent) ? $responseContent : [ - 'rawResponse' => $responseContent, // Gemini expects the response to be an object, but not everyone uses objects as their responses. + 'response' => \is_array($resultContent) ? $resultContent : [ + 'rawResponse' => $resultContent, // Gemini expects the response to be an object, but not everyone uses objects as their responses. ], ]), ]]; diff --git a/src/platform/src/Bridge/Google/Embeddings/ModelClient.php b/src/platform/src/Bridge/Google/Embeddings/ModelClient.php index 41186ef2..14ebd26e 100644 --- a/src/platform/src/Bridge/Google/Embeddings/ModelClient.php +++ b/src/platform/src/Bridge/Google/Embeddings/ModelClient.php @@ -14,7 +14,7 @@ use Symfony\AI\Platform\Bridge\Google\Embeddings; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Contracts\HttpClient\HttpClientInterface; /** @@ -34,12 +34,12 @@ public function supports(Model $model): bool return $model instanceof Embeddings; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { $url = \sprintf('https://generativelanguage.googleapis.com/v1beta/models/%s:%s', $model->getName(), 'batchEmbedContents'); $modelOptions = $model->getOptions(); - return new RawHttpResponse($this->httpClient->request('POST', $url, [ + return new RawHttpResult($this->httpClient->request('POST', $url, [ 'headers' => [ 'x-goog-api-key' => $this->apiKey, ], diff --git a/src/platform/src/Bridge/Google/Embeddings/ResponseConverter.php b/src/platform/src/Bridge/Google/Embeddings/ResultConverter.php similarity index 69% rename from src/platform/src/Bridge/Google/Embeddings/ResponseConverter.php rename to src/platform/src/Bridge/Google/Embeddings/ResultConverter.php index 67bfcb1c..5ba44de3 100644 --- a/src/platform/src/Bridge/Google/Embeddings/ResponseConverter.php +++ b/src/platform/src/Bridge/Google/Embeddings/ResultConverter.php @@ -14,30 +14,30 @@ use Symfony\AI\Platform\Bridge\Google\Embeddings; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\VectorResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\VectorResult; +use Symfony\AI\Platform\ResultConverterInterface; use Symfony\AI\Platform\Vector\Vector; /** * @author Valtteri R */ -final readonly class ResponseConverter implements ResponseConverterInterface +final readonly class ResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return $model instanceof Embeddings; } - public function convert(RawResponseInterface $response, array $options = []): VectorResponse + public function convert(RawResultInterface $result, array $options = []): VectorResult { - $data = $response->getRawData(); + $data = $result->getData(); if (!isset($data['embeddings'])) { throw new RuntimeException('Response does not contain data'); } - return new VectorResponse( + return new VectorResult( ...array_map( static fn (array $item): Vector => new Vector($item['values']), $data['embeddings'], diff --git a/src/platform/src/Bridge/Google/Gemini/ModelClient.php b/src/platform/src/Bridge/Google/Gemini/ModelClient.php index 871fd2b2..3ba08ae5 100644 --- a/src/platform/src/Bridge/Google/Gemini/ModelClient.php +++ b/src/platform/src/Bridge/Google/Gemini/ModelClient.php @@ -14,7 +14,7 @@ use Symfony\AI\Platform\Bridge\Google\Gemini; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -41,7 +41,7 @@ public function supports(Model $model): bool /** * @throws TransportExceptionInterface */ - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { $url = \sprintf( 'https://generativelanguage.googleapis.com/v1beta/models/%s:%s', @@ -73,7 +73,7 @@ public function request(Model $model, array|string $payload, array $options = [] $generationConfig['tools'][] = [$tool => true === $params ? new \ArrayObject() : $params]; } - return new RawHttpResponse($this->httpClient->request('POST', $url, [ + return new RawHttpResult($this->httpClient->request('POST', $url, [ 'headers' => [ 'x-goog-api-key' => $this->apiKey, ], diff --git a/src/platform/src/Bridge/Google/Gemini/ResponseConverter.php b/src/platform/src/Bridge/Google/Gemini/ResultConverter.php similarity index 74% rename from src/platform/src/Bridge/Google/Gemini/ResponseConverter.php rename to src/platform/src/Bridge/Google/Gemini/ResultConverter.php index adc5547e..560240c4 100644 --- a/src/platform/src/Bridge/Google/Gemini/ResponseConverter.php +++ b/src/platform/src/Bridge/Google/Gemini/ResultConverter.php @@ -14,36 +14,36 @@ use Symfony\AI\Platform\Bridge\Google\Gemini; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\Choice; -use Symfony\AI\Platform\Response\ChoiceResponse; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\Response\StreamResponse; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\Response\ToolCall; -use Symfony\AI\Platform\Response\ToolCallResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\Choice; +use Symfony\AI\Platform\Result\ChoiceResult; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\Result\StreamResult; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\Result\ToolCall; +use Symfony\AI\Platform\Result\ToolCallResult; +use Symfony\AI\Platform\ResultConverterInterface; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Contracts\HttpClient\ResponseInterface as HttpResponse; /** * @author Roy Garrido */ -final readonly class ResponseConverter implements ResponseConverterInterface +final readonly class ResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return $model instanceof Gemini; } - public function convert(RawResponseInterface|RawHttpResponse $response, array $options = []): ResponseInterface + public function convert(RawResultInterface|RawHttpResult $result, array $options = []): ResultInterface { if ($options['stream'] ?? false) { - return new StreamResponse($this->convertStream($response->getRawObject())); + return new StreamResult($this->convertStream($result->getObject())); } - $data = $response->getRawData(); + $data = $result->getData(); if (!isset($data['candidates'][0]['content']['parts'][0])) { throw new RuntimeException('Response does not contain any content'); @@ -53,19 +53,19 @@ public function convert(RawResponseInterface|RawHttpResponse $response, array $o $choices = array_map($this->convertChoice(...), $data['candidates']); if (1 !== \count($choices)) { - return new ChoiceResponse(...$choices); + return new ChoiceResult(...$choices); } if ($choices[0]->hasToolCall()) { - return new ToolCallResponse(...$choices[0]->getToolCalls()); + return new ToolCallResult(...$choices[0]->getToolCalls()); } - return new TextResponse($choices[0]->getContent()); + return new TextResult($choices[0]->getContent()); } - private function convertStream(HttpResponse $response): \Generator + private function convertStream(HttpResponse $result): \Generator { - foreach ((new EventSourceHttpClient())->stream($response) as $chunk) { + foreach ((new EventSourceHttpClient())->stream($result) as $chunk) { if ($chunk->isFirst() || $chunk->isLast()) { continue; } @@ -102,12 +102,12 @@ private function convertStream(HttpResponse $response): \Generator } if (1 !== \count($choices)) { - yield new ChoiceResponse(...$choices); + yield new ChoiceResult(...$choices); continue; } if ($choices[0]->hasToolCall()) { - yield new ToolCallResponse(...$choices[0]->getToolCalls()); + yield new ToolCallResult(...$choices[0]->getToolCalls()); } if ($choices[0]->hasContent()) { diff --git a/src/platform/src/Bridge/Google/PlatformFactory.php b/src/platform/src/Bridge/Google/PlatformFactory.php index afa61869..9213f3e8 100644 --- a/src/platform/src/Bridge/Google/PlatformFactory.php +++ b/src/platform/src/Bridge/Google/PlatformFactory.php @@ -13,9 +13,9 @@ use Symfony\AI\Platform\Bridge\Google\Contract\GoogleContract; use Symfony\AI\Platform\Bridge\Google\Embeddings\ModelClient as EmbeddingsModelClient; -use Symfony\AI\Platform\Bridge\Google\Embeddings\ResponseConverter as EmbeddingsResponseConverter; +use Symfony\AI\Platform\Bridge\Google\Embeddings\ResultConverter as EmbeddingsResultConverter; use Symfony\AI\Platform\Bridge\Google\Gemini\ModelClient as GeminiModelClient; -use Symfony\AI\Platform\Bridge\Google\Gemini\ResponseConverter as GeminiResponseConverter; +use Symfony\AI\Platform\Bridge\Google\Gemini\ResultConverter as GeminiResultConverter; use Symfony\AI\Platform\Contract; use Symfony\AI\Platform\Platform; use Symfony\Component\HttpClient\EventSourceHttpClient; @@ -36,7 +36,7 @@ public static function create( return new Platform( [new EmbeddingsModelClient($httpClient, $apiKey), new GeminiModelClient($httpClient, $apiKey)], - [new EmbeddingsResponseConverter(), new GeminiResponseConverter()], + [new EmbeddingsResultConverter(), new GeminiResultConverter()], $contract ?? GoogleContract::create(), ); } diff --git a/src/platform/src/Bridge/HuggingFace/ApiClient.php b/src/platform/src/Bridge/HuggingFace/ApiClient.php index 4a73325e..97f0f384 100644 --- a/src/platform/src/Bridge/HuggingFace/ApiClient.php +++ b/src/platform/src/Bridge/HuggingFace/ApiClient.php @@ -31,13 +31,13 @@ public function __construct( */ public function models(?string $provider, ?string $task): array { - $response = $this->httpClient->request('GET', 'https://huggingface.co/api/models', [ + $result = $this->httpClient->request('GET', 'https://huggingface.co/api/models', [ 'query' => [ 'inference_provider' => $provider, 'pipeline_tag' => $task, ], ]); - return array_map(fn (array $model) => new Model($model['id']), $response->toArray()); + return array_map(fn (array $model) => new Model($model['id']), $result->toArray()); } } diff --git a/src/platform/src/Bridge/HuggingFace/ModelClient.php b/src/platform/src/Bridge/HuggingFace/ModelClient.php index e9bb1f80..783e76ab 100644 --- a/src/platform/src/Bridge/HuggingFace/ModelClient.php +++ b/src/platform/src/Bridge/HuggingFace/ModelClient.php @@ -13,7 +13,7 @@ use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface as PlatformModelClient; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -41,13 +41,13 @@ public function supports(Model $model): bool /** * The difference in HuggingFace here is that we treat the payload as the options for the request not only the body. */ - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { // Extract task from options if provided $task = $options['task'] ?? null; unset($options['task']); - return new RawHttpResponse($this->httpClient->request('POST', $this->getUrl($model, $task), [ + return new RawHttpResult($this->httpClient->request('POST', $this->getUrl($model, $task), [ 'auth_bearer' => $this->apiKey, ...$this->getPayload($payload, $options), ])); diff --git a/src/platform/src/Bridge/HuggingFace/PlatformFactory.php b/src/platform/src/Bridge/HuggingFace/PlatformFactory.php index 75850141..cd1c6605 100644 --- a/src/platform/src/Bridge/HuggingFace/PlatformFactory.php +++ b/src/platform/src/Bridge/HuggingFace/PlatformFactory.php @@ -34,7 +34,7 @@ public static function create( return new Platform( [new ModelClient($httpClient, $provider, $apiKey)], - [new ResponseConverter()], + [new ResultConverter()], $contract ?? Contract::create( new FileNormalizer(), new MessageBagNormalizer(), diff --git a/src/platform/src/Bridge/HuggingFace/ResponseConverter.php b/src/platform/src/Bridge/HuggingFace/ResultConverter.php similarity index 55% rename from src/platform/src/Bridge/HuggingFace/ResponseConverter.php rename to src/platform/src/Bridge/HuggingFace/ResultConverter.php index d4bc10f1..c8d7519e 100644 --- a/src/platform/src/Bridge/HuggingFace/ResponseConverter.php +++ b/src/platform/src/Bridge/HuggingFace/ResultConverter.php @@ -23,29 +23,29 @@ use Symfony\AI\Platform\Exception\InvalidArgumentException; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\BinaryResponse; -use Symfony\AI\Platform\Response\ObjectResponse; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\Response\VectorResponse; -use Symfony\AI\Platform\ResponseConverterInterface as PlatformResponseConverter; +use Symfony\AI\Platform\Result\BinaryResult; +use Symfony\AI\Platform\Result\ObjectResult; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\Result\VectorResult; +use Symfony\AI\Platform\ResultConverterInterface as PlatformResponseConverter; use Symfony\AI\Platform\Vector\Vector; /** * @author Christopher Hertel */ -final readonly class ResponseConverter implements PlatformResponseConverter +final readonly class ResultConverter implements PlatformResponseConverter { public function supports(Model $model): bool { return true; } - public function convert(RawResponseInterface|RawHttpResponse $response, array $options = []): ResponseInterface + public function convert(RawResultInterface|RawHttpResult $result, array $options = []): ResultInterface { - $httpResponse = $response->getRawObject(); + $httpResponse = $result->getObject(); if (503 === $httpResponse->getStatusCode()) { return throw new RuntimeException('Service unavailable.'); } @@ -72,25 +72,25 @@ public function convert(RawResponseInterface|RawHttpResponse $response, array $o $task = $options['task'] ?? null; return match ($task) { - Task::AUDIO_CLASSIFICATION, Task::IMAGE_CLASSIFICATION => new ObjectResponse( + Task::AUDIO_CLASSIFICATION, Task::IMAGE_CLASSIFICATION => new ObjectResult( ClassificationResult::fromArray($content) ), - Task::AUTOMATIC_SPEECH_RECOGNITION => new TextResponse($content['text'] ?? ''), - Task::CHAT_COMPLETION => new TextResponse($content['choices'][0]['message']['content'] ?? ''), - Task::FEATURE_EXTRACTION => new VectorResponse(new Vector($content)), - Task::TEXT_CLASSIFICATION => new ObjectResponse(ClassificationResult::fromArray(reset($content) ?? [])), - Task::FILL_MASK => new ObjectResponse(FillMaskResult::fromArray($content)), - Task::IMAGE_SEGMENTATION => new ObjectResponse(ImageSegmentationResult::fromArray($content)), - Task::IMAGE_TO_TEXT, Task::TEXT_GENERATION => new TextResponse($content[0]['generated_text'] ?? ''), - Task::TEXT_TO_IMAGE => new BinaryResponse($content, $contentType), - Task::OBJECT_DETECTION => new ObjectResponse(ObjectDetectionResult::fromArray($content)), - Task::QUESTION_ANSWERING => new ObjectResponse(QuestionAnsweringResult::fromArray($content)), - Task::SENTENCE_SIMILARITY => new ObjectResponse(SentenceSimilarityResult::fromArray($content)), - Task::SUMMARIZATION => new TextResponse($content[0]['summary_text']), - Task::TABLE_QUESTION_ANSWERING => new ObjectResponse(TableQuestionAnsweringResult::fromArray($content)), - Task::TOKEN_CLASSIFICATION => new ObjectResponse(TokenClassificationResult::fromArray($content)), - Task::TRANSLATION => new TextResponse($content[0]['translation_text'] ?? ''), - Task::ZERO_SHOT_CLASSIFICATION => new ObjectResponse(ZeroShotClassificationResult::fromArray($content)), + Task::AUTOMATIC_SPEECH_RECOGNITION => new TextResult($content['text'] ?? ''), + Task::CHAT_COMPLETION => new TextResult($content['choices'][0]['message']['content'] ?? ''), + Task::FEATURE_EXTRACTION => new VectorResult(new Vector($content)), + Task::TEXT_CLASSIFICATION => new ObjectResult(ClassificationResult::fromArray(reset($content) ?? [])), + Task::FILL_MASK => new ObjectResult(FillMaskResult::fromArray($content)), + Task::IMAGE_SEGMENTATION => new ObjectResult(ImageSegmentationResult::fromArray($content)), + Task::IMAGE_TO_TEXT, Task::TEXT_GENERATION => new TextResult($content[0]['generated_text'] ?? ''), + Task::TEXT_TO_IMAGE => new BinaryResult($content, $contentType), + Task::OBJECT_DETECTION => new ObjectResult(ObjectDetectionResult::fromArray($content)), + Task::QUESTION_ANSWERING => new ObjectResult(QuestionAnsweringResult::fromArray($content)), + Task::SENTENCE_SIMILARITY => new ObjectResult(SentenceSimilarityResult::fromArray($content)), + Task::SUMMARIZATION => new TextResult($content[0]['summary_text']), + Task::TABLE_QUESTION_ANSWERING => new ObjectResult(TableQuestionAnsweringResult::fromArray($content)), + Task::TOKEN_CLASSIFICATION => new ObjectResult(TokenClassificationResult::fromArray($content)), + Task::TRANSLATION => new TextResult($content[0]['translation_text'] ?? ''), + Task::ZERO_SHOT_CLASSIFICATION => new ObjectResult(ZeroShotClassificationResult::fromArray($content)), default => throw new RuntimeException(\sprintf('Unsupported task: %s', $task)), }; diff --git a/src/platform/src/Bridge/LMStudio/Completions/ModelClient.php b/src/platform/src/Bridge/LMStudio/Completions/ModelClient.php index d6674592..f164b0ca 100644 --- a/src/platform/src/Bridge/LMStudio/Completions/ModelClient.php +++ b/src/platform/src/Bridge/LMStudio/Completions/ModelClient.php @@ -14,7 +14,7 @@ use Symfony\AI\Platform\Bridge\LMStudio\Completions; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface as PlatformResponseFactory; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -37,9 +37,9 @@ public function supports(Model $model): bool return $model instanceof Completions; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { - return new RawHttpResponse($this->httpClient->request('POST', \sprintf('%s/v1/chat/completions', $this->hostUrl), [ + return new RawHttpResult($this->httpClient->request('POST', \sprintf('%s/v1/chat/completions', $this->hostUrl), [ 'json' => array_merge($options, $payload), ])); } diff --git a/src/platform/src/Bridge/LMStudio/Completions/ResponseConverter.php b/src/platform/src/Bridge/LMStudio/Completions/ResultConverter.php similarity index 59% rename from src/platform/src/Bridge/LMStudio/Completions/ResponseConverter.php rename to src/platform/src/Bridge/LMStudio/Completions/ResultConverter.php index bfeb69f9..bb888fef 100644 --- a/src/platform/src/Bridge/LMStudio/Completions/ResponseConverter.php +++ b/src/platform/src/Bridge/LMStudio/Completions/ResultConverter.php @@ -12,16 +12,16 @@ namespace Symfony\AI\Platform\Bridge\LMStudio\Completions; use Symfony\AI\Platform\Bridge\LMStudio\Completions; -use Symfony\AI\Platform\Bridge\OpenAI\GPT\ResponseConverter as OpenAIResponseConverter; +use Symfony\AI\Platform\Bridge\OpenAI\GPT\ResultConverter as OpenAIResponseConverter; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\ResultConverterInterface; /** * @author André Lubian */ -final class ResponseConverter implements ResponseConverterInterface +final class ResultConverter implements ResultConverterInterface { public function __construct( private readonly OpenAIResponseConverter $gptResponseConverter = new OpenAIResponseConverter(), @@ -33,8 +33,8 @@ public function supports(Model $model): bool return $model instanceof Completions; } - public function convert(RawResponseInterface $response, array $options = []): ResponseInterface + public function convert(RawResultInterface $result, array $options = []): ResultInterface { - return $this->gptResponseConverter->convert($response, $options); + return $this->gptResponseConverter->convert($result, $options); } } diff --git a/src/platform/src/Bridge/LMStudio/Embeddings/ModelClient.php b/src/platform/src/Bridge/LMStudio/Embeddings/ModelClient.php index f00d6183..6aad6886 100644 --- a/src/platform/src/Bridge/LMStudio/Embeddings/ModelClient.php +++ b/src/platform/src/Bridge/LMStudio/Embeddings/ModelClient.php @@ -14,7 +14,7 @@ use Symfony\AI\Platform\Bridge\LMStudio\Embeddings; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface as PlatformResponseFactory; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Contracts\HttpClient\HttpClientInterface; /** @@ -34,9 +34,9 @@ public function supports(Model $model): bool return $model instanceof Embeddings; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { - return new RawHttpResponse($this->httpClient->request('POST', \sprintf('%s/v1/embeddings', $this->hostUrl), [ + return new RawHttpResult($this->httpClient->request('POST', \sprintf('%s/v1/embeddings', $this->hostUrl), [ 'json' => array_merge($options, [ 'model' => $model->getName(), 'input' => $payload, diff --git a/src/platform/src/Bridge/LMStudio/Embeddings/ResponseConverter.php b/src/platform/src/Bridge/LMStudio/Embeddings/ResultConverter.php similarity index 71% rename from src/platform/src/Bridge/LMStudio/Embeddings/ResponseConverter.php rename to src/platform/src/Bridge/LMStudio/Embeddings/ResultConverter.php index 5c671a3c..fcf7a145 100644 --- a/src/platform/src/Bridge/LMStudio/Embeddings/ResponseConverter.php +++ b/src/platform/src/Bridge/LMStudio/Embeddings/ResultConverter.php @@ -14,31 +14,31 @@ use Symfony\AI\Platform\Bridge\LMStudio\Embeddings; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\VectorResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\VectorResult; +use Symfony\AI\Platform\ResultConverterInterface; use Symfony\AI\Platform\Vector\Vector; /** * @author Christopher Hertel * @author André Lubian */ -final class ResponseConverter implements ResponseConverterInterface +final class ResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return $model instanceof Embeddings; } - public function convert(RawResponseInterface $response, array $options = []): VectorResponse + public function convert(RawResultInterface $result, array $options = []): VectorResult { - $data = $response->getRawData(); + $data = $result->getData(); if (!isset($data['data'])) { throw new RuntimeException('Response does not contain data'); } - return new VectorResponse( + return new VectorResult( ...array_map( static fn (array $item): Vector => new Vector($item['embedding']), $data['data'] diff --git a/src/platform/src/Bridge/LMStudio/PlatformFactory.php b/src/platform/src/Bridge/LMStudio/PlatformFactory.php index e9cb0b16..740f7608 100644 --- a/src/platform/src/Bridge/LMStudio/PlatformFactory.php +++ b/src/platform/src/Bridge/LMStudio/PlatformFactory.php @@ -35,8 +35,8 @@ public static function create( new Completions\ModelClient($httpClient, $hostUrl), ], [ - new Embeddings\ResponseConverter(), - new Completions\ResponseConverter(), + new Embeddings\ResultConverter(), + new Completions\ResultConverter(), ], $contract); } } diff --git a/src/platform/src/Bridge/Mistral/Embeddings/ModelClient.php b/src/platform/src/Bridge/Mistral/Embeddings/ModelClient.php index a5cb2385..5a2be7f9 100644 --- a/src/platform/src/Bridge/Mistral/Embeddings/ModelClient.php +++ b/src/platform/src/Bridge/Mistral/Embeddings/ModelClient.php @@ -14,7 +14,7 @@ use Symfony\AI\Platform\Bridge\Mistral\Embeddings; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -38,9 +38,9 @@ public function supports(Model $model): bool return $model instanceof Embeddings; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { - return new RawHttpResponse($this->httpClient->request('POST', 'https://api.mistral.ai/v1/embeddings', [ + return new RawHttpResult($this->httpClient->request('POST', 'https://api.mistral.ai/v1/embeddings', [ 'auth_bearer' => $this->apiKey, 'headers' => [ 'Content-Type' => 'application/json', diff --git a/src/platform/src/Bridge/Mistral/Embeddings/ResponseConverter.php b/src/platform/src/Bridge/Mistral/Embeddings/ResultConverter.php similarity index 69% rename from src/platform/src/Bridge/Mistral/Embeddings/ResponseConverter.php rename to src/platform/src/Bridge/Mistral/Embeddings/ResultConverter.php index e99029e6..32710f67 100644 --- a/src/platform/src/Bridge/Mistral/Embeddings/ResponseConverter.php +++ b/src/platform/src/Bridge/Mistral/Embeddings/ResultConverter.php @@ -14,37 +14,37 @@ use Symfony\AI\Platform\Bridge\Mistral\Embeddings; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\VectorResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\VectorResult; +use Symfony\AI\Platform\ResultConverterInterface; use Symfony\AI\Platform\Vector\Vector; /** * @author Christopher Hertel */ -final readonly class ResponseConverter implements ResponseConverterInterface +final readonly class ResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return $model instanceof Embeddings; } - public function convert(RawResponseInterface|RawHttpResponse $response, array $options = []): VectorResponse + public function convert(RawResultInterface|RawHttpResult $result, array $options = []): VectorResult { - $httpResponse = $response->getRawObject(); + $httpResponse = $result->getObject(); if (200 !== $httpResponse->getStatusCode()) { throw new RuntimeException(\sprintf('Unexpected response code %d: %s', $httpResponse->getStatusCode(), $httpResponse->getContent(false))); } - $data = $response->getRawData(); + $data = $result->getData(); if (!isset($data['data'])) { throw new RuntimeException('Response does not contain data'); } - return new VectorResponse( + return new VectorResult( ...array_map( static fn (array $item): Vector => new Vector($item['embedding']), $data['data'] diff --git a/src/platform/src/Bridge/Mistral/Llm/ModelClient.php b/src/platform/src/Bridge/Mistral/Llm/ModelClient.php index b8e3e5f0..a6b87233 100644 --- a/src/platform/src/Bridge/Mistral/Llm/ModelClient.php +++ b/src/platform/src/Bridge/Mistral/Llm/ModelClient.php @@ -14,7 +14,7 @@ use Symfony\AI\Platform\Bridge\Mistral\Mistral; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -38,9 +38,9 @@ public function supports(Model $model): bool return $model instanceof Mistral; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { - return new RawHttpResponse($this->httpClient->request('POST', 'https://api.mistral.ai/v1/chat/completions', [ + return new RawHttpResult($this->httpClient->request('POST', 'https://api.mistral.ai/v1/chat/completions', [ 'auth_bearer' => $this->apiKey, 'headers' => [ 'Content-Type' => 'application/json', diff --git a/src/platform/src/Bridge/Mistral/Llm/ResponseConverter.php b/src/platform/src/Bridge/Mistral/Llm/ResultConverter.php similarity index 80% rename from src/platform/src/Bridge/Mistral/Llm/ResponseConverter.php rename to src/platform/src/Bridge/Mistral/Llm/ResultConverter.php index de3dbe5b..65f7d0c7 100644 --- a/src/platform/src/Bridge/Mistral/Llm/ResponseConverter.php +++ b/src/platform/src/Bridge/Mistral/Llm/ResultConverter.php @@ -14,16 +14,16 @@ use Symfony\AI\Platform\Bridge\Mistral\Mistral; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\Choice; -use Symfony\AI\Platform\Response\ChoiceResponse; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\Response\StreamResponse; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\Response\ToolCall; -use Symfony\AI\Platform\Response\ToolCallResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\Choice; +use Symfony\AI\Platform\Result\ChoiceResult; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\Result\StreamResult; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\Result\ToolCall; +use Symfony\AI\Platform\Result\ToolCallResult; +use Symfony\AI\Platform\ResultConverterInterface; use Symfony\Component\HttpClient\Chunk\ServerSentEvent; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Component\HttpClient\Exception\JsonException; @@ -32,7 +32,7 @@ /** * @author Christopher Hertel */ -final readonly class ResponseConverter implements ResponseConverterInterface +final readonly class ResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { @@ -42,19 +42,19 @@ public function supports(Model $model): bool /** * @param array $options */ - public function convert(RawResponseInterface|RawHttpResponse $response, array $options = []): ResponseInterface + public function convert(RawResultInterface|RawHttpResult $result, array $options = []): ResultInterface { - $httpResponse = $response->getRawObject(); + $httpResponse = $result->getObject(); if ($options['stream'] ?? false) { - return new StreamResponse($this->convertStream($httpResponse)); + return new StreamResult($this->convertStream($httpResponse)); } if (200 !== $code = $httpResponse->getStatusCode()) { throw new RuntimeException(\sprintf('Unexpected response code %d: %s', $code, $httpResponse->getContent(false))); } - $data = $response->getRawData(); + $data = $result->getData(); if (!isset($data['choices'])) { throw new RuntimeException('Response does not contain choices'); @@ -64,20 +64,20 @@ public function convert(RawResponseInterface|RawHttpResponse $response, array $o $choices = array_map($this->convertChoice(...), $data['choices']); if (1 !== \count($choices)) { - return new ChoiceResponse(...$choices); + return new ChoiceResult(...$choices); } if ($choices[0]->hasToolCall()) { - return new ToolCallResponse(...$choices[0]->getToolCalls()); + return new ToolCallResult(...$choices[0]->getToolCalls()); } - return new TextResponse($choices[0]->getContent()); + return new TextResult($choices[0]->getContent()); } - private function convertStream(HttpResponse $response): \Generator + private function convertStream(HttpResponse $result): \Generator { $toolCalls = []; - foreach ((new EventSourceHttpClient())->stream($response) as $chunk) { + foreach ((new EventSourceHttpClient())->stream($result) as $chunk) { if (!$chunk instanceof ServerSentEvent || '[DONE]' === $chunk->getData()) { continue; } @@ -94,7 +94,7 @@ private function convertStream(HttpResponse $response): \Generator } if ([] !== $toolCalls && $this->isToolCallsStreamFinished($data)) { - yield new ToolCallResponse(...array_map($this->convertToolCall(...), $toolCalls)); + yield new ToolCallResult(...array_map($this->convertToolCall(...), $toolCalls)); } if (!isset($data['choices'][0]['delta']['content'])) { diff --git a/src/platform/src/Bridge/Mistral/PlatformFactory.php b/src/platform/src/Bridge/Mistral/PlatformFactory.php index 3f8f7890..f17e4a6d 100644 --- a/src/platform/src/Bridge/Mistral/PlatformFactory.php +++ b/src/platform/src/Bridge/Mistral/PlatformFactory.php @@ -12,10 +12,6 @@ namespace Symfony\AI\Platform\Bridge\Mistral; use Symfony\AI\Platform\Bridge\Mistral\Contract\ToolNormalizer; -use Symfony\AI\Platform\Bridge\Mistral\Embeddings\ModelClient as EmbeddingsModelClient; -use Symfony\AI\Platform\Bridge\Mistral\Embeddings\ResponseConverter as EmbeddingsResponseConverter; -use Symfony\AI\Platform\Bridge\Mistral\Llm\ModelClient as MistralModelClient; -use Symfony\AI\Platform\Bridge\Mistral\Llm\ResponseConverter as MistralResponseConverter; use Symfony\AI\Platform\Contract; use Symfony\AI\Platform\Platform; use Symfony\Component\HttpClient\EventSourceHttpClient; @@ -35,8 +31,8 @@ public static function create( $httpClient = $httpClient instanceof EventSourceHttpClient ? $httpClient : new EventSourceHttpClient($httpClient); return new Platform( - [new EmbeddingsModelClient($httpClient, $apiKey), new MistralModelClient($httpClient, $apiKey)], - [new EmbeddingsResponseConverter(), new MistralResponseConverter()], + [new Embeddings\ModelClient($httpClient, $apiKey), new Llm\ModelClient($httpClient, $apiKey)], + [new Embeddings\ResultConverter(), new Llm\ResultConverter()], $contract ?? Contract::create(new ToolNormalizer()), ); } diff --git a/src/platform/src/Bridge/Mistral/TokenOutputProcessor.php b/src/platform/src/Bridge/Mistral/TokenOutputProcessor.php index 84704b6a..6ddb6117 100644 --- a/src/platform/src/Bridge/Mistral/TokenOutputProcessor.php +++ b/src/platform/src/Bridge/Mistral/TokenOutputProcessor.php @@ -13,7 +13,7 @@ use Symfony\AI\Agent\Output; use Symfony\AI\Agent\OutputProcessorInterface; -use Symfony\AI\Platform\Response\StreamResponse; +use Symfony\AI\Platform\Result\StreamResult; use Symfony\Contracts\HttpClient\ResponseInterface; /** @@ -23,17 +23,17 @@ final class TokenOutputProcessor implements OutputProcessorInterface { public function processOutput(Output $output): void { - if ($output->response instanceof StreamResponse) { + if ($output->result instanceof StreamResult) { // Streams have to be handled manually as the tokens are part of the streamed chunks return; } - $rawResponse = $output->response->getRawResponse()?->getRawObject(); + $rawResponse = $output->result->getRawResult()?->getObject(); if (!$rawResponse instanceof ResponseInterface) { return; } - $metadata = $output->response->getMetadata(); + $metadata = $output->result->getMetadata(); $metadata->add( 'remaining_tokens_minute', diff --git a/src/platform/src/Bridge/Ollama/LlamaModelClient.php b/src/platform/src/Bridge/Ollama/LlamaModelClient.php index 2f0e2038..48de12c3 100644 --- a/src/platform/src/Bridge/Ollama/LlamaModelClient.php +++ b/src/platform/src/Bridge/Ollama/LlamaModelClient.php @@ -14,7 +14,7 @@ use Symfony\AI\Platform\Bridge\Meta\Llama; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Contracts\HttpClient\HttpClientInterface; /** @@ -33,12 +33,12 @@ public function supports(Model $model): bool return $model instanceof Llama; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { // Revert Ollama's default streaming behavior $options['stream'] ??= false; - return new RawHttpResponse($this->httpClient->request('POST', \sprintf('%s/api/chat', $this->hostUrl), [ + return new RawHttpResult($this->httpClient->request('POST', \sprintf('%s/api/chat', $this->hostUrl), [ 'headers' => ['Content-Type' => 'application/json'], 'json' => array_merge($options, $payload), ])); diff --git a/src/platform/src/Bridge/Ollama/LlamaResponseConverter.php b/src/platform/src/Bridge/Ollama/LlamaResultConverter.php similarity index 63% rename from src/platform/src/Bridge/Ollama/LlamaResponseConverter.php rename to src/platform/src/Bridge/Ollama/LlamaResultConverter.php index 0b8145a6..e7502f50 100644 --- a/src/platform/src/Bridge/Ollama/LlamaResponseConverter.php +++ b/src/platform/src/Bridge/Ollama/LlamaResultConverter.php @@ -14,24 +14,24 @@ use Symfony\AI\Platform\Bridge\Meta\Llama; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\ResultConverterInterface; /** * @author Christopher Hertel */ -final readonly class LlamaResponseConverter implements ResponseConverterInterface +final readonly class LlamaResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return $model instanceof Llama; } - public function convert(RawResponseInterface $response, array $options = []): ResponseInterface + public function convert(RawResultInterface $result, array $options = []): ResultInterface { - $data = $response->getRawData(); + $data = $result->getData(); if (!isset($data['message'])) { throw new RuntimeException('Response does not contain message'); @@ -41,6 +41,6 @@ public function convert(RawResponseInterface $response, array $options = []): Re throw new RuntimeException('Message does not contain content'); } - return new TextResponse($data['message']['content']); + return new TextResult($data['message']['content']); } } diff --git a/src/platform/src/Bridge/Ollama/PlatformFactory.php b/src/platform/src/Bridge/Ollama/PlatformFactory.php index c25cc9a0..584a8948 100644 --- a/src/platform/src/Bridge/Ollama/PlatformFactory.php +++ b/src/platform/src/Bridge/Ollama/PlatformFactory.php @@ -28,6 +28,6 @@ public static function create( ): Platform { $httpClient = $httpClient instanceof EventSourceHttpClient ? $httpClient : new EventSourceHttpClient($httpClient); - return new Platform([new LlamaModelClient($httpClient, $hostUrl)], [new LlamaResponseConverter()], $contract); + return new Platform([new LlamaModelClient($httpClient, $hostUrl)], [new LlamaResultConverter()], $contract); } } diff --git a/src/platform/src/Bridge/OpenAI/DallE/ImageResponse.php b/src/platform/src/Bridge/OpenAI/DallE/ImageResult.php similarity index 89% rename from src/platform/src/Bridge/OpenAI/DallE/ImageResponse.php rename to src/platform/src/Bridge/OpenAI/DallE/ImageResult.php index 8a7f1604..8984bf5d 100644 --- a/src/platform/src/Bridge/OpenAI/DallE/ImageResponse.php +++ b/src/platform/src/Bridge/OpenAI/DallE/ImageResult.php @@ -11,12 +11,12 @@ namespace Symfony\AI\Platform\Bridge\OpenAI\DallE; -use Symfony\AI\Platform\Response\BaseResponse; +use Symfony\AI\Platform\Result\BaseResult; /** * @author Denis Zunke */ -class ImageResponse extends BaseResponse +class ImageResult extends BaseResult { /** @var list */ private readonly array $images; diff --git a/src/platform/src/Bridge/OpenAI/DallE/ModelClient.php b/src/platform/src/Bridge/OpenAI/DallE/ModelClient.php index 4e015362..638a308f 100644 --- a/src/platform/src/Bridge/OpenAI/DallE/ModelClient.php +++ b/src/platform/src/Bridge/OpenAI/DallE/ModelClient.php @@ -15,7 +15,7 @@ use Symfony\AI\Platform\Exception\InvalidArgumentException; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Contracts\HttpClient\HttpClientInterface; /** @@ -39,9 +39,9 @@ public function supports(Model $model): bool return $model instanceof DallE; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { - return new RawHttpResponse($this->httpClient->request('POST', 'https://api.openai.com/v1/images/generations', [ + return new RawHttpResult($this->httpClient->request('POST', 'https://api.openai.com/v1/images/generations', [ 'auth_bearer' => $this->apiKey, 'json' => array_merge($options, [ 'model' => $model->getName(), diff --git a/src/platform/src/Bridge/OpenAI/DallE/ResponseConverter.php b/src/platform/src/Bridge/OpenAI/DallE/ResultConverter.php similarity index 64% rename from src/platform/src/Bridge/OpenAI/DallE/ResponseConverter.php rename to src/platform/src/Bridge/OpenAI/DallE/ResultConverter.php index a0bf1e31..23b11de8 100644 --- a/src/platform/src/Bridge/OpenAI/DallE/ResponseConverter.php +++ b/src/platform/src/Bridge/OpenAI/DallE/ResultConverter.php @@ -14,32 +14,32 @@ use Symfony\AI\Platform\Bridge\OpenAI\DallE; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\ResultConverterInterface; /** * @see https://platform.openai.com/docs/api-reference/images/create * * @author Denis Zunke */ -final readonly class ResponseConverter implements ResponseConverterInterface +final readonly class ResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return $model instanceof DallE; } - public function convert(RawResponseInterface $response, array $options = []): ResponseInterface + public function convert(RawResultInterface $result, array $options = []): ResultInterface { - $response = $response->getRawData(); + $result = $result->getData(); - if (!isset($response['data'][0])) { + if (!isset($result['data'][0])) { throw new RuntimeException('No image generated.'); } $images = []; - foreach ($response['data'] as $image) { + foreach ($result['data'] as $image) { if ('url' === $options['response_format']) { $images[] = new UrlImage($image['url']); @@ -49,6 +49,6 @@ public function convert(RawResponseInterface $response, array $options = []): Re $images[] = new Base64Image($image['b64_json']); } - return new ImageResponse($image['revised_prompt'] ?? null, ...$images); + return new ImageResult($image['revised_prompt'] ?? null, ...$images); } } diff --git a/src/platform/src/Bridge/OpenAI/Embeddings/ModelClient.php b/src/platform/src/Bridge/OpenAI/Embeddings/ModelClient.php index ecb18326..843908fe 100644 --- a/src/platform/src/Bridge/OpenAI/Embeddings/ModelClient.php +++ b/src/platform/src/Bridge/OpenAI/Embeddings/ModelClient.php @@ -15,7 +15,7 @@ use Symfony\AI\Platform\Exception\InvalidArgumentException; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface as PlatformResponseFactory; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Contracts\HttpClient\HttpClientInterface; /** @@ -37,9 +37,9 @@ public function supports(Model $model): bool return $model instanceof Embeddings; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { - return new RawHttpResponse($this->httpClient->request('POST', 'https://api.openai.com/v1/embeddings', [ + return new RawHttpResult($this->httpClient->request('POST', 'https://api.openai.com/v1/embeddings', [ 'auth_bearer' => $this->apiKey, 'json' => array_merge($options, [ 'model' => $model->getName(), diff --git a/src/platform/src/Bridge/OpenAI/Embeddings/ResponseConverter.php b/src/platform/src/Bridge/OpenAI/Embeddings/ResultConverter.php similarity index 70% rename from src/platform/src/Bridge/OpenAI/Embeddings/ResponseConverter.php rename to src/platform/src/Bridge/OpenAI/Embeddings/ResultConverter.php index d188ada8..d446de79 100644 --- a/src/platform/src/Bridge/OpenAI/Embeddings/ResponseConverter.php +++ b/src/platform/src/Bridge/OpenAI/Embeddings/ResultConverter.php @@ -14,30 +14,30 @@ use Symfony\AI\Platform\Bridge\OpenAI\Embeddings; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\VectorResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\VectorResult; +use Symfony\AI\Platform\ResultConverterInterface; use Symfony\AI\Platform\Vector\Vector; /** * @author Christopher Hertel */ -final class ResponseConverter implements ResponseConverterInterface +final class ResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return $model instanceof Embeddings; } - public function convert(RawResponseInterface $response, array $options = []): VectorResponse + public function convert(RawResultInterface $result, array $options = []): VectorResult { - $data = $response->getRawData(); + $data = $result->getData(); if (!isset($data['data'])) { throw new RuntimeException('Response does not contain data'); } - return new VectorResponse( + return new VectorResult( ...array_map( static fn (array $item): Vector => new Vector($item['embedding']), $data['data'] diff --git a/src/platform/src/Bridge/OpenAI/GPT/ModelClient.php b/src/platform/src/Bridge/OpenAI/GPT/ModelClient.php index b40763aa..b998c8d5 100644 --- a/src/platform/src/Bridge/OpenAI/GPT/ModelClient.php +++ b/src/platform/src/Bridge/OpenAI/GPT/ModelClient.php @@ -15,7 +15,7 @@ use Symfony\AI\Platform\Exception\InvalidArgumentException; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface as PlatformResponseFactory; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -41,9 +41,9 @@ public function supports(Model $model): bool return $model instanceof GPT; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { - return new RawHttpResponse($this->httpClient->request('POST', 'https://api.openai.com/v1/chat/completions', [ + return new RawHttpResult($this->httpClient->request('POST', 'https://api.openai.com/v1/chat/completions', [ 'auth_bearer' => $this->apiKey, 'json' => array_merge($options, $payload), ])); diff --git a/src/platform/src/Bridge/OpenAI/GPT/ResponseConverter.php b/src/platform/src/Bridge/OpenAI/GPT/ResultConverter.php similarity index 80% rename from src/platform/src/Bridge/OpenAI/GPT/ResponseConverter.php rename to src/platform/src/Bridge/OpenAI/GPT/ResultConverter.php index 1f93a6be..ce8bf4a0 100644 --- a/src/platform/src/Bridge/OpenAI/GPT/ResponseConverter.php +++ b/src/platform/src/Bridge/OpenAI/GPT/ResultConverter.php @@ -15,16 +15,16 @@ use Symfony\AI\Platform\Exception\ContentFilterException; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\Choice; -use Symfony\AI\Platform\Response\ChoiceResponse; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\Response\StreamResponse; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\Response\ToolCall; -use Symfony\AI\Platform\Response\ToolCallResponse; -use Symfony\AI\Platform\ResponseConverterInterface as PlatformResponseConverter; +use Symfony\AI\Platform\Result\Choice; +use Symfony\AI\Platform\Result\ChoiceResult; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\Result\StreamResult; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\Result\ToolCall; +use Symfony\AI\Platform\Result\ToolCallResult; +use Symfony\AI\Platform\ResultConverterInterface as PlatformResponseConverter; use Symfony\Component\HttpClient\Chunk\ServerSentEvent; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Component\HttpClient\Exception\JsonException; @@ -34,20 +34,20 @@ * @author Christopher Hertel * @author Denis Zunke */ -final class ResponseConverter implements PlatformResponseConverter +final class ResultConverter implements PlatformResponseConverter { public function supports(Model $model): bool { return $model instanceof GPT; } - public function convert(RawResponseInterface|RawHttpResponse $response, array $options = []): ResponseInterface + public function convert(RawResultInterface|RawHttpResult $result, array $options = []): ResultInterface { if ($options['stream'] ?? false) { - return new StreamResponse($this->convertStream($response->getRawObject())); + return new StreamResult($this->convertStream($result->getObject())); } - $data = $response->getRawData(); + $data = $result->getData(); if (isset($data['error']['code']) && 'content_filter' === $data['error']['code']) { throw new ContentFilterException($data['error']['message']); @@ -61,20 +61,20 @@ public function convert(RawResponseInterface|RawHttpResponse $response, array $o $choices = array_map($this->convertChoice(...), $data['choices']); if (1 !== \count($choices)) { - return new ChoiceResponse(...$choices); + return new ChoiceResult(...$choices); } if ($choices[0]->hasToolCall()) { - return new ToolCallResponse(...$choices[0]->getToolCalls()); + return new ToolCallResult(...$choices[0]->getToolCalls()); } - return new TextResponse($choices[0]->getContent()); + return new TextResult($choices[0]->getContent()); } - private function convertStream(HttpResponse $response): \Generator + private function convertStream(HttpResponse $result): \Generator { $toolCalls = []; - foreach ((new EventSourceHttpClient())->stream($response) as $chunk) { + foreach ((new EventSourceHttpClient())->stream($result) as $chunk) { if (!$chunk instanceof ServerSentEvent || '[DONE]' === $chunk->getData()) { continue; } @@ -91,7 +91,7 @@ private function convertStream(HttpResponse $response): \Generator } if ([] !== $toolCalls && $this->isToolCallsStreamFinished($data)) { - yield new ToolCallResponse(...array_map($this->convertToolCall(...), $toolCalls)); + yield new ToolCallResult(...array_map($this->convertToolCall(...), $toolCalls)); } if (!isset($data['choices'][0]['delta']['content'])) { diff --git a/src/platform/src/Bridge/OpenAI/PlatformFactory.php b/src/platform/src/Bridge/OpenAI/PlatformFactory.php index ff0613cb..62c09d1b 100644 --- a/src/platform/src/Bridge/OpenAI/PlatformFactory.php +++ b/src/platform/src/Bridge/OpenAI/PlatformFactory.php @@ -11,15 +11,9 @@ namespace Symfony\AI\Platform\Bridge\OpenAI; -use Symfony\AI\Platform\Bridge\OpenAI\DallE\ModelClient as DallEModelClient; -use Symfony\AI\Platform\Bridge\OpenAI\DallE\ResponseConverter as DallEResponseConverter; -use Symfony\AI\Platform\Bridge\OpenAI\Embeddings\ModelClient as EmbeddingsModelClient; -use Symfony\AI\Platform\Bridge\OpenAI\Embeddings\ResponseConverter as EmbeddingsResponseConverter; -use Symfony\AI\Platform\Bridge\OpenAI\GPT\ModelClient as GPTModelClient; -use Symfony\AI\Platform\Bridge\OpenAI\GPT\ResponseConverter as GPTResponseConverter; use Symfony\AI\Platform\Bridge\OpenAI\Whisper\AudioNormalizer; use Symfony\AI\Platform\Bridge\OpenAI\Whisper\ModelClient as WhisperModelClient; -use Symfony\AI\Platform\Bridge\OpenAI\Whisper\ResponseConverter as WhisperResponseConverter; +use Symfony\AI\Platform\Bridge\OpenAI\Whisper\ResultConverter as WhisperResponseConverter; use Symfony\AI\Platform\Contract; use Symfony\AI\Platform\Platform; use Symfony\Component\HttpClient\EventSourceHttpClient; @@ -40,15 +34,15 @@ public static function create( return new Platform( [ - new GPTModelClient($httpClient, $apiKey), - new EmbeddingsModelClient($httpClient, $apiKey), - new DallEModelClient($httpClient, $apiKey), + new GPT\ModelClient($httpClient, $apiKey), + new Embeddings\ModelClient($httpClient, $apiKey), + new DallE\ModelClient($httpClient, $apiKey), new WhisperModelClient($httpClient, $apiKey), ], [ - new GPTResponseConverter(), - new EmbeddingsResponseConverter(), - new DallEResponseConverter(), + new GPT\ResultConverter(), + new Embeddings\ResultConverter(), + new DallE\ResultConverter(), new WhisperResponseConverter(), ], $contract ?? Contract::create(new AudioNormalizer()), diff --git a/src/platform/src/Bridge/OpenAI/TokenOutputProcessor.php b/src/platform/src/Bridge/OpenAI/TokenOutputProcessor.php index d3561fcc..62e7b8d4 100644 --- a/src/platform/src/Bridge/OpenAI/TokenOutputProcessor.php +++ b/src/platform/src/Bridge/OpenAI/TokenOutputProcessor.php @@ -13,7 +13,7 @@ use Symfony\AI\Agent\Output; use Symfony\AI\Agent\OutputProcessorInterface; -use Symfony\AI\Platform\Response\StreamResponse; +use Symfony\AI\Platform\Result\StreamResult; use Symfony\Contracts\HttpClient\ResponseInterface; /** @@ -23,17 +23,17 @@ final class TokenOutputProcessor implements OutputProcessorInterface { public function processOutput(Output $output): void { - if ($output->response instanceof StreamResponse) { + if ($output->result instanceof StreamResult) { // Streams have to be handled manually as the tokens are part of the streamed chunks return; } - $rawResponse = $output->response->getRawResponse()?->getRawObject(); + $rawResponse = $output->result->getRawResult()?->getObject(); if (!$rawResponse instanceof ResponseInterface) { return; } - $metadata = $output->response->getMetadata(); + $metadata = $output->result->getMetadata(); $metadata->add( 'remaining_tokens', diff --git a/src/platform/src/Bridge/OpenAI/Whisper/ModelClient.php b/src/platform/src/Bridge/OpenAI/Whisper/ModelClient.php index e6fd0264..bfd3cc8b 100644 --- a/src/platform/src/Bridge/OpenAI/Whisper/ModelClient.php +++ b/src/platform/src/Bridge/OpenAI/Whisper/ModelClient.php @@ -15,7 +15,7 @@ use Symfony\AI\Platform\Exception\InvalidArgumentException; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface as BaseModelClient; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Contracts\HttpClient\HttpClientInterface; /** @@ -36,13 +36,13 @@ public function supports(Model $model): bool return $model instanceof Whisper; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { $task = $options['task'] ?? Task::TRANSCRIPTION; $endpoint = Task::TRANSCRIPTION === $task ? 'transcriptions' : 'translations'; unset($options['task']); - return new RawHttpResponse($this->httpClient->request('POST', \sprintf('https://api.openai.com/v1/audio/%s', $endpoint), [ + return new RawHttpResult($this->httpClient->request('POST', \sprintf('https://api.openai.com/v1/audio/%s', $endpoint), [ 'auth_bearer' => $this->apiKey, 'headers' => ['Content-Type' => 'multipart/form-data'], 'body' => array_merge($options, $payload, ['model' => $model->getName()]), diff --git a/src/platform/src/Bridge/OpenAI/Whisper/ResponseConverter.php b/src/platform/src/Bridge/OpenAI/Whisper/ResultConverter.php similarity index 53% rename from src/platform/src/Bridge/OpenAI/Whisper/ResponseConverter.php rename to src/platform/src/Bridge/OpenAI/Whisper/ResultConverter.php index 6125fd64..11ba6a3e 100644 --- a/src/platform/src/Bridge/OpenAI/Whisper/ResponseConverter.php +++ b/src/platform/src/Bridge/OpenAI/Whisper/ResultConverter.php @@ -13,25 +13,25 @@ use Symfony\AI\Platform\Bridge\OpenAI\Whisper; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\ResponseConverterInterface as BaseResponseConverter; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\ResultConverterInterface as BaseResponseConverter; /** * @author Christopher Hertel */ -final class ResponseConverter implements BaseResponseConverter +final class ResultConverter implements BaseResponseConverter { public function supports(Model $model): bool { return $model instanceof Whisper; } - public function convert(RawResponseInterface $response, array $options = []): ResponseInterface + public function convert(RawResultInterface $result, array $options = []): ResultInterface { - $data = $response->getRawData(); + $data = $result->getData(); - return new TextResponse($data['text']); + return new TextResult($data['text']); } } diff --git a/src/platform/src/Bridge/OpenRouter/ModelClient.php b/src/platform/src/Bridge/OpenRouter/ModelClient.php index 5933c74d..913e1955 100644 --- a/src/platform/src/Bridge/OpenRouter/ModelClient.php +++ b/src/platform/src/Bridge/OpenRouter/ModelClient.php @@ -14,7 +14,7 @@ use Symfony\AI\Platform\Exception\InvalidArgumentException; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Component\HttpClient\EventSourceHttpClient; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -39,9 +39,9 @@ public function supports(Model $model): bool return true; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { - return new RawHttpResponse($this->httpClient->request('POST', 'https://openrouter.ai/api/v1/chat/completions', [ + return new RawHttpResult($this->httpClient->request('POST', 'https://openrouter.ai/api/v1/chat/completions', [ 'auth_bearer' => $this->apiKey, 'json' => array_merge($options, $payload), ])); diff --git a/src/platform/src/Bridge/OpenRouter/PlatformFactory.php b/src/platform/src/Bridge/OpenRouter/PlatformFactory.php index 41849112..89dc8f86 100644 --- a/src/platform/src/Bridge/OpenRouter/PlatformFactory.php +++ b/src/platform/src/Bridge/OpenRouter/PlatformFactory.php @@ -34,7 +34,7 @@ public static function create( return new Platform( [new ModelClient($httpClient, $apiKey)], - [new ResponseConverter()], + [new ResultConverter()], $contract ?? Contract::create( new AssistantMessageNormalizer(), new MessageBagNormalizer(), diff --git a/src/platform/src/Bridge/OpenRouter/ResponseConverter.php b/src/platform/src/Bridge/OpenRouter/ResultConverter.php similarity index 61% rename from src/platform/src/Bridge/OpenRouter/ResponseConverter.php rename to src/platform/src/Bridge/OpenRouter/ResultConverter.php index 6432a975..54ca9e6d 100644 --- a/src/platform/src/Bridge/OpenRouter/ResponseConverter.php +++ b/src/platform/src/Bridge/OpenRouter/ResultConverter.php @@ -13,24 +13,24 @@ use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\ResultConverterInterface; /** * @author rglozman */ -final readonly class ResponseConverter implements ResponseConverterInterface +final readonly class ResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return true; } - public function convert(RawResponseInterface $response, array $options = []): ResponseInterface + public function convert(RawResultInterface $result, array $options = []): ResultInterface { - $data = $response->getRawData(); + $data = $result->getData(); if (!isset($data['choices'][0]['message'])) { throw new RuntimeException('Response does not contain message'); @@ -40,6 +40,6 @@ public function convert(RawResponseInterface $response, array $options = []): Re throw new RuntimeException('Message does not contain content'); } - return new TextResponse($data['choices'][0]['message']['content']); + return new TextResult($data['choices'][0]['message']['content']); } } diff --git a/src/platform/src/Bridge/Replicate/LlamaModelClient.php b/src/platform/src/Bridge/Replicate/LlamaModelClient.php index ae7e95c7..53af5d0e 100644 --- a/src/platform/src/Bridge/Replicate/LlamaModelClient.php +++ b/src/platform/src/Bridge/Replicate/LlamaModelClient.php @@ -15,7 +15,7 @@ use Symfony\AI\Platform\Exception\InvalidArgumentException; use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; /** * @author Christopher Hertel @@ -32,11 +32,11 @@ public function supports(Model $model): bool return $model instanceof Llama; } - public function request(Model $model, array|string $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string $payload, array $options = []): RawHttpResult { $model instanceof Llama || throw new InvalidArgumentException(\sprintf('The model must be an instance of "%s".', Llama::class)); - return new RawHttpResponse( + return new RawHttpResult( $this->client->request(\sprintf('meta/meta-%s', $model->getName()), 'predictions', $payload) ); } diff --git a/src/platform/src/Bridge/Replicate/LlamaResponseConverter.php b/src/platform/src/Bridge/Replicate/LlamaResultConverter.php similarity index 59% rename from src/platform/src/Bridge/Replicate/LlamaResponseConverter.php rename to src/platform/src/Bridge/Replicate/LlamaResultConverter.php index 8c129bba..fe90930c 100644 --- a/src/platform/src/Bridge/Replicate/LlamaResponseConverter.php +++ b/src/platform/src/Bridge/Replicate/LlamaResultConverter.php @@ -14,29 +14,29 @@ use Symfony\AI\Platform\Bridge\Meta\Llama; use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\ResultConverterInterface; /** * @author Christopher Hertel */ -final readonly class LlamaResponseConverter implements ResponseConverterInterface +final readonly class LlamaResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return $model instanceof Llama; } - public function convert(RawResponseInterface $response, array $options = []): ResponseInterface + public function convert(RawResultInterface $result, array $options = []): ResultInterface { - $data = $response->getRawData(); + $data = $result->getData(); if (!isset($data['output'])) { throw new RuntimeException('Response does not contain output'); } - return new TextResponse(implode('', $data['output'])); + return new TextResult(implode('', $data['output'])); } } diff --git a/src/platform/src/Bridge/Replicate/PlatformFactory.php b/src/platform/src/Bridge/Replicate/PlatformFactory.php index 49701e34..8b6039ad 100644 --- a/src/platform/src/Bridge/Replicate/PlatformFactory.php +++ b/src/platform/src/Bridge/Replicate/PlatformFactory.php @@ -31,7 +31,7 @@ public static function create( ): Platform { return new Platform( [new LlamaModelClient(new Client($httpClient ?? HttpClient::create(), new Clock(), $apiKey))], - [new LlamaResponseConverter()], + [new LlamaResultConverter()], $contract ?? Contract::create(new LlamaMessageBagNormalizer()), ); } diff --git a/src/platform/src/Bridge/TransformersPHP/ModelClient.php b/src/platform/src/Bridge/TransformersPHP/ModelClient.php index b9e1f873..49acc0c6 100644 --- a/src/platform/src/Bridge/TransformersPHP/ModelClient.php +++ b/src/platform/src/Bridge/TransformersPHP/ModelClient.php @@ -24,7 +24,7 @@ public function supports(Model $model): bool return true; } - public function request(Model $model, array|string $payload, array $options = []): RawPipelineResponse + public function request(Model $model, array|string $payload, array $options = []): RawPipelineResult { if (null === $task = $options['task'] ?? null) { throw new InvalidArgumentException('The task option is required.'); @@ -40,6 +40,6 @@ public function request(Model $model, array|string $payload, array $options = [] $options['modelFilename'] ?? null, ); - return new RawPipelineResponse(new PipelineExecution($pipeline, $payload)); + return new RawPipelineResult(new PipelineExecution($pipeline, $payload)); } } diff --git a/src/platform/src/Bridge/TransformersPHP/PlatformFactory.php b/src/platform/src/Bridge/TransformersPHP/PlatformFactory.php index 0e122d68..f4fa2924 100644 --- a/src/platform/src/Bridge/TransformersPHP/PlatformFactory.php +++ b/src/platform/src/Bridge/TransformersPHP/PlatformFactory.php @@ -26,6 +26,6 @@ public static function create(): Platform throw new RuntimeException('For using the TransformersPHP with FFI to run models in PHP, the codewithkyrian/transformers package is required. Try running "composer require codewithkyrian/transformers".'); } - return new Platform([new ModelClient()], [new ResponseConverter()]); + return new Platform([new ModelClient()], [new ResultConverter()]); } } diff --git a/src/platform/src/Bridge/TransformersPHP/RawPipelineResponse.php b/src/platform/src/Bridge/TransformersPHP/RawPipelineResult.php similarity index 72% rename from src/platform/src/Bridge/TransformersPHP/RawPipelineResponse.php rename to src/platform/src/Bridge/TransformersPHP/RawPipelineResult.php index 0a6199e4..c4841a70 100644 --- a/src/platform/src/Bridge/TransformersPHP/RawPipelineResponse.php +++ b/src/platform/src/Bridge/TransformersPHP/RawPipelineResult.php @@ -11,24 +11,24 @@ namespace Symfony\AI\Platform\Bridge\TransformersPHP; -use Symfony\AI\Platform\Response\RawResponseInterface; +use Symfony\AI\Platform\Result\RawResultInterface; /** * @author Christopher Hertel */ -final readonly class RawPipelineResponse implements RawResponseInterface +final readonly class RawPipelineResult implements RawResultInterface { public function __construct( private PipelineExecution $pipelineExecution, ) { } - public function getRawData(): array + public function getData(): array { return $this->pipelineExecution->getResult(); } - public function getRawObject(): PipelineExecution + public function getObject(): PipelineExecution { return $this->pipelineExecution; } diff --git a/src/platform/src/Bridge/TransformersPHP/ResponseConverter.php b/src/platform/src/Bridge/TransformersPHP/ResultConverter.php similarity index 52% rename from src/platform/src/Bridge/TransformersPHP/ResponseConverter.php rename to src/platform/src/Bridge/TransformersPHP/ResultConverter.php index 9b24381e..4aa703fa 100644 --- a/src/platform/src/Bridge/TransformersPHP/ResponseConverter.php +++ b/src/platform/src/Bridge/TransformersPHP/ResultConverter.php @@ -13,28 +13,28 @@ use Codewithkyrian\Transformers\Pipelines\Task; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\ObjectResponse; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\ObjectResult; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\ResultConverterInterface; -final readonly class ResponseConverter implements ResponseConverterInterface +final readonly class ResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return true; } - public function convert(RawResponseInterface $response, array $options = []): TextResponse|ObjectResponse + public function convert(RawResultInterface $result, array $options = []): TextResult|ObjectResult { - $data = $response->getRawData(); + $data = $result->getData(); if (Task::Text2TextGeneration === $options['task']) { $result = reset($data); - return new TextResponse($result['generated_text']); + return new TextResult($result['generated_text']); } - return new ObjectResponse($data); + return new ObjectResult($data); } } diff --git a/src/platform/src/Bridge/Voyage/ModelClient.php b/src/platform/src/Bridge/Voyage/ModelClient.php index 82584cb3..3da2a5f6 100644 --- a/src/platform/src/Bridge/Voyage/ModelClient.php +++ b/src/platform/src/Bridge/Voyage/ModelClient.php @@ -13,7 +13,7 @@ use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Contracts\HttpClient\HttpClientInterface; /** @@ -32,9 +32,9 @@ public function supports(Model $model): bool return $model instanceof Voyage; } - public function request(Model $model, object|string|array $payload, array $options = []): RawHttpResponse + public function request(Model $model, object|string|array $payload, array $options = []): RawHttpResult { - return new RawHttpResponse($this->httpClient->request('POST', 'https://api.voyageai.com/v1/embeddings', [ + return new RawHttpResult($this->httpClient->request('POST', 'https://api.voyageai.com/v1/embeddings', [ 'auth_bearer' => $this->apiKey, 'json' => [ 'model' => $model->getName(), diff --git a/src/platform/src/Bridge/Voyage/PlatformFactory.php b/src/platform/src/Bridge/Voyage/PlatformFactory.php index 5346944d..cb82e43f 100644 --- a/src/platform/src/Bridge/Voyage/PlatformFactory.php +++ b/src/platform/src/Bridge/Voyage/PlatformFactory.php @@ -29,6 +29,6 @@ public static function create( ): Platform { $httpClient = $httpClient instanceof EventSourceHttpClient ? $httpClient : new EventSourceHttpClient($httpClient); - return new Platform([new ModelClient($httpClient, $apiKey)], [new ResponseConverter()], $contract); + return new Platform([new ModelClient($httpClient, $apiKey)], [new ResultConverter()], $contract); } } diff --git a/src/platform/src/Bridge/Voyage/ResponseConverter.php b/src/platform/src/Bridge/Voyage/ResultConverter.php similarity index 57% rename from src/platform/src/Bridge/Voyage/ResponseConverter.php rename to src/platform/src/Bridge/Voyage/ResultConverter.php index 13263611..60a26d17 100644 --- a/src/platform/src/Bridge/Voyage/ResponseConverter.php +++ b/src/platform/src/Bridge/Voyage/ResultConverter.php @@ -13,32 +13,32 @@ use Symfony\AI\Platform\Exception\RuntimeException; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\Response\VectorResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\Result\VectorResult; +use Symfony\AI\Platform\ResultConverterInterface; use Symfony\AI\Platform\Vector\Vector; /** * @author Christopher Hertel */ -final readonly class ResponseConverter implements ResponseConverterInterface +final readonly class ResultConverter implements ResultConverterInterface { public function supports(Model $model): bool { return $model instanceof Voyage; } - public function convert(RawResponseInterface $response, array $options = []): ResponseInterface + public function convert(RawResultInterface $result, array $options = []): ResultInterface { - $response = $response->getRawData(); + $result = $result->getData(); - if (!isset($response['data'])) { + if (!isset($result['data'])) { throw new RuntimeException('Response does not contain embedding data'); } - $vectors = array_map(fn (array $data) => new Vector($data['embedding']), $response['data']); + $vectors = array_map(fn (array $data) => new Vector($data['embedding']), $result['data']); - return new VectorResponse($vectors[0]); + return new VectorResult($vectors[0]); } } diff --git a/src/platform/src/Contract.php b/src/platform/src/Contract.php index 4f3dd293..dc45f57a 100644 --- a/src/platform/src/Contract.php +++ b/src/platform/src/Contract.php @@ -20,7 +20,7 @@ use Symfony\AI\Platform\Contract\Normalizer\Message\SystemMessageNormalizer; use Symfony\AI\Platform\Contract\Normalizer\Message\ToolCallMessageNormalizer; use Symfony\AI\Platform\Contract\Normalizer\Message\UserMessageNormalizer; -use Symfony\AI\Platform\Contract\Normalizer\Response\ToolCallNormalizer; +use Symfony\AI\Platform\Contract\Normalizer\Result\ToolCallNormalizer; use Symfony\AI\Platform\Contract\Normalizer\ToolNormalizer; use Symfony\AI\Platform\Tool\Tool; use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; @@ -58,7 +58,7 @@ public static function create(NormalizerInterface ...$normalizer): self // Options $normalizer[] = new ToolNormalizer(); - // Response + // Result $normalizer[] = new ToolCallNormalizer(); // JsonSerializable objects as extension point to library interfaces diff --git a/src/platform/src/Contract/Normalizer/Response/ToolCallNormalizer.php b/src/platform/src/Contract/Normalizer/Result/ToolCallNormalizer.php similarity index 92% rename from src/platform/src/Contract/Normalizer/Response/ToolCallNormalizer.php rename to src/platform/src/Contract/Normalizer/Result/ToolCallNormalizer.php index 1771e323..22cf3357 100644 --- a/src/platform/src/Contract/Normalizer/Response/ToolCallNormalizer.php +++ b/src/platform/src/Contract/Normalizer/Result/ToolCallNormalizer.php @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Contract\Normalizer\Response; +namespace Symfony\AI\Platform\Contract\Normalizer\Result; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; /** diff --git a/src/platform/src/Exception/UnexpectedResponseTypeException.php b/src/platform/src/Exception/UnexpectedResultTypeException.php similarity index 89% rename from src/platform/src/Exception/UnexpectedResponseTypeException.php rename to src/platform/src/Exception/UnexpectedResultTypeException.php index d3829454..4780c30e 100644 --- a/src/platform/src/Exception/UnexpectedResponseTypeException.php +++ b/src/platform/src/Exception/UnexpectedResultTypeException.php @@ -11,7 +11,7 @@ namespace Symfony\AI\Platform\Exception; -class UnexpectedResponseTypeException extends RuntimeException +class UnexpectedResultTypeException extends RuntimeException { public function __construct(string $expectedType, string $actualType) { diff --git a/src/platform/src/Message/AssistantMessage.php b/src/platform/src/Message/AssistantMessage.php index b9cfb392..3a5a1741 100644 --- a/src/platform/src/Message/AssistantMessage.php +++ b/src/platform/src/Message/AssistantMessage.php @@ -11,7 +11,7 @@ namespace Symfony\AI\Platform\Message; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\Component\Uid\AbstractUid; use Symfony\Component\Uid\TimeBasedUidInterface; use Symfony\Component\Uid\Uuid; diff --git a/src/platform/src/Message/Message.php b/src/platform/src/Message/Message.php index 23872469..ae019533 100644 --- a/src/platform/src/Message/Message.php +++ b/src/platform/src/Message/Message.php @@ -13,7 +13,7 @@ use Symfony\AI\Platform\Message\Content\ContentInterface; use Symfony\AI\Platform\Message\Content\Text; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; /** * @author Christopher Hertel diff --git a/src/platform/src/Message/ToolCallMessage.php b/src/platform/src/Message/ToolCallMessage.php index 049234fa..19beb7fb 100644 --- a/src/platform/src/Message/ToolCallMessage.php +++ b/src/platform/src/Message/ToolCallMessage.php @@ -11,7 +11,7 @@ namespace Symfony\AI\Platform\Message; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\Component\Uid\AbstractUid; use Symfony\Component\Uid\TimeBasedUidInterface; use Symfony\Component\Uid\Uuid; diff --git a/src/platform/src/ModelClientInterface.php b/src/platform/src/ModelClientInterface.php index be3cf0d4..877bbd7e 100644 --- a/src/platform/src/ModelClientInterface.php +++ b/src/platform/src/ModelClientInterface.php @@ -11,7 +11,7 @@ namespace Symfony\AI\Platform; -use Symfony\AI\Platform\Response\RawResponseInterface; +use Symfony\AI\Platform\Result\RawResultInterface; /** * @author Christopher Hertel @@ -24,5 +24,5 @@ public function supports(Model $model): bool; * @param array $payload * @param array $options */ - public function request(Model $model, array|string $payload, array $options = []): RawResponseInterface; + public function request(Model $model, array|string $payload, array $options = []): RawResultInterface; } diff --git a/src/platform/src/Platform.php b/src/platform/src/Platform.php index 5a51bb7a..de5a16dc 100644 --- a/src/platform/src/Platform.php +++ b/src/platform/src/Platform.php @@ -12,8 +12,8 @@ namespace Symfony\AI\Platform; use Symfony\AI\Platform\Exception\RuntimeException; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponsePromise; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultPromise; /** * @author Christopher Hertel @@ -26,25 +26,25 @@ final class Platform implements PlatformInterface private readonly array $modelClients; /** - * @var ResponseConverterInterface[] + * @var ResultConverterInterface[] */ - private readonly array $responseConverter; + private readonly array $resultConverters; /** - * @param iterable $modelClients - * @param iterable $responseConverter + * @param iterable $modelClients + * @param iterable $resultConverters */ public function __construct( iterable $modelClients, - iterable $responseConverter, + iterable $resultConverters, private ?Contract $contract = null, ) { $this->contract = $contract ?? Contract::create(); $this->modelClients = $modelClients instanceof \Traversable ? iterator_to_array($modelClients) : $modelClients; - $this->responseConverter = $responseConverter instanceof \Traversable ? iterator_to_array($responseConverter) : $responseConverter; + $this->resultConverters = $resultConverters instanceof \Traversable ? iterator_to_array($resultConverters) : $resultConverters; } - public function request(Model $model, array|string|object $input, array $options = []): ResponsePromise + public function invoke(Model $model, array|string|object $input, array $options = []): ResultPromise { $payload = $this->contract->createRequestPayload($model, $input); $options = array_merge($model->getOptions(), $options); @@ -53,16 +53,16 @@ public function request(Model $model, array|string|object $input, array $options $options['tools'] = $this->contract->createToolOption($options['tools'], $model); } - $response = $this->doRequest($model, $payload, $options); + $result = $this->doInvoke($model, $payload, $options); - return $this->convertResponse($model, $response, $options); + return $this->convertResult($model, $result, $options); } /** * @param array $payload * @param array $options */ - private function doRequest(Model $model, array|string $payload, array $options = []): RawResponseInterface + private function doInvoke(Model $model, array|string $payload, array $options = []): RawResultInterface { foreach ($this->modelClients as $modelClient) { if ($modelClient->supports($model)) { @@ -70,20 +70,20 @@ private function doRequest(Model $model, array|string $payload, array $options = } } - throw new RuntimeException('No response factory registered for model "'.$model::class.'" with given input.'); + throw new RuntimeException(\sprintf('No ModelClient registered for model "%s" with given input.', $model::class)); } /** * @param array $options */ - private function convertResponse(Model $model, RawResponseInterface $response, array $options): ResponsePromise + private function convertResult(Model $model, RawResultInterface $result, array $options): ResultPromise { - foreach ($this->responseConverter as $responseConverter) { - if ($responseConverter->supports($model)) { - return new ResponsePromise($responseConverter->convert(...), $response, $options); + foreach ($this->resultConverters as $resultConverter) { + if ($resultConverter->supports($model)) { + return new ResultPromise($resultConverter->convert(...), $result, $options); } } - throw new RuntimeException('No response converter registered for model "'.$model::class.'" with given input.'); + throw new RuntimeException(\sprintf('No ResultConverter registered for model "%s" with given input.', $model::class)); } } diff --git a/src/platform/src/PlatformInterface.php b/src/platform/src/PlatformInterface.php index c51967d3..927a7715 100644 --- a/src/platform/src/PlatformInterface.php +++ b/src/platform/src/PlatformInterface.php @@ -11,7 +11,7 @@ namespace Symfony\AI\Platform; -use Symfony\AI\Platform\Response\ResponsePromise; +use Symfony\AI\Platform\Result\ResultPromise; /** * @author Christopher Hertel @@ -22,5 +22,5 @@ interface PlatformInterface * @param array|string|object $input * @param array $options */ - public function request(Model $model, array|string|object $input, array $options = []): ResponsePromise; + public function invoke(Model $model, array|string|object $input, array $options = []): ResultPromise; } diff --git a/src/platform/src/Response/RawResponseAwareTrait.php b/src/platform/src/Response/RawResponseAwareTrait.php deleted file mode 100644 index 15e20bc9..00000000 --- a/src/platform/src/Response/RawResponseAwareTrait.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\AI\Platform\Response; - -use Symfony\AI\Platform\Response\Exception\RawResponseAlreadySetException; - -/** - * @author Denis Zunke - */ -trait RawResponseAwareTrait -{ - protected ?RawResponseInterface $rawResponse = null; - - public function setRawResponse(RawResponseInterface $rawResponse): void - { - if (isset($this->rawResponse)) { - throw new RawResponseAlreadySetException(); - } - - $this->rawResponse = $rawResponse; - } - - public function getRawResponse(): ?RawResponseInterface - { - return $this->rawResponse; - } -} diff --git a/src/platform/src/Response/ResponsePromise.php b/src/platform/src/Response/ResponsePromise.php deleted file mode 100644 index 14f77e1a..00000000 --- a/src/platform/src/Response/ResponsePromise.php +++ /dev/null @@ -1,119 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\AI\Platform\Response; - -use Symfony\AI\Platform\Exception\UnexpectedResponseTypeException; -use Symfony\AI\Platform\Vector\Vector; - -/** - * @author Christopher Hertel - */ -final class ResponsePromise -{ - private bool $isConverted = false; - private ResponseInterface $convertedResponse; - - /** - * @param array $options - */ - public function __construct( - private readonly \Closure $responseConverter, - private readonly RawResponseInterface $response, - private readonly array $options = [], - ) { - } - - public function getResponse(): ResponseInterface - { - return $this->await(); - } - - public function getRawResponse(): RawResponseInterface - { - return $this->response; - } - - public function await(): ResponseInterface - { - if (!$this->isConverted) { - $this->convertedResponse = ($this->responseConverter)($this->response, $this->options); - - if (null === $this->convertedResponse->getRawResponse()) { - // Fallback to set the raw response when it was not handled by the response converter itself - $this->convertedResponse->setRawResponse($this->response); - } - - $this->isConverted = true; - } - - return $this->convertedResponse; - } - - public function asText(): string - { - return $this->as(TextResponse::class)->getContent(); - } - - public function asObject(): object - { - return $this->as(ObjectResponse::class)->getContent(); - } - - public function asBinary(): string - { - return $this->as(BinaryResponse::class)->getContent(); - } - - public function asBase64(): string - { - $response = $this->as(BinaryResponse::class); - - \assert($response instanceof BinaryResponse); - - return $response->toDataUri(); - } - - /** - * @return Vector[] - */ - public function asVectors(): array - { - return $this->as(VectorResponse::class)->getContent(); - } - - public function asStream(): \Generator - { - yield from $this->as(StreamResponse::class)->getContent(); - } - - /** - * @return ToolCall[] - */ - public function asToolCalls(): array - { - return $this->as(ToolCallResponse::class)->getContent(); - } - - /** - * @param class-string $type - */ - private function as(string $type): ResponseInterface - { - $response = $this->getResponse(); - - if (!$response instanceof $type) { - throw new UnexpectedResponseTypeException($type, $response::class); - } - - return $response; - } -} diff --git a/src/platform/src/Response/BaseResponse.php b/src/platform/src/Result/BaseResult.php similarity index 58% rename from src/platform/src/Response/BaseResponse.php rename to src/platform/src/Result/BaseResult.php index 0dec61e6..d439b784 100644 --- a/src/platform/src/Response/BaseResponse.php +++ b/src/platform/src/Result/BaseResult.php @@ -9,17 +9,17 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response; +namespace Symfony\AI\Platform\Result; -use Symfony\AI\Platform\Response\Metadata\MetadataAwareTrait; +use Symfony\AI\Platform\Result\Metadata\MetadataAwareTrait; /** - * Base response of converted response classes. + * Base result of converted result classes. * * @author Denis Zunke */ -abstract class BaseResponse implements ResponseInterface +abstract class BaseResult implements ResultInterface { use MetadataAwareTrait; - use RawResponseAwareTrait; + use RawResultAwareTrait; } diff --git a/src/platform/src/Response/BinaryResponse.php b/src/platform/src/Result/BinaryResult.php similarity index 91% rename from src/platform/src/Response/BinaryResponse.php rename to src/platform/src/Result/BinaryResult.php index 460df8ef..c137adfa 100644 --- a/src/platform/src/Response/BinaryResponse.php +++ b/src/platform/src/Result/BinaryResult.php @@ -9,14 +9,14 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response; +namespace Symfony\AI\Platform\Result; use Symfony\AI\Platform\Exception\RuntimeException; /** * @author Christopher Hertel */ -final class BinaryResponse extends BaseResponse +final class BinaryResult extends BaseResult { public function __construct( public string $data, diff --git a/src/platform/src/Response/Choice.php b/src/platform/src/Result/Choice.php similarity index 95% rename from src/platform/src/Response/Choice.php rename to src/platform/src/Result/Choice.php index fd5ef927..5016b2c2 100644 --- a/src/platform/src/Response/Choice.php +++ b/src/platform/src/Result/Choice.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response; +namespace Symfony\AI\Platform\Result; /** * @author Christopher Hertel diff --git a/src/platform/src/Response/ChoiceResponse.php b/src/platform/src/Result/ChoiceResult.php similarity index 79% rename from src/platform/src/Response/ChoiceResponse.php rename to src/platform/src/Result/ChoiceResult.php index 1690a473..ac2f5404 100644 --- a/src/platform/src/Response/ChoiceResponse.php +++ b/src/platform/src/Result/ChoiceResult.php @@ -9,14 +9,14 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response; +namespace Symfony\AI\Platform\Result; use Symfony\AI\Platform\Exception\InvalidArgumentException; /** * @author Christopher Hertel */ -final class ChoiceResponse extends BaseResponse +final class ChoiceResult extends BaseResult { /** * @var Choice[] @@ -26,7 +26,7 @@ final class ChoiceResponse extends BaseResponse public function __construct(Choice ...$choices) { if ([] === $choices) { - throw new InvalidArgumentException('Response must have at least one choice.'); + throw new InvalidArgumentException('Result must have at least one choice.'); } $this->choices = $choices; diff --git a/src/platform/src/Response/Exception/RawResponseAlreadySetException.php b/src/platform/src/Result/Exception/RawResultAlreadySetException.php similarity index 68% rename from src/platform/src/Response/Exception/RawResponseAlreadySetException.php rename to src/platform/src/Result/Exception/RawResultAlreadySetException.php index a8a6c1ca..96f3e75c 100644 --- a/src/platform/src/Response/Exception/RawResponseAlreadySetException.php +++ b/src/platform/src/Result/Exception/RawResultAlreadySetException.php @@ -9,17 +9,17 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response\Exception; +namespace Symfony\AI\Platform\Result\Exception; use Symfony\AI\Platform\Exception\RuntimeException; /** * @author Denis Zunke */ -final class RawResponseAlreadySetException extends RuntimeException +final class RawResultAlreadySetException extends RuntimeException { public function __construct() { - parent::__construct('The raw response was already set.'); + parent::__construct('The raw result was already set.'); } } diff --git a/src/platform/src/Response/Metadata/Metadata.php b/src/platform/src/Result/Metadata/Metadata.php similarity index 97% rename from src/platform/src/Response/Metadata/Metadata.php rename to src/platform/src/Result/Metadata/Metadata.php index ea6f04f1..07ce7c3b 100644 --- a/src/platform/src/Response/Metadata/Metadata.php +++ b/src/platform/src/Result/Metadata/Metadata.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response\Metadata; +namespace Symfony\AI\Platform\Result\Metadata; /** * @implements \IteratorAggregate diff --git a/src/platform/src/Response/Metadata/MetadataAwareTrait.php b/src/platform/src/Result/Metadata/MetadataAwareTrait.php similarity index 90% rename from src/platform/src/Response/Metadata/MetadataAwareTrait.php rename to src/platform/src/Result/Metadata/MetadataAwareTrait.php index ed3fffa6..bc367521 100644 --- a/src/platform/src/Response/Metadata/MetadataAwareTrait.php +++ b/src/platform/src/Result/Metadata/MetadataAwareTrait.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response\Metadata; +namespace Symfony\AI\Platform\Result\Metadata; /** * @author Denis Zunke diff --git a/src/platform/src/Response/ObjectResponse.php b/src/platform/src/Result/ObjectResult.php similarity index 88% rename from src/platform/src/Response/ObjectResponse.php rename to src/platform/src/Result/ObjectResult.php index f98ba36f..fb3118ba 100644 --- a/src/platform/src/Response/ObjectResponse.php +++ b/src/platform/src/Result/ObjectResult.php @@ -9,12 +9,12 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response; +namespace Symfony\AI\Platform\Result; /** * @author Christopher Hertel */ -final class ObjectResponse extends BaseResponse +final class ObjectResult extends BaseResult { /** * @param object|array $structuredOutput diff --git a/src/platform/src/Response/RawHttpResponse.php b/src/platform/src/Result/RawHttpResult.php similarity index 73% rename from src/platform/src/Response/RawHttpResponse.php rename to src/platform/src/Result/RawHttpResult.php index dbb53573..be236339 100644 --- a/src/platform/src/Response/RawHttpResponse.php +++ b/src/platform/src/Result/RawHttpResult.php @@ -9,26 +9,26 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response; +namespace Symfony\AI\Platform\Result; use Symfony\Contracts\HttpClient\ResponseInterface; /** * @author Christopher Hertel response->toArray(false); } - public function getRawObject(): ResponseInterface + public function getObject(): ResponseInterface { return $this->response; } diff --git a/src/platform/src/Result/RawResultAwareTrait.php b/src/platform/src/Result/RawResultAwareTrait.php new file mode 100644 index 00000000..1dfb3835 --- /dev/null +++ b/src/platform/src/Result/RawResultAwareTrait.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\AI\Platform\Result; + +use Symfony\AI\Platform\Result\Exception\RawResultAlreadySetException; + +/** + * @author Denis Zunke + */ +trait RawResultAwareTrait +{ + protected ?RawResultInterface $rawResult = null; + + public function setRawResult(RawResultInterface $rawResult): void + { + if (isset($this->rawResult)) { + throw new RawResultAlreadySetException(); + } + + $this->rawResult = $rawResult; + } + + public function getRawResult(): ?RawResultInterface + { + return $this->rawResult; + } +} diff --git a/src/platform/src/Response/RawResponseInterface.php b/src/platform/src/Result/RawResultInterface.php similarity index 58% rename from src/platform/src/Response/RawResponseInterface.php rename to src/platform/src/Result/RawResultInterface.php index f9b83656..6c000ef0 100644 --- a/src/platform/src/Response/RawResponseInterface.php +++ b/src/platform/src/Result/RawResultInterface.php @@ -9,21 +9,21 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response; +namespace Symfony\AI\Platform\Result; /** - * Base class for raw model responses. + * Base class for raw model result. * * @author Christopher Hertel */ -interface RawResponseInterface +interface RawResultInterface { /** - * Returns an array representation of the raw response data. + * Returns an array representation of the raw result data. * * @return array */ - public function getRawData(): array; + public function getData(): array; - public function getRawObject(): object; + public function getObject(): object; } diff --git a/src/platform/src/Response/ResponseInterface.php b/src/platform/src/Result/ResultInterface.php similarity index 56% rename from src/platform/src/Response/ResponseInterface.php rename to src/platform/src/Result/ResultInterface.php index e039a9a5..6f426c44 100644 --- a/src/platform/src/Response/ResponseInterface.php +++ b/src/platform/src/Result/ResultInterface.php @@ -9,16 +9,16 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response; +namespace Symfony\AI\Platform\Result; -use Symfony\AI\Platform\Response\Exception\RawResponseAlreadySetException; -use Symfony\AI\Platform\Response\Metadata\Metadata; +use Symfony\AI\Platform\Result\Exception\RawResultAlreadySetException; +use Symfony\AI\Platform\Result\Metadata\Metadata; /** * @author Christopher Hertel * @author Denis Zunke */ -interface ResponseInterface +interface ResultInterface { /** * @return string|iterable|object|null @@ -27,10 +27,10 @@ public function getContent(): string|iterable|object|null; public function getMetadata(): Metadata; - public function getRawResponse(): ?RawResponseInterface; + public function getRawResult(): ?RawResultInterface; /** - * @throws RawResponseAlreadySetException if the response is tried to be set more than once + * @throws RawResultAlreadySetException if the result is tried to be set more than once */ - public function setRawResponse(RawResponseInterface $rawResponse): void; + public function setRawResult(RawResultInterface $rawResult): void; } diff --git a/src/platform/src/Result/ResultPromise.php b/src/platform/src/Result/ResultPromise.php new file mode 100644 index 00000000..acb49dea --- /dev/null +++ b/src/platform/src/Result/ResultPromise.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\AI\Platform\Result; + +use Symfony\AI\Platform\Exception\UnexpectedResultTypeException; +use Symfony\AI\Platform\Vector\Vector; + +/** + * @author Christopher Hertel + */ +final class ResultPromise +{ + private bool $isConverted = false; + private ResultInterface $convertedResult; + + /** + * @param array $options + */ + public function __construct( + private readonly \Closure $resultConverter, + private readonly RawResultInterface $rawResult, + private readonly array $options = [], + ) { + } + + public function getResult(): ResultInterface + { + return $this->await(); + } + + public function getRawResult(): RawResultInterface + { + return $this->rawResult; + } + + public function await(): ResultInterface + { + if (!$this->isConverted) { + $this->convertedResult = ($this->resultConverter)($this->rawResult, $this->options); + + if (null === $this->convertedResult->getRawResult()) { + // Fallback to set the raw result when it was not handled by the ResultConverter itself + $this->convertedResult->setRawResult($this->rawResult); + } + + $this->isConverted = true; + } + + return $this->convertedResult; + } + + public function asText(): string + { + return $this->as(TextResult::class)->getContent(); + } + + public function asObject(): object + { + return $this->as(ObjectResult::class)->getContent(); + } + + public function asBinary(): string + { + return $this->as(BinaryResult::class)->getContent(); + } + + public function asBase64(): string + { + $result = $this->as(BinaryResult::class); + + \assert($result instanceof BinaryResult); + + return $result->toDataUri(); + } + + /** + * @return Vector[] + */ + public function asVectors(): array + { + return $this->as(VectorResult::class)->getContent(); + } + + public function asStream(): \Generator + { + yield from $this->as(StreamResult::class)->getContent(); + } + + /** + * @return ToolCall[] + */ + public function asToolCalls(): array + { + return $this->as(ToolCallResult::class)->getContent(); + } + + /** + * @param class-string $type + */ + private function as(string $type): ResultInterface + { + $result = $this->getResult(); + + if (!$result instanceof $type) { + throw new UnexpectedResultTypeException($type, $result::class); + } + + return $result; + } +} diff --git a/src/platform/src/Response/StreamResponse.php b/src/platform/src/Result/StreamResult.php similarity index 85% rename from src/platform/src/Response/StreamResponse.php rename to src/platform/src/Result/StreamResult.php index 684c4d8d..ef253ec3 100644 --- a/src/platform/src/Response/StreamResponse.php +++ b/src/platform/src/Result/StreamResult.php @@ -9,12 +9,12 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response; +namespace Symfony\AI\Platform\Result; /** * @author Christopher Hertel */ -final class StreamResponse extends BaseResponse +final class StreamResult extends BaseResult { public function __construct( private readonly \Generator $generator, diff --git a/src/platform/src/Response/TextResponse.php b/src/platform/src/Result/TextResult.php similarity index 84% rename from src/platform/src/Response/TextResponse.php rename to src/platform/src/Result/TextResult.php index 7bb9047c..ec6c41b4 100644 --- a/src/platform/src/Response/TextResponse.php +++ b/src/platform/src/Result/TextResult.php @@ -9,12 +9,12 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response; +namespace Symfony\AI\Platform\Result; /** * @author Christopher Hertel */ -final class TextResponse extends BaseResponse +final class TextResult extends BaseResult { public function __construct( private readonly string $content, diff --git a/src/platform/src/Response/ToolCall.php b/src/platform/src/Result/ToolCall.php similarity index 96% rename from src/platform/src/Response/ToolCall.php rename to src/platform/src/Result/ToolCall.php index 8633632f..6a4beeb4 100644 --- a/src/platform/src/Response/ToolCall.php +++ b/src/platform/src/Result/ToolCall.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response; +namespace Symfony\AI\Platform\Result; /** * @author Christopher Hertel diff --git a/src/platform/src/Response/ToolCallResponse.php b/src/platform/src/Result/ToolCallResult.php similarity index 90% rename from src/platform/src/Response/ToolCallResponse.php rename to src/platform/src/Result/ToolCallResult.php index fa1a52d1..77d4e06c 100644 --- a/src/platform/src/Response/ToolCallResponse.php +++ b/src/platform/src/Result/ToolCallResult.php @@ -9,14 +9,14 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response; +namespace Symfony\AI\Platform\Result; use Symfony\AI\Platform\Exception\InvalidArgumentException; /** * @author Christopher Hertel */ -final class ToolCallResponse extends BaseResponse +final class ToolCallResult extends BaseResult { /** * @var ToolCall[] diff --git a/src/platform/src/Response/VectorResponse.php b/src/platform/src/Result/VectorResult.php similarity index 88% rename from src/platform/src/Response/VectorResponse.php rename to src/platform/src/Result/VectorResult.php index e63c898c..0e098c58 100644 --- a/src/platform/src/Response/VectorResponse.php +++ b/src/platform/src/Result/VectorResult.php @@ -9,14 +9,14 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Response; +namespace Symfony\AI\Platform\Result; use Symfony\AI\Platform\Vector\Vector; /** * @author Christopher Hertel */ -final class VectorResponse extends BaseResponse +final class VectorResult extends BaseResult { /** * @var Vector[] diff --git a/src/platform/src/ResponseConverterInterface.php b/src/platform/src/ResultConverterInterface.php similarity index 64% rename from src/platform/src/ResponseConverterInterface.php rename to src/platform/src/ResultConverterInterface.php index 856c16a3..b7a5ffba 100644 --- a/src/platform/src/ResponseConverterInterface.php +++ b/src/platform/src/ResultConverterInterface.php @@ -11,18 +11,18 @@ namespace Symfony\AI\Platform; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponseInterface; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultInterface; /** * @author Christopher Hertel */ -interface ResponseConverterInterface +interface ResultConverterInterface { public function supports(Model $model): bool; /** * @param array $options */ - public function convert(RawResponseInterface $response, array $options = []): ResponseInterface; + public function convert(RawResultInterface $result, array $options = []): ResultInterface; } diff --git a/src/platform/tests/Bridge/Albert/EmbeddingsModelClientTest.php b/src/platform/tests/Bridge/Albert/EmbeddingsModelClientTest.php index 72207607..befa42bf 100644 --- a/src/platform/tests/Bridge/Albert/EmbeddingsModelClientTest.php +++ b/src/platform/tests/Bridge/Albert/EmbeddingsModelClientTest.php @@ -97,7 +97,7 @@ public function requestSendsCorrectHttpRequest(array|string $payload, array $opt ); $model = new Embeddings('text-embedding-ada-002'); - $response = $client->request($model, $payload, $options); + $result = $client->request($model, $payload, $options); self::assertNotNull($capturedRequest); self::assertSame('POST', $capturedRequest['method']); diff --git a/src/platform/tests/Bridge/Albert/GPTModelClientTest.php b/src/platform/tests/Bridge/Albert/GPTModelClientTest.php index a19bed03..43001d52 100644 --- a/src/platform/tests/Bridge/Albert/GPTModelClientTest.php +++ b/src/platform/tests/Bridge/Albert/GPTModelClientTest.php @@ -142,7 +142,7 @@ public function requestSendsCorrectHttpRequest(array|string $payload, array $opt ); $model = new GPT('gpt-3.5-turbo'); - $response = $client->request($model, $payload, $options); + $result = $client->request($model, $payload, $options); self::assertNotNull($capturedRequest); self::assertSame('POST', $capturedRequest['method']); diff --git a/src/platform/tests/Bridge/Anthropic/ResponseConverterTest.php b/src/platform/tests/Bridge/Anthropic/ResultConverterTest.php similarity index 58% rename from src/platform/tests/Bridge/Anthropic/ResponseConverterTest.php rename to src/platform/tests/Bridge/Anthropic/ResultConverterTest.php index 45717eee..7e65273a 100644 --- a/src/platform/tests/Bridge/Anthropic/ResponseConverterTest.php +++ b/src/platform/tests/Bridge/Anthropic/ResultConverterTest.php @@ -15,18 +15,18 @@ use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; -use Symfony\AI\Platform\Bridge\Anthropic\ResponseConverter; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\ToolCall; -use Symfony\AI\Platform\Response\ToolCallResponse; +use Symfony\AI\Platform\Bridge\Anthropic\ResultConverter; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\ToolCall; +use Symfony\AI\Platform\Result\ToolCallResult; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\Response\JsonMockResponse; -#[CoversClass(ResponseConverter::class)] +#[CoversClass(ResultConverter::class)] #[Small] #[UsesClass(ToolCall::class)] -#[UsesClass(ToolCallResponse::class)] -final class ResponseConverterTest extends TestCase +#[UsesClass(ToolCallResult::class)] +final class ResultConverterTest extends TestCase { public function testConvertThrowsExceptionWhenContentIsToolUseAndLacksText(): void { @@ -41,13 +41,13 @@ public function testConvertThrowsExceptionWhenContentIsToolUseAndLacksText(): vo ], ])); $httpResponse = $httpClient->request('POST', 'https://api.anthropic.com/v1/messages'); - $handler = new ResponseConverter(); + $handler = new ResultConverter(); - $response = $handler->convert(new RawHttpResponse($httpResponse)); - self::assertInstanceOf(ToolCallResponse::class, $response); - self::assertCount(1, $response->getContent()); - self::assertSame('toolu_01UM4PcTjC1UDiorSXVHSVFM', $response->getContent()[0]->id); - self::assertSame('xxx_tool', $response->getContent()[0]->name); - self::assertSame(['action' => 'get_data'], $response->getContent()[0]->arguments); + $result = $handler->convert(new RawHttpResult($httpResponse)); + self::assertInstanceOf(ToolCallResult::class, $result); + self::assertCount(1, $result->getContent()); + self::assertSame('toolu_01UM4PcTjC1UDiorSXVHSVFM', $result->getContent()[0]->id); + self::assertSame('xxx_tool', $result->getContent()[0]->name); + self::assertSame(['action' => 'get_data'], $result->getContent()[0]->arguments); } } diff --git a/src/platform/tests/Bridge/Azure/OpenAI/EmbeddingsModelClientTest.php b/src/platform/tests/Bridge/Azure/OpenAI/EmbeddingsModelClientTest.php index cf8531d6..ea34b03f 100644 --- a/src/platform/tests/Bridge/Azure/OpenAI/EmbeddingsModelClientTest.php +++ b/src/platform/tests/Bridge/Azure/OpenAI/EmbeddingsModelClientTest.php @@ -90,7 +90,7 @@ public function itIsSupportingTheCorrectModel(): void #[Test] public function itIsExecutingTheCorrectRequest(): void { - $responseCallback = static function (string $method, string $url, array $options): MockResponse { + $resultCallback = static function (string $method, string $url, array $options): MockResponse { self::assertSame('POST', $method); self::assertSame('https://test.azure.com/openai/deployments/embeddings-deployment/embeddings?api-version=2023-12-01', $url); self::assertSame(['api-key: test-api-key'], $options['normalized_headers']['api-key']); @@ -99,7 +99,7 @@ public function itIsExecutingTheCorrectRequest(): void return new MockResponse(); }; - $httpClient = new MockHttpClient([$responseCallback]); + $httpClient = new MockHttpClient([$resultCallback]); $client = new EmbeddingsModelClient($httpClient, 'test.azure.com', 'embeddings-deployment', '2023-12-01', 'test-api-key'); $client->request(new Embeddings(), 'Hello, world!'); } diff --git a/src/platform/tests/Bridge/Azure/OpenAI/GPTModelClientTest.php b/src/platform/tests/Bridge/Azure/OpenAI/GPTModelClientTest.php index efa74258..f89767a8 100644 --- a/src/platform/tests/Bridge/Azure/OpenAI/GPTModelClientTest.php +++ b/src/platform/tests/Bridge/Azure/OpenAI/GPTModelClientTest.php @@ -90,7 +90,7 @@ public function itIsSupportingTheCorrectModel(): void #[Test] public function itIsExecutingTheCorrectRequest(): void { - $responseCallback = static function (string $method, string $url, array $options): MockResponse { + $resultCallback = static function (string $method, string $url, array $options): MockResponse { self::assertSame('POST', $method); self::assertSame('https://test.azure.com/openai/deployments/gpt-deployment/chat/completions?api-version=2023-12-01', $url); self::assertSame(['api-key: test-api-key'], $options['normalized_headers']['api-key']); @@ -99,7 +99,7 @@ public function itIsExecutingTheCorrectRequest(): void return new MockResponse(); }; - $httpClient = new MockHttpClient([$responseCallback]); + $httpClient = new MockHttpClient([$resultCallback]); $client = new GPTModelClient($httpClient, 'test.azure.com', 'gpt-deployment', '2023-12-01', 'test-api-key'); $client->request(new GPT(), ['messages' => [['role' => 'user', 'content' => 'Hello']]]); } diff --git a/src/platform/tests/Bridge/Bedrock/Nova/ContractTest.php b/src/platform/tests/Bridge/Bedrock/Nova/ContractTest.php index c152cdfb..586ed25c 100644 --- a/src/platform/tests/Bridge/Bedrock/Nova/ContractTest.php +++ b/src/platform/tests/Bridge/Bedrock/Nova/ContractTest.php @@ -30,7 +30,7 @@ use Symfony\AI\Platform\Message\SystemMessage; use Symfony\AI\Platform\Message\ToolCallMessage; use Symfony\AI\Platform\Message\UserMessage; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; #[Medium] #[CoversClass(AssistantMessageNormalizer::class)] diff --git a/src/platform/tests/Bridge/Google/Contract/AssistantMessageNormalizerTest.php b/src/platform/tests/Bridge/Google/Contract/AssistantMessageNormalizerTest.php index a79ab424..af7779cf 100644 --- a/src/platform/tests/Bridge/Google/Contract/AssistantMessageNormalizerTest.php +++ b/src/platform/tests/Bridge/Google/Contract/AssistantMessageNormalizerTest.php @@ -22,7 +22,7 @@ use Symfony\AI\Platform\Contract; use Symfony\AI\Platform\Message\AssistantMessage; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; #[Small] #[CoversClass(AssistantMessageNormalizer::class)] diff --git a/src/platform/tests/Bridge/Google/Contract/ToolCallMessageNormalizerTest.php b/src/platform/tests/Bridge/Google/Contract/ToolCallMessageNormalizerTest.php index 35700d6d..4e81d1ab 100644 --- a/src/platform/tests/Bridge/Google/Contract/ToolCallMessageNormalizerTest.php +++ b/src/platform/tests/Bridge/Google/Contract/ToolCallMessageNormalizerTest.php @@ -22,7 +22,7 @@ use Symfony\AI\Platform\Contract; use Symfony\AI\Platform\Message\ToolCallMessage; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; #[Small] #[CoversClass(ToolCallMessageNormalizer::class)] diff --git a/src/platform/tests/Bridge/Google/Embeddings/ModelClientTest.php b/src/platform/tests/Bridge/Google/Embeddings/ModelClientTest.php index 5dfdae81..16dc0590 100644 --- a/src/platform/tests/Bridge/Google/Embeddings/ModelClientTest.php +++ b/src/platform/tests/Bridge/Google/Embeddings/ModelClientTest.php @@ -18,7 +18,7 @@ use PHPUnit\Framework\TestCase; use Symfony\AI\Platform\Bridge\Google\Embeddings; use Symfony\AI\Platform\Bridge\Google\Embeddings\ModelClient; -use Symfony\AI\Platform\Response\VectorResponse; +use Symfony\AI\Platform\Result\VectorResult; use Symfony\AI\Platform\Vector\Vector; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\ResponseInterface; @@ -26,15 +26,15 @@ #[CoversClass(ModelClient::class)] #[Small] #[UsesClass(Vector::class)] -#[UsesClass(VectorResponse::class)] +#[UsesClass(VectorResult::class)] #[UsesClass(Embeddings::class)] final class ModelClientTest extends TestCase { #[Test] public function itMakesARequestWithCorrectPayload(): void { - $response = $this->createStub(ResponseInterface::class); - $response + $result = $this->createStub(ResponseInterface::class); + $result ->method('toArray') ->willReturn(json_decode($this->getEmbeddingStub(), true)); @@ -64,12 +64,12 @@ public function itMakesARequestWithCorrectPayload(): void ], ], ) - ->willReturn($response); + ->willReturn($result); $model = new Embeddings(Embeddings::GEMINI_EMBEDDING_EXP_03_07, ['dimensions' => 1536, 'task_type' => 'CLASSIFICATION']); - $response = (new ModelClient($httpClient, 'test'))->request($model, ['payload1', 'payload2']); - self::assertSame(json_decode($this->getEmbeddingStub(), true), $response->getRawData()); + $result = (new ModelClient($httpClient, 'test'))->request($model, ['payload1', 'payload2']); + self::assertSame(json_decode($this->getEmbeddingStub(), true), $result->getData()); } private function getEmbeddingStub(): string diff --git a/src/platform/tests/Bridge/Google/Embeddings/ResponseConverterTest.php b/src/platform/tests/Bridge/Google/Embeddings/ResponseConverterTest.php index c97c10b8..5f8ecf20 100644 --- a/src/platform/tests/Bridge/Google/Embeddings/ResponseConverterTest.php +++ b/src/platform/tests/Bridge/Google/Embeddings/ResponseConverterTest.php @@ -17,28 +17,28 @@ use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; use Symfony\AI\Platform\Bridge\Google\Embeddings; -use Symfony\AI\Platform\Bridge\Google\Embeddings\ResponseConverter; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\VectorResponse; +use Symfony\AI\Platform\Bridge\Google\Embeddings\ResultConverter; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\VectorResult; use Symfony\AI\Platform\Vector\Vector; use Symfony\Contracts\HttpClient\ResponseInterface; -#[CoversClass(ResponseConverter::class)] +#[CoversClass(ResultConverter::class)] #[Small] #[UsesClass(Vector::class)] -#[UsesClass(VectorResponse::class)] +#[UsesClass(VectorResult::class)] #[UsesClass(Embeddings::class)] final class ResponseConverterTest extends TestCase { #[Test] public function itConvertsAResponseToAVectorResponse(): void { - $response = $this->createStub(ResponseInterface::class); - $response + $result = $this->createStub(ResponseInterface::class); + $result ->method('toArray') ->willReturn(json_decode($this->getEmbeddingStub(), true)); - $vectorResponse = (new ResponseConverter())->convert(new RawHttpResponse($response)); + $vectorResponse = (new ResultConverter())->convert(new RawHttpResult($result)); $convertedContent = $vectorResponse->getContent(); self::assertCount(2, $convertedContent); diff --git a/src/platform/tests/Bridge/LMStudio/Completions/ModelClientTest.php b/src/platform/tests/Bridge/LMStudio/Completions/ModelClientTest.php index be79e84f..b6131707 100644 --- a/src/platform/tests/Bridge/LMStudio/Completions/ModelClientTest.php +++ b/src/platform/tests/Bridge/LMStudio/Completions/ModelClientTest.php @@ -39,7 +39,7 @@ public function itIsSupportingTheCorrectModel(): void #[Test] public function itIsExecutingTheCorrectRequest(): void { - $responseCallback = static function (string $method, string $url, array $options): MockResponse { + $resultCallback = static function (string $method, string $url, array $options): MockResponse { self::assertSame('POST', $method); self::assertSame('http://localhost:1234/v1/chat/completions', $url); self::assertSame( @@ -50,7 +50,7 @@ public function itIsExecutingTheCorrectRequest(): void return new MockResponse(); }; - $httpClient = new MockHttpClient([$responseCallback]); + $httpClient = new MockHttpClient([$resultCallback]); $client = new ModelClient($httpClient, 'http://localhost:1234'); $payload = [ @@ -66,7 +66,7 @@ public function itIsExecutingTheCorrectRequest(): void #[Test] public function itMergesOptionsWithPayload(): void { - $responseCallback = static function (string $method, string $url, array $options): MockResponse { + $resultCallback = static function (string $method, string $url, array $options): MockResponse { self::assertSame('POST', $method); self::assertSame('http://localhost:1234/v1/chat/completions', $url); self::assertSame( @@ -77,7 +77,7 @@ public function itMergesOptionsWithPayload(): void return new MockResponse(); }; - $httpClient = new MockHttpClient([$responseCallback]); + $httpClient = new MockHttpClient([$resultCallback]); $client = new ModelClient($httpClient, 'http://localhost:1234'); $payload = [ diff --git a/src/platform/tests/Bridge/LMStudio/Completions/ResponseConverterTest.php b/src/platform/tests/Bridge/LMStudio/Completions/ResponseConverterTest.php index 5da6f9b9..488aac11 100644 --- a/src/platform/tests/Bridge/LMStudio/Completions/ResponseConverterTest.php +++ b/src/platform/tests/Bridge/LMStudio/Completions/ResponseConverterTest.php @@ -17,10 +17,10 @@ use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; use Symfony\AI\Platform\Bridge\LMStudio\Completions; -use Symfony\AI\Platform\Bridge\LMStudio\Completions\ResponseConverter; -use Symfony\AI\Platform\Bridge\OpenAI\GPT\ResponseConverter as OpenAIResponseConverter; +use Symfony\AI\Platform\Bridge\LMStudio\Completions\ResultConverter; +use Symfony\AI\Platform\Bridge\OpenAI\GPT\ResultConverter as OpenAIResponseConverter; -#[CoversClass(ResponseConverter::class)] +#[CoversClass(ResultConverter::class)] #[UsesClass(Completions::class)] #[UsesClass(OpenAIResponseConverter::class)] #[Small] @@ -29,7 +29,7 @@ class ResponseConverterTest extends TestCase #[Test] public function itSupportsCompletionsModel(): void { - $converter = new ResponseConverter(); + $converter = new ResultConverter(); self::assertTrue($converter->supports(new Completions('test-model'))); } diff --git a/src/platform/tests/Bridge/LMStudio/Embeddings/ModelClientTest.php b/src/platform/tests/Bridge/LMStudio/Embeddings/ModelClientTest.php index a4c6e888..204dae6e 100644 --- a/src/platform/tests/Bridge/LMStudio/Embeddings/ModelClientTest.php +++ b/src/platform/tests/Bridge/LMStudio/Embeddings/ModelClientTest.php @@ -37,7 +37,7 @@ public function itIsSupportingTheCorrectModel(): void #[Test] public function itIsExecutingTheCorrectRequest(): void { - $responseCallback = static function (string $method, string $url, array $options): MockResponse { + $resultCallback = static function (string $method, string $url, array $options): MockResponse { self::assertSame('POST', $method); self::assertSame('http://localhost:1234/v1/embeddings', $url); self::assertSame('{"model":"test-model","input":"Hello, world!"}', $options['body']); @@ -45,7 +45,7 @@ public function itIsExecutingTheCorrectRequest(): void return new MockResponse(); }; - $httpClient = new MockHttpClient([$responseCallback]); + $httpClient = new MockHttpClient([$resultCallback]); $client = new ModelClient($httpClient, 'http://localhost:1234'); $model = new Embeddings('test-model'); @@ -56,7 +56,7 @@ public function itIsExecutingTheCorrectRequest(): void #[Test] public function itMergesOptionsWithPayload(): void { - $responseCallback = static function (string $method, string $url, array $options): MockResponse { + $resultCallback = static function (string $method, string $url, array $options): MockResponse { self::assertSame('POST', $method); self::assertSame('http://localhost:1234/v1/embeddings', $url); self::assertSame( @@ -67,7 +67,7 @@ public function itMergesOptionsWithPayload(): void return new MockResponse(); }; - $httpClient = new MockHttpClient([$responseCallback]); + $httpClient = new MockHttpClient([$resultCallback]); $client = new ModelClient($httpClient, 'http://localhost:1234'); $model = new Embeddings('test-model'); @@ -78,7 +78,7 @@ public function itMergesOptionsWithPayload(): void #[Test] public function itHandlesArrayInput(): void { - $responseCallback = static function (string $method, string $url, array $options): MockResponse { + $resultCallback = static function (string $method, string $url, array $options): MockResponse { self::assertSame('POST', $method); self::assertSame('http://localhost:1234/v1/embeddings', $url); self::assertSame('{"model":"test-model","input":["Hello","world"]}', $options['body']); @@ -86,7 +86,7 @@ public function itHandlesArrayInput(): void return new MockResponse(); }; - $httpClient = new MockHttpClient([$responseCallback]); + $httpClient = new MockHttpClient([$resultCallback]); $client = new ModelClient($httpClient, 'http://localhost:1234'); $model = new Embeddings('test-model'); diff --git a/src/platform/tests/Bridge/LMStudio/Embeddings/ResponseConverterTest.php b/src/platform/tests/Bridge/LMStudio/Embeddings/ResultConverterTest.php similarity index 76% rename from src/platform/tests/Bridge/LMStudio/Embeddings/ResponseConverterTest.php rename to src/platform/tests/Bridge/LMStudio/Embeddings/ResultConverterTest.php index af6ef08e..a4a230e8 100644 --- a/src/platform/tests/Bridge/LMStudio/Embeddings/ResponseConverterTest.php +++ b/src/platform/tests/Bridge/LMStudio/Embeddings/ResultConverterTest.php @@ -17,25 +17,25 @@ use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; use Symfony\AI\Platform\Bridge\LMStudio\Embeddings; -use Symfony\AI\Platform\Bridge\LMStudio\Embeddings\ResponseConverter; +use Symfony\AI\Platform\Bridge\LMStudio\Embeddings\ResultConverter; use Symfony\AI\Platform\Exception\RuntimeException; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\VectorResponse; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\VectorResult; use Symfony\AI\Platform\Vector\Vector; use Symfony\Contracts\HttpClient\ResponseInterface; -#[CoversClass(ResponseConverter::class)] +#[CoversClass(ResultConverter::class)] #[Small] #[UsesClass(Vector::class)] -#[UsesClass(VectorResponse::class)] +#[UsesClass(VectorResult::class)] #[UsesClass(Embeddings::class)] -class ResponseConverterTest extends TestCase +class ResultConverterTest extends TestCase { #[Test] public function itConvertsAResponseToAVectorResponse(): void { - $response = $this->createStub(ResponseInterface::class); - $response + $result = $this->createStub(ResponseInterface::class); + $result ->method('toArray') ->willReturn( json_decode( @@ -60,8 +60,8 @@ public function itConvertsAResponseToAVectorResponse(): void ) ); - $vectorResponse = (new ResponseConverter())->convert(new RawHttpResponse($response)); - $convertedContent = $vectorResponse->getContent(); + $vectorResult = (new ResultConverter())->convert(new RawHttpResult($result)); + $convertedContent = $vectorResult->getContent(); self::assertCount(2, $convertedContent); @@ -72,21 +72,21 @@ public function itConvertsAResponseToAVectorResponse(): void #[Test] public function itThrowsExceptionWhenResponseDoesNotContainData(): void { - $response = $this->createStub(ResponseInterface::class); - $response + $result = $this->createStub(ResponseInterface::class); + $result ->method('toArray') ->willReturn(['invalid' => 'response']); $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Response does not contain data'); - (new ResponseConverter())->convert(new RawHttpResponse($response)); + (new ResultConverter())->convert(new RawHttpResult($result)); } #[Test] public function itSupportsEmbeddingsModel(): void { - $converter = new ResponseConverter(); + $converter = new ResultConverter(); self::assertTrue($converter->supports(new Embeddings('test-model'))); } diff --git a/src/platform/tests/Bridge/Mistral/TokenOutputProcessorTest.php b/src/platform/tests/Bridge/Mistral/TokenOutputProcessorTest.php index 75970fe1..e838325f 100644 --- a/src/platform/tests/Bridge/Mistral/TokenOutputProcessorTest.php +++ b/src/platform/tests/Bridge/Mistral/TokenOutputProcessorTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Bridge\Mistral; +namespace Symfony\AI\Platform\Tests\Bridge\Mistral; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Small; @@ -20,17 +20,17 @@ use Symfony\AI\Platform\Bridge\Mistral\TokenOutputProcessor; use Symfony\AI\Platform\Message\MessageBagInterface; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\Metadata\Metadata; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\Response\StreamResponse; -use Symfony\AI\Platform\Response\TextResponse; +use Symfony\AI\Platform\Result\Metadata\Metadata; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\Result\StreamResult; +use Symfony\AI\Platform\Result\TextResult; use Symfony\Contracts\HttpClient\ResponseInterface as SymfonyHttpResponse; #[CoversClass(TokenOutputProcessor::class)] #[UsesClass(Output::class)] -#[UsesClass(TextResponse::class)] -#[UsesClass(StreamResponse::class)] +#[UsesClass(TextResult::class)] +#[UsesClass(StreamResult::class)] #[UsesClass(Metadata::class)] #[Small] final class TokenOutputProcessorTest extends TestCase @@ -39,12 +39,12 @@ final class TokenOutputProcessorTest extends TestCase public function itHandlesStreamResponsesWithoutProcessing(): void { $processor = new TokenOutputProcessor(); - $streamResponse = new StreamResponse((static function () { yield 'test'; })()); - $output = $this->createOutput($streamResponse); + $streamResult = new StreamResult((static function () { yield 'test'; })()); + $output = $this->createOutput($streamResult); $processor->processOutput($output); - $metadata = $output->response->getMetadata(); + $metadata = $output->result->getMetadata(); self::assertCount(0, $metadata); } @@ -52,12 +52,12 @@ public function itHandlesStreamResponsesWithoutProcessing(): void public function itDoesNothingWithoutRawResponse(): void { $processor = new TokenOutputProcessor(); - $textResponse = new TextResponse('test'); - $output = $this->createOutput($textResponse); + $textResult = new TextResult('test'); + $output = $this->createOutput($textResult); $processor->processOutput($output); - $metadata = $output->response->getMetadata(); + $metadata = $output->result->getMetadata(); self::assertCount(0, $metadata); } @@ -65,15 +65,15 @@ public function itDoesNothingWithoutRawResponse(): void public function itAddsRemainingTokensToMetadata(): void { $processor = new TokenOutputProcessor(); - $textResponse = new TextResponse('test'); + $textResult = new TextResult('test'); - $textResponse->setRawResponse($this->createRawResponse()); + $textResult->setRawResult($this->createRawResponse()); - $output = $this->createOutput($textResponse); + $output = $this->createOutput($textResult); $processor->processOutput($output); - $metadata = $output->response->getMetadata(); + $metadata = $output->result->getMetadata(); self::assertCount(2, $metadata); self::assertSame(1000, $metadata->get('remaining_tokens_minute')); self::assertSame(1000000, $metadata->get('remaining_tokens_month')); @@ -83,7 +83,7 @@ public function itAddsRemainingTokensToMetadata(): void public function itAddsUsageTokensToMetadata(): void { $processor = new TokenOutputProcessor(); - $textResponse = new TextResponse('test'); + $textResult = new TextResult('test'); $rawResponse = $this->createRawResponse([ 'usage' => [ @@ -93,13 +93,13 @@ public function itAddsUsageTokensToMetadata(): void ], ]); - $textResponse->setRawResponse($rawResponse); + $textResult->setRawResult($rawResponse); - $output = $this->createOutput($textResponse); + $output = $this->createOutput($textResult); $processor->processOutput($output); - $metadata = $output->response->getMetadata(); + $metadata = $output->result->getMetadata(); self::assertCount(5, $metadata); self::assertSame(1000, $metadata->get('remaining_tokens_minute')); self::assertSame(1000000, $metadata->get('remaining_tokens_month')); @@ -112,7 +112,7 @@ public function itAddsUsageTokensToMetadata(): void public function itHandlesMissingUsageFields(): void { $processor = new TokenOutputProcessor(); - $textResponse = new TextResponse('test'); + $textResult = new TextResult('test'); $rawResponse = $this->createRawResponse([ 'usage' => [ @@ -121,13 +121,13 @@ public function itHandlesMissingUsageFields(): void ], ]); - $textResponse->setRawResponse($rawResponse); + $textResult->setRawResult($rawResponse); - $output = $this->createOutput($textResponse); + $output = $this->createOutput($textResult); $processor->processOutput($output); - $metadata = $output->response->getMetadata(); + $metadata = $output->result->getMetadata(); self::assertCount(5, $metadata); self::assertSame(1000, $metadata->get('remaining_tokens_minute')); self::assertSame(1000000, $metadata->get('remaining_tokens_month')); @@ -136,7 +136,7 @@ public function itHandlesMissingUsageFields(): void self::assertNull($metadata->get('total_tokens')); } - private function createRawResponse(array $data = []): RawHttpResponse + private function createRawResponse(array $data = []): RawHttpResult { $rawResponse = self::createStub(SymfonyHttpResponse::class); $rawResponse->method('getHeaders')->willReturn([ @@ -146,14 +146,14 @@ private function createRawResponse(array $data = []): RawHttpResponse $rawResponse->method('toArray')->willReturn($data); - return new RawHttpResponse($rawResponse); + return new RawHttpResult($rawResponse); } - private function createOutput(ResponseInterface $response): Output + private function createOutput(ResultInterface $result): Output { return new Output( self::createStub(Model::class), - $response, + $result, self::createStub(MessageBagInterface::class), [], ); diff --git a/src/platform/tests/Bridge/OpenAI/DallE/ImageResponseTest.php b/src/platform/tests/Bridge/OpenAI/DallE/ImageResultTest.php similarity index 55% rename from src/platform/tests/Bridge/OpenAI/DallE/ImageResponseTest.php rename to src/platform/tests/Bridge/OpenAI/DallE/ImageResultTest.php index 75e9ce84..407a5b93 100644 --- a/src/platform/tests/Bridge/OpenAI/DallE/ImageResponseTest.php +++ b/src/platform/tests/Bridge/OpenAI/DallE/ImageResultTest.php @@ -17,35 +17,35 @@ use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; use Symfony\AI\Platform\Bridge\OpenAI\DallE\Base64Image; -use Symfony\AI\Platform\Bridge\OpenAI\DallE\ImageResponse; +use Symfony\AI\Platform\Bridge\OpenAI\DallE\ImageResult; use Symfony\AI\Platform\Bridge\OpenAI\DallE\UrlImage; -#[CoversClass(ImageResponse::class)] +#[CoversClass(ImageResult::class)] #[UsesClass(Base64Image::class)] #[UsesClass(UrlImage::class)] #[Small] -final class ImageResponseTest extends TestCase +final class ImageResultTest extends TestCase { #[Test] public function itCreatesImagesResponse(): void { $base64Image = new Base64Image('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='); - $generatedImagesResponse = new ImageResponse(null, $base64Image); + $generatedImagesResult = new ImageResult(null, $base64Image); - self::assertNull($generatedImagesResponse->revisedPrompt); - self::assertCount(1, $generatedImagesResponse->getContent()); - self::assertSame($base64Image, $generatedImagesResponse->getContent()[0]); + self::assertNull($generatedImagesResult->revisedPrompt); + self::assertCount(1, $generatedImagesResult->getContent()); + self::assertSame($base64Image, $generatedImagesResult->getContent()[0]); } #[Test] public function itCreatesImagesResponseWithRevisedPrompt(): void { $base64Image = new Base64Image('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='); - $generatedImagesResponse = new ImageResponse('revised prompt', $base64Image); + $generatedImagesResult = new ImageResult('revised prompt', $base64Image); - self::assertSame('revised prompt', $generatedImagesResponse->revisedPrompt); - self::assertCount(1, $generatedImagesResponse->getContent()); - self::assertSame($base64Image, $generatedImagesResponse->getContent()[0]); + self::assertSame('revised prompt', $generatedImagesResult->revisedPrompt); + self::assertCount(1, $generatedImagesResult->getContent()); + self::assertSame($base64Image, $generatedImagesResult->getContent()[0]); } #[Test] @@ -54,10 +54,10 @@ public function itIsCreatableWithMultipleImages(): void $image1 = new UrlImage('https://example'); $image2 = new UrlImage('https://example2'); - $generatedImagesResponse = new ImageResponse(null, $image1, $image2); + $generatedImagesResult = new ImageResult(null, $image1, $image2); - self::assertCount(2, $generatedImagesResponse->getContent()); - self::assertSame($image1, $generatedImagesResponse->getContent()[0]); - self::assertSame($image2, $generatedImagesResponse->getContent()[1]); + self::assertCount(2, $generatedImagesResult->getContent()); + self::assertSame($image1, $generatedImagesResult->getContent()[0]); + self::assertSame($image2, $generatedImagesResult->getContent()[1]); } } diff --git a/src/platform/tests/Bridge/OpenAI/DallE/ModelClientTest.php b/src/platform/tests/Bridge/OpenAI/DallE/ModelClientTest.php index 2e44568c..dfe58684 100644 --- a/src/platform/tests/Bridge/OpenAI/DallE/ModelClientTest.php +++ b/src/platform/tests/Bridge/OpenAI/DallE/ModelClientTest.php @@ -72,7 +72,7 @@ public function itIsSupportingTheCorrectModel(): void #[Test] public function itIsExecutingTheCorrectRequest(): void { - $responseCallback = static function (string $method, string $url, array $options): HttpResponse { + $resultCallback = static function (string $method, string $url, array $options): HttpResponse { self::assertSame('POST', $method); self::assertSame('https://api.openai.com/v1/images/generations', $url); self::assertSame('Authorization: Bearer sk-api-key', $options['normalized_headers']['authorization'][0]); @@ -80,7 +80,7 @@ public function itIsExecutingTheCorrectRequest(): void return new MockResponse(); }; - $httpClient = new MockHttpClient([$responseCallback]); + $httpClient = new MockHttpClient([$resultCallback]); $modelClient = new ModelClient($httpClient, 'sk-api-key'); $modelClient->request(new DallE(), 'foo', ['n' => 1, 'response_format' => 'url']); } diff --git a/src/platform/tests/Bridge/OpenAI/DallE/ResponseConverterTest.php b/src/platform/tests/Bridge/OpenAI/DallE/ResponseConverterTest.php index 660b7ff8..22578a9e 100644 --- a/src/platform/tests/Bridge/OpenAI/DallE/ResponseConverterTest.php +++ b/src/platform/tests/Bridge/OpenAI/DallE/ResponseConverterTest.php @@ -17,16 +17,16 @@ use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; use Symfony\AI\Platform\Bridge\OpenAI\DallE\Base64Image; -use Symfony\AI\Platform\Bridge\OpenAI\DallE\ImageResponse; -use Symfony\AI\Platform\Bridge\OpenAI\DallE\ResponseConverter; +use Symfony\AI\Platform\Bridge\OpenAI\DallE\ImageResult; +use Symfony\AI\Platform\Bridge\OpenAI\DallE\ResultConverter; use Symfony\AI\Platform\Bridge\OpenAI\DallE\UrlImage; -use Symfony\AI\Platform\Response\RawHttpResponse; +use Symfony\AI\Platform\Result\RawHttpResult; use Symfony\Contracts\HttpClient\ResponseInterface as HttpResponse; -#[CoversClass(ResponseConverter::class)] +#[CoversClass(ResultConverter::class)] #[UsesClass(UrlImage::class)] #[UsesClass(Base64Image::class)] -#[UsesClass(ImageResponse::class)] +#[UsesClass(ImageResult::class)] #[Small] final class ResponseConverterTest extends TestCase { @@ -40,12 +40,12 @@ public function itIsConvertingTheResponse(): void ], ]); - $responseConverter = new ResponseConverter(); - $response = $responseConverter->convert(new RawHttpResponse($httpResponse), ['response_format' => 'url']); + $resultConverter = new ResultConverter(); + $result = $resultConverter->convert(new RawHttpResult($httpResponse), ['response_format' => 'url']); - self::assertCount(1, $response->getContent()); - self::assertInstanceOf(UrlImage::class, $response->getContent()[0]); - self::assertSame('https://example.com/image.jpg', $response->getContent()[0]->url); + self::assertCount(1, $result->getContent()); + self::assertInstanceOf(UrlImage::class, $result->getContent()[0]); + self::assertSame('https://example.com/image.jpg', $result->getContent()[0]->url); } #[Test] @@ -60,13 +60,13 @@ public function itIsConvertingTheResponseWithRevisedPrompt(): void ], ]); - $responseConverter = new ResponseConverter(); - $response = $responseConverter->convert(new RawHttpResponse($httpResponse), ['response_format' => 'b64_json']); + $resultConverter = new ResultConverter(); + $result = $resultConverter->convert(new RawHttpResult($httpResponse), ['response_format' => 'b64_json']); - self::assertInstanceOf(ImageResponse::class, $response); - self::assertCount(1, $response->getContent()); - self::assertInstanceOf(Base64Image::class, $response->getContent()[0]); - self::assertSame($emptyPixel, $response->getContent()[0]->encodedImage); - self::assertSame('revised prompt', $response->revisedPrompt); + self::assertInstanceOf(ImageResult::class, $result); + self::assertCount(1, $result->getContent()); + self::assertInstanceOf(Base64Image::class, $result->getContent()[0]); + self::assertSame($emptyPixel, $result->getContent()[0]->encodedImage); + self::assertSame('revised prompt', $result->revisedPrompt); } } diff --git a/src/platform/tests/Bridge/OpenAI/Embeddings/ResponseConverterTest.php b/src/platform/tests/Bridge/OpenAI/Embeddings/ResponseConverterTest.php index f1ccc37b..cf5b04b5 100644 --- a/src/platform/tests/Bridge/OpenAI/Embeddings/ResponseConverterTest.php +++ b/src/platform/tests/Bridge/OpenAI/Embeddings/ResponseConverterTest.php @@ -16,27 +16,27 @@ use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; -use Symfony\AI\Platform\Bridge\OpenAI\Embeddings\ResponseConverter; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\VectorResponse; +use Symfony\AI\Platform\Bridge\OpenAI\Embeddings\ResultConverter; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\VectorResult; use Symfony\AI\Platform\Vector\Vector; use Symfony\Contracts\HttpClient\ResponseInterface; -#[CoversClass(ResponseConverter::class)] +#[CoversClass(ResultConverter::class)] #[Small] #[UsesClass(Vector::class)] -#[UsesClass(VectorResponse::class)] +#[UsesClass(VectorResult::class)] class ResponseConverterTest extends TestCase { #[Test] public function itConvertsAResponseToAVectorResponse(): void { - $response = $this->createStub(ResponseInterface::class); - $response + $result = $this->createStub(ResponseInterface::class); + $result ->method('toArray') ->willReturn(json_decode($this->getEmbeddingStub(), true)); - $vectorResponse = (new ResponseConverter())->convert(new RawHttpResponse($response)); + $vectorResponse = (new ResultConverter())->convert(new RawHttpResult($result)); $convertedContent = $vectorResponse->getContent(); self::assertCount(2, $convertedContent); diff --git a/src/platform/tests/Bridge/OpenAI/GPT/ResponseConverterTest.php b/src/platform/tests/Bridge/OpenAI/GPT/ResultConverterTest.php similarity index 76% rename from src/platform/tests/Bridge/OpenAI/GPT/ResponseConverterTest.php rename to src/platform/tests/Bridge/OpenAI/GPT/ResultConverterTest.php index d5e77f74..658657e1 100644 --- a/src/platform/tests/Bridge/OpenAI/GPT/ResponseConverterTest.php +++ b/src/platform/tests/Bridge/OpenAI/GPT/ResultConverterTest.php @@ -15,30 +15,30 @@ use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; -use Symfony\AI\Platform\Bridge\OpenAI\GPT\ResponseConverter; +use Symfony\AI\Platform\Bridge\OpenAI\GPT\ResultConverter; use Symfony\AI\Platform\Exception\ContentFilterException; use Symfony\AI\Platform\Exception\RuntimeException; -use Symfony\AI\Platform\Response\Choice; -use Symfony\AI\Platform\Response\ChoiceResponse; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\Response\ToolCall; -use Symfony\AI\Platform\Response\ToolCallResponse; +use Symfony\AI\Platform\Result\Choice; +use Symfony\AI\Platform\Result\ChoiceResult; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\Result\ToolCall; +use Symfony\AI\Platform\Result\ToolCallResult; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\ResponseInterface; -#[CoversClass(ResponseConverter::class)] +#[CoversClass(ResultConverter::class)] #[Small] #[UsesClass(Choice::class)] -#[UsesClass(ChoiceResponse::class)] -#[UsesClass(TextResponse::class)] +#[UsesClass(ChoiceResult::class)] +#[UsesClass(TextResult::class)] #[UsesClass(ToolCall::class)] -#[UsesClass(ToolCallResponse::class)] -class ResponseConverterTest extends TestCase +#[UsesClass(ToolCallResult::class)] +class ResultConverterTest extends TestCase { public function testConvertTextResponse(): void { - $converter = new ResponseConverter(); + $converter = new ResultConverter(); $httpResponse = self::createMock(ResponseInterface::class); $httpResponse->method('toArray')->willReturn([ 'choices' => [ @@ -52,15 +52,15 @@ public function testConvertTextResponse(): void ], ]); - $response = $converter->convert(new RawHttpResponse($httpResponse)); + $result = $converter->convert(new RawHttpResult($httpResponse)); - self::assertInstanceOf(TextResponse::class, $response); - self::assertSame('Hello world', $response->getContent()); + self::assertInstanceOf(TextResult::class, $result); + self::assertSame('Hello world', $result->getContent()); } public function testConvertToolCallResponse(): void { - $converter = new ResponseConverter(); + $converter = new ResultConverter(); $httpResponse = self::createMock(ResponseInterface::class); $httpResponse->method('toArray')->willReturn([ 'choices' => [ @@ -84,10 +84,10 @@ public function testConvertToolCallResponse(): void ], ]); - $response = $converter->convert(new RawHttpResponse($httpResponse)); + $result = $converter->convert(new RawHttpResult($httpResponse)); - self::assertInstanceOf(ToolCallResponse::class, $response); - $toolCalls = $response->getContent(); + self::assertInstanceOf(ToolCallResult::class, $result); + $toolCalls = $result->getContent(); self::assertCount(1, $toolCalls); self::assertSame('call_123', $toolCalls[0]->id); self::assertSame('test_function', $toolCalls[0]->name); @@ -96,7 +96,7 @@ public function testConvertToolCallResponse(): void public function testConvertMultipleChoices(): void { - $converter = new ResponseConverter(); + $converter = new ResultConverter(); $httpResponse = self::createMock(ResponseInterface::class); $httpResponse->method('toArray')->willReturn([ 'choices' => [ @@ -117,10 +117,10 @@ public function testConvertMultipleChoices(): void ], ]); - $response = $converter->convert(new RawHttpResponse($httpResponse)); + $result = $converter->convert(new RawHttpResult($httpResponse)); - self::assertInstanceOf(ChoiceResponse::class, $response); - $choices = $response->getContent(); + self::assertInstanceOf(ChoiceResult::class, $result); + $choices = $result->getContent(); self::assertCount(2, $choices); self::assertSame('Choice 1', $choices[0]->getContent()); self::assertSame('Choice 2', $choices[1]->getContent()); @@ -128,7 +128,7 @@ public function testConvertMultipleChoices(): void public function testContentFilterException(): void { - $converter = new ResponseConverter(); + $converter = new ResultConverter(); $httpResponse = self::createMock(ResponseInterface::class); $httpResponse->expects($this->exactly(1)) @@ -154,24 +154,24 @@ public function getResponse(): ResponseInterface self::expectException(ContentFilterException::class); self::expectExceptionMessage('Content was filtered'); - $converter->convert(new RawHttpResponse($httpResponse)); + $converter->convert(new RawHttpResult($httpResponse)); } public function testThrowsExceptionWhenNoChoices(): void { - $converter = new ResponseConverter(); + $converter = new ResultConverter(); $httpResponse = self::createMock(ResponseInterface::class); $httpResponse->method('toArray')->willReturn([]); self::expectException(RuntimeException::class); self::expectExceptionMessage('Response does not contain choices'); - $converter->convert(new RawHttpResponse($httpResponse)); + $converter->convert(new RawHttpResult($httpResponse)); } public function testThrowsExceptionForUnsupportedFinishReason(): void { - $converter = new ResponseConverter(); + $converter = new ResultConverter(); $httpResponse = self::createMock(ResponseInterface::class); $httpResponse->method('toArray')->willReturn([ 'choices' => [ @@ -188,6 +188,6 @@ public function testThrowsExceptionForUnsupportedFinishReason(): void self::expectException(RuntimeException::class); self::expectExceptionMessage('Unsupported finish reason "unsupported_reason"'); - $converter->convert(new RawHttpResponse($httpResponse)); + $converter->convert(new RawHttpResult($httpResponse)); } } diff --git a/src/platform/tests/Bridge/OpenAI/TokenOutputProcessorTest.php b/src/platform/tests/Bridge/OpenAI/TokenOutputProcessorTest.php index d2a48c36..0256b0ab 100644 --- a/src/platform/tests/Bridge/OpenAI/TokenOutputProcessorTest.php +++ b/src/platform/tests/Bridge/OpenAI/TokenOutputProcessorTest.php @@ -20,17 +20,17 @@ use Symfony\AI\Platform\Bridge\OpenAI\TokenOutputProcessor; use Symfony\AI\Platform\Message\MessageBagInterface; use Symfony\AI\Platform\Model; -use Symfony\AI\Platform\Response\Metadata\Metadata; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\Response\StreamResponse; -use Symfony\AI\Platform\Response\TextResponse; +use Symfony\AI\Platform\Result\Metadata\Metadata; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\Result\StreamResult; +use Symfony\AI\Platform\Result\TextResult; use Symfony\Contracts\HttpClient\ResponseInterface as SymfonyHttpResponse; #[CoversClass(TokenOutputProcessor::class)] #[UsesClass(Output::class)] -#[UsesClass(TextResponse::class)] -#[UsesClass(StreamResponse::class)] +#[UsesClass(TextResult::class)] +#[UsesClass(StreamResult::class)] #[UsesClass(Metadata::class)] #[Small] final class TokenOutputProcessorTest extends TestCase @@ -39,12 +39,12 @@ final class TokenOutputProcessorTest extends TestCase public function itHandlesStreamResponsesWithoutProcessing(): void { $processor = new TokenOutputProcessor(); - $streamResponse = new StreamResponse((static function () { yield 'test'; })()); - $output = $this->createOutput($streamResponse); + $streamResult = new StreamResult((static function () { yield 'test'; })()); + $output = $this->createOutput($streamResult); $processor->processOutput($output); - $metadata = $output->response->getMetadata(); + $metadata = $output->result->getMetadata(); self::assertCount(0, $metadata); } @@ -52,12 +52,12 @@ public function itHandlesStreamResponsesWithoutProcessing(): void public function itDoesNothingWithoutRawResponse(): void { $processor = new TokenOutputProcessor(); - $textResponse = new TextResponse('test'); - $output = $this->createOutput($textResponse); + $textResult = new TextResult('test'); + $output = $this->createOutput($textResult); $processor->processOutput($output); - $metadata = $output->response->getMetadata(); + $metadata = $output->result->getMetadata(); self::assertCount(0, $metadata); } @@ -65,15 +65,15 @@ public function itDoesNothingWithoutRawResponse(): void public function itAddsRemainingTokensToMetadata(): void { $processor = new TokenOutputProcessor(); - $textResponse = new TextResponse('test'); + $textResult = new TextResult('test'); - $textResponse->setRawResponse($this->createRawResponse()); + $textResult->setRawResult($this->createRawResult()); - $output = $this->createOutput($textResponse); + $output = $this->createOutput($textResult); $processor->processOutput($output); - $metadata = $output->response->getMetadata(); + $metadata = $output->result->getMetadata(); self::assertCount(1, $metadata); self::assertSame(1000, $metadata->get('remaining_tokens')); } @@ -82,9 +82,9 @@ public function itAddsRemainingTokensToMetadata(): void public function itAddsUsageTokensToMetadata(): void { $processor = new TokenOutputProcessor(); - $textResponse = new TextResponse('test'); + $textResult = new TextResult('test'); - $rawResponse = $this->createRawResponse([ + $rawResponse = $this->createRawResult([ 'usage' => [ 'prompt_tokens' => 10, 'completion_tokens' => 20, @@ -92,13 +92,13 @@ public function itAddsUsageTokensToMetadata(): void ], ]); - $textResponse->setRawResponse($rawResponse); + $textResult->setRawResult($rawResponse); - $output = $this->createOutput($textResponse); + $output = $this->createOutput($textResult); $processor->processOutput($output); - $metadata = $output->response->getMetadata(); + $metadata = $output->result->getMetadata(); self::assertCount(4, $metadata); self::assertSame(1000, $metadata->get('remaining_tokens')); self::assertSame(10, $metadata->get('prompt_tokens')); @@ -110,22 +110,22 @@ public function itAddsUsageTokensToMetadata(): void public function itHandlesMissingUsageFields(): void { $processor = new TokenOutputProcessor(); - $textResponse = new TextResponse('test'); + $textResult = new TextResult('test'); - $rawResponse = $this->createRawResponse([ + $rawResult = $this->createRawResult([ 'usage' => [ // Missing some fields 'prompt_tokens' => 10, ], ]); - $textResponse->setRawResponse($rawResponse); + $textResult->setRawResult($rawResult); - $output = $this->createOutput($textResponse); + $output = $this->createOutput($textResult); $processor->processOutput($output); - $metadata = $output->response->getMetadata(); + $metadata = $output->result->getMetadata(); self::assertCount(4, $metadata); self::assertSame(1000, $metadata->get('remaining_tokens')); self::assertSame(10, $metadata->get('prompt_tokens')); @@ -133,7 +133,7 @@ public function itHandlesMissingUsageFields(): void self::assertNull($metadata->get('total_tokens')); } - private function createRawResponse(array $data = []): RawHttpResponse + private function createRawResult(array $data = []): RawHttpResult { $rawResponse = self::createStub(SymfonyHttpResponse::class); $rawResponse->method('getHeaders')->willReturn([ @@ -141,14 +141,14 @@ private function createRawResponse(array $data = []): RawHttpResponse ]); $rawResponse->method('toArray')->willReturn($data); - return new RawHttpResponse($rawResponse); + return new RawHttpResult($rawResponse); } - private function createOutput(ResponseInterface $response): Output + private function createOutput(ResultInterface $result): Output { return new Output( self::createStub(Model::class), - $response, + $result, self::createStub(MessageBagInterface::class), [], ); diff --git a/src/platform/tests/Contract/Normalizer/Message/AssistantMessageNormalizerTest.php b/src/platform/tests/Contract/Normalizer/Message/AssistantMessageNormalizerTest.php index 22630267..783b7f9b 100644 --- a/src/platform/tests/Contract/Normalizer/Message/AssistantMessageNormalizerTest.php +++ b/src/platform/tests/Contract/Normalizer/Message/AssistantMessageNormalizerTest.php @@ -17,7 +17,7 @@ use PHPUnit\Framework\TestCase; use Symfony\AI\Platform\Contract\Normalizer\Message\AssistantMessageNormalizer; use Symfony\AI\Platform\Message\AssistantMessage; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; #[CoversClass(AssistantMessageNormalizer::class)] diff --git a/src/platform/tests/Contract/Normalizer/Message/ToolCallMessageNormalizerTest.php b/src/platform/tests/Contract/Normalizer/Message/ToolCallMessageNormalizerTest.php index b14b0add..3e02adb2 100644 --- a/src/platform/tests/Contract/Normalizer/Message/ToolCallMessageNormalizerTest.php +++ b/src/platform/tests/Contract/Normalizer/Message/ToolCallMessageNormalizerTest.php @@ -17,7 +17,7 @@ use PHPUnit\Framework\TestCase; use Symfony\AI\Platform\Contract\Normalizer\Message\ToolCallMessageNormalizer; use Symfony\AI\Platform\Message\ToolCallMessage; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; #[CoversClass(ToolCallMessageNormalizer::class)] diff --git a/src/platform/tests/ContractTest.php b/src/platform/tests/ContractTest.php index e370ac87..2bb18dbc 100644 --- a/src/platform/tests/ContractTest.php +++ b/src/platform/tests/ContractTest.php @@ -30,7 +30,7 @@ use Symfony\AI\Platform\Contract\Normalizer\Message\SystemMessageNormalizer; use Symfony\AI\Platform\Contract\Normalizer\Message\ToolCallMessageNormalizer; use Symfony\AI\Platform\Contract\Normalizer\Message\UserMessageNormalizer; -use Symfony\AI\Platform\Contract\Normalizer\Response\ToolCallNormalizer; +use Symfony\AI\Platform\Contract\Normalizer\Result\ToolCallNormalizer; use Symfony\AI\Platform\Message\AssistantMessage; use Symfony\AI\Platform\Message\Content\Audio; use Symfony\AI\Platform\Message\Content\Image; diff --git a/src/platform/tests/Message/AssistantMessageTest.php b/src/platform/tests/Message/AssistantMessageTest.php index 3f193f95..62f41120 100644 --- a/src/platform/tests/Message/AssistantMessageTest.php +++ b/src/platform/tests/Message/AssistantMessageTest.php @@ -18,7 +18,7 @@ use PHPUnit\Framework\TestCase; use Symfony\AI\Platform\Message\AssistantMessage; use Symfony\AI\Platform\Message\Role; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\AI\Platform\Tests\Helper\UuidAssertionTrait; use Symfony\Component\Uid\AbstractUid; use Symfony\Component\Uid\TimeBasedUidInterface; diff --git a/src/platform/tests/Message/MessageBagTest.php b/src/platform/tests/Message/MessageBagTest.php index 17a0c5a6..a1790753 100644 --- a/src/platform/tests/Message/MessageBagTest.php +++ b/src/platform/tests/Message/MessageBagTest.php @@ -24,7 +24,7 @@ use Symfony\AI\Platform\Message\SystemMessage; use Symfony\AI\Platform\Message\ToolCallMessage; use Symfony\AI\Platform\Message\UserMessage; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; #[CoversClass(MessageBag::class)] #[UsesClass(Message::class)] diff --git a/src/platform/tests/Message/MessageTest.php b/src/platform/tests/Message/MessageTest.php index 525882a3..b20eaef7 100644 --- a/src/platform/tests/Message/MessageTest.php +++ b/src/platform/tests/Message/MessageTest.php @@ -25,7 +25,7 @@ use Symfony\AI\Platform\Message\SystemMessage; use Symfony\AI\Platform\Message\ToolCallMessage; use Symfony\AI\Platform\Message\UserMessage; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; #[CoversClass(Message::class)] #[UsesClass(UserMessage::class)] diff --git a/src/platform/tests/Message/ToolCallMessageTest.php b/src/platform/tests/Message/ToolCallMessageTest.php index 455459fa..c38e1fd3 100644 --- a/src/platform/tests/Message/ToolCallMessageTest.php +++ b/src/platform/tests/Message/ToolCallMessageTest.php @@ -17,7 +17,7 @@ use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; use Symfony\AI\Platform\Message\ToolCallMessage; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; use Symfony\AI\Platform\Tests\Helper\UuidAssertionTrait; use Symfony\Component\Uid\AbstractUid; use Symfony\Component\Uid\TimeBasedUidInterface; diff --git a/src/platform/tests/Response/BaseResponseTest.php b/src/platform/tests/Response/BaseResponseTest.php deleted file mode 100644 index 1d700a08..00000000 --- a/src/platform/tests/Response/BaseResponseTest.php +++ /dev/null @@ -1,95 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\AI\Platform\Tests\Response; - -use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\Attributes\Small; -use PHPUnit\Framework\Attributes\Test; -use PHPUnit\Framework\Attributes\UsesClass; -use PHPUnit\Framework\Attributes\UsesTrait; -use PHPUnit\Framework\TestCase; -use Symfony\AI\Platform\Response\BaseResponse; -use Symfony\AI\Platform\Response\Exception\RawResponseAlreadySetException; -use Symfony\AI\Platform\Response\Metadata\Metadata; -use Symfony\AI\Platform\Response\Metadata\MetadataAwareTrait; -use Symfony\AI\Platform\Response\RawResponseAwareTrait; -use Symfony\AI\Platform\Response\RawResponseInterface; - -#[CoversClass(BaseResponse::class)] -#[UsesTrait(MetadataAwareTrait::class)] -#[UsesTrait(RawResponseAwareTrait::class)] -#[UsesClass(Metadata::class)] -#[UsesClass(RawResponseAlreadySetException::class)] -#[Small] -final class BaseResponseTest extends TestCase -{ - #[Test] - public function itCanHandleMetadata(): void - { - $response = $this->createResponse(); - $metadata = $response->getMetadata(); - - self::assertCount(0, $metadata); - - $metadata->add('key', 'value'); - $metadata = $response->getMetadata(); - - self::assertCount(1, $metadata); - } - - #[Test] - public function itCanBeEnrichedWithARawResponse(): void - { - $response = $this->createResponse(); - $rawResponse = $this->createRawResponse(); - - $response->setRawResponse($rawResponse); - self::assertSame($rawResponse, $response->getRawResponse()); - } - - #[Test] - public function itThrowsAnExceptionWhenSettingARawResponseTwice(): void - { - self::expectException(RawResponseAlreadySetException::class); - - $response = $this->createResponse(); - $rawResponse = $this->createRawResponse(); - - $response->setRawResponse($rawResponse); - $response->setRawResponse($rawResponse); - } - - private function createResponse(): BaseResponse - { - return new class extends BaseResponse { - public function getContent(): string - { - return 'test'; - } - }; - } - - public function createRawResponse(): RawResponseInterface - { - return new class implements RawResponseInterface { - public function getRawData(): array - { - return ['key' => 'value']; - } - - public function getRawObject(): object - { - return new \stdClass(); - } - }; - } -} diff --git a/src/platform/tests/Response/ResponsePromiseTest.php b/src/platform/tests/Response/ResponsePromiseTest.php deleted file mode 100644 index de5997eb..00000000 --- a/src/platform/tests/Response/ResponsePromiseTest.php +++ /dev/null @@ -1,159 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\AI\Platform\Tests\Response; - -use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\Attributes\Small; -use PHPUnit\Framework\Attributes\Test; -use PHPUnit\Framework\Attributes\UsesClass; -use PHPUnit\Framework\TestCase; -use Symfony\AI\Platform\Response\BaseResponse; -use Symfony\AI\Platform\Response\Exception\RawResponseAlreadySetException; -use Symfony\AI\Platform\Response\Metadata\Metadata; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\Response\ResponsePromise; -use Symfony\AI\Platform\Response\TextResponse; -use Symfony\AI\Platform\ResponseConverterInterface; -use Symfony\Contracts\HttpClient\ResponseInterface as SymfonyHttpResponse; - -#[CoversClass(ResponsePromise::class)] -#[UsesClass(Metadata::class)] -#[UsesClass(TextResponse::class)] -#[UsesClass(RawResponseAlreadySetException::class)] -#[Small] -final class ResponsePromiseTest extends TestCase -{ - #[Test] - public function itUnwrapsTheResponseWhenGettingContent(): void - { - $httpResponse = $this->createStub(SymfonyHttpResponse::class); - $rawHttpResponse = new RawHttpResponse($httpResponse); - $textResponse = new TextResponse('test content'); - - $responseConverter = self::createMock(ResponseConverterInterface::class); - $responseConverter->expects(self::once()) - ->method('convert') - ->with($rawHttpResponse, []) - ->willReturn($textResponse); - - $responsePromise = new ResponsePromise($responseConverter->convert(...), $rawHttpResponse); - - self::assertSame('test content', $responsePromise->getResponse()->getContent()); - } - - #[Test] - public function itConvertsTheResponseOnlyOnce(): void - { - $httpResponse = $this->createStub(SymfonyHttpResponse::class); - $rawHttpResponse = new RawHttpResponse($httpResponse); - $textResponse = new TextResponse('test content'); - - $responseConverter = self::createMock(ResponseConverterInterface::class); - $responseConverter->expects(self::once()) - ->method('convert') - ->with($rawHttpResponse, []) - ->willReturn($textResponse); - - $responsePromise = new ResponsePromise($responseConverter->convert(...), $rawHttpResponse); - - // Call unwrap multiple times, but the converter should only be called once - $responsePromise->await(); - $responsePromise->await(); - $responsePromise->getResponse(); - } - - #[Test] - public function itGetsRawResponseDirectly(): void - { - $httpResponse = $this->createStub(SymfonyHttpResponse::class); - $responseConverter = $this->createStub(ResponseConverterInterface::class); - - $responsePromise = new ResponsePromise($responseConverter->convert(...), new RawHttpResponse($httpResponse)); - - self::assertSame($httpResponse, $responsePromise->getRawResponse()->getRawObject()); - } - - #[Test] - public function itSetsRawResponseOnUnwrappedResponseWhenNeeded(): void - { - $httpResponse = $this->createStub(SymfonyHttpResponse::class); - - $unwrappedResponse = $this->createResponse(null); - - $responseConverter = $this->createStub(ResponseConverterInterface::class); - $responseConverter->method('convert')->willReturn($unwrappedResponse); - - $responsePromise = new ResponsePromise($responseConverter->convert(...), new RawHttpResponse($httpResponse)); - $responsePromise->await(); - - // The raw response in the model response is now set and not null anymore - self::assertSame($httpResponse, $unwrappedResponse->getRawResponse()->getRawObject()); - } - - #[Test] - public function itDoesNotSetRawResponseOnUnwrappedResponseWhenAlreadySet(): void - { - $originHttpResponse = $this->createStub(SymfonyHttpResponse::class); - $anotherHttpResponse = $this->createStub(SymfonyHttpResponse::class); - - $unwrappedResponse = $this->createResponse($anotherHttpResponse); - - $responseConverter = $this->createStub(ResponseConverterInterface::class); - $responseConverter->method('convert')->willReturn($unwrappedResponse); - - $responsePromise = new ResponsePromise($responseConverter->convert(...), new RawHttpResponse($originHttpResponse)); - $responsePromise->await(); - - // It is still the same raw response as set initially and so not overwritten - self::assertSame($anotherHttpResponse, $unwrappedResponse->getRawResponse()->getRawObject()); - } - - #[Test] - public function itPassesOptionsToConverter(): void - { - $httpResponse = $this->createStub(SymfonyHttpResponse::class); - $rawHttpResponse = new RawHttpResponse($httpResponse); - $options = ['option1' => 'value1', 'option2' => 'value2']; - - $responseConverter = self::createMock(ResponseConverterInterface::class); - $responseConverter->expects(self::once()) - ->method('convert') - ->with($rawHttpResponse, $options) - ->willReturn($this->createResponse(null)); - - $responsePromise = new ResponsePromise($responseConverter->convert(...), $rawHttpResponse, $options); - $responsePromise->await(); - } - - /** - * Workaround for low deps because mocking the ResponseInterface leads to an exception with - * mock creation "Type Traversable|object|array|string|null contains both object and a class type" - * in PHPUnit MockClass. - */ - private function createResponse(?SymfonyHttpResponse $httpResponse): ResponseInterface - { - $rawResponse = null !== $httpResponse ? new RawHttpResponse($httpResponse) : null; - - return new class($rawResponse) extends BaseResponse { - public function __construct(protected ?RawResponseInterface $rawResponse) - { - } - - public function getContent(): string - { - return 'test content'; - } - }; - } -} diff --git a/src/platform/tests/Result/BaseResultTest.php b/src/platform/tests/Result/BaseResultTest.php new file mode 100644 index 00000000..c99de86b --- /dev/null +++ b/src/platform/tests/Result/BaseResultTest.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\AI\Platform\Tests\Result; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\Attributes\UsesTrait; +use PHPUnit\Framework\TestCase; +use Symfony\AI\Platform\Result\BaseResult; +use Symfony\AI\Platform\Result\Exception\RawResultAlreadySetException; +use Symfony\AI\Platform\Result\Metadata\Metadata; +use Symfony\AI\Platform\Result\Metadata\MetadataAwareTrait; +use Symfony\AI\Platform\Result\RawResultAwareTrait; +use Symfony\AI\Platform\Result\RawResultInterface; + +#[CoversClass(BaseResult::class)] +#[UsesTrait(MetadataAwareTrait::class)] +#[UsesTrait(RawResultAwareTrait::class)] +#[UsesClass(Metadata::class)] +#[UsesClass(RawResultAlreadySetException::class)] +#[Small] +final class BaseResultTest extends TestCase +{ + #[Test] + public function itCanHandleMetadata(): void + { + $result = $this->createResponse(); + $metadata = $result->getMetadata(); + + self::assertCount(0, $metadata); + + $metadata->add('key', 'value'); + $metadata = $result->getMetadata(); + + self::assertCount(1, $metadata); + } + + #[Test] + public function itCanBeEnrichedWithARawResponse(): void + { + $result = $this->createResponse(); + $rawResponse = $this->createRawResponse(); + + $result->setRawResult($rawResponse); + self::assertSame($rawResponse, $result->getRawResult()); + } + + #[Test] + public function itThrowsAnExceptionWhenSettingARawResponseTwice(): void + { + self::expectException(RawResultAlreadySetException::class); + + $result = $this->createResponse(); + $rawResponse = $this->createRawResponse(); + + $result->setRawResult($rawResponse); + $result->setRawResult($rawResponse); + } + + private function createResponse(): BaseResult + { + return new class extends BaseResult { + public function getContent(): string + { + return 'test'; + } + }; + } + + public function createRawResponse(): RawResultInterface + { + return new class implements RawResultInterface { + public function getData(): array + { + return ['key' => 'value']; + } + + public function getObject(): object + { + return new \stdClass(); + } + }; + } +} diff --git a/src/platform/tests/Response/ChoiceResponseTest.php b/src/platform/tests/Result/ChoiceResultTest.php similarity index 56% rename from src/platform/tests/Response/ChoiceResponseTest.php rename to src/platform/tests/Result/ChoiceResultTest.php index f2938cd6..09074d79 100644 --- a/src/platform/tests/Response/ChoiceResponseTest.php +++ b/src/platform/tests/Result/ChoiceResultTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Tests\Response; +namespace Symfony\AI\Platform\Tests\Result; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Small; @@ -17,13 +17,13 @@ use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; use Symfony\AI\Platform\Exception\InvalidArgumentException; -use Symfony\AI\Platform\Response\Choice; -use Symfony\AI\Platform\Response\ChoiceResponse; +use Symfony\AI\Platform\Result\Choice; +use Symfony\AI\Platform\Result\ChoiceResult; -#[CoversClass(ChoiceResponse::class)] +#[CoversClass(ChoiceResult::class)] #[UsesClass(Choice::class)] #[Small] -final class ChoiceResponseTest extends TestCase +final class ChoiceResultTest extends TestCase { #[Test] public function choiceResponseCreation(): void @@ -31,20 +31,20 @@ public function choiceResponseCreation(): void $choice1 = new Choice('choice1'); $choice2 = new Choice(null); $choice3 = new Choice('choice3'); - $response = new ChoiceResponse($choice1, $choice2, $choice3); + $result = new ChoiceResult($choice1, $choice2, $choice3); - self::assertCount(3, $response->getContent()); - self::assertSame('choice1', $response->getContent()[0]->getContent()); - self::assertNull($response->getContent()[1]->getContent()); - self::assertSame('choice3', $response->getContent()[2]->getContent()); + self::assertCount(3, $result->getContent()); + self::assertSame('choice1', $result->getContent()[0]->getContent()); + self::assertNull($result->getContent()[1]->getContent()); + self::assertSame('choice3', $result->getContent()[2]->getContent()); } #[Test] public function choiceResponseWithNoChoices(): void { self::expectException(InvalidArgumentException::class); - self::expectExceptionMessage('Response must have at least one choice.'); + self::expectExceptionMessage('Result must have at least one choice.'); - new ChoiceResponse(); + new ChoiceResult(); } } diff --git a/src/platform/tests/Response/ChoiceTest.php b/src/platform/tests/Result/ChoiceTest.php similarity index 93% rename from src/platform/tests/Response/ChoiceTest.php rename to src/platform/tests/Result/ChoiceTest.php index 8fcff232..057995bb 100644 --- a/src/platform/tests/Response/ChoiceTest.php +++ b/src/platform/tests/Result/ChoiceTest.php @@ -9,15 +9,15 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Tests\Response; +namespace Symfony\AI\Platform\Tests\Result; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; -use Symfony\AI\Platform\Response\Choice; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\Choice; +use Symfony\AI\Platform\Result\ToolCall; #[CoversClass(Choice::class)] #[UsesClass(ToolCall::class)] diff --git a/src/platform/tests/Response/Exception/RawResponseAlreadySetTest.php b/src/platform/tests/Result/Exception/RawResultAlreadySetTest.php similarity index 55% rename from src/platform/tests/Response/Exception/RawResponseAlreadySetTest.php rename to src/platform/tests/Result/Exception/RawResultAlreadySetTest.php index 1cb27558..324add0f 100644 --- a/src/platform/tests/Response/Exception/RawResponseAlreadySetTest.php +++ b/src/platform/tests/Result/Exception/RawResultAlreadySetTest.php @@ -9,23 +9,23 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Tests\Response\Exception; +namespace Symfony\AI\Platform\Tests\Result\Exception; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; -use Symfony\AI\Platform\Response\Exception\RawResponseAlreadySetException; +use Symfony\AI\Platform\Result\Exception\RawResultAlreadySetException; -#[CoversClass(RawResponseAlreadySetException::class)] +#[CoversClass(RawResultAlreadySetException::class)] #[Small] -final class RawResponseAlreadySetTest extends TestCase +final class RawResultAlreadySetTest extends TestCase { #[Test] public function itHasCorrectExceptionMessage(): void { - $exception = new RawResponseAlreadySetException(); + $exception = new RawResultAlreadySetException(); - self::assertSame('The raw response was already set.', $exception->getMessage()); + self::assertSame('The raw result was already set.', $exception->getMessage()); } } diff --git a/src/platform/tests/Response/Metadata/MetadataAwareTraitTest.php b/src/platform/tests/Result/Metadata/MetadataAwareTraitTest.php similarity index 74% rename from src/platform/tests/Response/Metadata/MetadataAwareTraitTest.php rename to src/platform/tests/Result/Metadata/MetadataAwareTraitTest.php index 5edb3337..28188863 100644 --- a/src/platform/tests/Response/Metadata/MetadataAwareTraitTest.php +++ b/src/platform/tests/Result/Metadata/MetadataAwareTraitTest.php @@ -9,15 +9,15 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Tests\Response\Metadata; +namespace Symfony\AI\Platform\Tests\Result\Metadata; use PHPUnit\Framework\Attributes\CoversTrait; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; -use Symfony\AI\Platform\Response\Metadata\Metadata; -use Symfony\AI\Platform\Response\Metadata\MetadataAwareTrait; +use Symfony\AI\Platform\Result\Metadata\Metadata; +use Symfony\AI\Platform\Result\Metadata\MetadataAwareTrait; #[CoversTrait(MetadataAwareTrait::class)] #[Small] @@ -27,13 +27,13 @@ final class MetadataAwareTraitTest extends TestCase #[Test] public function itCanHandleMetadata(): void { - $response = $this->createTestClass(); - $metadata = $response->getMetadata(); + $result = $this->createTestClass(); + $metadata = $result->getMetadata(); self::assertCount(0, $metadata); $metadata->add('key', 'value'); - $metadata = $response->getMetadata(); + $metadata = $result->getMetadata(); self::assertCount(1, $metadata); } diff --git a/src/platform/tests/Response/Metadata/MetadataTest.php b/src/platform/tests/Result/Metadata/MetadataTest.php similarity index 97% rename from src/platform/tests/Response/Metadata/MetadataTest.php rename to src/platform/tests/Result/Metadata/MetadataTest.php index f55e62b8..724ee5f6 100644 --- a/src/platform/tests/Response/Metadata/MetadataTest.php +++ b/src/platform/tests/Result/Metadata/MetadataTest.php @@ -9,13 +9,13 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Tests\Response\Metadata; +namespace Symfony\AI\Platform\Tests\Result\Metadata; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; -use Symfony\AI\Platform\Response\Metadata\Metadata; +use Symfony\AI\Platform\Result\Metadata\Metadata; #[CoversClass(Metadata::class)] #[Small] diff --git a/src/platform/tests/Response/StructuredResponseTest.php b/src/platform/tests/Result/ObjectResultTest.php similarity index 52% rename from src/platform/tests/Response/StructuredResponseTest.php rename to src/platform/tests/Result/ObjectResultTest.php index 69c1232f..7af43118 100644 --- a/src/platform/tests/Response/StructuredResponseTest.php +++ b/src/platform/tests/Result/ObjectResultTest.php @@ -9,29 +9,29 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Tests\Response; +namespace Symfony\AI\Platform\Tests\Result; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; -use Symfony\AI\Platform\Response\ObjectResponse; +use Symfony\AI\Platform\Result\ObjectResult; -#[CoversClass(ObjectResponse::class)] +#[CoversClass(ObjectResult::class)] #[Small] -final class StructuredResponseTest extends TestCase +final class ObjectResultTest extends TestCase { #[Test] public function getContentWithArray(): void { - $response = new ObjectResponse($expected = ['foo' => 'bar', 'baz' => ['qux']]); - self::assertSame($expected, $response->getContent()); + $result = new ObjectResult($expected = ['foo' => 'bar', 'baz' => ['qux']]); + self::assertSame($expected, $result->getContent()); } #[Test] public function getContentWithObject(): void { - $response = new ObjectResponse($expected = (object) ['foo' => 'bar', 'baz' => ['qux']]); - self::assertSame($expected, $response->getContent()); + $result = new ObjectResult($expected = (object) ['foo' => 'bar', 'baz' => ['qux']]); + self::assertSame($expected, $result->getContent()); } } diff --git a/src/platform/tests/Response/RawResponseAwareTraitTest.php b/src/platform/tests/Result/RawResultAwareTraitTest.php similarity index 52% rename from src/platform/tests/Response/RawResponseAwareTraitTest.php rename to src/platform/tests/Result/RawResultAwareTraitTest.php index 2f90332e..336bd9cf 100644 --- a/src/platform/tests/Response/RawResponseAwareTraitTest.php +++ b/src/platform/tests/Result/RawResultAwareTraitTest.php @@ -9,49 +9,49 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Tests\Response; +namespace Symfony\AI\Platform\Tests\Result; use PHPUnit\Framework\Attributes\CoversTrait; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; -use Symfony\AI\Platform\Response\Exception\RawResponseAlreadySetException; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\RawResponseAwareTrait; +use Symfony\AI\Platform\Result\Exception\RawResultAlreadySetException; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\RawResultAwareTrait; use Symfony\Contracts\HttpClient\ResponseInterface as SymfonyHttpResponse; -#[CoversTrait(RawResponseAwareTrait::class)] +#[CoversTrait(RawResultAwareTrait::class)] #[Small] -#[UsesClass(RawResponseAlreadySetException::class)] -final class RawResponseAwareTraitTest extends TestCase +#[UsesClass(RawResultAlreadySetException::class)] +final class RawResultAwareTraitTest extends TestCase { #[Test] public function itCanBeEnrichedWithARawResponse(): void { - $response = $this->createTestClass(); + $result = $this->createTestClass(); $rawResponse = self::createMock(SymfonyHttpResponse::class); - $response->setRawResponse(new RawHttpResponse($rawResponse)); - self::assertSame($rawResponse, $response->getRawResponse()?->getRawObject()); + $result->setRawResult(new RawHttpResult($rawResponse)); + self::assertSame($rawResponse, $result->getRawResult()?->getObject()); } #[Test] public function itThrowsAnExceptionWhenSettingARawResponseTwice(): void { - self::expectException(RawResponseAlreadySetException::class); + self::expectException(RawResultAlreadySetException::class); - $response = $this->createTestClass(); + $result = $this->createTestClass(); $rawResponse = self::createMock(SymfonyHttpResponse::class); - $response->setRawResponse(new RawHttpResponse($rawResponse)); - $response->setRawResponse(new RawHttpResponse($rawResponse)); + $result->setRawResult(new RawHttpResult($rawResponse)); + $result->setRawResult(new RawHttpResult($rawResponse)); } private function createTestClass(): object { return new class { - use RawResponseAwareTrait; + use RawResultAwareTrait; }; } } diff --git a/src/platform/tests/Result/ResultPromiseTest.php b/src/platform/tests/Result/ResultPromiseTest.php new file mode 100644 index 00000000..4af80cfd --- /dev/null +++ b/src/platform/tests/Result/ResultPromiseTest.php @@ -0,0 +1,159 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\AI\Platform\Tests\Result; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; +use Symfony\AI\Platform\Result\BaseResult; +use Symfony\AI\Platform\Result\Exception\RawResultAlreadySetException; +use Symfony\AI\Platform\Result\Metadata\Metadata; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\Result\ResultPromise; +use Symfony\AI\Platform\Result\TextResult; +use Symfony\AI\Platform\ResultConverterInterface; +use Symfony\Contracts\HttpClient\ResponseInterface as SymfonyHttpResponse; + +#[CoversClass(ResultPromise::class)] +#[UsesClass(Metadata::class)] +#[UsesClass(TextResult::class)] +#[UsesClass(RawResultAlreadySetException::class)] +#[Small] +final class ResultPromiseTest extends TestCase +{ + #[Test] + public function itUnwrapsTheResultWhenGettingContent(): void + { + $httpResponse = $this->createStub(SymfonyHttpResponse::class); + $rawHttpResult = new RawHttpResult($httpResponse); + $textResult = new TextResult('test content'); + + $resultConverter = self::createMock(ResultConverterInterface::class); + $resultConverter->expects(self::once()) + ->method('convert') + ->with($rawHttpResult, []) + ->willReturn($textResult); + + $resultPromise = new ResultPromise($resultConverter->convert(...), $rawHttpResult); + + self::assertSame('test content', $resultPromise->getResult()->getContent()); + } + + #[Test] + public function itConvertsTheResponseOnlyOnce(): void + { + $httpResponse = $this->createStub(SymfonyHttpResponse::class); + $rawHttpResult = new RawHttpResult($httpResponse); + $textResult = new TextResult('test content'); + + $resultConverter = self::createMock(ResultConverterInterface::class); + $resultConverter->expects(self::once()) + ->method('convert') + ->with($rawHttpResult, []) + ->willReturn($textResult); + + $resultPromise = new ResultPromise($resultConverter->convert(...), $rawHttpResult); + + // Call unwrap multiple times, but the converter should only be called once + $resultPromise->await(); + $resultPromise->await(); + $resultPromise->getResult(); + } + + #[Test] + public function itGetsRawResponseDirectly(): void + { + $httpResponse = $this->createStub(SymfonyHttpResponse::class); + $resultConverter = $this->createStub(ResultConverterInterface::class); + + $resultPromise = new ResultPromise($resultConverter->convert(...), new RawHttpResult($httpResponse)); + + self::assertSame($httpResponse, $resultPromise->getRawResult()->getObject()); + } + + #[Test] + public function itSetsRawResponseOnUnwrappedResponseWhenNeeded(): void + { + $httpResponse = $this->createStub(SymfonyHttpResponse::class); + + $unwrappedResponse = $this->createResult(null); + + $resultConverter = $this->createStub(ResultConverterInterface::class); + $resultConverter->method('convert')->willReturn($unwrappedResponse); + + $resultPromise = new ResultPromise($resultConverter->convert(...), new RawHttpResult($httpResponse)); + $resultPromise->await(); + + // The raw response in the model response is now set and not null anymore + self::assertSame($httpResponse, $unwrappedResponse->getRawResult()->getObject()); + } + + #[Test] + public function itDoesNotSetRawResponseOnUnwrappedResponseWhenAlreadySet(): void + { + $originHttpResponse = $this->createStub(SymfonyHttpResponse::class); + $anotherHttpResponse = $this->createStub(SymfonyHttpResponse::class); + + $unwrappedResult = $this->createResult($anotherHttpResponse); + + $resultConverter = $this->createStub(ResultConverterInterface::class); + $resultConverter->method('convert')->willReturn($unwrappedResult); + + $resultPromise = new ResultPromise($resultConverter->convert(...), new RawHttpResult($originHttpResponse)); + $resultPromise->await(); + + // It is still the same raw response as set initially and so not overwritten + self::assertSame($anotherHttpResponse, $unwrappedResult->getRawResult()->getObject()); + } + + #[Test] + public function itPassesOptionsToConverter(): void + { + $httpResponse = $this->createStub(SymfonyHttpResponse::class); + $rawHttpResponse = new RawHttpResult($httpResponse); + $options = ['option1' => 'value1', 'option2' => 'value2']; + + $resultConverter = self::createMock(ResultConverterInterface::class); + $resultConverter->expects(self::once()) + ->method('convert') + ->with($rawHttpResponse, $options) + ->willReturn($this->createResult(null)); + + $resultPromise = new ResultPromise($resultConverter->convert(...), $rawHttpResponse, $options); + $resultPromise->await(); + } + + /** + * Workaround for low deps because mocking the ResponseInterface leads to an exception with + * mock creation "Type Traversable|object|array|string|null contains both object and a class type" + * in PHPUnit MockClass. + */ + private function createResult(?SymfonyHttpResponse $httpResponse): ResultInterface + { + $rawResult = null !== $httpResponse ? new RawHttpResult($httpResponse) : null; + + return new class($rawResult) extends BaseResult { + public function __construct(protected ?RawResultInterface $rawResult) + { + } + + public function getContent(): string + { + return 'test content'; + } + }; + } +} diff --git a/src/platform/tests/Response/StreamResponseTest.php b/src/platform/tests/Result/StreamResultTest.php similarity index 65% rename from src/platform/tests/Response/StreamResponseTest.php rename to src/platform/tests/Result/StreamResultTest.php index 3242f974..e210fe53 100644 --- a/src/platform/tests/Response/StreamResponseTest.php +++ b/src/platform/tests/Result/StreamResultTest.php @@ -9,17 +9,17 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Tests\Response; +namespace Symfony\AI\Platform\Tests\Result; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; -use Symfony\AI\Platform\Response\StreamResponse; +use Symfony\AI\Platform\Result\StreamResult; -#[CoversClass(StreamResponse::class)] +#[CoversClass(StreamResultTest::class)] #[Small] -final class StreamResponseTest extends TestCase +final class StreamResultTest extends TestCase { #[Test] public function getContent(): void @@ -29,10 +29,10 @@ public function getContent(): void yield 'data2'; })(); - $response = new StreamResponse($generator); - self::assertInstanceOf(\Generator::class, $response->getContent()); + $result = new StreamResult($generator); + self::assertInstanceOf(\Generator::class, $result->getContent()); - $content = iterator_to_array($response->getContent()); + $content = iterator_to_array($result->getContent()); self::assertCount(2, $content); self::assertSame('data1', $content[0]); diff --git a/src/platform/tests/Response/TextResponseTest.php b/src/platform/tests/Result/TextResultTest.php similarity index 61% rename from src/platform/tests/Response/TextResponseTest.php rename to src/platform/tests/Result/TextResultTest.php index 9a2fd13c..372af0e2 100644 --- a/src/platform/tests/Response/TextResponseTest.php +++ b/src/platform/tests/Result/TextResultTest.php @@ -9,22 +9,22 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Tests\Response; +namespace Symfony\AI\Platform\Tests\Result; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; -use Symfony\AI\Platform\Response\TextResponse; +use Symfony\AI\Platform\Result\TextResult; -#[CoversClass(TextResponse::class)] +#[CoversClass(TextResult::class)] #[Small] -final class TextResponseTest extends TestCase +final class TextResultTest extends TestCase { #[Test] public function getContent(): void { - $response = new TextResponse($expected = 'foo'); - self::assertSame($expected, $response->getContent()); + $result = new TextResult($expected = 'foo'); + self::assertSame($expected, $result->getContent()); } } diff --git a/src/platform/tests/Response/TollCallResponseTest.php b/src/platform/tests/Result/TollCallResultTest.php similarity index 66% rename from src/platform/tests/Response/TollCallResponseTest.php rename to src/platform/tests/Result/TollCallResultTest.php index 8978f17e..4bc4d2b9 100644 --- a/src/platform/tests/Response/TollCallResponseTest.php +++ b/src/platform/tests/Result/TollCallResultTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Tests\Response; +namespace Symfony\AI\Platform\Tests\Result; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Small; @@ -17,13 +17,13 @@ use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; use Symfony\AI\Platform\Exception\InvalidArgumentException; -use Symfony\AI\Platform\Response\ToolCall; -use Symfony\AI\Platform\Response\ToolCallResponse; +use Symfony\AI\Platform\Result\ToolCall; +use Symfony\AI\Platform\Result\ToolCallResult; -#[CoversClass(ToolCallResponse::class)] +#[CoversClass(ToolCallResult::class)] #[UsesClass(ToolCall::class)] #[Small] -final class TollCallResponseTest extends TestCase +final class TollCallResultTest extends TestCase { #[Test] public function throwsIfNoToolCall(): void @@ -31,13 +31,13 @@ public function throwsIfNoToolCall(): void self::expectException(InvalidArgumentException::class); self::expectExceptionMessage('Response must have at least one tool call.'); - new ToolCallResponse(); + new ToolCallResult(); } #[Test] public function getContent(): void { - $response = new ToolCallResponse($toolCall = new ToolCall('ID', 'name', ['foo' => 'bar'])); - self::assertSame([$toolCall], $response->getContent()); + $result = new ToolCallResult($toolCall = new ToolCall('ID', 'name', ['foo' => 'bar'])); + self::assertSame([$toolCall], $result->getContent()); } } diff --git a/src/platform/tests/Response/ToolCallTest.php b/src/platform/tests/Result/ToolCallTest.php similarity index 92% rename from src/platform/tests/Response/ToolCallTest.php rename to src/platform/tests/Result/ToolCallTest.php index 5737c6b8..3e9d240a 100644 --- a/src/platform/tests/Response/ToolCallTest.php +++ b/src/platform/tests/Result/ToolCallTest.php @@ -9,13 +9,13 @@ * file that was distributed with this source code. */ -namespace Symfony\AI\Platform\Tests\Response; +namespace Symfony\AI\Platform\Tests\Result; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; -use Symfony\AI\Platform\Response\ToolCall; +use Symfony\AI\Platform\Result\ToolCall; #[CoversClass(ToolCall::class)] #[Small] diff --git a/src/store/src/Bridge/Azure/SearchStore.php b/src/store/src/Bridge/Azure/SearchStore.php index a2b945e5..082f7788 100644 --- a/src/store/src/Bridge/Azure/SearchStore.php +++ b/src/store/src/Bridge/Azure/SearchStore.php @@ -61,7 +61,7 @@ public function query(Vector $vector, array $options = [], ?float $minScore = nu private function request(string $endpoint, array $payload): array { $url = \sprintf('%s/indexes/%s/docs/%s', $this->endpointUrl, $this->indexName, $endpoint); - $response = $this->httpClient->request('POST', $url, [ + $result = $this->httpClient->request('POST', $url, [ 'headers' => [ 'api-key' => $this->apiKey, ], @@ -69,7 +69,7 @@ private function request(string $endpoint, array $payload): array 'json' => $payload, ]); - return $response->toArray(); + return $result->toArray(); } /** diff --git a/src/store/src/Bridge/Meilisearch/Store.php b/src/store/src/Bridge/Meilisearch/Store.php index f46d2cc0..b6497116 100644 --- a/src/store/src/Bridge/Meilisearch/Store.php +++ b/src/store/src/Bridge/Meilisearch/Store.php @@ -50,7 +50,7 @@ public function add(VectorDocument ...$documents): void public function query(Vector $vector, array $options = [], ?float $minScore = null): array { - $response = $this->request('POST', \sprintf('indexes/%s/search', $this->indexName), [ + $result = $this->request('POST', \sprintf('indexes/%s/search', $this->indexName), [ 'vector' => $vector->getData(), 'showRankingScore' => true, 'retrieveVectors' => true, @@ -60,7 +60,7 @@ public function query(Vector $vector, array $options = [], ?float $minScore = nu ], ]); - return array_map($this->convertToVectorDocument(...), $response['hits']); + return array_map($this->convertToVectorDocument(...), $result['hits']); } public function initialize(array $options = []): void @@ -92,14 +92,14 @@ public function initialize(array $options = []): void private function request(string $method, string $endpoint, array $payload): array { $url = \sprintf('%s/%s', $this->endpointUrl, $endpoint); - $response = $this->httpClient->request($method, $url, [ + $result = $this->httpClient->request($method, $url, [ 'headers' => [ 'Authorization' => \sprintf('Bearer %s', $this->apiKey), ], 'json' => $payload, ]); - return $response->toArray(); + return $result->toArray(); } /** diff --git a/src/store/src/Bridge/Pinecone/Store.php b/src/store/src/Bridge/Pinecone/Store.php index b07ee0ca..79bbab01 100644 --- a/src/store/src/Bridge/Pinecone/Store.php +++ b/src/store/src/Bridge/Pinecone/Store.php @@ -59,7 +59,7 @@ public function add(VectorDocument ...$documents): void public function query(Vector $vector, array $options = [], ?float $minScore = null): array { - $response = $this->getVectors()->query( + $result = $this->getVectors()->query( vector: $vector->getData(), namespace: $options['namespace'] ?? $this->namespace, filter: $options['filter'] ?? $this->filter, @@ -68,7 +68,7 @@ public function query(Vector $vector, array $options = [], ?float $minScore = nu ); $documents = []; - foreach ($response->json()['matches'] as $match) { + foreach ($result->json()['matches'] as $match) { $documents[] = new VectorDocument( id: Uuid::fromString($match['id']), vector: new Vector($match['values']), diff --git a/src/store/src/Document/Vectorizer.php b/src/store/src/Document/Vectorizer.php index 12a8ea85..86ce2e36 100644 --- a/src/store/src/Document/Vectorizer.php +++ b/src/store/src/Document/Vectorizer.php @@ -35,18 +35,18 @@ public function __construct( public function vectorizeDocuments(array $documents): array { if ($this->model->supports(Capability::INPUT_MULTIPLE)) { - $response = $this->platform->request($this->model, array_map(fn (TextDocument $document) => $document->content, $documents)); + $result = $this->platform->invoke($this->model, array_map(fn (TextDocument $document) => $document->content, $documents)); - $vectors = $response->asVectors(); + $vectors = $result->asVectors(); } else { - $responses = []; + $results = []; foreach ($documents as $document) { - $responses[] = $this->platform->request($this->model, $document->content); + $results[] = $this->platform->invoke($this->model, $document->content); } $vectors = []; - foreach ($responses as $response) { - $vectors = array_merge($vectors, $response->asVectors()); + foreach ($results as $result) { + $vectors = array_merge($vectors, $result->asVectors()); } } diff --git a/src/store/tests/Double/PlatformTestHandler.php b/src/store/tests/Double/PlatformTestHandler.php index 9cd08562..0a9406f3 100644 --- a/src/store/tests/Double/PlatformTestHandler.php +++ b/src/store/tests/Double/PlatformTestHandler.php @@ -14,24 +14,24 @@ use Symfony\AI\Platform\Model; use Symfony\AI\Platform\ModelClientInterface; use Symfony\AI\Platform\Platform; -use Symfony\AI\Platform\Response\RawHttpResponse; -use Symfony\AI\Platform\Response\RawResponseInterface; -use Symfony\AI\Platform\Response\ResponseInterface; -use Symfony\AI\Platform\Response\VectorResponse; -use Symfony\AI\Platform\ResponseConverterInterface; +use Symfony\AI\Platform\Result\RawHttpResult; +use Symfony\AI\Platform\Result\RawResultInterface; +use Symfony\AI\Platform\Result\ResultInterface; +use Symfony\AI\Platform\Result\VectorResult; +use Symfony\AI\Platform\ResultConverterInterface; use Symfony\AI\Platform\Vector\Vector; use Symfony\Component\HttpClient\Response\MockResponse; -final class PlatformTestHandler implements ModelClientInterface, ResponseConverterInterface +final class PlatformTestHandler implements ModelClientInterface, ResultConverterInterface { public int $createCalls = 0; public function __construct( - private readonly ?ResponseInterface $create = null, + private readonly ?ResultInterface $create = null, ) { } - public static function createPlatform(?ResponseInterface $create = null): Platform + public static function createPlatform(?ResultInterface $create = null): Platform { $handler = new self($create); @@ -43,15 +43,15 @@ public function supports(Model $model): bool return true; } - public function request(Model $model, array|string|object $payload, array $options = []): RawHttpResponse + public function request(Model $model, array|string|object $payload, array $options = []): RawHttpResult { ++$this->createCalls; - return new RawHttpResponse(new MockResponse()); + return new RawHttpResult(new MockResponse()); } - public function convert(RawResponseInterface $response, array $options = []): ResponseInterface + public function convert(RawResultInterface $result, array $options = []): ResultInterface { - return $this->create ?? new VectorResponse(new Vector([1, 2, 3])); + return $this->create ?? new VectorResult(new Vector([1, 2, 3])); } } diff --git a/src/store/tests/IndexerTest.php b/src/store/tests/IndexerTest.php index 52537e76..23260bb1 100644 --- a/src/store/tests/IndexerTest.php +++ b/src/store/tests/IndexerTest.php @@ -20,9 +20,9 @@ use Symfony\AI\Platform\Bridge\OpenAI\Embeddings; use Symfony\AI\Platform\Message\ToolCallMessage; use Symfony\AI\Platform\Platform; -use Symfony\AI\Platform\Response\ResponsePromise; -use Symfony\AI\Platform\Response\ToolCall; -use Symfony\AI\Platform\Response\VectorResponse; +use Symfony\AI\Platform\Result\ResultPromise; +use Symfony\AI\Platform\Result\ToolCall; +use Symfony\AI\Platform\Result\VectorResult; use Symfony\AI\Platform\Vector\Vector; use Symfony\AI\Store\Document\Metadata; use Symfony\AI\Store\Document\TextDocument; @@ -42,8 +42,8 @@ #[UsesClass(ToolCall::class)] #[UsesClass(Embeddings::class)] #[UsesClass(Platform::class)] -#[UsesClass(ResponsePromise::class)] -#[UsesClass(VectorResponse::class)] +#[UsesClass(ResultPromise::class)] +#[UsesClass(VectorResult::class)] final class IndexerTest extends TestCase { #[Test] @@ -51,7 +51,7 @@ public function indexSingleDocument(): void { $document = new TextDocument($id = Uuid::v4(), 'Test content'); $vector = new Vector([0.1, 0.2, 0.3]); - $vectorizer = new Vectorizer(PlatformTestHandler::createPlatform(new VectorResponse($vector)), new Embeddings()); + $vectorizer = new Vectorizer(PlatformTestHandler::createPlatform(new VectorResult($vector)), new Embeddings()); $indexer = new Indexer($vectorizer, $store = new TestStore()); $indexer->index($document); @@ -81,7 +81,7 @@ public function indexDocumentWithMetadata(): void $metadata = new Metadata(['key' => 'value']); $document = new TextDocument($id = Uuid::v4(), 'Test content', $metadata); $vector = new Vector([0.1, 0.2, 0.3]); - $vectorizer = new Vectorizer(PlatformTestHandler::createPlatform(new VectorResponse($vector)), new Embeddings()); + $vectorizer = new Vectorizer(PlatformTestHandler::createPlatform(new VectorResult($vector)), new Embeddings()); $indexer = new Indexer($vectorizer, $store = new TestStore()); $indexer->index($document);