CS follows Symfony rules update

This commit is contained in:
Christopher Hertel
2026-01-23 21:56:05 +01:00
parent 27ccc0d27f
commit 8ec894f532
69 changed files with 164 additions and 165 deletions

View File

@@ -13,6 +13,6 @@ use App\Kernel;
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
return static function (array $context) {
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
};

View File

@@ -50,7 +50,7 @@ final class Recipe
public function toString(): string
{
$ingredients = implode(\PHP_EOL, array_map(fn (Ingredient $ing) => $ing->toString(), $this->ingredients));
$ingredients = implode(\PHP_EOL, array_map(static fn (Ingredient $ing) => $ing->toString(), $this->ingredients));
$steps = implode(\PHP_EOL, $this->steps);
return <<<RECIPE

View File

@@ -30,7 +30,7 @@ final class TranscriptFetcher
$list = $fetcher->fetch($videoId);
$transcript = $list->findTranscript($list->getAvailableLanguageCodes());
return array_reduce($transcript->fetch(), function (string $carry, array $item): string {
return array_reduce($transcript->fetch(), static function (string $carry, array $item): string {
return $carry.\PHP_EOL.$item['text'];
}, '');
}

View File

@@ -25,5 +25,5 @@ printf(
"String: %s\nVector dimensions: %d\nFirst 5 values: [%s]\n",
$string,
$vector->getDimensions(),
implode(', ', array_map(fn ($val) => number_format($val, 6), array_slice($vector->getData(), 0, 5)))
implode(', ', array_map(static fn ($val) => number_format($val, 6), array_slice($vector->getData(), 0, 5)))
);

View File

@@ -21,7 +21,7 @@ require_once dirname(__DIR__).'/bootstrap.php';
$app = (new SingleCommandApplication('Albert API Model Listing'))
->setDescription('Lists all available models on Albert API')
->setCode(function (InputInterface $input, OutputInterface $output) {
->setCode(static function (InputInterface $input, OutputInterface $output) {
$io = new SymfonyStyle($input, $output);
$io->title('Albert API Model Listing');
@@ -35,7 +35,7 @@ $app = (new SingleCommandApplication('Albert API Model Listing'))
}
$io->listing(
array_map(fn (Model $model) => $model->getName(), $models)
array_map(static fn (Model $model) => $model->getName(), $models)
);
return Command::SUCCESS;

View File

@@ -74,7 +74,7 @@ function logger(): LoggerInterface
// Add context display for debug verbosity
if ($this->output->getVerbosity() >= ConsoleOutput::VERBOSITY_DEBUG && [] !== $context) {
// Filter out special keys that are already handled
$displayContext = array_filter($context, function ($key) {
$displayContext = array_filter($context, static function ($key) {
return !in_array($key, ['exception', 'error', 'object'], true);
}, \ARRAY_FILTER_USE_KEY);
@@ -160,7 +160,7 @@ function print_vectors(DeferredResult $result): void
output()->writeln(sprintf('Dimensions: %d', $result->asVectors()[0]->getDimensions()));
}
set_exception_handler(function ($exception) {
set_exception_handler(static function ($exception) {
if ($exception instanceof AgentException || $exception instanceof PlatformException || $exception instanceof StoreException) {
output()->writeln(sprintf('<error>%s</error>', $exception->getMessage()));

View File

@@ -28,4 +28,4 @@ $textDocuments = [
$vectorizer = new Vectorizer($platform, 'text-embedding-3-large');
$vectorDocuments = $vectorizer->vectorize($textDocuments);
dump(array_map(fn (VectorDocument $document) => $document->vector->getDimensions(), $vectorDocuments));
dump(array_map(static fn (VectorDocument $document) => $document->vector->getDimensions(), $vectorDocuments));

View File

@@ -25,5 +25,5 @@ printf(
"String: %s\nVector dimensions: %d\nFirst 5 values: [%s]\n",
$string,
$vector->getDimensions(),
implode(', ', array_map(fn ($val) => number_format($val, 6), array_slice($vector->getData(), 0, 5)))
implode(', ', array_map(static fn ($val) => number_format($val, 6), array_slice($vector->getData(), 0, 5)))
);

View File

@@ -31,7 +31,7 @@ $processor = new AgentProcessor($toolbox, eventDispatcher: $eventDispatcher);
$agent = new Agent($platform, 'gpt-4o-mini', [$processor], [$processor]);
// Add tool call result listener to enforce chain exits direct with structured response for weather tools
$eventDispatcher->addListener(ToolCallsExecuted::class, function (ToolCallsExecuted $event): void {
$eventDispatcher->addListener(ToolCallsExecuted::class, static function (ToolCallsExecuted $event): void {
foreach ($event->getToolResults() as $toolCallResult) {
if (str_starts_with($toolCallResult->getToolCall()->getName(), 'weather_')) {
$event->setResult(new ObjectResult($toolCallResult->getResult()));

View File

@@ -44,7 +44,7 @@ final class Wikipedia implements HasSourcesInterface
'srsearch' => $query,
], $this->locale);
$titles = array_map(fn (array $item) => $item['title'], $result['query']['search']);
$titles = array_map(static fn (array $item) => $item['title'], $result['query']['search']);
if ([] === $titles) {
return 'No articles were found on Wikipedia.';

View File

@@ -67,7 +67,7 @@ final class SystemPromptInputProcessor implements InputProcessorInterface
$this->logger->debug('Append tool definitions to system prompt.');
$tools = implode(\PHP_EOL.\PHP_EOL, array_map(
fn (Tool $tool) => <<<TOOL
static fn (Tool $tool) => <<<TOOL
## {$tool->getName()}
{$tool->getDescription()}
TOOL,

View File

@@ -73,7 +73,7 @@ final class MultiAgent implements AgentInterface
$userText = $userMessage->asText();
$this->logger->debug('MultiAgent: Processing user message', ['user_text' => $userText]);
$this->logger->debug('MultiAgent: Available agents for routing', ['agents' => array_map(fn ($handoff) => [
$this->logger->debug('MultiAgent: Available agents for routing', ['agents' => array_map(static fn ($handoff) => [
'to' => $handoff->getTo()->getName(),
'when' => $handoff->getWhen(),
], $this->handoffs)]);

View File

@@ -67,7 +67,7 @@ final class AgentProcessor implements InputProcessorInterface, OutputProcessorIn
$options = $input->getOptions();
// only filter tool map if list of strings is provided as option
if (isset($options['tools']) && $this->isFlatStringArray($options['tools'])) {
$toolMap = array_values(array_filter($toolMap, fn (Tool $tool) => \in_array($tool->getName(), $options['tools'], true)));
$toolMap = array_values(array_filter($toolMap, static fn (Tool $tool) => \in_array($tool->getName(), $options['tools'], true)));
}
$options['tools'] = $toolMap;
@@ -98,7 +98,7 @@ final class AgentProcessor implements InputProcessorInterface, OutputProcessorIn
*/
private function isFlatStringArray(array $tools): bool
{
return array_reduce($tools, fn (bool $carry, mixed $item) => $carry && \is_string($item), true);
return array_reduce($tools, static fn (bool $carry, mixed $item) => $carry && \is_string($item), true);
}
private function handleToolCallsCallback(Output $output, ToolCallResult $result, ?AssistantMessage $streamedAssistantResponse = null): ResultInterface

View File

@@ -40,7 +40,7 @@ final class FaultTolerantToolbox implements ToolboxInterface
} catch (ToolExecutionExceptionInterface $e) {
return new ToolResult($toolCall, $e->getToolCallResult());
} catch (ToolNotFoundException) {
$names = array_map(fn (Tool $metadata) => $metadata->getName(), $this->getTools());
$names = array_map(static fn (Tool $metadata) => $metadata->getName(), $this->getTools());
return new ToolResult(
$toolCall,

View File

@@ -154,7 +154,7 @@ final class StreamingAgentToolCallTest extends TestCase
private function createStreamResultWithToolCall(string $text, ToolCall $toolCall, TokenUsage $tokenUsage): StreamResult
{
$result = new StreamResult((function () use ($text, $toolCall) {
$result = new StreamResult((static function () use ($text, $toolCall) {
yield $text;
yield new ToolCallResult($toolCall);
})());

View File

@@ -122,7 +122,7 @@ final class EmbeddingProviderTest extends TestCase
->willReturn($deferredResult);
$store = $this->createMock(StoreInterface::class);
$generator = (function () {
$generator = (static function () {
yield (object) ['metadata' => ['fact' => 'The sky is blue']];
yield (object) ['metadata' => ['fact' => 'Water is wet']];
})();

View File

@@ -348,7 +348,7 @@ final class MockAgentTest extends TestCase
public function testCallableResponse()
{
$agent = new MockAgent();
$agent->addResponse('dynamic', function ($messages, $options, $input) {
$agent->addResponse('dynamic', static function ($messages, $options, $input) {
return "Dynamic response for: {$input}";
});
@@ -361,7 +361,7 @@ final class MockAgentTest extends TestCase
public function testCallableResponseWithParameters()
{
$agent = new MockAgent();
$agent->addResponse('test', function ($messages, $options, $input) {
$agent->addResponse('test', static function ($messages, $options, $input) {
$messageCount = \count($messages->getMessages());
$optionKeys = implode(',', array_keys($options));
@@ -381,7 +381,7 @@ final class MockAgentTest extends TestCase
public function testCallableReturningMockResponse()
{
$agent = new MockAgent();
$agent->addResponse('complex', function ($messages, $options, $input) {
$agent->addResponse('complex', static function ($messages, $options, $input) {
return new MockResponse("Complex response for: {$input}");
});
@@ -394,7 +394,7 @@ final class MockAgentTest extends TestCase
public function testCallableTrackingInCalls()
{
$agent = new MockAgent();
$agent->addResponse('tracked', function ($messages, $options, $input) {
$agent->addResponse('tracked', static function ($messages, $options, $input) {
return "Tracked: {$input}";
});

View File

@@ -245,7 +245,7 @@ class MultiAgentTest extends TestCase
->method('call')
->with(
$this->isInstanceOf(MessageBag::class),
$this->callback(fn ($opts) => isset($opts['temperature']) && 0.7 === $opts['temperature']
$this->callback(static fn ($opts) => isset($opts['temperature']) && 0.7 === $opts['temperature']
&& isset($opts['max_tokens']) && 100 === $opts['max_tokens']
&& isset($opts['response_format']) && Decision::class === $opts['response_format']
)
@@ -352,7 +352,7 @@ class MultiAgentTest extends TestCase
$orchestrator->expects($this->once())
->method('call')
->with(
$this->callback(function (MessageBag $messages) {
$this->callback(static function (MessageBag $messages) {
$userMessage = $messages->getUserMessage();
$text = $userMessage?->asText();

View File

@@ -249,7 +249,7 @@ class AgentProcessorTest extends TestCase
->method('execute')
->willReturn(new ToolResult($toolCall, 'Response based on the two articles.', new SourceCollection([$source1, $source2])));
$result = new StreamResult((function () use ($toolCall) {
$result = new StreamResult((static function () use ($toolCall) {
yield 'chunk1';
yield 'chunk2';
yield new ToolCallResult($toolCall);
@@ -284,7 +284,7 @@ class AgentProcessorTest extends TestCase
->method('execute')
->willReturn(new ToolResult($toolCall, 'Tool responded'));
$result = new StreamResult((function () use ($toolCall) {
$result = new StreamResult((static function () use ($toolCall) {
yield 'partial-1';
yield 'partial-2';
yield new ToolCallResult($toolCall);
@@ -294,7 +294,7 @@ class AgentProcessorTest extends TestCase
$agent
->expects($this->once())
->method('call')
->willReturnCallback(function () {
->willReturnCallback(static function () {
$final = new TextResult('Final content after tool');
$final->getMetadata()->add('foo', 'bar');
@@ -322,7 +322,7 @@ class AgentProcessorTest extends TestCase
->method('execute')
->willReturn(new ToolResult($toolCall, 'Tool responded'));
$result = new StreamResult((function () use ($toolCall) {
$result = new StreamResult((static function () use ($toolCall) {
yield 'partial-1';
yield 'partial-2';
yield new ToolCallResult($toolCall);
@@ -333,7 +333,7 @@ class AgentProcessorTest extends TestCase
$agent
->expects($this->once())
->method('call')
->willReturnCallback(function () {
->willReturnCallback(static function () {
$toolResult = new TextResult('Final content after tool');
$toolResult->getMetadata()->add('token_usage', new TokenUsage(totalTokens: 10));

View File

@@ -29,7 +29,7 @@ final class FaultTolerantToolboxTest extends TestCase
public function testFaultyToolExecution()
{
$faultyToolbox = $this->createFaultyToolbox(
fn (ToolCall $toolCall) => ToolExecutionException::executionFailed($toolCall, new \Exception('error'))
static fn (ToolCall $toolCall) => ToolExecutionException::executionFailed($toolCall, new \Exception('error'))
);
$faultTolerantToolbox = new FaultTolerantToolbox($faultyToolbox);
@@ -44,7 +44,7 @@ final class FaultTolerantToolboxTest extends TestCase
public function testFaultyToolCall()
{
$faultyToolbox = $this->createFaultyToolbox(
fn (ToolCall $toolCall) => ToolNotFoundException::notFoundForToolCall($toolCall)
static fn (ToolCall $toolCall) => ToolNotFoundException::notFoundForToolCall($toolCall)
);
$faultTolerantToolbox = new FaultTolerantToolbox($faultyToolbox);

View File

@@ -27,13 +27,13 @@ final class StreamListenerTest extends TestCase
{
public function testGetContentWithOnlyStringValues()
{
$streamResult = new StreamResult((function (): \Generator {
$streamResult = new StreamResult((static function (): \Generator {
yield 'Hello ';
yield 'World';
})());
$callbackCalled = false;
$handleToolCallsCallback = function () use (&$callbackCalled) {
$handleToolCallsCallback = static function () use (&$callbackCalled) {
$callbackCalled = true;
};
@@ -47,7 +47,7 @@ final class StreamListenerTest extends TestCase
public function testGetContentWithToolCallResultAfterStringValues()
{
$toolCallResult = new ToolCallResult(new ToolCall('test-id', 'test_tool'));
$streamResult = new StreamResult((function () use ($toolCallResult): \Generator {
$streamResult = new StreamResult((static function () use ($toolCallResult): \Generator {
yield 'Initial ';
yield 'content ';
yield $toolCallResult;
@@ -55,7 +55,7 @@ final class StreamListenerTest extends TestCase
$capturedAssistantMessage = null;
$capturedToolCallResult = null;
$handleToolCallsCallback = function (ToolCallResult $tcr, AssistantMessage $msg) use (&$capturedAssistantMessage, &$capturedToolCallResult) {
$handleToolCallsCallback = static function (ToolCallResult $tcr, AssistantMessage $msg) use (&$capturedAssistantMessage, &$capturedToolCallResult) {
$capturedToolCallResult = $tcr;
$capturedAssistantMessage = $msg;
@@ -74,12 +74,12 @@ final class StreamListenerTest extends TestCase
public function testGetContentWithToolCallResultAsFirstValue()
{
$streamResult = new StreamResult((function (): \Generator {
$streamResult = new StreamResult((static function (): \Generator {
yield new ToolCallResult(new ToolCall('test-id', 'test_tool'));
})());
$capturedAssistantMessage = null;
$handleToolCallsCallback = function (ToolCallResult $tcr, AssistantMessage $msg) use (&$capturedAssistantMessage) {
$handleToolCallsCallback = static function (ToolCallResult $tcr, AssistantMessage $msg) use (&$capturedAssistantMessage) {
$capturedAssistantMessage = $msg;
return new TextResult('Immediate tool response');
@@ -95,16 +95,16 @@ final class StreamListenerTest extends TestCase
public function testGetContentWithToolCallResultReturningGenerator()
{
$streamResult = new StreamResult((function (): \Generator {
$streamResult = new StreamResult((static function (): \Generator {
yield 'Start';
yield new ToolCallResult(new ToolCall('test-id', 'test_tool'));
})());
$capturedAssistantMessage = null;
$handleToolCallsCallback = function (ToolCallResult $tcr, AssistantMessage $msg) use (&$capturedAssistantMessage) {
$handleToolCallsCallback = static function (ToolCallResult $tcr, AssistantMessage $msg) use (&$capturedAssistantMessage) {
$capturedAssistantMessage = $msg;
return new StreamResult((function (): \Generator {
return new StreamResult((static function (): \Generator {
yield 'Part 1';
yield 'Part 2';
yield 'Part 3';
@@ -120,14 +120,14 @@ final class StreamListenerTest extends TestCase
public function testGetContentStopsAfterToolCallResult()
{
$streamResult = new StreamResult((function (): \Generator {
$streamResult = new StreamResult((static function (): \Generator {
yield 'Before';
yield new ToolCallResult(new ToolCall('test-id', 'test_tool'));
yield 'After'; // This should not be yielded
})());
$innerResult = new TextResult('Tool output');
$handleToolCallsCallback = fn () => $innerResult;
$handleToolCallsCallback = static fn () => $innerResult;
$streamResult->addListener(new StreamListener($handleToolCallsCallback));
$result = iterator_to_array($streamResult->getContent(), false);
@@ -137,7 +137,7 @@ final class StreamListenerTest extends TestCase
public function testMetadataPropagationFromTextResult()
{
$streamResult = new StreamResult((function (): \Generator {
$streamResult = new StreamResult((static function (): \Generator {
yield 'Before tool';
yield new ToolCallResult(new ToolCall('test-id', 'test_tool'));
})());
@@ -146,7 +146,7 @@ final class StreamListenerTest extends TestCase
$innerResult = new TextResult('Tool response');
$innerResult->getMetadata()->add('token_usage', new TokenUsage(promptTokens: 200, completionTokens: 20, totalTokens: 220));
$streamResult->addListener(new StreamListener(fn () => $innerResult));
$streamResult->addListener(new StreamListener(static fn () => $innerResult));
iterator_to_array($streamResult->getContent());
$this->assertTrue($streamResult->getMetadata()->has('token_usage'));
@@ -158,19 +158,19 @@ final class StreamListenerTest extends TestCase
{
$innerTokenUsage = new TokenUsage(promptTokens: 200, completionTokens: 20, totalTokens: 220);
$streamResult = new StreamResult((function (): \Generator {
$streamResult = new StreamResult((static function (): \Generator {
yield 'Before tool';
yield new ToolCallResult(new ToolCall('test-id', 'test_tool'));
})());
$streamResult->getMetadata()->add('token_usage', new TokenUsage(promptTokens: 100, completionTokens: 10, totalTokens: 110));
$innerResult = new StreamResult((function (): \Generator {
$innerResult = new StreamResult((static function (): \Generator {
yield 'Part 1';
yield 'Part 2';
})());
$innerResult->getMetadata()->add('token_usage', $innerTokenUsage);
$streamResult->addListener(new StreamListener(fn () => $innerResult));
$streamResult->addListener(new StreamListener(static fn () => $innerResult));
iterator_to_array($streamResult->getContent());
$this->assertTrue($streamResult->getMetadata()->has('token_usage'));
@@ -180,13 +180,13 @@ final class StreamListenerTest extends TestCase
public function testMetadataPropagationFromNestedStreamResultWithLazyMetadata()
{
$streamResult = new StreamResult((function (): \Generator {
$streamResult = new StreamResult((static function (): \Generator {
yield 'Before tool';
yield new ToolCallResult(new ToolCall('test-id', 'test_tool'));
})());
$streamResult->getMetadata()->add('token_usage', new TokenUsage(promptTokens: 100, completionTokens: 10, totalTokens: 110));
$innerResult = new StreamResult((function (): \Generator {
$innerResult = new StreamResult((static function (): \Generator {
yield 'Part 1';
yield 'Part 2';
})());
@@ -199,7 +199,7 @@ final class StreamListenerTest extends TestCase
}
});
$streamResult->addListener(new StreamListener(fn () => $innerResult));
$streamResult->addListener(new StreamListener(static fn () => $innerResult));
iterator_to_array($streamResult->getContent());
$this->assertTrue($streamResult->getMetadata()->has('token_usage'));

View File

@@ -311,13 +311,13 @@ return static function (DefinitionConfigurator $configurator): void {
->defaultValue(Model::class)
->cannotBeEmpty()
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
return !class_exists($v);
})
->thenInvalid('The model class "%s" does not exist.')
->end()
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
return !is_a($v, Model::class, true);
})
->thenInvalid('The model class "%s" must extend '.Model::class.'.')
@@ -348,13 +348,13 @@ return static function (DefinitionConfigurator $configurator): void {
->end()
->variableNode('model')
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
return !\is_string($v) && (!\is_array($v) || !isset($v['name']));
})
->thenInvalid('Model must be a string or an array with a "name" key.')
->end()
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
// Check if both query parameters and options array are provided
if (\is_array($v) && isset($v['name']) && isset($v['options']) && [] !== $v['options']) {
return str_contains($v['name'], '?');
@@ -365,7 +365,7 @@ return static function (DefinitionConfigurator $configurator): void {
->thenInvalid('Cannot use both query parameters in model name and options array.')
->end()
->beforeNormalization()
->always(function ($v) {
->always(static function ($v) {
if (\is_string($v)) {
return $v;
}
@@ -416,19 +416,19 @@ return static function (DefinitionConfigurator $configurator): void {
->info('Memory configuration: string for static memory, or array with "service" key for service reference')
->defaultNull()
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
return \is_string($v) && '' === $v;
})
->thenInvalid('Memory cannot be empty.')
->end()
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
return \is_array($v) && !isset($v['service']);
})
->thenInvalid('Memory array configuration must contain a "service" key.')
->end()
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
return \is_array($v) && isset($v['service']) && '' === $v['service'];
})
->thenInvalid('Memory service cannot be empty.')
@@ -438,12 +438,12 @@ return static function (DefinitionConfigurator $configurator): void {
->info('The system prompt configuration')
->beforeNormalization()
->ifString()
->then(function (string $v) {
->then(static function (string $v) {
return ['text' => $v];
})
->end()
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
if (!\is_array($v)) {
return false;
}
@@ -454,25 +454,25 @@ return static function (DefinitionConfigurator $configurator): void {
->thenInvalid('Either "text" or "file" must be configured for prompt.')
->end()
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
return \is_array($v) && isset($v['text']) && isset($v['file']);
})
->thenInvalid('Cannot use both "text" and "file" for prompt. Choose one.')
->end()
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
return \is_array($v) && isset($v['text']) && '' === trim($v['text']);
})
->thenInvalid('The "text" cannot be empty.')
->end()
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
return \is_array($v) && isset($v['file']) && '' === trim($v['file']);
})
->thenInvalid('The "file" cannot be empty.')
->end()
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
return \is_array($v) && ($v['enabled'] ?? false) && !interface_exists(TranslatorInterface::class);
})
->thenInvalid('System prompt translation is enabled, but no translator is present. Try running `composer require symfony/translation`.')
@@ -505,7 +505,7 @@ return static function (DefinitionConfigurator $configurator): void {
->treatNullLike(['enabled' => true])
->beforeNormalization()
->ifArray()
->then(function (array $v): array {
->then(static function (array $v): array {
return [
'enabled' => $v['enabled'] ?? true,
'services' => $v['services'] ?? $v,
@@ -525,7 +525,7 @@ return static function (DefinitionConfigurator $configurator): void {
->end()
->beforeNormalization()
->ifString()
->then(function (string $v) {
->then(static function (string $v) {
return ['service' => $v];
})
->end()
@@ -1150,13 +1150,13 @@ return static function (DefinitionConfigurator $configurator): void {
->end()
->variableNode('model')
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
return !\is_string($v) && (!\is_array($v) || !isset($v['name']));
})
->thenInvalid('Model must be a string or an array with a "name" key.')
->end()
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
// Check if both query parameters and options array are provided
if (\is_array($v) && isset($v['name']) && isset($v['options']) && [] !== $v['options']) {
return str_contains($v['name'], '?');
@@ -1167,7 +1167,7 @@ return static function (DefinitionConfigurator $configurator): void {
->thenInvalid('Cannot use both query parameters in model name and options array.')
->end()
->beforeNormalization()
->always(function ($v) {
->always(static function ($v) {
if (\is_string($v) || null === $v) {
return $v;
}
@@ -1268,7 +1268,7 @@ return static function (DefinitionConfigurator $configurator): void {
->end()
->end()
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
if (!isset($v['agent']) || !isset($v['multi_agent'])) {
return false;
}
@@ -1279,7 +1279,7 @@ return static function (DefinitionConfigurator $configurator): void {
return !empty($duplicates);
})
->then(function ($v) {
->then(static function ($v) {
$agentNames = array_keys($v['agent'] ?? []);
$multiAgentNames = array_keys($v['multi_agent'] ?? []);
$duplicates = array_intersect($agentNames, $multiAgentNames);
@@ -1288,7 +1288,7 @@ return static function (DefinitionConfigurator $configurator): void {
})
->end()
->validate()
->ifTrue(function ($v) {
->ifTrue(static function ($v) {
if (!isset($v['multi_agent']) || !isset($v['agent'])) {
return false;
}
@@ -1316,7 +1316,7 @@ return static function (DefinitionConfigurator $configurator): void {
return false;
})
->then(function ($v) {
->then(static function ($v) {
$agentNames = array_keys($v['agent']);
foreach ($v['multi_agent'] as $multiAgentName => $multiAgent) {

View File

@@ -84,7 +84,7 @@ final class DataCollector extends AbstractDataCollector implements LateDataColle
$this->data = [
'tools' => $this->getAllTools(),
'platform_calls' => array_merge(...array_map($this->awaitCallResults(...), $this->platforms)),
'tool_calls' => array_merge(...array_map(fn (TraceableToolbox $toolbox) => $toolbox->calls, $this->toolboxes)),
'tool_calls' => array_merge(...array_map(static fn (TraceableToolbox $toolbox) => $toolbox->calls, $this->toolboxes)),
'messages' => array_merge(...array_map(static fn (TraceableMessageStore $messageStore): array => $messageStore->calls, $this->messageStores)),
'chats' => array_merge(...array_map(static fn (TraceableChat $chat): array => $chat->calls, $this->chats)),
];
@@ -140,7 +140,7 @@ final class DataCollector extends AbstractDataCollector implements LateDataColle
*/
private function getAllTools(): array
{
return array_merge(...array_map(fn (TraceableToolbox $toolbox) => $toolbox->getTools(), $this->toolboxes));
return array_merge(...array_map(static fn (TraceableToolbox $toolbox) => $toolbox->getTools(), $this->toolboxes));
}
/**

View File

@@ -185,7 +185,7 @@ final class AgentCallCommandTest extends TestCase
$agent->expects($this->exactly(2))
->method('call')
->willReturnCallback(function (MessageBag $messages) use ($result) {
->willReturnCallback(static function (MessageBag $messages) use ($result) {
// Simulate SystemPromptInputProcessor behavior - add system prompt if not present
if (null === $messages->getSystemMessage()) {
$messages->withSystemMessage(Message::forSystem('System prompt'));

View File

@@ -58,7 +58,7 @@ class DataCollectorTest extends TestCase
$traceablePlatform = new TraceablePlatform($platform);
$messageBag = new MessageBag(Message::ofUser(new Text('Hello')));
$result = new StreamResult(
(function () {
(static function () {
yield 'Assistant ';
yield 'response';
})(),
@@ -82,7 +82,7 @@ class DataCollectorTest extends TestCase
$traceablePlatform = new TraceablePlatform($platform);
$messageBag = new MessageBag(Message::ofUser(new Text('Hello')));
$result = new StreamResult(
(function () {
(static function () {
yield 'Assistant ';
yield 'response';
})(),
@@ -107,7 +107,7 @@ class DataCollectorTest extends TestCase
$messageBag = new MessageBag(Message::ofUser(new Text('Hello')));
$originalStream = new StreamResult(
(function () {
(static function () {
yield 'foo';
yield 'bar';
})(),

View File

@@ -52,7 +52,7 @@ final class ChatTest extends TestCase
$this->agent->expects($this->once())
->method('call')
->with($this->callback(function (MessageBag $messages) use ($userMessage) {
->with($this->callback(static function (MessageBag $messages) use ($userMessage) {
$messagesArray = $messages->getMessages();
return end($messagesArray) === $userMessage;
@@ -100,7 +100,7 @@ final class ChatTest extends TestCase
$this->agent->expects($this->once())
->method('call')
->with($this->callback(function (MessageBag $messages) {
->with($this->callback(static function (MessageBag $messages) {
$messagesArray = $messages->getMessages();
return 1 === \count($messagesArray);

View File

@@ -63,7 +63,7 @@ final class App
self::addCommand($application, new ToolsCallCommand($logger, $container));
if (\defined('SIGUSR1') && class_exists(RunnerControl::class)) {
$application->getSignalRegistry()->register(\SIGUSR1, function () {
$application->getSignalRegistry()->register(\SIGUSR1, static function () {
RunnerControl::$state = RunnerState::STOP;
});
}

View File

@@ -16,7 +16,7 @@ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigura
use function Symfony\Component\DependencyInjection\Loader\Configurator\service;
return function (ContainerConfigurator $configurator) {
return static function (ContainerConfigurator $configurator) {
$configurator->parameters()
->set('ai_mate_monolog.log_dir', '%mate.root_dir%/var/log');

View File

@@ -136,7 +136,7 @@ class DiscoverCommand extends Command
if (\count($removedPackages) > 0) {
$io->warning([
\sprintf('Removed %d extension%s no longer found:', \count($removedPackages), 1 === \count($removedPackages) ? '' : 's'),
...array_map(fn ($pkg) => ' • '.$pkg, $removedPackages),
...array_map(static fn ($pkg) => ' • '.$pkg, $removedPackages),
]);
}

View File

@@ -49,7 +49,7 @@ final class FilteredDiscoveryLoaderTest extends TestCase
$registry = $this->createMock(RegistryInterface::class);
$registry->expects($this->once())
->method('setDiscoveryState')
->with($this->callback(function (DiscoveryState $state) {
->with($this->callback(static function (DiscoveryState $state) {
return 2 === \count($state->getTools());
}));
@@ -90,7 +90,7 @@ final class FilteredDiscoveryLoaderTest extends TestCase
$registry = $this->createMock(RegistryInterface::class);
$registry->expects($this->once())
->method('setDiscoveryState')
->with($this->callback(function (DiscoveryState $state) {
->with($this->callback(static function (DiscoveryState $state) {
$tools = $state->getTools();
// Only tool1 should be present (tool2 is disabled)
@@ -139,7 +139,7 @@ final class FilteredDiscoveryLoaderTest extends TestCase
$registry = $this->createMock(RegistryInterface::class);
$registry->expects($this->once())
->method('setDiscoveryState')
->with($this->callback(function (DiscoveryState $state) {
->with($this->callback(static function (DiscoveryState $state) {
$tools = $state->getTools();
// tool1 and tool3 should be present (tool2 is disabled)
@@ -189,7 +189,7 @@ final class FilteredDiscoveryLoaderTest extends TestCase
$registry = $this->createMock(RegistryInterface::class);
$registry->expects($this->once())
->method('setDiscoveryState')
->with($this->callback(function (DiscoveryState $state) {
->with($this->callback(static function (DiscoveryState $state) {
$resources = $state->getResources();
return 1 === \count($resources) && isset($resources['config://resource1']);
@@ -236,7 +236,7 @@ final class FilteredDiscoveryLoaderTest extends TestCase
$registry = $this->createMock(RegistryInterface::class);
$registry->expects($this->once())
->method('setDiscoveryState')
->with($this->callback(function (DiscoveryState $state) {
->with($this->callback(static function (DiscoveryState $state) {
$prompts = $state->getPrompts();
return 1 === \count($prompts) && isset($prompts['prompt1']);
@@ -283,7 +283,7 @@ final class FilteredDiscoveryLoaderTest extends TestCase
$registry = $this->createMock(RegistryInterface::class);
$registry->expects($this->once())
->method('setDiscoveryState')
->with($this->callback(function (DiscoveryState $state) {
->with($this->callback(static function (DiscoveryState $state) {
$templates = $state->getResourceTemplates();
return 1 === \count($templates) && isset($templates['template1']);
@@ -329,7 +329,7 @@ final class FilteredDiscoveryLoaderTest extends TestCase
$registry = $this->createMock(RegistryInterface::class);
$registry->expects($this->once())
->method('setDiscoveryState')
->with($this->callback(function (DiscoveryState $state) {
->with($this->callback(static function (DiscoveryState $state) {
return 1 === \count($state->getTools());
}));
@@ -369,7 +369,7 @@ final class FilteredDiscoveryLoaderTest extends TestCase
$registry = $this->createMock(RegistryInterface::class);
$registry->expects($this->once())
->method('setDiscoveryState')
->with($this->callback(function (DiscoveryState $state) {
->with($this->callback(static function (DiscoveryState $state) {
return 2 === \count($state->getTools());
}));
@@ -413,7 +413,7 @@ final class FilteredDiscoveryLoaderTest extends TestCase
$registry = $this->createMock(RegistryInterface::class);
$registry->expects($this->once())
->method('setDiscoveryState')
->with($this->callback(function (DiscoveryState $state) {
->with($this->callback(static function (DiscoveryState $state) {
// tool1 should still be present even though nonexistent_tool is configured
return 1 === \count($state->getTools()) && isset($state->getTools()['tool1']);
}));

View File

@@ -48,7 +48,7 @@ final class DataCollector extends AbstractDataCollector implements LateDataColle
$prompts[] = [
'name' => $prompt->name,
'description' => $prompt->description,
'arguments' => array_map(fn ($arg) => [
'arguments' => array_map(static fn ($arg) => [
'name' => $arg->name,
'description' => $arg->description,
'required' => $arg->required,

View File

@@ -93,7 +93,7 @@ final class McpPassTest extends TestCase
// Should not create any service locator
$serviceIds = array_keys($container->getDefinitions());
$serviceLocators = array_filter($serviceIds, fn ($id) => str_contains($id, 'service_locator'));
$serviceLocators = array_filter($serviceIds, static fn ($id) => str_contains($id, 'service_locator'));
$this->assertEmpty($serviceLocators);
}

View File

@@ -37,6 +37,6 @@ final class ApiClient
'auth_bearer' => $this->apiKey,
]);
return array_map(fn (array $model) => new Model($model['id']), $result->toArray()['data']);
return array_map(static fn (array $model) => new Model($model['id']), $result->toArray()['data']);
}
}

View File

@@ -82,7 +82,7 @@ final class WhisperModelClientTest extends TestCase
public function testItUsesTranscriptionEndpointByDefault()
{
$httpClient = new MockHttpClient([
function ($method, $url): MockResponse {
static function ($method, $url): MockResponse {
self::assertSame('POST', $method);
self::assertSame('https://test.azure.com/openai/deployments/whspr/audio/transcriptions?api-version=2023-12', $url);
@@ -99,7 +99,7 @@ final class WhisperModelClientTest extends TestCase
public function testItUsesTranscriptionEndpointWhenTaskIsSpecified()
{
$httpClient = new MockHttpClient([
function ($method, $url): MockResponse {
static function ($method, $url): MockResponse {
self::assertSame('POST', $method);
self::assertSame('https://test.azure.com/openai/deployments/whspr/audio/transcriptions?api-version=2023-12', $url);
@@ -116,7 +116,7 @@ final class WhisperModelClientTest extends TestCase
public function testItUsesTranslationEndpointWhenTaskIsSpecified()
{
$httpClient = new MockHttpClient([
function ($method, $url): MockResponse {
static function ($method, $url): MockResponse {
self::assertSame('POST', $method);
self::assertSame('https://test.azure.com/openai/deployments/whspr/audio/translations?api-version=2023-12', $url);

View File

@@ -44,7 +44,7 @@ final class ModelClientTest extends TestCase
public function testRequestSendsToCorrectEndpoint()
{
$requestMade = false;
$httpClient = new MockHttpClient(function ($method, $url, $options) use (&$requestMade) {
$httpClient = new MockHttpClient(static function ($method, $url, $options) use (&$requestMade) {
$requestMade = true;
self::assertSame('POST', $method);
self::assertSame('https://api.deepseek.com/chat/completions', $url);
@@ -65,7 +65,7 @@ final class ModelClientTest extends TestCase
public function testRequestMergesOptionsWithPayload()
{
$requestMade = false;
$httpClient = new MockHttpClient(function ($method, $url, $options) use (&$requestMade) {
$httpClient = new MockHttpClient(static function ($method, $url, $options) use (&$requestMade) {
$requestMade = true;
$body = json_decode($options['body'], true);
self::assertArrayHasKey('messages', $body);

View File

@@ -61,7 +61,7 @@ final class MessageBagNormalizerTest extends TestCase
$mockNormalizer = $this->createMock(NormalizerInterface::class);
$mockNormalizer->method('normalize')
->willReturnCallback(function ($message) use ($userMessageNormalizer, $assistantMessageNormalizer): ?array {
->willReturnCallback(static function ($message) use ($userMessageNormalizer, $assistantMessageNormalizer): ?array {
if ($message instanceof UserMessage) {
return $userMessageNormalizer->normalize($message);
}

View File

@@ -123,7 +123,7 @@ class ResultConverterTest extends TestCase
$httpResponse->expects($this->exactly(1))
->method('toArray')
->willReturnCallback(function ($throw = true) {
->willReturnCallback(static function ($throw = true) {
if ($throw) {
throw new class extends \Exception implements ClientExceptionInterface {
public function getResponse(): ResponseInterface

View File

@@ -54,7 +54,7 @@ final class ModelInfoCommand
} else {
$io->horizontalTable(
['Provider', 'Status', 'Provider ID', 'Task', 'Is Model Author'],
array_map(fn (string $provider, array $data) => [
array_map(static fn (string $provider, array $data) => [
$provider,
$data['status'],
$data['providerId'],

View File

@@ -30,7 +30,7 @@ final class ClassificationResult
public static function fromArray(array $data): self
{
return new self(
array_map(fn (array $item) => new Classification($item['label'], $item['score']), $data)
array_map(static fn (array $item) => new Classification($item['label'], $item['score']), $data)
);
}
}

View File

@@ -30,7 +30,7 @@ final class FillMaskResult
public static function fromArray(array $data): self
{
return new self(array_map(
fn (array $item) => new MaskFill(
static fn (array $item) => new MaskFill(
$item['token'],
$item['token_str'],
$item['sequence'],

View File

@@ -30,7 +30,7 @@ final class ImageSegmentationResult
public static function fromArray(array $data): self
{
return new self(
array_map(fn (array $item) => new ImageSegment($item['label'], $item['score'], $item['mask']), $data)
array_map(static fn (array $item) => new ImageSegment($item['label'], $item['score'], $item['mask']), $data)
);
}
}

View File

@@ -30,7 +30,7 @@ final class ObjectDetectionResult
public static function fromArray(array $data): self
{
return new self(array_map(
fn (array $item) => new DetectedObject(
static fn (array $item) => new DetectedObject(
$item['label'],
$item['score'],
$item['box']['xmin'],

View File

@@ -30,7 +30,7 @@ final class TokenClassificationResult
public static function fromArray(array $data): self
{
return new self(array_map(
fn (array $item) => new Token(
static fn (array $item) => new Token(
$item['entity_group'],
$item['score'],
$item['word'],

View File

@@ -58,7 +58,7 @@ final class MessageBagNormalizerTest extends TestCase
$mockNormalizer = $this->createMock(NormalizerInterface::class);
$mockNormalizer->method('normalize')
->willReturnCallback(function ($messages) use ($userMessageNormalizer): array {
->willReturnCallback(static function ($messages) use ($userMessageNormalizer): array {
$result = [];
foreach ($messages as $message) {
if ($message instanceof UserMessage) {

View File

@@ -171,7 +171,7 @@ final class ObjectDetectionResultTest extends TestCase
$this->assertCount(4, $result->objects);
// Check multiple instances of same class
$personCount = array_filter($result->objects, fn ($obj) => 'person' === $obj->label);
$personCount = array_filter($result->objects, static fn ($obj) => 'person' === $obj->label);
$this->assertCount(2, $personCount);
}
}

View File

@@ -33,7 +33,7 @@ final class LlamaPromptConverter
$messages[] = self::convertMessage($message);
}
$messages = array_filter($messages, fn ($message) => '' !== $message);
$messages = array_filter($messages, static fn ($message) => '' !== $message);
return trim(implode(\PHP_EOL.\PHP_EOL, $messages)).\PHP_EOL.\PHP_EOL.'<|start_header_id|>assistant<|end_header_id|>';
}

View File

@@ -118,7 +118,7 @@ class ResultConverterTest extends TestCase
$httpResponse->expects($this->exactly(1))
->method('toArray')
->willReturnCallback(function ($throw = true) {
->willReturnCallback(static function ($throw = true) {
if ($throw) {
throw new class extends \Exception implements ClientExceptionInterface {
public function getResponse(): ResponseInterface

View File

@@ -61,7 +61,7 @@ final class ModelClientTest extends TestCase
public function testItUsesTranscriptionEndpointByDefault()
{
$httpClient = new MockHttpClient([
function ($method, $url): MockResponse {
static function ($method, $url): MockResponse {
self::assertSame('POST', $method);
self::assertSame('https://api.openai.com/v1/audio/transcriptions', $url);
@@ -78,7 +78,7 @@ final class ModelClientTest extends TestCase
public function testItUsesTranscriptionEndpointWhenTaskIsSpecified()
{
$httpClient = new MockHttpClient([
function ($method, $url): MockResponse {
static function ($method, $url): MockResponse {
self::assertSame('POST', $method);
self::assertSame('https://api.openai.com/v1/audio/transcriptions', $url);
@@ -95,7 +95,7 @@ final class ModelClientTest extends TestCase
public function testItUsesTranslationEndpointWhenTaskIsSpecified()
{
$httpClient = new MockHttpClient([
function ($method, $url): MockResponse {
static function ($method, $url): MockResponse {
self::assertSame('POST', $method);
self::assertSame('https://api.openai.com/v1/audio/translations', $url);
@@ -115,7 +115,7 @@ final class ModelClientTest extends TestCase
public function testItUsesCorrectRegionUrlForTranscription(?string $region, string $expectedUrl)
{
$httpClient = new MockHttpClient([
function ($method, $url) use ($expectedUrl): MockResponse {
static function ($method, $url) use ($expectedUrl): MockResponse {
self::assertSame('POST', $method);
self::assertSame($expectedUrl, $url);
@@ -135,7 +135,7 @@ final class ModelClientTest extends TestCase
public function testItUsesCorrectRegionUrlForTranslation(?string $region, string $expectedUrl)
{
$httpClient = new MockHttpClient([
function ($method, $url) use ($expectedUrl): MockResponse {
static function ($method, $url) use ($expectedUrl): MockResponse {
self::assertSame('POST', $method);
self::assertSame($expectedUrl, $url);

View File

@@ -68,7 +68,7 @@ final class ResultConverter implements ResultConverterInterface
$data['text'],
$data['language'],
$data['duration'],
array_map(fn (array $segment) => new Segment($segment['start'], $segment['end'], $segment['text']), $data['segments']),
array_map(static fn (array $segment) => new Segment($segment['start'], $segment['end'], $segment['text']), $data['segments']),
));
}
}

View File

@@ -52,7 +52,7 @@ final class ClientTest extends TestCase
public function testRequestAuthenticationHeader()
{
$httpClient = new MockHttpClient(function (string $method, string $url, array $options) {
$httpClient = new MockHttpClient(static function (string $method, string $url, array $options) {
self::assertSame('Authorization: Bearer secret-key', $options['normalized_headers']['authorization'][0]);
return new MockResponse('{"status": "succeeded"}');
@@ -64,7 +64,7 @@ final class ClientTest extends TestCase
public function testRequestUrl()
{
$httpClient = new MockHttpClient(function (string $method, string $url, array $options) {
$httpClient = new MockHttpClient(static function (string $method, string $url, array $options) {
self::assertSame('POST', $method);
self::assertSame('https://api.replicate.com/v1/models/meta/llama-3.1-405b-instruct/predictions', $url);

View File

@@ -124,7 +124,7 @@ final class ResultConverterTest extends TestCase
$httpResponse->expects($this->exactly(1))
->method('toArray')
->willReturnCallback(function ($throw = true) {
->willReturnCallback(static function ($throw = true) {
if ($throw) {
throw new class extends \Exception implements ClientExceptionInterface {
public function getResponse(): ResponseInterface

View File

@@ -61,7 +61,7 @@ final class MessageBagNormalizerTest extends TestCase
$mockNormalizer = $this->createMock(NormalizerInterface::class);
$mockNormalizer->method('normalize')
->willReturnCallback(function ($message) use ($userMessageNormalizer, $assistantMessageNormalizer): ?array {
->willReturnCallback(static function ($message) use ($userMessageNormalizer, $assistantMessageNormalizer): ?array {
if ($message instanceof UserMessage) {
return $userMessageNormalizer->normalize($message);
}

View File

@@ -48,7 +48,7 @@ final class MultimodalNormalizer implements NormalizerInterface, NormalizerAware
return false;
}
return \is_array($data) && [] === array_filter($data, fn ($item) => !$item instanceof ContentInterface);
return \is_array($data) && [] === array_filter($data, static fn ($item) => !$item instanceof ContentInterface);
}
public function getSupportedTypes(?string $format): array

View File

@@ -54,7 +54,7 @@ final class With
) {
if (\is_array($enum)) {
/* @phpstan-ignore-next-line function.alreadyNarrowedType */
if (array_filter($enum, fn (mixed $item) => null === $item || \is_int($item) || \is_float($item) || \is_string($item)) !== $enum) {
if (array_filter($enum, static fn (mixed $item) => null === $item || \is_int($item) || \is_float($item) || \is_string($item)) !== $enum) {
throw new InvalidArgumentException('All enum values must be float, integer, strings, or null.');
}
}

View File

@@ -131,7 +131,7 @@ final class Factory
// Check for ToolParameter attributes
$attributes = $element->getAttributes(With::class);
if (\count($attributes) > 0) {
$attributeState = array_filter((array) $attributes[0]->newInstance(), fn ($value) => null !== $value);
$attributeState = array_filter((array) $attributes[0]->newInstance(), static fn ($value) => null !== $value);
$schema = array_merge($schema, $attributeState);
}
@@ -228,12 +228,11 @@ final class Factory
if (\in_array($className, ['DateTime', 'DateTimeImmutable', 'DateTimeInterface'], true)) {
return ['type' => 'string', 'format' => 'date-time'];
} else {
// Recursively build the schema for an object type
return $this->buildProperties($className) ?? ['type' => 'object'];
}
// no break
// Recursively build the schema for an object type
return $this->buildProperties($className) ?? ['type' => 'object'];
case $type->isIdentifiedBy(TypeIdentifier::NULL):
return ['type' => 'null'];
case $type->isIdentifiedBy(TypeIdentifier::STRING):

View File

@@ -56,47 +56,47 @@ final class TokenUsageAggregation implements TokenUsageInterface, MergeableMetad
public function getPromptTokens(): ?int
{
return $this->sum(fn (TokenUsageInterface $usage) => $usage->getPromptTokens());
return $this->sum(static fn (TokenUsageInterface $usage) => $usage->getPromptTokens());
}
public function getCompletionTokens(): ?int
{
return $this->sum(fn (TokenUsageInterface $usage) => $usage->getCompletionTokens());
return $this->sum(static fn (TokenUsageInterface $usage) => $usage->getCompletionTokens());
}
public function getThinkingTokens(): ?int
{
return $this->sum(fn (TokenUsageInterface $usage) => $usage->getThinkingTokens());
return $this->sum(static fn (TokenUsageInterface $usage) => $usage->getThinkingTokens());
}
public function getToolTokens(): ?int
{
return $this->sum(fn (TokenUsageInterface $usage) => $usage->getToolTokens());
return $this->sum(static fn (TokenUsageInterface $usage) => $usage->getToolTokens());
}
public function getCachedTokens(): ?int
{
return $this->sum(fn (TokenUsageInterface $usage) => $usage->getCachedTokens());
return $this->sum(static fn (TokenUsageInterface $usage) => $usage->getCachedTokens());
}
public function getRemainingTokens(): ?int
{
return $this->min(fn (TokenUsageInterface $usage) => $usage->getRemainingTokens());
return $this->min(static fn (TokenUsageInterface $usage) => $usage->getRemainingTokens());
}
public function getRemainingTokensMinute(): ?int
{
return $this->min(fn (TokenUsageInterface $usage) => $usage->getRemainingTokensMinute());
return $this->min(static fn (TokenUsageInterface $usage) => $usage->getRemainingTokensMinute());
}
public function getRemainingTokensMonth(): ?int
{
return $this->min(fn (TokenUsageInterface $usage) => $usage->getRemainingTokensMonth());
return $this->min(static fn (TokenUsageInterface $usage) => $usage->getRemainingTokensMonth());
}
public function getTotalTokens(): ?int
{
return $this->sum(fn (TokenUsageInterface $usage) => $usage->getTotalTokens());
return $this->sum(static fn (TokenUsageInterface $usage) => $usage->getTotalTokens());
}
private function sum(\Closure $mapFunction): ?int

View File

@@ -29,7 +29,7 @@ class InMemoryPlatformTest extends TestCase
public function testPlatformInvokeWithCallableResult()
{
$platform = new InMemoryPlatform(function (Model $model, $input) {
$platform = new InMemoryPlatform(static function (Model $model, $input) {
return strtoupper((string) $input);
});
@@ -41,7 +41,7 @@ class InMemoryPlatformTest extends TestCase
public function testPlatformInvokeWithVectorResultResponse()
{
$platform = new InMemoryPlatform(
fn () => new VectorResult(new Vector([0.1, 0.1, 0.5]))
static fn () => new VectorResult(new Vector([0.1, 0.1, 0.5]))
);
$result = $platform->invoke('test', 'dynamic text');

View File

@@ -153,7 +153,7 @@ final class DeferredResultTest extends TestCase
public function testTokenUsageGetsPromotedFromStream()
{
$result = new StreamResult((function () {
$result = new StreamResult((static function () {
yield 'part 1';
yield 'part 2';
yield new TokenUsage(123456);

View File

@@ -37,7 +37,7 @@ final class StreamResultTest extends TestCase
public function testGetChunk()
{
$result = new StreamResult((function () {
$result = new StreamResult((static function () {
yield 'chunk1';
yield 'chunk2';
})());
@@ -62,7 +62,7 @@ final class StreamResultTest extends TestCase
public function testListenerCanAddMetadataDuringStreaming()
{
$result = new StreamResult((function () {
$result = new StreamResult((static function () {
yield 'chunk1';
yield 'chunk2';
})());

View File

@@ -174,7 +174,7 @@ final class StoreTest extends TestCase
]);
$result = iterator_to_array($store->query(new Vector([0.0, 0.1, 0.6]), [
'filter' => fn (VectorDocument $doc) => 'products' === $doc->metadata['category'],
'filter' => static fn (VectorDocument $doc) => 'products' === $doc->metadata['category'],
]));
$this->assertCount(2, $result);
@@ -193,7 +193,7 @@ final class StoreTest extends TestCase
]);
$result = iterator_to_array($store->query(new Vector([0.0, 0.1, 0.6]), [
'filter' => fn (VectorDocument $doc) => 'products' === $doc->metadata['category'],
'filter' => static fn (VectorDocument $doc) => 'products' === $doc->metadata['category'],
'maxItems' => 2,
]));
@@ -212,7 +212,7 @@ final class StoreTest extends TestCase
]);
$result = iterator_to_array($store->query(new Vector([0.0, 0.1, 0.6]), [
'filter' => fn (VectorDocument $doc) => $doc->metadata['price'] <= 150 && $doc->metadata['stock'] > 0,
'filter' => static fn (VectorDocument $doc) => $doc->metadata['price'] <= 150 && $doc->metadata['stock'] > 0,
]));
$this->assertCount(2, $result);
@@ -228,7 +228,7 @@ final class StoreTest extends TestCase
]);
$result = iterator_to_array($store->query(new Vector([0.0, 0.1, 0.6]), [
'filter' => fn (VectorDocument $doc) => 'S' === $doc->metadata['options']['size'],
'filter' => static fn (VectorDocument $doc) => 'S' === $doc->metadata['options']['size'],
]));
$this->assertCount(2, $result);
@@ -247,7 +247,7 @@ final class StoreTest extends TestCase
$allowedBrands = ['Nike', 'Adidas', 'Puma'];
$result = iterator_to_array($store->query(new Vector([0.0, 0.1, 0.6]), [
'filter' => fn (VectorDocument $doc) => \in_array($doc->metadata['brand'] ?? '', $allowedBrands, true),
'filter' => static fn (VectorDocument $doc) => \in_array($doc->metadata['brand'] ?? '', $allowedBrands, true),
]));
$this->assertCount(2, $result);

View File

@@ -115,7 +115,7 @@ final class StoreTest extends TestCase
$uuid = Uuid::v4();
$document = new VectorDocument($uuid, new Vector([0.1, 0.2, 0.3]));
$httpClient = new MockHttpClient(function (string $method, string $url, array $options) {
$httpClient = new MockHttpClient(static function (string $method, string $url, array $options) {
return new MockResponse('Internal Server Error', ['http_code' => 500]);
});
@@ -220,7 +220,7 @@ final class StoreTest extends TestCase
],
];
$httpClient = new MockHttpClient(function (string $method, string $url, array $options) use ($responseData) {
$httpClient = new MockHttpClient(static function (string $method, string $url, array $options) use ($responseData) {
return new MockResponse(json_encode($responseData));
});

View File

@@ -67,7 +67,7 @@ final class Store implements ManagedStoreInterface, StoreInterface
$documents,
);
$this->request('POST', \sprintf('vectorize/v2/indexes/%s/upsert', $this->index), function () use ($payload) {
$this->request('POST', \sprintf('vectorize/v2/indexes/%s/upsert', $this->index), static function () use ($payload) {
foreach ($payload as $entry) {
yield json_encode($entry).\PHP_EOL;
}

View File

@@ -83,7 +83,7 @@ final class Store implements ManagedStoreInterface, StoreInterface
'metadata' => json_encode($document->metadata->getArrayCopy()),
];
$this->request('POST', '_bulk', function () use ($documents, $documentToIndex, $documentToPayload) {
$this->request('POST', '_bulk', static function () use ($documents, $documentToIndex, $documentToPayload) {
foreach ($documents as $document) {
yield json_encode($documentToIndex($document)).\PHP_EOL.json_encode($documentToPayload($document)).\PHP_EOL;
}

View File

@@ -78,7 +78,7 @@ final class Store implements ManagedStoreInterface, StoreInterface
$documents,
);
$this->request('bulk', function () use ($payload) {
$this->request('bulk', static function () use ($payload) {
foreach ($payload as $document) {
yield json_encode($document).\PHP_EOL;
}

View File

@@ -88,7 +88,7 @@ final class Store implements ManagedStoreInterface, StoreInterface
'metadata' => json_encode($document->metadata->getArrayCopy()),
];
$this->request('POST', '_bulk', function () use ($documents, $documentToIndex, $documentToPayload) {
$this->request('POST', '_bulk', static function () use ($documents, $documentToIndex, $documentToPayload) {
foreach ($documents as $document) {
yield json_encode($documentToIndex($document)).\PHP_EOL.json_encode($documentToPayload($document)).\PHP_EOL;
}

View File

@@ -443,7 +443,7 @@ final class StoreTest extends TestCase
$this->anything(),
$this->anything(),
'query_vector',
$this->callback(function ($vectorBytes) {
$this->callback(static function ($vectorBytes) {
// Vector [0.1, 0.2, 0.3] packed as 32-bit floats
$expected = pack('f', 0.1).pack('f', 0.2).pack('f', 0.3);

View File

@@ -124,7 +124,7 @@ final class Vectorizer implements VectorizerInterface
$this->logger->info('Starting vectorization of strings', ['string_count' => $stringCount]);
// Convert all values to strings
$stringValues = array_map(fn (string|\Stringable $s) => (string) $s, $strings);
$stringValues = array_map(static fn (string|\Stringable $s) => (string) $s, $strings);
if ($this->platform->getModelCatalog()->getModel($this->model)->supports(Capability::INPUT_MULTIPLE)) {
$this->logger->debug('Using batch vectorization with model that supports multiple inputs');
@@ -165,7 +165,7 @@ final class Vectorizer implements VectorizerInterface
if ($this->platform->getModelCatalog()->getModel($this->model)->supports(Capability::INPUT_MULTIPLE)) {
$this->logger->debug('Using batch vectorization with model that supports multiple inputs');
$result = $this->platform->invoke($this->model, array_map(fn (EmbeddableDocumentInterface $document) => $document->getContent(), $documents), $options);
$result = $this->platform->invoke($this->model, array_map(static fn (EmbeddableDocumentInterface $document) => $document->getContent(), $documents), $options);
$vectors = $result->asVectors();
$this->logger->debug('Batch vectorization completed', ['vector_count' => \count($vectors)]);

View File

@@ -123,7 +123,7 @@ final class DistanceCalculatorTest extends TestCase
// d: [1.0, 1.0] -> sqrt(2) ≈ 1.414
// e: [0.5, 0.5] -> sqrt(0.5) ≈ 0.707
$ids = array_map(fn ($doc) => $doc->metadata['id'], $result);
$ids = array_map(static fn ($doc) => $doc->metadata['id'], $result);
$this->assertSame(['a', 'e', 'b'], $ids); // a is closest, then e, then b/c (same distance)
}

View File

@@ -173,7 +173,7 @@ final class StoreTest extends TestCase
]);
$result = iterator_to_array($store->query(new Vector([0.0, 0.1, 0.6]), [
'filter' => fn (VectorDocument $doc) => 'products' === $doc->metadata['category'],
'filter' => static fn (VectorDocument $doc) => 'products' === $doc->metadata['category'],
]));
$this->assertCount(2, $result);
@@ -192,7 +192,7 @@ final class StoreTest extends TestCase
]);
$result = iterator_to_array($store->query(new Vector([0.0, 0.1, 0.6]), [
'filter' => fn (VectorDocument $doc) => 'products' === $doc->metadata['category'],
'filter' => static fn (VectorDocument $doc) => 'products' === $doc->metadata['category'],
'maxItems' => 2,
]));
@@ -211,7 +211,7 @@ final class StoreTest extends TestCase
]);
$result = iterator_to_array($store->query(new Vector([0.0, 0.1, 0.6]), [
'filter' => fn (VectorDocument $doc) => $doc->metadata['price'] <= 150 && $doc->metadata['stock'] > 0,
'filter' => static fn (VectorDocument $doc) => $doc->metadata['price'] <= 150 && $doc->metadata['stock'] > 0,
]));
$this->assertCount(2, $result);
@@ -227,7 +227,7 @@ final class StoreTest extends TestCase
]);
$result = iterator_to_array($store->query(new Vector([0.0, 0.1, 0.6]), [
'filter' => fn (VectorDocument $doc) => 'S' === $doc->metadata['options']['size'],
'filter' => static fn (VectorDocument $doc) => 'S' === $doc->metadata['options']['size'],
]));
$this->assertCount(2, $result);
@@ -246,7 +246,7 @@ final class StoreTest extends TestCase
$allowedBrands = ['Nike', 'Adidas', 'Puma'];
$result = iterator_to_array($store->query(new Vector([0.0, 0.1, 0.6]), [
'filter' => fn (VectorDocument $doc) => \in_array($doc->metadata['brand'] ?? '', $allowedBrands, true),
'filter' => static fn (VectorDocument $doc) => \in_array($doc->metadata['brand'] ?? '', $allowedBrands, true),
]));
$this->assertCount(2, $result);