48 lines
1.9 KiB
PHP
48 lines
1.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Chatbot\Mcp\Tool;
|
|
|
|
use App\Chatbot\Mcp\Sites;
|
|
use App\Chatbot\Mcp\ToolCallRunner;
|
|
use App\Chatbot\Search\ContentSearch;
|
|
use Mcp\Capability\Attribute\McpTool;
|
|
use Mcp\Capability\Attribute\Schema;
|
|
use Mcp\Exception\ToolCallException;
|
|
use Mcp\Schema\Result\CallToolResult;
|
|
use Mcp\Schema\ToolAnnotations;
|
|
|
|
#[McpTool(
|
|
name: 'search_content',
|
|
description: "Search the websites' editorial content: destinations, hotels, travel information, FAQs, terms, blog articles, general company information. Use for questions that are not about specific dates or prices. Returns excerpts; use get_document for the full text of a hit.",
|
|
annotations: new ToolAnnotations(readOnlyHint: true, openWorldHint: false),
|
|
)]
|
|
final class SearchContentTool
|
|
{
|
|
public function __construct(
|
|
private readonly ContentSearch $search,
|
|
private readonly ToolCallRunner $runner,
|
|
) {
|
|
}
|
|
|
|
public function __invoke(
|
|
#[Schema(description: 'What to look for, in German keywords works best, e.g. "Gepäck Snowboard Bus".', minLength: 1)]
|
|
string $query,
|
|
#[Schema(description: 'Restrict to one kind of content. destination = region, country or town.', enum: ['page', 'product', 'hotel', 'destination', 'concept', 'news'])]
|
|
?string $type = null,
|
|
#[Schema(description: Sites::DESCRIPTION, enum: Sites::IDENTIFIERS)]
|
|
?string $site = null,
|
|
#[Schema(description: 'Number of hits, default 5, at most 8.', minimum: 1, maximum: 8)]
|
|
?int $limit = null,
|
|
): CallToolResult {
|
|
return $this->runner->run('search_content', get_defined_vars(), function () use ($query, $type, $site, $limit): array {
|
|
if ('' === trim($query)) {
|
|
throw new ToolCallException('query must not be empty.');
|
|
}
|
|
|
|
return ['results' => $this->search->search($query, $type, $site, max(1, min(8, $limit ?? 5)))];
|
|
});
|
|
}
|
|
}
|