'test-key', 'comment_spam.ai.base_url' => 'https://api.together.test/v1', 'comment_spam.ai.model' => 'meta-llama/Llama-3.2-3B-Instruct-Turbo', ]); }); it('classifies using the strict Together JSON contract', function (string $model): void { config(['comment_spam.ai.model' => $model]); Http::fake([ 'https://api.together.test/*' => Http::response([ 'choices' => [['message' => ['content' => '{"spam":true,"confidence":0.95,"reason":"Unsolicited promotion."}']]], ]), ]); $result = app(TogetherCommentSpamClassifier::class)->classify('Buy now at example.test'); expect($result->spam)->toBeTrue() ->and($result->confidence)->toBe(0.95) ->and($result->provider)->toBe('together') ->and($result->model)->toBe($model); })->with([ 'Llama' => ['meta-llama/Llama-3.2-3B-Instruct-Turbo'], 'Bonsai' => ['Prism-ML/Ternary-Bonsai-27B'], ]); it('rejects an unsupported configured model before making an HTTP request', function (): void { config(['comment_spam.ai.model' => 'some/unsupported-model']); Http::fake(); expect(fn () => app(TogetherCommentSpamClassifier::class)->classify('hello')) ->toThrow(RuntimeException::class, 'Unsupported Together AI comment spam model.'); Http::assertNothingSent(); }); it('rejects malformed or out of range classifier output', function (array $json): void { Http::fake([ 'https://api.together.test/*' => Http::response([ 'choices' => [['message' => ['content' => json_encode($json)]]], ]), ]); expect(fn () => app(TogetherCommentSpamClassifier::class)->classify('hello')) ->toThrow(RuntimeException::class); })->with([ [['spam' => 'true', 'confidence' => 0.9, 'reason' => 'bad type']], [['spam' => true, 'confidence' => 1.1, 'reason' => 'out of range']], [['spam' => true, 'confidence' => 0.9]], ]); it('fails closed when Together is not configured', function (): void { config(['comment_spam.ai.api_key' => '']); expect(fn () => app(TogetherCommentSpamClassifier::class)->classify('hello')) ->toThrow(RuntimeException::class); });