LocalLens
ウォークスルー

1. ドメイン型

他のすべてのモジュールが import する語彙。

src/domain.ts は、プロジェクト内で唯一、内部 import を持たない ファイルです。アプリの残り全部が共有する語彙です。

ここに置くもの

src/domain.ts
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. モジュール間で動くデータの形を 1 か所に固定する。 BrainTextChunkSearchHitChatAnswer は他のすべてのファイルが触ります。 それらを 1 か所に置くことで、3 つのモジュールがそれぞれ少しずつ違う TextChunk のイメージを持つような事態を防げます。
  2. AppError を再利用可能にする。 どのモジュールからも HTTP スタイルの ステータス付き AppError を投げることができ、サーバーはそれを そのままレスポンスにマップできます。これがないと、各レイヤーに独自の エラー型が増えていきます。

ローカルとブラウザのつなぎ目

LocalDocumentBrowserDocumentInput は意図的に分けてあります。

  • LocalDocumentchecksum を持ちます。ローカルフォルダのウォーカーが ディスクから計算できるからです。
  • BrowserDocumentInput は持ちません。ファイルピッカーから渡るのは 内容とバイト数だけで、checksum は下流のファイルアダプタが計算します。

この 2 つの型を分けておくことで、ワークフローは最後のステップに至るまで 「この brain はディスクから来た」「この brain はブラウザのアップロード から来た」を区別する必要がありません。

Citation はスコアを持ち、SearchHit は本文を持つ

SearchHit extends Citation という関係です。この分割が効きます。

  • SearchHitragSearch が返すものです。プロンプトビルダーがチャンク 本文を必要とするので、本文が含まれます。
  • Citation は呼び出し元に返すものです。チャンク本文は意図的に落として います。呼び出し元はソースをそのまま描画する必要はなく、リンクできれば 十分です。

小さなパターンですが、これでチャンクのテキストが HTTP レスポンスに 漏れることを防げます。

動かせるもの

domain.ts だけを書いた段階で次を実行できます。

bun run typecheck

これは通ります。他のファイルはまだ存在しないのでコンパイル対象が ありませんが、ドメインファイル単体ではエラーがありません。

次はチャンク化と根拠付きプロンプトです。 ここで定義した型を import し、実際に使い始めます。

On this page