mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-21 22:46:32 +00:00
fix(assistant): the found places of every search in one strip
An answer that searched several times showed only its last search, about ten places. The strip now holds the places of all its searches, each once (the same Google or OSM id, or the same name at the same spot), and shows up to 60.
This commit is contained in:
@@ -9,7 +9,7 @@ import { useAssistantView } from './assistantViewContext';
|
||||
import { useAssistantPlaceStrip } from './useAssistantPlaceStrip';
|
||||
|
||||
/** Cards the strip shows, every one the server sends; what it left out is counted on the tile at its end. */
|
||||
const SHOWN = 20;
|
||||
const SHOWN = 60;
|
||||
|
||||
// In the strip's head, never over a card: a press that ends a pixel off still lands on the arrow.
|
||||
const ARROW =
|
||||
|
||||
@@ -183,21 +183,23 @@ function adds(id: string, spot: { lat: number; lng: number } | null, placeId: nu
|
||||
}
|
||||
|
||||
describe('messageBlocks: found places and weather', () => {
|
||||
it('FE-AI-PARTS-008: shows only the newest search, and steps after it join the row before it', () => {
|
||||
it('FE-AI-PARTS-008: joins the places of all searches into one strip, each once, and steps after it join the row before it', () => {
|
||||
const blocks = messageBlocks(
|
||||
message([
|
||||
read('s1', []),
|
||||
places('s1', [found('s1:0')]),
|
||||
places('s1', [found('s1:0'), found('s1:1', { googlePlaceId: 'ChIJa' })], 2),
|
||||
read('s2', []),
|
||||
places('s2', [found('s2:0'), found('s2:1', { lat: 40 })], 3),
|
||||
{ type: 'text', text: 'Two good ones.' },
|
||||
places('s2', [found('s2:0', { name: 'Place s1:0' }), found('s2:1', { googlePlaceId: 'ChIJa', lat: 40 })], 3),
|
||||
places('s3', [found('s3:0', { lat: 40 })]),
|
||||
{ type: 'text', text: 'Three good ones.' },
|
||||
]),
|
||||
false
|
||||
);
|
||||
expect(blocks.map((b) => b.kind)).toEqual(['steps', 'places', 'text']);
|
||||
expect(blocks[0]).toMatchObject({ steps: [{ toolCallId: 's1' }, { toolCallId: 's2' }] });
|
||||
// The same name at the same spot, or the same Google id, shows once.
|
||||
expect(blocks[1]).toMatchObject({
|
||||
found: { toolCallId: 's2', more: 3, places: [{ ref: 's2:0' }, { ref: 's2:1' }] },
|
||||
found: { toolCallId: 's3', more: 5, places: [{ ref: 's1:0' }, { ref: 's1:1' }, { ref: 's3:0' }] },
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -82,6 +82,37 @@ function weatherDays(parts: readonly AssistantMessagePart[]): AssistantWeatherDa
|
||||
return [...byDate.values()].sort((a, b) => a.date.localeCompare(b.date));
|
||||
}
|
||||
|
||||
/** The handles one place goes by: its ids, and its name at its spot (to about 100 m). */
|
||||
function placeKeys(place: AssistantFoundPlace): string[] {
|
||||
const ids = [place.googlePlaceId && `g:${place.googlePlaceId}`, place.osmId && `o:${place.osmId}`];
|
||||
const spot = `n:${place.name.trim().toLowerCase()}@${place.lat.toFixed(3)},${place.lng.toFixed(3)}`;
|
||||
return [...ids.filter((key): key is string => !!key), spot];
|
||||
}
|
||||
|
||||
/**
|
||||
* The places all searches of an answer found, in the order they came, each
|
||||
* once (also when two searches name it by different ids, as long as name and
|
||||
* spot agree), with what the searches left out counted together.
|
||||
*/
|
||||
function allFound(parts: AssistantMessage['parts']): AssistantPlaces {
|
||||
const seen = new Set<string>();
|
||||
const places: AssistantFoundPlace[] = [];
|
||||
let more = 0;
|
||||
let toolCallId = '';
|
||||
for (const part of parts) {
|
||||
if (part.type !== 'data-trek-places') continue;
|
||||
toolCallId = part.data.toolCallId;
|
||||
more += part.data.more;
|
||||
for (const place of part.data.places) {
|
||||
const keys = placeKeys(place);
|
||||
if (keys.some((key) => seen.has(key))) continue;
|
||||
keys.forEach((key) => seen.add(key));
|
||||
places.push(place);
|
||||
}
|
||||
}
|
||||
return { toolCallId, places, more };
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a change to the change block before it, or starts one. A suggestion
|
||||
* from the strip is a block of its own, decided apart from the changes before
|
||||
@@ -121,8 +152,9 @@ function changeState(part: ToolCallPart, applied: AssistantApplied | null): Chan
|
||||
* message is still being streamed, so a step without a result is running and
|
||||
* not merely unanswered.
|
||||
*
|
||||
* Only the newest search shows its places, without the ones a change the
|
||||
* model proposed in the answer already holds; the weather of all steps joins
|
||||
* The places of all its searches join into one strip where the newest search
|
||||
* sat, each place once, without the ones a change the model proposed in the
|
||||
* answer already holds; the weather of all steps joins
|
||||
* into one row where the first look sat. A strip does not split the steps
|
||||
* around it: a step after it joins the row of steps before it.
|
||||
*/
|
||||
@@ -152,8 +184,9 @@ export function messageBlocks(message: AssistantMessage, writing: boolean): Mess
|
||||
return;
|
||||
}
|
||||
if (part.type === 'data-trek-places' && index === lastPlaces) {
|
||||
const places = part.data.places.filter((place) => !proposed(place, effects));
|
||||
if (places.length > 0) blocks.push({ kind: 'places', key: `places-${index}`, found: { ...part.data, places } });
|
||||
const found = allFound(message.parts);
|
||||
const places = found.places.filter((place) => !proposed(place, effects));
|
||||
if (places.length > 0) blocks.push({ kind: 'places', key: `places-${index}`, found: { ...found, places } });
|
||||
return;
|
||||
}
|
||||
if (part.type === 'data-trek-weather' && index === firstWeather) {
|
||||
|
||||
Reference in New Issue
Block a user