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);
});