mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-24 16:03:02 +00:00
d07b8ba56e
- Web search: ChatGPT (Responses web_search), Anthropic (web_search server
tool) and OpenRouter (web plugin) search the web themselves when the admin
switch allows it (on as it ships). A search shows as a step ("Searching the
web for ..."), the cited pages as source chips under the answer. Anthropic
answers that searched are replayed with their blocks (new provider state
adapter); the search step never goes back to the model as a call. The
prompt says when to search and that chosen places still go through
search_place.
- Tour writes: assign_tour_track (undo: take that assignment off),
unassign_tour_track, set_tour_activity_excluded (undo: the other switch),
link_tour_packing and unlink_tour_packing (undo from the link before, which
both answers now name) get change cards and their ways back.
49 lines
2.0 KiB
TypeScript
49 lines
2.0 KiB
TypeScript
import type { AssistantSources as Sources } from '@trek/shared';
|
|
import { Globe } from 'lucide-react';
|
|
|
|
import { useTranslation } from '../../i18n';
|
|
|
|
/** A page's host without "www.", as the chip names it; the whole address where it does not read as one. */
|
|
function hostOf(url: string): string {
|
|
try {
|
|
return new URL(url).hostname.replace(/^www\./, '');
|
|
} catch {
|
|
return url;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The pages an answer drew on from the provider's web search, under its text:
|
|
* a row of quiet chips with each page's site and title, opening in a new tab.
|
|
* No page's icon is loaded, so showing the sources asks no site for anything.
|
|
*/
|
|
export default function AssistantSources({ sources }: { sources: Sources['sources'] }) {
|
|
const { t } = useTranslation();
|
|
return (
|
|
<nav aria-label={t('assistant.sources.title')} className="flex flex-col gap-1.5">
|
|
<span className="font-geist text-caption font-bold uppercase tracking-[.08em] text-content-faint">
|
|
{t('assistant.sources.title')}
|
|
</span>
|
|
<ul className="m-0 flex list-none flex-wrap gap-1.5 p-0">
|
|
{sources.map((source) => (
|
|
<li key={source.url} className="min-w-0 max-w-full">
|
|
<a
|
|
href={source.url}
|
|
target="_blank"
|
|
rel="noopener noreferrer nofollow"
|
|
title={source.title}
|
|
className="flex min-w-0 max-w-[16rem] items-center gap-1.5 rounded-full border border-edge-faint bg-surface-secondary px-2.5 py-1 text-caption text-content-secondary no-underline transition-colors hover:bg-surface-hover hover:text-content"
|
|
>
|
|
<Globe size={11} strokeWidth={2.2} aria-hidden="true" className="flex-none text-content-faint" />
|
|
<span className="flex-none font-medium">{hostOf(source.url)}</span>
|
|
{source.title && source.title !== source.url && (
|
|
<bdi className="min-w-0 truncate text-content-muted">{source.title}</bdi>
|
|
)}
|
|
</a>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</nav>
|
|
);
|
|
}
|