@curless/hotel-storefront 0.27.26 → 0.27.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend.d.ts +17 -0
- package/dist/backend.d.ts.map +1 -1
- package/dist/backend.js.map +1 -1
- package/dist/card.generated.d.ts +1 -1
- package/dist/card.generated.js +2 -2
- package/dist/card.generated.js.map +1 -1
- package/dist/demo-hotels.d.ts +7 -0
- package/dist/demo-hotels.d.ts.map +1 -1
- package/dist/demo-hotels.js +42 -5
- package/dist/demo-hotels.js.map +1 -1
- package/dist/huazhu/backend.d.ts +4 -0
- package/dist/huazhu/backend.d.ts.map +1 -1
- package/dist/huazhu/backend.js +66 -6
- package/dist/huazhu/backend.js.map +1 -1
- package/dist/huazhu/check.d.ts.map +1 -1
- package/dist/huazhu/check.js +7 -1
- package/dist/huazhu/check.js.map +1 -1
- package/dist/huazhu/drift.d.ts +7 -0
- package/dist/huazhu/drift.d.ts.map +1 -0
- package/dist/huazhu/drift.js +248 -0
- package/dist/huazhu/drift.js.map +1 -0
- package/dist/legal.js +2 -2
- package/dist/limits.d.ts +10 -0
- package/dist/limits.d.ts.map +1 -1
- package/dist/limits.js +2 -1
- package/dist/limits.js.map +1 -1
- package/dist/present.d.ts +19 -1
- package/dist/present.d.ts.map +1 -1
- package/dist/present.js +28 -2
- package/dist/present.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +92 -13
- package/dist/tools.js.map +1 -1
- package/package.json +1 -1
package/dist/tools.js
CHANGED
|
@@ -3,7 +3,7 @@ import { MAX_GUESTS, isDay, nights as nightsBetween } from './dates.js';
|
|
|
3
3
|
import { FACILITIES } from './facilities.js';
|
|
4
4
|
import { DESCRIPTION_MAX, POLICY_MAX, guestText, hotelText } from './fence.js';
|
|
5
5
|
import { formatMoney, money, multiplyMoney, toMinor } from './money.js';
|
|
6
|
-
import { MAX_COMPARED, MAX_CONS, MAX_DAYS, MAX_ITEMS_PER_DAY, MAX_MOMENTS, MAX_PROS, buildItinerary, compareHotels, } from './present.js';
|
|
6
|
+
import { MAX_COMPARED, MAX_CONS, MAX_DAYS, MAX_ITEMS_PER_DAY, MAX_MOMENTS, MAX_PROS, buildItinerary, candidatesFor, compareHotels, namesMoreThanOne, } from './present.js';
|
|
7
7
|
import { regionOf } from './regions.js';
|
|
8
8
|
import { MAX_EXTRA_QUANTITY, MAX_ROOMS_PER_LINE, TRIP_TTL_MS, clampCount, shownOf, tripKey, } from './trip.js';
|
|
9
9
|
import { DEMO_NOTE, branded, catalogue, upFirst } from './vocab.js';
|
|
@@ -770,6 +770,8 @@ const TRIP_SCHEMA = {
|
|
|
770
770
|
memberSaving: OBJ,
|
|
771
771
|
days: ARR,
|
|
772
772
|
dropped: ARR,
|
|
773
|
+
/** A name that fits more than one hotel: the ones it fits (`namesLike`). */
|
|
774
|
+
candidates: ARR,
|
|
773
775
|
},
|
|
774
776
|
required: ['view'],
|
|
775
777
|
};
|
|
@@ -891,6 +893,8 @@ export const buildOutputSchemas = (n) => ({
|
|
|
891
893
|
policies: ARR,
|
|
892
894
|
/** Arrivals a few days either side, each re-quoted for the same nights. */
|
|
893
895
|
dates: ARR,
|
|
896
|
+
/** A name that fits more than one hotel: the ones it fits (`namesLike`). */
|
|
897
|
+
candidates: ARR,
|
|
894
898
|
},
|
|
895
899
|
required: ['view'],
|
|
896
900
|
},
|
|
@@ -905,6 +909,8 @@ export const buildOutputSchemas = (n) => ({
|
|
|
905
909
|
demoNote: STR,
|
|
906
910
|
hotel: OBJ,
|
|
907
911
|
extras: ARR,
|
|
912
|
+
/** A name that fits more than one hotel: the ones it fits (`namesLike`). */
|
|
913
|
+
candidates: ARR,
|
|
908
914
|
},
|
|
909
915
|
required: ['view'],
|
|
910
916
|
},
|
|
@@ -1032,7 +1038,10 @@ export const buildOutputSchemas = (n) => ({
|
|
|
1032
1038
|
hotels: ARR,
|
|
1033
1039
|
stay: OBJ,
|
|
1034
1040
|
total: { type: 'number' },
|
|
1035
|
-
|
|
1041
|
+
/** The names that did not open one hotel - none answered, or more than one did. */
|
|
1042
|
+
dropped: STRS,
|
|
1043
|
+
/** For a name that fits more than one hotel, the ones it fits - each with \`for\`, the name. */
|
|
1044
|
+
candidates: ARR,
|
|
1036
1045
|
},
|
|
1037
1046
|
required: ['view'],
|
|
1038
1047
|
},
|
|
@@ -1045,6 +1054,8 @@ export const buildOutputSchemas = (n) => ({
|
|
|
1045
1054
|
bookingMode: STR,
|
|
1046
1055
|
demo: BOOL,
|
|
1047
1056
|
hotel: OBJ,
|
|
1057
|
+
/** A name that fits more than one hotel: the ones it fits (`namesLike`). */
|
|
1058
|
+
candidates: ARR,
|
|
1048
1059
|
topic: STR,
|
|
1049
1060
|
title: STR,
|
|
1050
1061
|
text: STR,
|
|
@@ -2021,6 +2032,14 @@ export const handleTool = async (deps, name, rawArgs, ctx) => {
|
|
|
2021
2032
|
? { ...answer, structured: { ...answer.structured, suggestions } }
|
|
2022
2033
|
: answer;
|
|
2023
2034
|
};
|
|
2035
|
+
/**
|
|
2036
|
+
* For each left-out name that fits more than one hotel, the sentence that says
|
|
2037
|
+
* which - for the model, in the tool's text, never on the card (see
|
|
2038
|
+
* `MORE_THAN_ONE`).
|
|
2039
|
+
*/
|
|
2040
|
+
const fitsManyOf = (deps, dropped) => dropped.flatMap((d) => d.candidates?.length
|
|
2041
|
+
? [`"${d.name}" ${namesMoreThanOne(d.candidates, branded(deps.vocab, deps.vocab.noun))}`]
|
|
2042
|
+
: []);
|
|
2024
2043
|
const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
2025
2044
|
const args = countsAsNumbers((rawArgs ?? {}));
|
|
2026
2045
|
const t = deps.tools;
|
|
@@ -2422,9 +2441,17 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
2422
2441
|
const who = identity(deps, ctx, key);
|
|
2423
2442
|
const detail = await deps.backend.getHotel(wanted, stay, who);
|
|
2424
2443
|
if (!detail) {
|
|
2444
|
+
const candidates = candidatesFor(deps.backend, wanted);
|
|
2425
2445
|
return {
|
|
2426
|
-
structured: {
|
|
2427
|
-
|
|
2446
|
+
structured: {
|
|
2447
|
+
view: 'hotel-not-found',
|
|
2448
|
+
...common(deps, key),
|
|
2449
|
+
query: wanted,
|
|
2450
|
+
...(candidates.length ? { candidates } : {}),
|
|
2451
|
+
},
|
|
2452
|
+
text: candidates.length
|
|
2453
|
+
? `"${wanted}" ${namesMoreThanOne(candidates, branded(deps.vocab, deps.vocab.noun))}`
|
|
2454
|
+
: `No ${branded(deps.vocab, deps.vocab.noun)} by that name. ${t.listHotels} lists them.`,
|
|
2428
2455
|
};
|
|
2429
2456
|
}
|
|
2430
2457
|
const h = detail.hotel;
|
|
@@ -2556,14 +2583,21 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
2556
2583
|
const city = str(args.city);
|
|
2557
2584
|
const ids = [];
|
|
2558
2585
|
const dropped = [];
|
|
2586
|
+
/** For each name that fits more than one, which ones - see `namesLike`. */
|
|
2587
|
+
const candidates = [];
|
|
2559
2588
|
let total = 0;
|
|
2560
2589
|
if (named.length) {
|
|
2561
2590
|
for (const ref of named) {
|
|
2562
2591
|
const found = await deps.backend.getHotel(ref);
|
|
2563
2592
|
if (found)
|
|
2564
2593
|
ids.push(found.hotel.id);
|
|
2565
|
-
else
|
|
2594
|
+
else {
|
|
2566
2595
|
dropped.push(ref);
|
|
2596
|
+
// The same name asked twice is named once.
|
|
2597
|
+
if (!candidates.some((c) => c.for === ref))
|
|
2598
|
+
for (const c of candidatesFor(deps.backend, ref))
|
|
2599
|
+
candidates.push({ for: ref, ...c });
|
|
2600
|
+
}
|
|
2567
2601
|
}
|
|
2568
2602
|
total = ids.length;
|
|
2569
2603
|
}
|
|
@@ -2573,17 +2607,28 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
2573
2607
|
total = found.total;
|
|
2574
2608
|
}
|
|
2575
2609
|
const unique = [...new Set(ids)];
|
|
2610
|
+
// A name that fits more than one is said with the ones it fits; the rest are not found.
|
|
2611
|
+
const notFound = dropped.filter((d) => !candidates.some((c) => c.for === d));
|
|
2612
|
+
const fitsMany = [...new Set(candidates.map((c) => c.for))].map((ref) => `"${ref}" ${namesMoreThanOne(candidates.filter((c) => c.for === ref), branded(deps.vocab, deps.vocab.noun))}`);
|
|
2576
2613
|
if (unique.length === 0) {
|
|
2577
2614
|
return {
|
|
2578
2615
|
structured: {
|
|
2579
2616
|
view: 'nothing-found',
|
|
2580
2617
|
...common(deps, key),
|
|
2581
2618
|
...(dropped.length ? { dropped } : {}),
|
|
2619
|
+
...(candidates.length ? { candidates } : {}),
|
|
2582
2620
|
},
|
|
2583
2621
|
text: city
|
|
2584
2622
|
? `No ${branded(deps.vocab, deps.vocab.nounPlural)} in "${city}". ${t.listHotels} with no place shows the places there are.`
|
|
2585
2623
|
: named.length
|
|
2586
|
-
?
|
|
2624
|
+
? [
|
|
2625
|
+
notFound.length
|
|
2626
|
+
? `No ${branded(deps.vocab, deps.vocab.noun)} answers to ${notFound.map((d) => `"${d}"`).join(', ')}.`
|
|
2627
|
+
: '',
|
|
2628
|
+
...fitsMany,
|
|
2629
|
+
]
|
|
2630
|
+
.filter(Boolean)
|
|
2631
|
+
.join('\n')
|
|
2587
2632
|
: `Name a \`city\`, or up to ${LOOK_UP_MAX} ${deps.vocab.nounPlural} in \`${deps.vocab.nounPlural}\`.`,
|
|
2588
2633
|
};
|
|
2589
2634
|
}
|
|
@@ -2635,11 +2680,13 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
2635
2680
|
...(stay ? { stay } : {}),
|
|
2636
2681
|
total,
|
|
2637
2682
|
...(dropped.length ? { dropped } : {}),
|
|
2683
|
+
...(candidates.length ? { candidates } : {}),
|
|
2638
2684
|
},
|
|
2639
2685
|
text: [
|
|
2640
2686
|
`Read ${read.length}${total > read.length ? ` of ${total}` : ''} ${read.length === 1 ? deps.vocab.noun : deps.vocab.nounPlural}. Nothing was shown to the guest.`,
|
|
2641
2687
|
...blocks,
|
|
2642
|
-
|
|
2688
|
+
notFound.length ? `Not found: ${notFound.map((d) => `"${d}"`).join(', ')}.` : '',
|
|
2689
|
+
...fitsMany,
|
|
2643
2690
|
total > read.length
|
|
2644
2691
|
? `${total - read.length} more ${total - read.length === 1 ? 'is' : 'are'} there; name ${total - read.length === 1 ? 'it' : 'them'} in \`${deps.vocab.nounPlural}\` to read ${total - read.length === 1 ? 'it' : 'them'}.`
|
|
2645
2692
|
: '',
|
|
@@ -2697,9 +2744,17 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
2697
2744
|
const wanted = booked ? booked.hotelId : str(args.hotel);
|
|
2698
2745
|
const detail = await deps.backend.getHotel(wanted);
|
|
2699
2746
|
if (!detail) {
|
|
2747
|
+
const candidates = candidatesFor(deps.backend, wanted);
|
|
2700
2748
|
return {
|
|
2701
|
-
structured: {
|
|
2702
|
-
|
|
2749
|
+
structured: {
|
|
2750
|
+
view: 'hotel-not-found',
|
|
2751
|
+
...common(deps, key),
|
|
2752
|
+
query: wanted,
|
|
2753
|
+
...(candidates.length ? { candidates } : {}),
|
|
2754
|
+
},
|
|
2755
|
+
text: candidates.length
|
|
2756
|
+
? `"${wanted}" ${namesMoreThanOne(candidates, branded(deps.vocab, deps.vocab.noun))}`
|
|
2757
|
+
: `No ${branded(deps.vocab, deps.vocab.noun)} by that name.`,
|
|
2703
2758
|
};
|
|
2704
2759
|
}
|
|
2705
2760
|
const extras = await deps.backend.extrasFor(detail.hotel.id, booked?.stay ?? asStay(args));
|
|
@@ -2736,14 +2791,18 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
2736
2791
|
const wanted = str(args.hotel);
|
|
2737
2792
|
const detail = await deps.backend.getHotel(wanted);
|
|
2738
2793
|
if (!detail) {
|
|
2794
|
+
const candidates = candidatesFor(deps.backend, wanted);
|
|
2739
2795
|
return {
|
|
2740
2796
|
structured: {
|
|
2741
2797
|
view: 'error',
|
|
2742
2798
|
...common(deps, key),
|
|
2743
2799
|
error: 'hotel-not-found',
|
|
2744
2800
|
query: wanted,
|
|
2801
|
+
...(candidates.length ? { candidates } : {}),
|
|
2745
2802
|
},
|
|
2746
|
-
text:
|
|
2803
|
+
text: candidates.length
|
|
2804
|
+
? `"${wanted}" ${namesMoreThanOne(candidates, branded(deps.vocab, deps.vocab.noun))}`
|
|
2805
|
+
: `No ${branded(deps.vocab, deps.vocab.noun)} by that name.`,
|
|
2747
2806
|
};
|
|
2748
2807
|
}
|
|
2749
2808
|
const hotelId = detail.hotel.id;
|
|
@@ -3345,13 +3404,23 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
3345
3404
|
who: identity(deps, ctx, key),
|
|
3346
3405
|
});
|
|
3347
3406
|
if (comparison.columns.length === 0) {
|
|
3407
|
+
const unknown = comparison.dropped.filter((d) => !d.candidates?.length);
|
|
3408
|
+
const fitsMany = fitsManyOf(deps, comparison.dropped);
|
|
3348
3409
|
return {
|
|
3349
3410
|
structured: {
|
|
3350
3411
|
view: 'nothing-to-compare',
|
|
3351
3412
|
...common(deps, key),
|
|
3352
3413
|
dropped: comparison.dropped,
|
|
3353
3414
|
},
|
|
3354
|
-
|
|
3415
|
+
// A name that fits several IS one of ours - only the rest are "none".
|
|
3416
|
+
text: [
|
|
3417
|
+
...(unknown.length || !fitsMany.length
|
|
3418
|
+
? [
|
|
3419
|
+
`None of those are ${catalogue(deps.vocab)}: ${unknown.map((d) => d.name).join(', ')}.`,
|
|
3420
|
+
]
|
|
3421
|
+
: []),
|
|
3422
|
+
...fitsMany,
|
|
3423
|
+
].join('\n'),
|
|
3355
3424
|
};
|
|
3356
3425
|
}
|
|
3357
3426
|
return {
|
|
@@ -3376,6 +3445,7 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
3376
3445
|
? `These are priced in different currencies (${comparison.currencies.join(', ')}) and nothing here converts them — do not call one cheaper than another.`
|
|
3377
3446
|
: '',
|
|
3378
3447
|
...comparison.dropped.map((d) => `Left out: ${d.name} — ${d.why}`),
|
|
3448
|
+
...fitsManyOf(deps, comparison.dropped),
|
|
3379
3449
|
deps.vocab.demo ? DEMO_NOTE : '',
|
|
3380
3450
|
]
|
|
3381
3451
|
.filter(Boolean)
|
|
@@ -3419,6 +3489,7 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
3419
3489
|
`**${plan.title}** · ${plan.days.length} ${plan.days.length === 1 ? 'day' : 'days'}. ${gap}`,
|
|
3420
3490
|
stays.length ? `Stays, priced on: ${stays.join('; ')}.` : '',
|
|
3421
3491
|
...plan.dropped.map((d) => `Left out: ${d.name} — ${d.why}`),
|
|
3492
|
+
...fitsManyOf(deps, plan.dropped),
|
|
3422
3493
|
deps.vocab.demo ? DEMO_NOTE : '',
|
|
3423
3494
|
]
|
|
3424
3495
|
.filter(Boolean)
|
|
@@ -3505,9 +3576,17 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
3505
3576
|
const wanted = str(args.hotel);
|
|
3506
3577
|
const detail = await deps.backend.getHotel(wanted);
|
|
3507
3578
|
if (!detail) {
|
|
3579
|
+
const candidates = candidatesFor(deps.backend, wanted);
|
|
3508
3580
|
return {
|
|
3509
|
-
structured: {
|
|
3510
|
-
|
|
3581
|
+
structured: {
|
|
3582
|
+
view: 'hotel-not-found',
|
|
3583
|
+
...common(deps, key),
|
|
3584
|
+
query: wanted,
|
|
3585
|
+
...(candidates.length ? { candidates } : {}),
|
|
3586
|
+
},
|
|
3587
|
+
text: candidates.length
|
|
3588
|
+
? `"${wanted}" ${namesMoreThanOne(candidates, branded(deps.vocab, deps.vocab.noun))}`
|
|
3589
|
+
: `No ${branded(deps.vocab, deps.vocab.noun)} by that name.`,
|
|
3511
3590
|
};
|
|
3512
3591
|
}
|
|
3513
3592
|
const policies = await deps.backend.policies(detail.hotel.id);
|