Joel Stevick

Appendix B · section 28 of 32

ask/ask.ts

From Failing Closed.

import { referenceOf } from "./answer.js";
import { livePipeline } from "./live.js";
import { answerQuestion, type Citation } from "./pipeline.js";
import { requireApiKey } from "./setup.js";

requireApiKey();

// One line naming the sources: the manual once with its pages, a code
// section once however many subsections were cited, a schedule once by its
// title, and the earliest as-of date -- only when every citation has one.
function sourcesLine(citations: Citation[]): string {
  const names: string[] = [];
  const pages: string[] = [];
  for (const citation of citations) {
    const reference = referenceOf(citation.location);
    if (citation.kind === undefined) {
      pages.push(reference.replace(/\s*\(printed\)$/, ""));
      continue;
    }
    const name =
      citation.kind === "statute"
        ? reference.replace(/(?:\s*[–-]?\s*\([^()]*\))+[\s–-]*$/, "")
        : reference;
    if (!names.includes(name)) names.push(name);
  }
  if (pages.length > 0) names.unshift(`Maryland driver's manual ${pages.join(", ")}`);
  const dates = citations.map((citation) => citation.asOf);
  const asOf = dates.every((date): date is string => date !== undefined) ? [...dates].sort()[0] : null;
  return `Sources: ${names.join(" · ")}${asOf === null ? "" : ` · as of ${asOf}`}`;
}

async function main(): Promise<void> {
  const question = process.argv.slice(2).join(" ");
  if (question.length === 0) {
    console.error('usage: tsx ask/ask.ts "<question>"');
    process.exit(1);
  }
  const { body, outcome } = await answerQuestion(question, [], await livePipeline());
  if (body.id === "answer") {
    console.log(body.answer);
    console.log(sourcesLine(body.citations));
  } else {
    console.log(body.pointer);
  }
  console.log(`\n[${outcome.model}]`);
}

main().catch((error: unknown) => {
  console.error(error instanceof Error ? error.message : String(error));
  process.exit(1);
});