Entity disambiguation

Pro

When a name matches more than one thing ("Account" the table, the report, the record type), the agent asks which one instead of guessing. Each candidate shows its kind, API name and what sets it apart. "None of these" is always offered. Once chosen, the card shows the answer.

Markdown

Preview

Install

With the Candor CLI

First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/entity-disambiguation

Brings in: chat, entity-chip, locale, terms, utils · npm: lucide-react@^1.67.0

Usage

TSX · The example above
"use client"

import * as React from "react"
import { EntityDisambiguation, type EntityCandidate } from "@/components/entity-disambiguation"
import type { EntityRef } from "@/lib/chat"

const candidates: EntityCandidate[] = [
  { entity: { kind: "table", name: "public.orders", label: "orders" }, detail: "Table in the main database, 1.2M rows" },
  { entity: { kind: "report", name: "reports/orders-weekly", label: "Orders" }, detail: "Weekly report in the Finance folder" },
  { entity: { kind: "workflow", name: "flows.orders_sync", label: "Orders sync" }, detail: "Runs every hour on Staging" },
]

export default function Example() {
  const [chosen, setChosen] = React.useState<EntityRef | null | undefined>(undefined)
  return (
    <div className="flex max-w-lg flex-col gap-3">
      <EntityDisambiguation term="orders" candidates={candidates} onChoose={setChosen} onNone={() => setChosen(null)} chosen={chosen} />
      {chosen !== undefined && (
        <button type="button" onClick={() => setChosen(undefined)} className="self-start text-xs text-muted-foreground underline underline-offset-2">
          Ask again
        </button>
      )}
    </div>
  )
}

<EntityDisambiguation>

PropTypeDefaultDescription
termrequiredstring—What the person typed, e.g. "Account".
candidatesrequiredEntityCandidate[]—The things the term could mean, with kind, API name and what sets each apart.
onChooserequired(entity: EntityRef) => void—Called with the chosen entity.
onNone(() => void) | undefined—Shows "None of these"; called when it's picked.
chosenEntityRef | null | undefined—The settled choice, if one was made.
classNamestring | undefined—Extra classes for the outer element.

Strings

The fixed words, in English by default. Change any of them under entityDisambiguation in <LocaleProvider strings={{ … }}>; the table is exported as entityDisambiguationStrings.

KeyEnglish
means“{term}” means
noneNone of the matches for “{term}”; the agent will ask what you meant.
question{ one: "“{term}” matches {count} thing in the {environment}. Which one?", other: "“{term}” matches {count} things in the {environment}. Which one?", }
noneOfTheseNone of these

Types

EntityCandidate
{ entity: EntityRef /** What tells it apart: "Standard object, 18,240 records", "Report in Sales folder". */ detail: string }