Skip to content

feat: add ResponseContract handling [by Claude Code] #338

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

chr-hertel
Copy link
Member

@chr-hertel chr-hertel commented Jun 22, 2025

Input:

When you look at the different implementations of ResponseConverterInterface in the various Platform\Bridge namespace, there is a lot of redundancies. I would think, that similar with
the Contract handling with the Normalizers, it is somehow possible to abstract away the response conversion into DTOs so we can share behavior of conversion between the
implementations. especially around tool call and stream handling.

@chr-hertel chr-hertel requested a review from Copilot June 22, 2025 11:11
Copilot

This comment was marked as outdated.

@chr-hertel chr-hertel force-pushed the feat-response-contract branch 2 times, most recently from 3622f44 to 239ed8a Compare June 22, 2025 12:02
@chr-hertel chr-hertel requested a review from Copilot June 22, 2025 12:03
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a unified ResponseContract system to replace redundant per-platform response converters, streamlining response parsing and conversion across LLM platforms.

  • Adds ResponseContract and ResponseContractFactory to centralize denormalization logic.
  • Updates OpenAI and Mistral factories to use ResponseContract instead of separate converters.
  • Provides extensive DTOs and denormalizers with full test coverage for parsing, streaming, and tool-call handling.

Reviewed Changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Platform/ResponseContract.php Core coordinator and factory for denormalizers
src/Platform/ResponseContractFactory.php Stateful adapter implementing ResponseConverterInterface
src/Platform/Bridge/OpenAI/PlatformFactory.php Switched to ResponseContract-based converter for OpenAI
src/Platform/Bridge/Mistral/PlatformFactory.php Switched to ResponseContract-based converter for Mistral
tests/Platform/ResponseContractTest.php Coverage for simple text, tool calls, and non-streaming responses
tests/Platform/Bridge/** New parser/stream tests for OpenAI and Mistral response formats
Comments suppressed due to low confidence (1)

tests/Platform/ResponseContractTest.php:60

  • Consider adding a dedicated test for multi-choice responses (i.e., when choices contains more than one element) to cover the ChoiceResponse path in TextResponseDenormalizer.
    public function testConvertResponseSimpleText(): void

public static function create(DenormalizerInterface ...$denormalizers): self
{
return new self(
new ResponseDenormalizer(...$denormalizers),
);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public static methods go directly after the constructor

public function supportsModel(Model $model): bool
{
// Check if any denormalizer supports this model by testing denormalization
$context = [self::CONTEXT_MODEL => $model];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this variable is not needed - just add the array directly to the supportsDenormalization method

Copy link
Member Author

@chr-hertel chr-hertel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, a few things here:

  • let's not duplicate DTOs like ToolCall and ParsedToolCall but use the same - meaning the already existing PhpLlm\LlmChain\Platform\Response\ToolCall class - same for others.
  • Let's get rid off the ResponseConverterInterface now and the corresponding code in the bridge classes

@chr-hertel chr-hertel force-pushed the feat-response-contract branch from 239ed8a to af06a40 Compare June 22, 2025 12:27
@chr-hertel
Copy link
Member Author

Claude usage limit reached. Your limit will reset at 5pm (Europe/Berlin).

I guess my prompt in the beginning send Claude into introducing new DTOs and should have been more explicit about DTO usage, adding and running tests.

@chr-hertel chr-hertel force-pushed the feat-response-contract branch 2 times, most recently from 35ec6ac to 164dba4 Compare June 22, 2025 15:12
@chr-hertel chr-hertel force-pushed the feat-response-contract branch from 164dba4 to dbbc502 Compare June 22, 2025 15:15
@chr-hertel
Copy link
Member Author

alrighty, fun but trash.

@chr-hertel chr-hertel closed this Jun 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant