Skip to content

Remove candidate token count #42

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

Merged
merged 2 commits into from
Aug 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 4 additions & 30 deletions src/Results/DTO/Candidate.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,14 @@
*
* @phpstan-import-type MessageArrayShape from Message
*
* @phpstan-type CandidateArrayShape array{message: MessageArrayShape, finishReason: string, tokenCount: int}
* @phpstan-type CandidateArrayShape array{message: MessageArrayShape, finishReason: string}
*
* @extends AbstractDataTransferObject<CandidateArrayShape>
*/
class Candidate extends AbstractDataTransferObject
{
public const KEY_MESSAGE = 'message';
public const KEY_FINISH_REASON = 'finishReason';
public const KEY_TOKEN_COUNT = 'tokenCount';
/**
* @var Message The generated message.
*/
Expand All @@ -38,21 +37,15 @@ class Candidate extends AbstractDataTransferObject
*/
private FinishReasonEnum $finishReason;

/**
* @var int The number of tokens in this candidate.
*/
private int $tokenCount;

/**
* Constructor.
*
* @since n.e.x.t
*
* @param Message $message The generated message.
* @param FinishReasonEnum $finishReason The reason generation stopped.
* @param int $tokenCount The number of tokens in this candidate.
*/
public function __construct(Message $message, FinishReasonEnum $finishReason, int $tokenCount)
public function __construct(Message $message, FinishReasonEnum $finishReason)
{
if (!$message->getRole()->isModel()) {
throw new InvalidArgumentException(
Expand All @@ -62,7 +55,6 @@ public function __construct(Message $message, FinishReasonEnum $finishReason, in

$this->message = $message;
$this->finishReason = $finishReason;
$this->tokenCount = $tokenCount;
}

/**
Expand All @@ -89,18 +81,6 @@ public function getFinishReason(): FinishReasonEnum
return $this->finishReason;
}

/**
* Gets the token count.
*
* @since n.e.x.t
*
* @return int The token count.
*/
public function getTokenCount(): int
{
return $this->tokenCount;
}

/**
* {@inheritDoc}
*
Expand All @@ -117,12 +97,8 @@ public static function getJsonSchema(): array
'enum' => FinishReasonEnum::getValues(),
'description' => 'The reason generation stopped.',
],
self::KEY_TOKEN_COUNT => [
'type' => 'integer',
'description' => 'The number of tokens in this candidate.',
],
],
'required' => [self::KEY_MESSAGE, self::KEY_FINISH_REASON, self::KEY_TOKEN_COUNT],
'required' => [self::KEY_MESSAGE, self::KEY_FINISH_REASON],
];
}

Expand All @@ -138,7 +114,6 @@ public function toArray(): array
return [
self::KEY_MESSAGE => $this->message->toArray(),
self::KEY_FINISH_REASON => $this->finishReason->value,
self::KEY_TOKEN_COUNT => $this->tokenCount,
];
}

Expand All @@ -149,14 +124,13 @@ public function toArray(): array
*/
public static function fromArray(array $array): self
{
static::validateFromArrayData($array, [self::KEY_MESSAGE, self::KEY_FINISH_REASON, self::KEY_TOKEN_COUNT]);
static::validateFromArrayData($array, [self::KEY_MESSAGE, self::KEY_FINISH_REASON]);

$messageData = $array[self::KEY_MESSAGE];

return new self(
Message::fromArray($messageData),
FinishReasonEnum::from($array[self::KEY_FINISH_REASON]),
$array[self::KEY_TOKEN_COUNT]
);
}
}
1 change: 0 additions & 1 deletion tests/unit/Operations/DTO/GenerativeAiOperationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,6 @@ public function testFromArraySucceededState(): void
]
],
Candidate::KEY_FINISH_REASON => FinishReasonEnum::stop()->value,
Candidate::KEY_TOKEN_COUNT => 30
]
],
GenerativeAiResult::KEY_TOKEN_USAGE => [
Expand Down
93 changes: 13 additions & 80 deletions tests/unit/Results/DTO/CandidateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,10 @@ public function testCreateWithBasicProperties(): void
$candidate = new Candidate(
$message,
FinishReasonEnum::stop(),
25
);

$this->assertSame($message, $candidate->getMessage());
$this->assertEquals(FinishReasonEnum::stop(), $candidate->getFinishReason());
$this->assertEquals(25, $candidate->getTokenCount());
}

/**
Expand All @@ -58,7 +56,7 @@ public function testWithDifferentFinishReasons(FinishReasonEnum $finishReason):
{
$message = new ModelMessage([new MessagePart('Response')]);

$candidate = new Candidate($message, $finishReason, 10);
$candidate = new Candidate($message, $finishReason);

$this->assertEquals($finishReason, $candidate->getFinishReason());
}
Expand Down Expand Up @@ -103,13 +101,11 @@ public function testWithComplexMessage(): void

$candidate = new Candidate(
$message,
FinishReasonEnum::toolCalls(),
150
FinishReasonEnum::toolCalls()
);

$this->assertCount(6, $candidate->getMessage()->getParts());
$this->assertTrue($candidate->getFinishReason()->isToolCalls());
$this->assertEquals(150, $candidate->getTokenCount());
}

/**
Expand All @@ -134,7 +130,6 @@ public function testWithMessageContainingFiles(): void
$candidate = new Candidate(
$message,
FinishReasonEnum::stop(),
85
);

$parts = $candidate->getMessage()->getParts();
Expand All @@ -143,42 +138,6 @@ public function testWithMessageContainingFiles(): void
$this->assertEquals('The image shows a flowchart of the process.', $parts[2]->getText());
}

/**
* Tests candidate with different token counts.
*
* @dataProvider tokenCountProvider
* @param int $tokenCount
* @return void
*/
public function testWithDifferentTokenCounts(int $tokenCount): void
{
$message = new ModelMessage([new MessagePart('Response')]);

$candidate = new Candidate(
$message,
FinishReasonEnum::stop(),
$tokenCount
);

$this->assertEquals($tokenCount, $candidate->getTokenCount());
}

/**
* Provides different token counts.
*
* @return array
*/
public function tokenCountProvider(): array
{
return [
'zero' => [0],
'small' => [10],
'medium' => [500],
'large' => [4000],
'very_large' => [100000],
];
}

/**
* Tests candidate rejects non-model message.
*
Expand All @@ -195,8 +154,7 @@ public function testRejectsNonModelMessage(): void

new Candidate(
$userMessage,
FinishReasonEnum::stop(),
10
FinishReasonEnum::stop()
);
}

Expand All @@ -217,8 +175,7 @@ public function testRejectsMessageWithDifferentRole(): void

new Candidate(
$message,
FinishReasonEnum::stop(),
10
FinishReasonEnum::stop()
);
}

Expand All @@ -238,7 +195,6 @@ public function testJsonSchema(): void
$this->assertArrayHasKey('properties', $schema);
$this->assertArrayHasKey(Candidate::KEY_MESSAGE, $schema['properties']);
$this->assertArrayHasKey(Candidate::KEY_FINISH_REASON, $schema['properties']);
$this->assertArrayHasKey(Candidate::KEY_TOKEN_COUNT, $schema['properties']);

// Check finishReason property
$finishReasonSchema = $schema['properties'][Candidate::KEY_FINISH_REASON];
Expand All @@ -250,16 +206,9 @@ public function testJsonSchema(): void
$this->assertContains('tool_calls', $finishReasonSchema['enum']);
$this->assertContains('error', $finishReasonSchema['enum']);

// Check tokenCount property
$tokenCountSchema = $schema['properties'][Candidate::KEY_TOKEN_COUNT];
$this->assertEquals('integer', $tokenCountSchema['type']);

// Check required fields
$this->assertArrayHasKey('required', $schema);
$this->assertEquals(
[Candidate::KEY_MESSAGE, Candidate::KEY_FINISH_REASON, Candidate::KEY_TOKEN_COUNT],
$schema['required']
);
$this->assertEquals([Candidate::KEY_MESSAGE, Candidate::KEY_FINISH_REASON], $schema['required']);
}

/**
Expand All @@ -273,12 +222,10 @@ public function testWithEmptyMessageParts(): void

$candidate = new Candidate(
$message,
FinishReasonEnum::stop(),
0
FinishReasonEnum::stop()
);

$this->assertCount(0, $candidate->getMessage()->getParts());
$this->assertEquals(0, $candidate->getTokenCount());
}

/**
Expand All @@ -294,12 +241,10 @@ public function testWithMaxLengthFinishReason(): void

$candidate = new Candidate(
$message,
FinishReasonEnum::length(),
4096
FinishReasonEnum::length()
);

$this->assertTrue($candidate->getFinishReason()->isLength());
$this->assertEquals(4096, $candidate->getTokenCount());
}

/**
Expand All @@ -315,8 +260,7 @@ public function testWithContentFilterFinishReason(): void

$candidate = new Candidate(
$message,
FinishReasonEnum::contentFilter(),
8
FinishReasonEnum::contentFilter()
);

$this->assertTrue($candidate->getFinishReason()->isContentFilter());
Expand All @@ -335,8 +279,7 @@ public function testWithErrorFinishReason(): void

$candidate = new Candidate(
$message,
FinishReasonEnum::error(),
9
FinishReasonEnum::error()
);

$this->assertTrue($candidate->getFinishReason()->isError());
Expand All @@ -356,19 +299,14 @@ public function testToArray(): void

$candidate = new Candidate(
$message,
FinishReasonEnum::stop(),
45
FinishReasonEnum::stop()
);

$json = $this->assertToArrayReturnsArray($candidate);

$this->assertArrayHasKeys(
$json,
[Candidate::KEY_MESSAGE, Candidate::KEY_FINISH_REASON, Candidate::KEY_TOKEN_COUNT]
);
$this->assertArrayHasKeys($json, [Candidate::KEY_MESSAGE, Candidate::KEY_FINISH_REASON]);
$this->assertIsArray($json[Candidate::KEY_MESSAGE]);
$this->assertEquals(FinishReasonEnum::stop()->value, $json[Candidate::KEY_FINISH_REASON]);
$this->assertEquals(45, $json[Candidate::KEY_TOKEN_COUNT]);
}

/**
Expand All @@ -393,14 +331,12 @@ public function testFromArray(): void
]
],
Candidate::KEY_FINISH_REASON => FinishReasonEnum::stop()->value,
Candidate::KEY_TOKEN_COUNT => 75
];

$candidate = Candidate::fromArray($json);

$this->assertInstanceOf(Candidate::class, $candidate);
$this->assertEquals(FinishReasonEnum::stop(), $candidate->getFinishReason());
$this->assertEquals(75, $candidate->getTokenCount());
$this->assertCount(2, $candidate->getMessage()->getParts());
$this->assertEquals('Response text 1', $candidate->getMessage()->getParts()[0]->getText());
$this->assertEquals('Response text 2', $candidate->getMessage()->getParts()[1]->getText());
Expand All @@ -419,12 +355,10 @@ public function testArrayRoundTrip(): void
new MessagePart('Generated response'),
new MessagePart(new FunctionCall('call_123', 'search', ['q' => 'test']))
]),
FinishReasonEnum::toolCalls(),
120
FinishReasonEnum::toolCalls()
),
function ($original, $restored) {
$this->assertEquals($original->getFinishReason()->value, $restored->getFinishReason()->value);
$this->assertEquals($original->getTokenCount(), $restored->getTokenCount());
$this->assertCount(
count($original->getMessage()->getParts()),
$restored->getMessage()->getParts()
Expand All @@ -450,8 +384,7 @@ public function testImplementsWithArrayTransformationInterface(): void
{
$candidate = new Candidate(
new ModelMessage([new MessagePart('test')]),
FinishReasonEnum::stop(),
10
FinishReasonEnum::stop()
);
$this->assertImplementsArrayTransformation($candidate);
}
Expand Down
1 change: 0 additions & 1 deletion tests/unit/Results/DTO/GenerativeAiResultTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,6 @@ public function testFromArray(): void
]
],
Candidate::KEY_FINISH_REASON => FinishReasonEnum::stop()->value,
Candidate::KEY_TOKEN_COUNT => 20
]
],
GenerativeAiResult::KEY_TOKEN_USAGE => [
Expand Down