AI Elements

Sources

Displays the links the agent used for a reply.

How do I start an Astro project with pnpm?

Run pnpm create astro@latest and follow the prompts. It scaffolds the project and installs the dependencies.

Sources is a line that lists the links the agent used for a reply. It says how many there are, like "Used 3 sources", and opens into a link for each one.

Sources is built with UiTrace with a UiTraceCollapsible for the list.

Installation

Sources is built with the Trace component.

Usage

<template>
  <UiTrace>
    <UiTraceCollapsible>
      <UiTraceCollapsibleTrigger>
        <UiTraceLine>
          <UiTraceIcon>
            <UiIcon name="lucide:globe" />
          </UiTraceIcon>
          <UiTraceTitle>Used {{ sources.length }} sources</UiTraceTitle>
        </UiTraceLine>
      </UiTraceCollapsibleTrigger>
      <UiTraceCollapsibleContent>
        <UiTrace>
          <a
            v-for="source in sources"
            :key="source.url"
            :href="source.url"
            target="_blank"
            rel="noreferrer"
          >
            <UiTraceLine>
              <UiTraceIcon>
                <UiIcon name="lucide:globe" />
              </UiTraceIcon>
              <UiTraceTitle>
                {{ source.title ?? getHostname(source.url) }}
                <span class="sr-only"> (opens in a new tab)</span>
              </UiTraceTitle>
              <UiTraceIcon>
                <UiIcon name="lucide:arrow-up-right" />
              </UiTraceIcon>
            </UiTraceLine>
          </a>
        </UiTrace>
      </UiTraceCollapsibleContent>
    </UiTraceCollapsible>
  </UiTrace>
</template>

<script lang="ts" setup>
  function getHostname(url: string) {
    return new URL(url).hostname;
  }
</script>

AI SDK

Collect the source-url parts of a message and render them after the text. The agent can cite the same page more than once, so dedupe them by url.

const sources = computed(() =>
  props.message.parts
    .filter((part) => part.type === "source-url")
    .filter((part, index, all) => all.findIndex((other) => other.url === part.url) === index)
);

title is optional on a source-url part. Fall back to the hostname of the URL.

Accessibility

Each source is a plain link inside the list.

  • Links open in a new tab. Add sr-only text, like "(opens in a new tab)", so screen readers announce it.
  • The arrow icon is decorative. The title is the name of the link.
  • The count in the trigger, like "Used 3 sources", tells the person what opens before they open it.

API Reference

See Trace.