ウォークスルー
1. ドメイン型
他のすべてのモジュールが import する語彙。
src/domain.ts は、プロジェクト内で唯一、内部 import を持たない
ファイルです。アプリの残り全部が共有する語彙です。
ここに置くもの
export type Brain = {
id: string;
name: string;
folderPath: string;
workspace: string;
status: "indexing" | "indexed" | "error";
fileCount: number;
chunkCount: number;
createdAt: string;
updatedAt: string;
lastIndexedAt?: string;
lastError?: string;
};
export type LocalDocument = {
relativePath: string;
content: string;
checksum: string;
bytes: number;
};
export type BrowserDocumentInput = {
relativePath: string;
content: string;
bytes: number;
};
export type TextChunk = {
id: string;
brainId: string;
relativePath: string;
chunkIndex: number;
content: string;
checksum: string;
};
export type ChatMessage = {
role: "user" | "assistant" | "system";
content: string;
};
export type Citation = {
id: string;
relativePath: string;
chunkIndex: number;
score?: number;
};
export type SearchHit = Citation & { content: string };
export type ChatAnswer = { answer: string; citations: Citation[] };
export type CreateBrainFromFilesInput = {
name: string;
folderName: string;
documents: BrowserDocumentInput[];
};
export type CreateBrainFromFolderInput = {
name: string;
folderPath: string;
};
export class AppError extends Error {
constructor(
message: string,
readonly status = 400,
) {
super(message);
this.name = "AppError";
}
}このファイルが存在する理由
理由は 2 つです。
- モジュール間で動くデータの形を 1 か所に固定する。
Brain、TextChunk、SearchHit、ChatAnswerは他のすべてのファイルが触ります。 それらを 1 か所に置くことで、3 つのモジュールがそれぞれ少しずつ違うTextChunkのイメージを持つような事態を防げます。 AppErrorを再利用可能にする。 どのモジュールからも HTTP スタイルの ステータス付きAppErrorを投げることができ、サーバーはそれを そのままレスポンスにマップできます。これがないと、各レイヤーに独自の エラー型が増えていきます。
ローカルとブラウザのつなぎ目
LocalDocument と BrowserDocumentInput は意図的に分けてあります。
LocalDocumentはchecksumを持ちます。ローカルフォルダのウォーカーが ディスクから計算できるからです。BrowserDocumentInputは持ちません。ファイルピッカーから渡るのは 内容とバイト数だけで、checksum は下流のファイルアダプタが計算します。
この 2 つの型を分けておくことで、ワークフローは最後のステップに至るまで 「この brain はディスクから来た」「この brain はブラウザのアップロード から来た」を区別する必要がありません。
Citation はスコアを持ち、SearchHit は本文を持つ
SearchHit extends Citation という関係です。この分割が効きます。
SearchHitはragSearchが返すものです。プロンプトビルダーがチャンク 本文を必要とするので、本文が含まれます。Citationは呼び出し元に返すものです。チャンク本文は意図的に落として います。呼び出し元はソースをそのまま描画する必要はなく、リンクできれば 十分です。
小さなパターンですが、これでチャンクのテキストが HTTP レスポンスに 漏れることを防げます。
動かせるもの
domain.ts だけを書いた段階で次を実行できます。
bun run typecheckこれは通ります。他のファイルはまだ存在しないのでコンパイル対象が ありませんが、ドメインファイル単体ではエラーがありません。
次はチャンク化と根拠付きプロンプトです。 ここで定義した型を import し、実際に使い始めます。