"use client" // The search form: one question, cited answers. The disclosure the EU AI Act Article 50 asks for // rides with the results, and every answer names its source and chunk — a person checks a passage // against the file, never a model's word. import { formatMessage } from "@conusai-kit/i18n/format" import { AiDisclosureBadge, type ProjectSlugs } from "@conusai-kit/ui" import { useDataClient } from "@conusai-kit/ui/data" import { FormLayout, type FormValues, PageSection, TextField } from "@conusai-kit/ui/patterns" import { Alert, AlertDescription } from "@conusai-kit/ui/primitives" import { type ReactElement, useState } from "react" import type { SearchResult } from "../contract/index.js" import { type RefusalNotice, refusalOf, type SearchFormLabels } from "./labels.js" export function SearchForm({ slugs, collectionName, labels, locale, }: { slugs: ProjectSlugs collectionName: string labels: SearchFormLabels locale: string }): ReactElement { const client = useDataClient() const [results, setResults] = useState(null) const [refused, setRefused] = useState(undefined) const search = async ({ query = "" }: FormValues): Promise => { setResults(null) setRefused(undefined) try { const { value: answer } = await client.call<{ results: SearchResult[] }>("knowledge.search", { ...slugs, collectionName, query, }) setResults(answer.results) } catch (error) { // A refusal of the service has its own words. Anything else is FormLayout's to show. const notice = refusalOf(labels.refusals, error) if (notice === undefined) throw error setRefused(notice) } } return ( {refused ? ( {refused.text} ) : null} {results === null ? null : results.length === 0 ? (

{labels.empty}

) : (
    {results.map((result, at) => (
  1. {result.snippet}

    {labels.source}: {result.filename} · {labels.chunk.replace("{chunk}", String(result.chunk))} {result.page === undefined ? null : ` · ${labels.page.replace("{page}", String(result.page))}`} {result.blockId ? {result.blockId} : null}

  2. ))}
)}
) }