diff --git a/app/Commands/KnowledgeSearchCommand.php b/app/Commands/KnowledgeSearchCommand.php index 57487ca..7bbd310 100644 --- a/app/Commands/KnowledgeSearchCommand.php +++ b/app/Commands/KnowledgeSearchCommand.php @@ -27,7 +27,8 @@ class KnowledgeSearchCommand extends Command {--semantic : Use semantic search if available} {--include-superseded : Include superseded entries in results} {--project= : Override project namespace} - {--global : Search across all projects}'; + {--global : Search across all projects} + {--collection= : Search a raw Qdrant collection directly (bypasses knowledge_ prefix)}'; /** * @var string @@ -69,6 +70,12 @@ public function handle(QdrantService $qdrant, EntryMetadataService $metadata): i // Use project-aware search $searchQuery = is_string($query) ? $query : ''; + // Raw collection search — bypasses knowledge_ prefix and metadata formatting + $rawCollection = $this->option('collection'); + if (is_string($rawCollection) && $rawCollection !== '') { + return $this->searchRawCollection($qdrant, $rawCollection, $searchQuery, $limit); + } + if ($this->isGlobal()) { $collections = $qdrant->listCollections(); $results = collect(); @@ -147,4 +154,40 @@ public function handle(QdrantService $qdrant, EntryMetadataService $metadata): i return self::SUCCESS; } + + private function searchRawCollection(QdrantService $qdrant, string $collection, string $query, int $limit): int + { + $results = $qdrant->searchRawCollection($collection, $query, $limit); + + if ($results->isEmpty()) { + $this->line('No results found.'); + + return self::SUCCESS; + } + + $this->info("Found {$results->count()} ".str('result')->plural($results->count())." in {$collection}"); + $this->newLine(); + + foreach ($results as $result) { + $score = $result['score'] ?? 0.0; + $payload = $result['payload'] ?? []; + + $this->line(''.number_format($score, 3).' | '.($payload['description'] ?? json_encode($payload))); + + // Show key payload fields + $fields = collect($payload) + ->except(['description', 'vector']) + ->filter(fn ($v): bool => $v !== null && $v !== '') + ->map(fn ($v, $k): string => "{$k}: {$v}") + ->implode(' | '); + + if ($fields !== '') { + $this->line(" {$fields}"); + } + + $this->newLine(); + } + + return self::SUCCESS; + } } diff --git a/app/Services/QdrantService.php b/app/Services/QdrantService.php index eadf9c7..cdd86d7 100644 --- a/app/Services/QdrantService.php +++ b/app/Services/QdrantService.php @@ -977,4 +977,32 @@ public function getCollectionName(string $project): string { return 'knowledge_'.str_replace(['/', '\\', ' '], '_', $project); } + + /** + * Search any Qdrant collection by name — no knowledge_ prefix, no metadata mapping. + * + * @return Collection}> + */ + public function searchRawCollection(string $collection, string $query, int $limit = 10): Collection + { + $queryVector = $this->getCachedEmbedding($query); + + if ($queryVector === []) { + return collect(); + } + + $response = $this->connector->send( + new SearchPoints($collection, $queryVector, $limit, 0.0) + ); + + if (! $response->successful()) { + return collect(); + } + + return collect($response->json('result') ?? [])->map(fn (array $r): array => [ + 'id' => $r['id'], + 'score' => $r['score'] ?? 0.0, + 'payload' => $r['payload'] ?? [], + ]); + } } diff --git a/composer.json b/composer.json index 4707cf3..f7c4000 100644 --- a/composer.json +++ b/composer.json @@ -20,18 +20,19 @@ "illuminate/database": "^12.17", "laravel-zero/framework": "^12.0.2", "laravel/mcp": "^0.6.0", - "saloonphp/saloon": "^3.14", + "saloonphp/saloon": "^4.0", "symfony/uid": "^8.0" }, "require-dev": { "fakerphp/faker": "^1.23", "laravel/pint": "^1.25.1", "mockery/mockery": "^1.6.12", - "pestphp/pest": "^3.8.4|^4.1.2", + "pestphp/pest": "4.3.2", "phpstan/extension-installer": "*", "phpstan/phpstan": "^1.0", "phpstan/phpstan-deprecation-rules": "^1.2", "phpstan/phpstan-strict-rules": "^1.6", + "phpunit/phpunit": "12.5.8", "rector/rector": "^1.2" }, "autoload": { diff --git a/composer.lock b/composer.lock index 95abd29..eb282d4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "81a5724d1efaf7499f2dea856b5b6775", + "content-hash": "5c46758a9bbfbf48911a9147412e047d", "packages": [ { "name": "brick/math", @@ -848,16 +848,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.8.0", + "version": "2.9.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "21dc724a0583619cd1652f673303492272778051" + "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", - "reference": "21dc724a0583619cd1652f673303492272778051", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/7d0ed42f28e42d61352a7a79de682e5e67fec884", + "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884", "shasum": "" }, "require": { @@ -873,6 +873,7 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "0.9.0", + "jshttp/mime-db": "1.54.0.1", "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "suggest": { @@ -944,7 +945,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.8.0" + "source": "https://github.com/guzzle/psr7/tree/2.9.0" }, "funding": [ { @@ -960,7 +961,7 @@ "type": "tidelift" } ], - "time": "2025-08-23T21:21:41+00:00" + "time": "2026-03-10T16:41:02+00:00" }, { "name": "guzzlehttp/uri-template", @@ -3206,39 +3207,36 @@ }, { "name": "nunomaduro/collision", - "version": "v8.8.3", + "version": "v8.9.2", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4" + "reference": "6eb16883e74fd725ac64dbe81544c961ab448ba5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/1dc9e88d105699d0fee8bb18890f41b274f6b4c4", - "reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/6eb16883e74fd725ac64dbe81544c961ab448ba5", + "reference": "6eb16883e74fd725ac64dbe81544c961ab448ba5", "shasum": "" }, "require": { - "filp/whoops": "^2.18.1", - "nunomaduro/termwind": "^2.3.1", + "filp/whoops": "^2.18.4", + "nunomaduro/termwind": "^2.4.0", "php": "^8.2.0", - "symfony/console": "^7.3.0" + "symfony/console": "^7.4.8 || ^8.0.4" }, "conflict": { - "laravel/framework": "<11.44.2 || >=13.0.0", - "phpunit/phpunit": "<11.5.15 || >=13.0.0" + "laravel/framework": "<11.48.0 || >=14.0.0", + "phpunit/phpunit": "<11.5.50 || >=14.0.0" }, "require-dev": { - "brianium/paratest": "^7.8.3", - "larastan/larastan": "^3.4.2", - "laravel/framework": "^11.44.2 || ^12.18", - "laravel/pint": "^1.22.1", - "laravel/sail": "^1.43.1", - "laravel/sanctum": "^4.1.1", - "laravel/tinker": "^2.10.1", - "orchestra/testbench-core": "^9.12.0 || ^10.4", - "pestphp/pest": "^3.8.2 || ^4.0.0", - "sebastian/environment": "^7.2.1 || ^8.0" + "brianium/paratest": "^7.8.5", + "larastan/larastan": "^3.9.3", + "laravel/framework": "^11.48.0 || ^12.56.0 || ^13.2.0", + "laravel/pint": "^1.29.0", + "orchestra/testbench-core": "^9.12.0 || ^10.12.1 || ^11.0.0", + "pestphp/pest": "^3.8.5 || ^4.4.3 || ^5.0.0", + "sebastian/environment": "^7.2.1 || ^8.0.4 || ^9.0.0" }, "type": "library", "extra": { @@ -3301,7 +3299,7 @@ "type": "patreon" } ], - "time": "2025-11-20T02:55:25+00:00" + "time": "2026-03-31T21:51:27+00:00" }, { "name": "nunomaduro/laravel-console-summary", @@ -3499,31 +3497,31 @@ }, { "name": "nunomaduro/termwind", - "version": "v2.3.3", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/termwind.git", - "reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017" + "reference": "712a31b768f5daea284c2169a7d227031001b9a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/6fb2a640ff502caace8e05fd7be3b503a7e1c017", - "reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/712a31b768f5daea284c2169a7d227031001b9a8", + "reference": "712a31b768f5daea284c2169a7d227031001b9a8", "shasum": "" }, "require": { "ext-mbstring": "*", "php": "^8.2", - "symfony/console": "^7.3.6" + "symfony/console": "^7.4.4 || ^8.0.4" }, "require-dev": { - "illuminate/console": "^11.46.1", - "laravel/pint": "^1.25.1", + "illuminate/console": "^11.47.0", + "laravel/pint": "^1.27.1", "mockery/mockery": "^1.6.12", - "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.1.3", + "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.3.2", "phpstan/phpstan": "^1.12.32", "phpstan/phpstan-strict-rules": "^1.6.2", - "symfony/var-dumper": "^7.3.5", + "symfony/var-dumper": "^7.3.5 || ^8.0.4", "thecodingmachine/phpstan-strict-rules": "^1.0.0" }, "type": "library", @@ -3555,7 +3553,7 @@ "email": "enunomaduro@gmail.com" } ], - "description": "Its like Tailwind CSS, but for the console.", + "description": "It's like Tailwind CSS, but for the console.", "keywords": [ "cli", "console", @@ -3566,7 +3564,7 @@ ], "support": { "issues": "https://github.com/nunomaduro/termwind/issues", - "source": "https://github.com/nunomaduro/termwind/tree/v2.3.3" + "source": "https://github.com/nunomaduro/termwind/tree/v2.4.0" }, "funding": [ { @@ -3582,7 +3580,7 @@ "type": "github" } ], - "time": "2025-11-20T02:34:59+00:00" + "time": "2026-02-16T23:10:27+00:00" }, { "name": "phpoption/phpoption", @@ -4271,16 +4269,16 @@ }, { "name": "saloonphp/saloon", - "version": "v3.14.2", + "version": "v4.0.0", "source": { "type": "git", "url": "https://github.com/saloonphp/saloon.git", - "reference": "634be16ca5eb0b71ab01533f58dc88d174a2e28b" + "reference": "1307b1d72cacdd2c9c20978cdf7a0b720b4bf3bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/saloonphp/saloon/zipball/634be16ca5eb0b71ab01533f58dc88d174a2e28b", - "reference": "634be16ca5eb0b71ab01533f58dc88d174a2e28b", + "url": "https://api.github.com/repos/saloonphp/saloon/zipball/1307b1d72cacdd2c9c20978cdf7a0b720b4bf3bb", + "reference": "1307b1d72cacdd2c9c20978cdf7a0b720b4bf3bb", "shasum": "" }, "require": { @@ -4340,7 +4338,7 @@ ], "support": { "issues": "https://github.com/saloonphp/saloon/issues", - "source": "https://github.com/saloonphp/saloon/tree/v3.14.2" + "source": "https://github.com/saloonphp/saloon/tree/v4.0.0" }, "funding": [ { @@ -4348,7 +4346,7 @@ "type": "github" } ], - "time": "2025-11-20T21:42:32+00:00" + "time": "2026-03-17T22:58:33+00:00" }, { "name": "symfony/clock", @@ -4429,16 +4427,16 @@ }, { "name": "symfony/console", - "version": "v7.4.4", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "41e38717ac1dd7a46b6bda7d6a82af2d98a78894" + "reference": "1e92e39c51f95b88e3d66fa2d9f06d1fb45dd707" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/41e38717ac1dd7a46b6bda7d6a82af2d98a78894", - "reference": "41e38717ac1dd7a46b6bda7d6a82af2d98a78894", + "url": "https://api.github.com/repos/symfony/console/zipball/1e92e39c51f95b88e3d66fa2d9f06d1fb45dd707", + "reference": "1e92e39c51f95b88e3d66fa2d9f06d1fb45dd707", "shasum": "" }, "require": { @@ -4503,7 +4501,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.4" + "source": "https://github.com/symfony/console/tree/v7.4.8" }, "funding": [ { @@ -4523,7 +4521,7 @@ "type": "tidelift" } ], - "time": "2026-01-13T11:36:38+00:00" + "time": "2026-03-30T13:54:39+00:00" }, { "name": "symfony/deprecation-contracts", @@ -4837,16 +4835,16 @@ }, { "name": "symfony/finder", - "version": "v7.4.5", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb" + "reference": "e0be088d22278583a82da281886e8c3592fbf149" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", - "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", + "url": "https://api.github.com/repos/symfony/finder/zipball/e0be088d22278583a82da281886e8c3592fbf149", + "reference": "e0be088d22278583a82da281886e8c3592fbf149", "shasum": "" }, "require": { @@ -4881,7 +4879,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.4.5" + "source": "https://github.com/symfony/finder/tree/v7.4.8" }, "funding": [ { @@ -4901,7 +4899,7 @@ "type": "tidelift" } ], - "time": "2026-01-26T15:07:59+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/http-foundation", @@ -6024,16 +6022,16 @@ }, { "name": "symfony/process", - "version": "v7.4.5", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "608476f4604102976d687c483ac63a79ba18cc97" + "reference": "60f19cd3badc8de688421e21e4305eba50f8089a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/608476f4604102976d687c483ac63a79ba18cc97", - "reference": "608476f4604102976d687c483ac63a79ba18cc97", + "url": "https://api.github.com/repos/symfony/process/zipball/60f19cd3badc8de688421e21e4305eba50f8089a", + "reference": "60f19cd3badc8de688421e21e4305eba50f8089a", "shasum": "" }, "require": { @@ -6065,7 +6063,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.4.5" + "source": "https://github.com/symfony/process/tree/v7.4.8" }, "funding": [ { @@ -6085,7 +6083,7 @@ "type": "tidelift" } ], - "time": "2026-01-26T15:07:59+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/routing", @@ -6261,16 +6259,16 @@ }, { "name": "symfony/string", - "version": "v8.0.4", + "version": "v8.0.8", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "758b372d6882506821ed666032e43020c4f57194" + "reference": "ae9488f874d7603f9d2dfbf120203882b645d963" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/758b372d6882506821ed666032e43020c4f57194", - "reference": "758b372d6882506821ed666032e43020c4f57194", + "url": "https://api.github.com/repos/symfony/string/zipball/ae9488f874d7603f9d2dfbf120203882b645d963", + "reference": "ae9488f874d7603f9d2dfbf120203882b645d963", "shasum": "" }, "require": { @@ -6327,7 +6325,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v8.0.4" + "source": "https://github.com/symfony/string/tree/v8.0.8" }, "funding": [ { @@ -6347,7 +6345,7 @@ "type": "tidelift" } ], - "time": "2026-01-12T12:37:40+00:00" + "time": "2026-03-30T15:14:47+00:00" }, { "name": "symfony/translation", @@ -6851,16 +6849,16 @@ "packages-dev": [ { "name": "brianium/paratest", - "version": "v7.16.1", + "version": "v7.17.0", "source": { "type": "git", "url": "https://github.com/paratestphp/paratest.git", - "reference": "f0fdfd8e654e0d38bc2ba756a6cabe7be287390b" + "reference": "53cb90a6aa3ef3840458781600628ade058a18b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/f0fdfd8e654e0d38bc2ba756a6cabe7be287390b", - "reference": "f0fdfd8e654e0d38bc2ba756a6cabe7be287390b", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/53cb90a6aa3ef3840458781600628ade058a18b9", + "reference": "53cb90a6aa3ef3840458781600628ade058a18b9", "shasum": "" }, "require": { @@ -6874,7 +6872,7 @@ "phpunit/php-code-coverage": "^12.5.2", "phpunit/php-file-iterator": "^6", "phpunit/php-timer": "^8", - "phpunit/phpunit": "^12.5.4", + "phpunit/phpunit": "^12.5.8", "sebastian/environment": "^8.0.3", "symfony/console": "^7.3.4 || ^8.0.0", "symfony/process": "^7.3.4 || ^8.0.0" @@ -6884,10 +6882,10 @@ "ext-pcntl": "*", "ext-pcov": "*", "ext-posix": "*", - "phpstan/phpstan": "^2.1.33", + "phpstan/phpstan": "^2.1.38", "phpstan/phpstan-deprecation-rules": "^2.0.3", - "phpstan/phpstan-phpunit": "^2.0.11", - "phpstan/phpstan-strict-rules": "^2.0.7", + "phpstan/phpstan-phpunit": "^2.0.12", + "phpstan/phpstan-strict-rules": "^2.0.8", "symfony/filesystem": "^7.3.2 || ^8.0.0" }, "bin": [ @@ -6928,7 +6926,7 @@ ], "support": { "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v7.16.1" + "source": "https://github.com/paratestphp/paratest/tree/v7.17.0" }, "funding": [ { @@ -6940,33 +6938,33 @@ "type": "paypal" } ], - "time": "2026-01-08T07:23:06+00:00" + "time": "2026-02-05T09:14:44+00:00" }, { "name": "doctrine/deprecations", - "version": "1.1.5", + "version": "1.1.6", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "conflict": { - "phpunit/phpunit": "<=7.5 || >=13" + "phpunit/phpunit": "<=7.5 || >=14" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^12 || ^13", - "phpstan/phpstan": "1.4.10 || 2.1.11", + "doctrine/coding-standard": "^9 || ^12 || ^14", + "phpstan/phpstan": "1.4.10 || 2.1.30", "phpstan/phpstan-phpunit": "^1.0 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0", "psr/log": "^1 || ^2 || ^3" }, "suggest": { @@ -6986,9 +6984,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.5" + "source": "https://github.com/doctrine/deprecations/tree/1.1.6" }, - "time": "2025-04-07T20:06:18+00:00" + "time": "2026-02-07T07:09:04+00:00" }, { "name": "fakerphp/faker", @@ -8054,16 +8052,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "6.0.1", + "version": "6.0.3", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "2f5cbed597cb261d1ea458f3da3a9ad32e670b1e" + "reference": "7bae67520aa9f5ecc506d646810bd40d9da54582" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/2f5cbed597cb261d1ea458f3da3a9ad32e670b1e", - "reference": "2f5cbed597cb261d1ea458f3da3a9ad32e670b1e", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/7bae67520aa9f5ecc506d646810bd40d9da54582", + "reference": "7bae67520aa9f5ecc506d646810bd40d9da54582", "shasum": "" }, "require": { @@ -8113,9 +8111,9 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/6.0.1" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/6.0.3" }, - "time": "2026-01-20T15:30:42+00:00" + "time": "2026-03-18T20:49:53+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -8421,16 +8419,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "12.5.2", + "version": "12.5.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "4a9739b51cbcb355f6e95659612f92e282a7077b" + "reference": "b015312f28dd75b75d3422ca37dff2cd1a565e8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4a9739b51cbcb355f6e95659612f92e282a7077b", - "reference": "4a9739b51cbcb355f6e95659612f92e282a7077b", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b015312f28dd75b75d3422ca37dff2cd1a565e8d", + "reference": "b015312f28dd75b75d3422ca37dff2cd1a565e8d", "shasum": "" }, "require": { @@ -8486,7 +8484,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.5.2" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.5.3" }, "funding": [ { @@ -8506,7 +8504,7 @@ "type": "tidelift" } ], - "time": "2025-12-24T07:03:04+00:00" + "time": "2026-02-06T06:01:44+00:00" }, { "name": "phpunit/php-file-iterator", @@ -9217,16 +9215,16 @@ }, { "name": "sebastian/environment", - "version": "8.0.3", + "version": "8.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68" + "reference": "7b8842c2d8e85d0c3a5831236bf5869af6ab2a11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/24a711b5c916efc6d6e62aa65aa2ec98fef77f68", - "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/7b8842c2d8e85d0c3a5831236bf5869af6ab2a11", + "reference": "7b8842c2d8e85d0c3a5831236bf5869af6ab2a11", "shasum": "" }, "require": { @@ -9269,7 +9267,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", "security": "https://github.com/sebastianbergmann/environment/security/policy", - "source": "https://github.com/sebastianbergmann/environment/tree/8.0.3" + "source": "https://github.com/sebastianbergmann/environment/tree/8.0.4" }, "funding": [ { @@ -9289,7 +9287,7 @@ "type": "tidelift" } ], - "time": "2025-08-12T14:11:56+00:00" + "time": "2026-03-15T07:05:40+00:00" }, { "name": "sebastian/exporter", @@ -9880,23 +9878,23 @@ }, { "name": "ta-tikoma/phpunit-architecture-test", - "version": "0.8.6", + "version": "0.8.7", "source": { "type": "git", "url": "https://github.com/ta-tikoma/phpunit-architecture-test.git", - "reference": "ad48430b92901fd7d003fdaf2d7b139f96c0906e" + "reference": "1248f3f506ca9641d4f68cebcd538fa489754db8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/ad48430b92901fd7d003fdaf2d7b139f96c0906e", - "reference": "ad48430b92901fd7d003fdaf2d7b139f96c0906e", + "url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/1248f3f506ca9641d4f68cebcd538fa489754db8", + "reference": "1248f3f506ca9641d4f68cebcd538fa489754db8", "shasum": "" }, "require": { "nikic/php-parser": "^4.18.0 || ^5.0.0", "php": "^8.1.0", "phpdocumentor/reflection-docblock": "^5.3.0 || ^6.0.0", - "phpunit/phpunit": "^10.5.5 || ^11.0.0 || ^12.0.0", + "phpunit/phpunit": "^10.5.5 || ^11.0.0 || ^12.0.0 || ^13.0.0", "symfony/finder": "^6.4.0 || ^7.0.0 || ^8.0.0" }, "require-dev": { @@ -9933,9 +9931,9 @@ ], "support": { "issues": "https://github.com/ta-tikoma/phpunit-architecture-test/issues", - "source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.6" + "source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.7" }, - "time": "2026-01-30T07:16:00+00:00" + "time": "2026-02-17T17:25:14+00:00" }, { "name": "theseer/tokenizer", @@ -9989,16 +9987,16 @@ }, { "name": "webmozart/assert", - "version": "2.1.2", + "version": "2.1.6", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "ce6a2f100c404b2d32a1dd1270f9b59ad4f57649" + "reference": "ff31ad6efc62e66e518fbab1cde3453d389bcdc8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/ce6a2f100c404b2d32a1dd1270f9b59ad4f57649", - "reference": "ce6a2f100c404b2d32a1dd1270f9b59ad4f57649", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/ff31ad6efc62e66e518fbab1cde3453d389bcdc8", + "reference": "ff31ad6efc62e66e518fbab1cde3453d389bcdc8", "shasum": "" }, "require": { @@ -10045,9 +10043,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/2.1.2" + "source": "https://github.com/webmozarts/assert/tree/2.1.6" }, - "time": "2026-01-13T14:02:24+00:00" + "time": "2026-02-27T10:28:38+00:00" } ], "aliases": [], diff --git a/phpunit.xml b/phpunit.xml index c122375..777ee2b 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -17,11 +17,4 @@ ./app - - - - - - - diff --git a/tests/Unit/Services/QdrantServiceTest.php b/tests/Unit/Services/QdrantServiceTest.php index 5252e8c..0a1bdc9 100644 --- a/tests/Unit/Services/QdrantServiceTest.php +++ b/tests/Unit/Services/QdrantServiceTest.php @@ -1723,3 +1723,64 @@ function mockCollectionExists(Mockery\MockInterface $connector, int $times = 1): expect($result)->toBe($embedding); }); }); + +describe('searchRawCollection', function (): void { + it('returns results from any collection by name', function (): void { + $embedding = array_fill(0, 384, 0.1); + + $this->mockEmbedding->shouldReceive('generate') + ->once() + ->with('punk rock') + ->andReturn($embedding); + + $searchResults = [ + ['id' => 'abc', 'score' => 0.95, 'payload' => ['track' => 'Punkrocker', 'artist' => 'Teddybears']], + ['id' => 'def', 'score' => 0.85, 'payload' => ['track' => 'Blitzkrieg Bop', 'artist' => 'Ramones']], + ]; + + $mockResponse = Mockery::mock(\Saloon\Http\Response::class); + $mockResponse->shouldReceive('successful')->andReturn(true); + $mockResponse->shouldReceive('json')->with('result')->andReturn($searchResults); + + $this->mockConnector->shouldReceive('send') + ->with(Mockery::type(SearchPoints::class)) + ->once() + ->andReturn($mockResponse); + + $results = $this->service->searchRawCollection('music_events', 'punk rock', 10); + + expect($results)->toHaveCount(2) + ->and($results[0]['payload']['track'])->toBe('Punkrocker') + ->and($results[0]['score'])->toBe(0.95) + ->and($results[1]['payload']['artist'])->toBe('Ramones'); + }); + + it('returns empty collection when embedding fails', function (): void { + $this->mockEmbedding->shouldReceive('generate') + ->once() + ->andReturn([]); + + $results = $this->service->searchRawCollection('music_events', 'test', 10); + + expect($results)->toBeEmpty(); + }); + + it('returns empty collection on failed response', function (): void { + $embedding = array_fill(0, 384, 0.1); + + $this->mockEmbedding->shouldReceive('generate') + ->once() + ->andReturn($embedding); + + $mockResponse = createMockResponse(false, 500); + + $this->mockConnector->shouldReceive('send') + ->with(Mockery::type(SearchPoints::class)) + ->once() + ->andReturn($mockResponse); + + $results = $this->service->searchRawCollection('music_events', 'test', 10); + + expect($results)->toBeEmpty(); + }); +});