feat: let get_trip resolve a date code to its trip and date

This commit is contained in:
fromme committed 2026-10-08 11:46:59 +02:00
1 parent 754360605c
commit 3af41c06ab
4 files changed
+45 -9

No files matched your search

+3 -3
View File
@@ -14,7 +14,7 @@ use Mcp\Schema\ToolAnnotations;
#[McpTool(
name: 'get_trip',
description: 'Full details of one trip: description, included services, programme, hotel, all upcoming dates with rooms, prices per person in EUR and availability, pickup points and departure times, FAQs. Use after search_trips, or when the user names a specific trip. Prices and availability are a snapshot as of dataAsOf; the booking page is binding.',
description: 'Full details of one trip: description, included services, programme, hotel, all upcoming dates with rooms, prices per person in EUR and availability, pickup points and departure times, FAQs. Use after search_trips, or when the user names a specific trip or a booked date (date codes such as SSLMP061226 narrow the answer to that date). Prices and availability are a snapshot as of dataAsOf; the booking page is binding.',
annotations: new ToolAnnotations(readOnlyHint: true, openWorldHint: false),
)]
final class GetTripTool
@@ -26,7 +26,7 @@ final class GetTripTool
}
public function __invoke(
#[Schema(description: 'Trip code, as returned by search_trips.', minLength: 1)]
#[Schema(description: 'Trip code as returned by search_trips, or a date code (dateCode) for one date of a trip.', minLength: 1)]
string $code,
#[Schema(description: 'Narrows the dates to one hotel when a trip has several.')]
?string $hotelCode = null,
@@ -35,7 +35,7 @@ final class GetTripTool
$trip = $this->catalog->get(trim($code), $hotelCode);
if (null === $trip) {
throw new ToolCallException(sprintf('No trip with code "%s". Use search_trips to find trip codes.', $code));
throw new ToolCallException(sprintf('No trip or date with code "%s". Use search_trips to find trip codes.', $code));
}
return $trip;
+25 -3
View File
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Chatbot;
use App\BusProNet\Utility\DateCodeUtility;
use App\Chatbot\Search\ContentSearchQuery;
use App\Entity\ContentDocument;
use App\Model\Chatbot\TripCriteria;
@@ -79,6 +80,7 @@ class TripCatalog
$current = $dates[$dateId] ?? null;
$dates[$dateId] = [
'dateCode' => $row['date']['code'],
'dateFrom' => $row['date']['from'],
'dateTo' => $row['date']['to'],
'priceFrom' => null === $current ? $summary['priceFrom'] : $this->minPrice($current['priceFrom'], $summary['priceFrom']),
@@ -107,12 +109,29 @@ class TripCatalog
/**
* Everything about one trip, or null for a code no published product carries.
*
* Takes a product code or a date code. A date code is what customers read on their
* booking documents (SSLMP061226 is product SSLMP on 06.12.26); it narrows the trip to
* that date, shown even when it has already started.
*
* @return array<string, mixed>|null
*/
public function get(string $code, ?string $hotelCode = null): ?array
{
$catalog = $this->load();
$products = $catalog['productsByCode'][$this->normalize($code)] ?? [];
$code = (new DateCodeUtility())->sanitize(trim($code));
$dateCode = null;
if (!isset($catalog['productsByCode'][$code])) {
foreach ($catalog['export']->rows as $row) {
if ($this->normalize($row['date']['code'] ?? null) === $code) {
$dateCode = $code;
$code = $this->normalize($row['product']['code'] ?? null);
break;
}
}
}
$products = $catalog['productsByCode'][$code] ?? [];
if ([] === $products) {
return null;
@@ -123,8 +142,10 @@ class TripCatalog
$today = $this->today();
$rows = array_values(array_filter(
$catalog['rowsByCode'][$this->normalize($code)] ?? [],
fn (array $row): bool => $row['date']['from'] >= $today,
$catalog['rowsByCode'][$code] ?? [],
fn (array $row): bool => null === $dateCode
? $row['date']['from'] >= $today
: $this->normalize($row['date']['code'] ?? null) === $dateCode,
));
if (null !== $hotelCode && '' !== trim($hotelCode)) {
@@ -545,6 +566,7 @@ class TripCatalog
}
$dates[$dateId] ??= [
'dateCode' => $row['date']['code'],
'dateFrom' => $row['date']['from'],
'dateTo' => $row['date']['to'],
'hotels' => [],