内製AIエージェントアーキテクチャ
アプリ内蔵エージェントのアーキテクチャと設計概要
12. 内製AIエージェントアーキテクチャ (Internal AI Agent)
1. 概要
このドキュメントは、BluePeriodアプリ内に組み込まれた**「内製エージェント(Integrated Agent)」**のアーキテクチャについて説明します。 BluePeriodのチャット機能は、単発の「プロンプトエンジン」に加え、LangGraph.jsを用いた「自律型エージェント」モードをサポートしています。エージェントモードでは、AIはツール(Web検索、プロジェクトデータ参照等)を自律的に使用して、ユーザーの質問に回答します。
※ 外部エージェント(Claude Code等)と連携するためのMCP(Model Context Protocol)アーキテクチャについては、19_mcp_architecture.md を参照してください。
2. アーキテクチャ設計
2.1. Client-Side LangGraph
BluePeriodはLocal-First(IndexedDB主体)のアプリであるため、エージェントの頭脳(LangGraph)はクライアントサイド(ブラウザ内)で実行します。これにより、エージェントはローカルのプロジェクトデータに遅延なくアクセスでき、セキュリティとレスポンス性を両立します。
2.2. Session Artifacts(資料管理)
Session Artifactsは、エージェントがツール実行によって得た情報を「机の上の資料」として管理する仕組みです。これは、単なるキャッシュではなく、ユーザーとAIが共有し、目に見える形でコンテキストを管理するための機能です。
2.2.1. 設計哲学
「静謐なアトリエ(09_design_system)」の哲学に基づき、Artifactsは以下の特徴を持ちます:
- 透明性: AIが得た情報は隠蔽されず、ユーザーがいつでも確認できる
- コントロール: ユーザーはどの資料をコンテキストとして使用するか選択できる(
isActiveトグル) - 再利用性: 一度検索した結果を再利用し、再検索コスト(APIコール・トークン)を削減
- セッション限定: 資料は現在のセッションに紐付けられ、他のセッションには影響しない
2.2.2. データ構造
// Dexie.js Version 20 で定義されるテーブル
interface SessionArtifact {
id: string; // UUID
sessionId: string; // 紐付くチャットセッション
type: ArtifactType; // 'web_search' | 'project_data' | 'text'
title: string; // 例: "Search: Claude Opus 4.5"
content: string; // 検索結果やデータの内容
isActive: boolean; // コンテキスト注入のON/OFF
createdAt: number; // タイムスタンプ
updatedAt: number; // 更新タイムスタンプ
}2.2.3. ライフサイクル
2.3. ReActパターンとグラフ構造
エージェントは ReAct (Reason + Act) パターンを採用し、Router Patternによる分岐構造を持っています。
2.3.1. Router Pattern(分岐パターン)
「雑談(chat)」と「調査・執筆支援」を分類し、適切な処理ルートに振り分けます。
問題: 単一のReActパターンで全てを処理すると、挨拶などの雑談でもツールを使おうとする「過剰反応」が発生します。
解決: Router Nodeを導入し、役割分担を行います。
注: 2026-03-29にGraph設計リファクタリングを実施。
firstResponse/finalResponseノードを削除し、direct_research/first_response_then_research戦略をgeneral_agentに統合した。詳細は 2026-03-29_1600_report_agent-graph-refactoring を参照。
2.3.2. ノード詳細
| ノード | 役割 | 使用モデル | 実装ファイル |
|---|---|---|---|
router | 雑談/一般調査/執筆戦略を分類(3択) | SubModel(軽量) | nodes/routerNode.ts |
simpleChat | ツールを使わないシンプルな会話 | MainModel | nodes/simpleChatNode.ts |
agent | 一般調査・クリエイティブタスク。軽量ツールセット | MainModel | assistantGraph.ts |
writingAgent | 執筆・プロット操作に特化。フルツールセット | MainModel | assistantGraph.ts |
rethink | ツール未使用時の再考を促すガード | - | assistantGraph.ts |
searchOptimizer | Web検索クエリを最適化 | SubModel | nodes/searchOptimizerNode.ts |
tools | 実際のツールを実行するLangChain ToolNode | - | (標準コンポーネント) |
memoryJudge | 記憶すべきかを判定 | SubModel | nodes/memoryNodes.ts |
memoryRefiner | 記憶を要約・タグ付けして保存 | SubModel | nodes/memoryNodes.ts |
2.3.3. SubModel / SubTaskModel
軽量モデル(例: Gemini Flash)を使用して、以下のユーティリティタスクを効率化します:
- Router: 入力の分類
- Search Optimizer: クエリの最適化
- Memory Judge/Refiner: 記憶の判定・精製
メリット:
- メインモデルのトークン消費量を削減
- レスポンス速度の向上
- コストの削減
設定: useSubModelAtom、subLlmProviderAtom、subModelAtom で制御。
2.3.4. フェーズ遷移
planning → researching → answering → memorizing → idle
↓ ↓ ↓ ↓
(思考) (ツール実行) (回答生成) (記憶判定)- planning: ユーザーの質問を分析し、必要なツールを決定
- researching: ツールを実行し、結果を取得
2.4. 思考のストリーミング (Thought Streaming)
エージェントは「思考プロセス」をリアルタイムでメインストリームに出力し、ユーザーに透明性を提供します。
2.4.1. メインストリーム統合
旧来の「サンドイッチ構造」(FirstResponse → ThoughtLog → FinalResponse)を廃止し、エージェントの全出力(思考、ツール実行、回答)を単一の content に統合しました。
ツール呼び出しはMarkdownのセマンティック・コードブロックとして content に埋め込まれます:
| ブロック種別 | ツール | UI表現 |
|---|---|---|
```thought``` | record_thought | Reasoning アコーディオン(折りたたみ) |
```plan``` | plan_task | Execution Plan カード(常時展開) |
```progress``` | report_progress | Progress ピル(パルスアニメ付き) |
```call``` | 技術ツール全般 | Tool Executed ピル(アイコン付き) |
| 直接テキスト | response / 生テキスト | メイン回答(Markdown) |
2.4.2. セマンティック・レンダリング
MarkdownRenderer.tsx が特殊コードブロックを検知し、専用のUIコンポーネントに変換して表示します。ChatMessageCard.tsx は単一の MarkdownRenderer に message.content を渡すだけで済むようになりました。
2.4.3. ツールセットの分離
エージェントの用途に応じてツールセットを分離しています:
| ツール | general_agent | writingAgent |
|---|---|---|
| Web検索, 時刻, 進捗, URL | ○ | ○ |
| record_thought, plan_task, response | ○ | ○ |
| finish_task, memory_tools | ○ | ○ |
| artifact_tools | ○ | × |
| editorial/writing tools | × | ○ |
歴史的経緯: 2026-03-27〜29にかけて、サンドイッチ構造を廃止し「思考のストリーミング」モデルに移行した。旧来の
firstResponse/finalResponseノードはグラフから削除され、direct_research/first_response_then_research戦略はgeneral_agentに統合された。
3. ディレクトリ構成
src/
├── ai/
│ └── agents/
│ ├── assistantGraph.ts # LangGraphグラフ定義
│ ├── state.ts # エージェント状態型定義(routingDecision含む)
│ ├── nodes/
│ │ ├── memoryNodes.ts # メモリ判定/精製ノード
│ │ ├── searchOptimizerNode.ts # 検索クエリ最適化ノード
│ │ ├── routerNode.ts # Router(雑談/調査分類)ノード
│ │ └── simpleChatNode.ts # シンプルチャットノード
│ ├── utils/
│ │ ├── proxyModel.ts # /api/chat と連携するプロキシモデル
│ │ ├── artifactWrapper.ts # ツール結果をArtifactとして保存するラッパー
│ │ └── normalizeMessages.ts # メッセージの正規化ロジック (formatters.ts 参照)
│ └── tools/
│ ├── webSearchTool.ts # Web検索ツール
│ ├── (removed) projectReaderTool.ts # Standardized tools relocated to features/
│ ├── artifactEditorTool.ts # Artifact編集ツール(AIによるメモ作成・編集)
│ ├── openUrlTool.ts # URLオープンツール(HTML→Markdown)
│ ├── recordThoughtTool.ts # 思考記録ツール(段階的処理)
│ ├── currentTimeTool.ts # 現在時刻取得ツール
│ ├── reportProgressTool.ts # 進捗報告ツール
│ └── memoryTools.ts # メモリ操作ツール群
├── lib/
│ └── features/
│ ├── projects/
│ │ └── tools.ts # 標準プロジェクトツール (blueperiod_get_project等)
│ └── editorial/
│ └── tools/
│ ├── manuscript-tools.ts # 標準原稿ツール (blueperiod_apply_adit_edits等)
│ └── plot-tools.ts # 標準プロットツール (blueperiod_edit_plot_item等)
└── lib/
└── adit/ # Adit編集ライブラリ
├── core.ts # Aditクラス本体(ハイブリッド制御)
├── parser.ts # SEARCH/REPLACEブロックのパース
├── engine.ts # 置換実行エンジン(Progressive Matching実装)
└── schema.ts # 内部データ構造・Zodスキーマの定義
└── stores/
└── chat/
├── agent.ts # エージェント用Atoms
└── atoms.ts # chatAbortControllerAtom等4. グラフ定義 (assistantGraph.ts)
4.1. AgentState
エージェントの状態を表す型定義です。UIでの進捗表示やコンテキスト管理に使用されます。
interface AgentState {
messages: BaseMessage[];
currentPhase: 'idle' | 'planning' | 'researching' | 'answering' | 'memorizing';
activeTool: string | null;
routingDecision: 'chat' | 'research' | 'writing' | null; // Routerの判定結果
strategy: 'chat_only' | 'general_agent' | 'writing' | null; // 戦略(3択に簡素化)
latestNodeName: string | null; // 現在実行中のノード名
loopCount: number; // 再考ループのカウント
}4.4. 履歴の再構築とコンテキストの維持 (Context Consistency)
エージェントモードと通常チャットモード(Agent: OFF)の間で文脈を共有するため、メッセージ履歴をLLMに渡す際に以下の処理を行います。
思考ログの埋め込み (formatMessageWithThoughts)
エージェントが実行した内部的な思考やツール呼び出しの記録(thoughtLog)を、次ターンのコンテキストとしてLLMに提示します。
- 実装:
src/lib/chat/formatters.ts - 内容:
[THOUGHT]: AIの思考、分析過程[ACTION]: 実行したツール名と引数
- コンテキスト最適化(重要):
- トークン爆発を防ぐため、
blueperiod_apply_artifact_adit、blueperiod_apply_manuscript_aditなどのaditOutputフィールドなどの巨大な引数は、formatMessageWithThoughts内で文字数サマリー(例:Content summarized: 20000 chars)に置換されます。 - その他の長大な文字列も一定長で切り詰められます。
- トークン爆発を防ぐため、
- メリット: AIは「何のアクションをしたか」という要約を履歴として持ちつつ、巨大なコンテンツ自体は Artifact という外部メモリにパージされた状態を維持できます。
- 適用範囲:
agent.ts(エージェント実行時)およびactions.ts(通常チャット送信時)の両方で適用。
4.2. ノード定義
| ノード | 役割 |
|---|---|
router | ユーザー入力を「雑談」「一般調査」「執筆支援」の3択に分類 |
simpleChat | ツールを使わないシンプルな会話処理 |
agent | 一般調査エージェント(軽量ツールセット + artifact_tools) |
writingAgent | 執筆エージェント(フルツールセット + editorial tools) |
rethink | ツール未使用時に再考を促すガードノード |
tools | ToolNode(LangChain付属)を使用し、実際のツールを実行 |
4.3. エッジ定義
| エッジ | 条件 |
|---|---|
__start__ → router | 常にRouterへ |
router → simpleChat | 戦略が chat_only の場合 |
router → agent | 戦略が general_agent の場合 |
router → writingAgent | 戦略が writing の場合 |
simpleChat → memoryJudge | メモリ有効時 |
simpleChat → END | メモリ無効時 |
agent → searchOptimizer | web_search ツール使用時 |
agent → tools | その他のツール使用時 |
agent → rethink | ツール未使用・回答未完了時 |
agent → memoryJudge | finish_task 完了、メモリ有効時 |
agent → END | finish_task 完了、メモリ無効時 |
writingAgent → tools | 執筆ツールの使用時 |
writingAgent → memoryJudge | finish_task 完了、メモリ有効時 |
writingAgent → END | finish_task 完了、メモリ無効時 |
tools → agent | general_agent 実行中 |
tools → writingAgent | writing 実行中 |
searchOptimizer → tools | 常に(最適化後にツール実行) |
5. Session Artifactsの仕組み
5.1. Artifact Wrapper(ツール結果の自動保存)
全てのエージェントツールは createArtifactTool() でラップされ、実行結果が自動的にArtifactとして保存されます。
実装: next-app/src/ai/agents/utils/artifactWrapper.ts
export function createArtifactTool(
tool: StructuredTool,
type: ArtifactType, // 'web_search' | 'project_data' | 'text'
sessionId?: string,
options: { shouldPersist?: boolean } = { shouldPersist: true }
): StructuredTool特徴:
shouldPersist: falseのツール(current_time,report_progress)は保存されない- タイトルの自動生成: 検索クエリやセクションIDから人間に読みやすいタイトルを作成
- エラー時のフォールバック: 保存に失敗してもツール本来の結果は返される
5.2. Context Injection(コンテキスト注入)
エージェントがLLMを呼び出す直前に、現在のセッションの「有効(isActive: true)」なArtifactsを取得し、メッセージ履歴の先頭付近に注入します。
実装場所: assistantGraph.ts の agentNode
5.2.1. インデックス化とスニペット(Snippet-based Injection)
トークン消費量を節約し、コンテキストウィンドウの鮮度を保つため、Artifactの内容を全文注入するのではなく、インデックス(目次)とスニペットのみを提示する「疎結合な注入」を採用しています。
// assistantGraph.ts 内の注入ロジック(簡略化)
const artifacts = await db.sessionArtifacts
.where('sessionId').equals(config.sessionId)
.filter(a => a.isActive) // ユーザーがONにしているもののみ
.toArray();
const artifactsText = `
## Session Context (Artifacts Index)
Below is a list of artifacts available in your workspace.
IMPORTANT: To save tokens, only SNIPPETS are shown here.
If you need to see or edit the FULL content of an artifact, you MUST call 'blueperiod_get_artifact' first.
${artifacts.map(a => `### [ID: ${a.id}] ${a.title}\nSnippet: ${a.content.substring(0, 300)}...`).join("\n\n")}
`;5.2.2. 特徴とメリット
- isActive トグル: ユーザーはUI上の各Artifactカードにあるトグルを操作することで、特定の情報をAIの文脈に含めるかどうかを動的に制御できます。
- オンデマンド読込: AIはスニペットを見て「この資料の全貌が必要だ」と判断した際、
blueperiod_get_artifactツールを使用して自律的に全文を取得します。 - 履歴の汚染防止: 一度読み取られた全文は、そのターンの推論に使用された後、次ターンの履歴からは再びサマリー化(#4.4.-履歴の再構築とコンテキストの維持-(Context-Consistency)参照)されるため、コンテキストが肥大化しません。
5.2.3. 通常チャット(Agent: OFF)での動作
エージェントモードが OFF の場合でも、isActive: true な Artifacts はコンテキストに注入されます。ただし、通常モードの AI は read ツールを持っていないため、スニペットではなく 全文(Full Content) が注入されます。これにより、エージェントが作成した成果物をベースに、通常の会話でフィードバックをもらったり、要約させたりすることが可能になります。
5.3. システムステータスの知覚 (System Status Awareness)
AI が現在の実行環境や能力を正しく把握(メタ認知)できるよう、リクエストごとに以下のステータス情報を注入しています。
- 注入場所:
assistantGraph.ts(Agent) およびactions.ts(Normal Chat) - 内容:
- Agent Mode: 現在の会話がエージェント(ツール使用可能)モードか、通常モードか。
- Long-term Memory: 長期記憶(過去の会話からの事実抽出)が有効か。
これにより、AI は「現在はエージェントモードではないため、Web 検索を実行できません」といった正確な自己説明を行うことができ、ユーザーとの期待値調整がスムーズになります。
5.4. UIコンポーネント
ArtifactCard (next-app/src/components/ArtifactCard.tsx):
- 資料の表示カード(プロンプトカード風のデザイン)
isActiveトグルでコンテキスト注入のON/OFF- 削除ボタンで資料を削除
- コンテンツの展開/折りたたみ(長いテキスト対応)
ArtifactsList (next-app/src/components/ArtifactsList.tsx):
- 現在のセッションの資料一覧を表示
- Dexie LiveQuery でリアルタイム更新
useLiveQueryによる自動再フェッチ
ChatView統合:
- ヘッダーに「📑 (Files)」ボタンを追加
- サイドパネル形式でArtifacts一覧を表示
- システムプロンプトカードと同様のデザイン言語で統一
6. エージェンツール
6.1. Web検索ツール (webSearchTool)
役割: Tavily Search APIを使用して、最新のWeb情報を取得します。
実装: /api/tools/web-search APIエンドポイントを呼び出し、結果をJSONで返します。
createWebSearchTool(userApiKeys.tavily)設定: tavilyApiKeyAtom(src/stores/settingsAtoms.ts)でAPIキーを管理。
特徴:
search_depth: "advanced"で高精度な検索を実行searchOptimizerNodeによりクエリが最適化される
6.2. プロジェクト参照ツール (Standardized Project Tools)
役割: 現在のプロジェクトのメタデータ、アウトライン、設定、原稿を IndexedDB から取得します。
実装: src/lib/features/projects/tools.ts
| ツール名 | 役割 | 特徴 |
|---|---|---|
blueperiod_get_project | プロジェクト全般の取得 | パフォーマンス最適化: 原稿本文を除いた軽量データを返します。 |
blueperiod_get_metadata | メタデータのみ取得 | タイトル、著者、言語設定、文字数統計など。 |
blueperiod_get_outline | プロットの階層構造を取得 | Markdownのツリー形式で階層構造(Part/Arc/Chapter等)を提示。 |
blueperiod_list_projects | プロジェクト一覧を取得 | IDの発見や切り替えに使用。 |
6.3. プロット&原稿操作ツール (Editorial Tools)
役割: 本文の編集やプロットの構造変更を行います。
実装: src/lib/features/editorial/tools/
| ツール名 | 役割 | 編集方式 |
|---|---|---|
blueperiod_get_raw_manuscript | 指定セクションの本文取得 | Reader (Pure Text) |
blueperiod_apply_adit_edits | Adit形式による精密編集 | Writer (Search/Replace JSON) |
blueperiod_apply_adit_delimiter | デリミタ形式による一括編集 | Writer (SEARCH/REPLACE blocks) |
blueperiod_overwrite_manuscript | 本文の完全上書き | Writer (Full Text) |
blueperiod_edit_plot_item | プロット項目の属性編集 | Writer (Metadata) |
blueperiod_add_plot_structure | プロット項目の新規追加 | Writer (Structural) |
blueperiod_get_plot_context | 項目周辺の文脈取得 | Reader (Hierarchy) |
6.3. メモリツール (memoryTools)
役割: 長期記憶(Orama)への検索・取得を行います。
実装: next-app/src/ai/agents/tools/memoryTools.ts
6.3.1. list_memory_dates
記憶が存在する日付の一覧を取得します。
// 使用例
const dates = await getAllMemoryDates(activeCharacterId);
// ["2026-01-20", "2026-01-21", "2026-01-26"]用途: エージェントが「どの期間に情報があるか」を把握するために使用します。
6.3.2. read_memories_by_date
特定の日付または日付範囲の記憶を取得します。
// 使用例
read_memories_by_date({
startDate: "2026-01-20", // 必須
endDate: "2026-01-26" // 任意(省略時はstartDateのみ)
});Multi-hop Retrieval の実装:
- ユーザーが「あの時の話」と曖昧に言及
- エージェントが
list_memory_datesで日付の一覧を取得 read_memories_by_dateで該当期間の記憶を読み取り- Semantic Search で特定のエピソードを特定
6.4. 補助ツール
6.4.1. current_time
現在時刻を取得します。shouldPersist: false でArtifactに保存されません。
// 出力例
"2026年1月27日 月曜日 16:30 JST"6.4.2. report_progress
エージェントが作業状況をユーザーに報告するために使用します。shouldPersist: false でArtifactに保存されません。
// 使用例
report_progress({ message: "承知しました、〇〇について調べます" })6.5. Artifact Editor Tool (artifactEditorTool)
役割: AIがSession Artifact(メモ・資料)を自律的に作成・編集・削除するためのツールです。
実装: next-app/src/ai/agents/tools/artifactEditorTool.ts
アクション:
| アクション | 説明 |
|---|---|
create | 新しいメモを作成 |
edit | Adit(AI編集ライブラリ)を使用して部分編集 |
overwrite | 内容を完全に置換(翻訳・要約等に使用) |
delete | メモを削除 |
list | セッション内の全メモを一覧表示 |
Adit連携:
editアクションでは、決定論的なテキスト編集ライブラリ「Adit Hybrid」を使用。- Dual Engine: 高性能モデルには
Structured Output(JSON) を使用し、軽量モデルやエラー発生時にはSEARCH/REPLACEブロック形式に自動フォールバックします。 - Progressive Matching: インデントや空白の差異を許容し、段階的に緩和しながら編集箇所を特定。
- Indentation Preservation: 編集箇所の周囲からインデントを自動取得し、置換後コードに反映。
- 詳細は「## 9. Adit編集ライブラリ」を参照。
Fuzzy ID Resolution:
- ArtifactIDだけでなくタイトルでも検索可能
- 同名のArtifactがある場合は最初の1件を取得
6.6. Open URL Tool (openUrlTool)
役割: ユーザーが提供したURLのコンテンツを取得し、Markdownとして解析します。
実装: next-app/src/ai/agents/tools/openUrlTool.ts
APIエンドポイント: /api/tools/open-url
使用ライブラリ:
- cheerio: HTMLパースと不要要素の削除(script, style, nav等)
- turndown: HTMLからMarkdownへの変換
処理フロー:
- ユーザーがURLを提供(またはエージェントが検索結果からURLを取得)
- サーバーサイドでHTMLをフェッチ(User-Agent設定済み)
- 不要な要素を削除
- Markdownに変換して返却
- 結果は自動的にArtifactとして保存
制限:
- JavaScriptレンダリングが必要なページは取得できない
- CORS制限のあるURLは取得できない場合がある
6.7. Record Thought Tool (recordThoughtTool)
役割: エージェントが短い内省や独り言を記録する軽量ツール。
実装: next-app/src/ai/agents/tools/recordThoughtTool.ts
パラメータ:
| パラメータ | 説明 |
|---|---|
thought | 思考内容(必須、単一フィールド) |
UI表示: ```thought``` ブロックとしてメインストリームに埋め込まれ、Reasoning アコーディオンとして折りたたまれる。
特徴:
- DBには保存されず、チャットのメッセージ
contentにのみ残る - リッチな構造(ステップ、フェーズ等)は
plan_taskツールに移譲 - 短い推論や自己評価に使用
6.7b. Plan Task Tool (planTool) — 新設 (2026-03-28)
役割: エージェントがタスクの実行計画(ロードマップ)を提示するツール。record_thought の上位互換。
実装: next-app/src/ai/agents/tools/planTool.ts
パラメータ:
| パラメータ | 説明 |
|---|---|
thought | 戦略的推論・分析(必須) |
phase | 現在のフェーズ(analyzing, executing等) |
step | ステップ番号 |
step_title | ステップのタイトル |
next_step | 次に行う予定 |
UI表示: ```plan``` ブロックとしてメインストリームに埋め込まれ、Execution Plan カードとして常に展開で表示される。
6.7c. Response Tool (responseTool) — 新設 (2026-03-28)
役割: エージェントがユーザーへの「メイン回答」を明示的に送信するツール。
実装: next-app/src/ai/agents/tools/responseTool.ts
パラメータ:
| パラメータ | 説明 |
|---|---|
content | ユーザーへの回答内容(必須) |
UI表示: メインストリームに直接Markdownとして表示。record_thought が「思考」であるのに対し、response は「回答」として扱われる。
6.8. Writing Tools (writingTools)
役割: 執筆画面におけるプロット操作や原稿生成を自律的に行います。既存のJotai Atomsをツールとしてラップすることで、GUI操作と同等の品質を保証します。
実装: next-app/src/lib/features/editorial/tools/
| カテゴリ | ツール名 | 役割 | 連携Atom |
|---|---|---|---|
| Plot | get_structured_plot | 現在のプロット階層を取得 | structuredPlotAtom |
| Plot | parse_plot_to_structure | テキストを解析してプロット化 | structurePlotAtom |
| Plot | refine_plot_item | プロット項目をAIでブラッシュアップ | refinePlotItemAtom |
| Plot | add_plot_structure | 新しいプロット項目を追加 | structurePlotAtom |
| Plot | edit_plot_item | 既存のプロット項目を編集 | structurePlotAtom |
| Manuscript | generate_manuscript | 指定された節の本文を生成 | generateSectionAtom |
| Manuscript | rewrite_manuscript | 原稿の部分書き直し・推敲 | rewriteSectionAtom |
| Manuscript | translate_manuscript | 原稿の多言語翻訳 | translateSectionAtom |
特徴:
- HITL統合: 破壊的な変更(削除や大規模な書き換え)の前には、必ず
AgentConfirmationCardを通じてユーザーの承認を求めます。 - コンテキストの共有: 原稿生成時には、これまでの章の流れやプロット設定を自動的に取得してLLMに渡します。
- MCPへの対応: ツールは独立した関数として定義されており、将来的な MCP サーバー化が容易な構造になっています。
7. 専用ノード
7.1. Routerノード
ユーザー入力を「雑談」と「調査」に分類するノードです。
実装: next-app/src/ai/agents/nodes/routerNode.ts
分類基準:
| 分類 | 条件 |
|---|---|
chat | 挨拶、感情表現、雑談、一般的な知識で答えられる質問 |
general_agent | 外部情報の調査、クリエイティブなタスク、計画立案などツール使用が想定されるタスク全般 |
writing | プロット構造操作、原稿生成/編集、翻訳などプロジェクトの本文に直接触れるタスク |
プロンプト: ROUTER_SYSTEM_PROMPT
// 出力: "chat" または "research" のみ
const response = await classificationModel.invoke([
new SystemMessage(ROUTER_SYSTEM_PROMPT),
new HumanMessage(userContent)
]);使用モデル: SubModel(軽量モデル)を使用し、高速に判定します。
7.2. SimpleChatノード
ツールを使わないシンプルな会話処理を行うノードです。
実装: next-app/src/ai/agents/nodes/simpleChatNode.ts
特徴:
- ツールがバインドされていない純粋なChatModelとして動作
- 雑談に対して迅速に応答
- Memory Judgeを経由して長期記憶に保存可能
7.3. Search Optimizerノード
Web検索のクエリを最適化するノードです。
実装: next-app/src/ai/agents/nodes/searchOptimizerNode.ts
機能:
- 多言語対応: 技術用語や普遍的なトピックを英語に変換
- 地域最適化: 地域固有の情報は現地言語で検索
- クエリ結合: 複数の検索リクエストを単一の最適なクエリに統合
プロンプト: SEARCH_OPTIMIZER_PROMPT
// 出力例
{
"fix_query": "Claude Opus 4.5 release date features",
"reason": "普遍的な技術情報のため英語で検索"
}7.4. Memory Judgeノード
会話の内容が長期記憶に保存されるべきかを判定します。
実装: next-app/src/ai/agents/nodes/memoryNodes.ts
判定基準:
- ユーザーの好み(「SFが好き」など)
- プロジェクトの核心設定(「2050年の世界」など)
- ユーザーの具体的な決定
- 個人的な詳細
無視するもの:
- 挨拶や雑談
- 一時的なコンテキスト
- 単純な生成要求
7.5. Memory Refinerノード
記憶を要約・タグ付けしてOramaに保存します。
実装: next-app/src/ai/agents/nodes/memoryNodes.ts
機能:
- 会話から重要な事実を抽出
- キャラクターの視点で日記風に要約
- タグ付けで検索性を向上
7.6. Human-in-the-Loop (HITL) Integration
エージェントがファイル作成や編集などの「破壊的な操作」を行う前に、ユーザーの確認を求める仕組みです。
実装: assistantGraph.ts の hitlToolsNode および AgentToolReviewDialog コンポーネント。
対象ツール:
blueperiod_apply_artifact_adit,blueperiod_apply_artifact_delimiter,blueperiod_overwrite_artifactblueperiod_apply_manuscript_adit,blueperiod_apply_manuscript_delimiter,blueperiod_overwrite_manuscript
フロー:
- AIが
blueperiod_apply_artifact_aditなどの編集ツールを呼び出す。 - グラフが
hitlToolsNodeに到達し、ツール実行を一時停止。 - UI側で
AgentToolReviewDialogが表示され、ユーザーに「差分(Diff)」を提示。 - ユーザーが承認(Approve)すると、実際のツール実行が再開。却下(Reject)するとツール実行はキャンセルされ、エージェントに「ユーザーにより却下されました」というフィードバックが返る。
8. エージェント設定 (AgentSettingsPanel)
エージェントが使用するLLMプロバイダーやモデル、ツールごとの設定を管理します。
8.1. ツールの分類管理
ツール数の増加に伴い、以下のカテゴリで分類管理されています:
- General Capabilities: Web検索、ドキュメント編集(Artifacts)、内部思考、プロジェクト参照などの基本ツール。
- Manuscript Tools: AIによるドラフト生成、リライト、翻訳などの執筆直接支援ツール。
- Plot & Structure: プロットの構造化、リファイン、階層操作などの構成支援ツール。
8.2. Human-in-the-Loop (HITL) 設定
各ツールに対して、「使用前に承認を要求する」かどうかを個別に設定可能です。 特に「Manuscript Tools」のリライトや「Plot & Structure」の構造化など、既存のデータを上書きする可能性のある破壊的なツールについては、デフォルトで HITL が有効に設定されています。
8.3. その他の設定
- Always expand thought log: チャット内のエージェントの推論プロセスを最初から展開するかどうか。
- Artifact Full Threshold: どの程度の文字数までであれば Artifact の全文をコンテキストに直接注入するか。
- Provider/Model: ツール実行ノードで使用するメインLLMの選択。
- Search API Key: Tavily 等の検索ツール用キー。
- Adit Model: テキスト編集用の高精度モデルの個別指定。
これにより、Web検索には Gemini Flash を使い、精緻なプロット編集(Editorial Tools)には Claude 3.5 Sonnet を使うといった、タスクに応じたモデルの使い分け(Model Chaining)を柔軟に行えます。
8.1. AGENT_AUTONOMY_GUIDELINE
エージェントの自律的な動作を制御する基本指針です。
export const AGENT_AUTONOMY_GUIDELINE = `
# AGENT BEHAVIOR GUIDELINES
You are an autonomous agent capable of using tools to fulfill user requests.
Adhere to the following guidelines:
## 1. Proactive Research & Execution
- **DO NOT ASK** for permission to use tools. If you think a tool is needed, **USE IT IMMEDIATELY.**
- Instead of saying "Shall I search for...?", say "I will search for..." and **execute the 'web_search' tool in the same turn.**
- If you cannot answer a question based on your current knowledge, or if you need specific context (e.g., manuscript content), **IMMEDIATELY use tools.**
## 2. Critical Rules for Tools
- **No Hallucination:** NEVER invent project details or manuscript content. You MUST use 'read_project_data' to fetch facts.
- **Web Search:** Use 'web_search' whenever the user asks for external information, trends, or facts.
- **ID Discovery:** If you need to read a manuscript but don't have the ID, NEVER ask the user for it. First call 'read_project_data(category="outline")' or 'read_project_data(category="list")' to find the ID yourself.
...
`;定義場所: src/lib/chat/prompts.ts
8.2. SEARCH_AGENT_SYSTEM_PROMPT
ツールを使用して情報を取得した場合の「最終回答」フォーマットを統一するプロンプトです。
重要: 以下のルールは、ツールを使用して情報を取得した場合の「最終回答」にのみ適用されます。
主な指示:
- 見出し記号 (
#) の禁止、代わりに太字や引用を使用 - 出典と引用(脚注スタイル
[^1])の厳格な実施 - 情報のクロスリファレンス(3つ以上のソース)
- 雑談や単純な回答の場合は「関連する質問」を提案しない
8.4. AGENT_AUTONOMY_GUIDELINE(改善点)
進捗報告の追加:
- ツールを使用する前に
report_progressを使用して、ユーザーに作業内容を通知 - 特に
web_searchや大量データの読み取り時に並列実行
例外処理の追加:
- 雑談、挨拶、一般的な知識で答えられる質問にはツールを使用しない
8.5. ROUTER_SYSTEM_PROMPT
Routerノードで使用する分類プロンプトです。3択分類に簡素化されました。
const ROUTER_SYSTEM_PROMPT = `
You are a strategic classification assistant.
CATEGORIES:
1. "chat_only": Simple conversation, greetings, or short questions that don't need tools.
2. "general_agent": General questions requiring research, web search, or information gathering. Also for creative tasks where you want to plan and think through the process.
3. "writing": Specifically for book project management tasks (plot structure, manuscript generation/editing, project-specific metadata).
Reply ONLY with JSON:
{
"strategy": "chat_only" | "general_agent" | "writing",
"reasoning": "brief explanation"
}
`;8.6. SEARCH_OPTIMIZER_PROMPT
検索クエリの最適化を行うプロンプトです。
機能:
- 検索APIへの最適なクエリへ調整
- 多言語対応(技術用語→英語、地域情報→現地語)
- 文化的多様性への配慮
8.7. Progressive Thinking(段階的思考)
複雑なタスクを一度に回答せず、record_thought ツールを使用して段階的に進めるためのガイドラインです。
主な指示:
- 複雑なタスクは
record_thoughtでステップに分解 - 各ステップの思考と次のアクションを記録
- 自己評価と修正を行い、品質を確認してから最終回答
8.8. Context Management(コンテキスト管理)
Artifactsを使用した思考や計画の管理ガイドラインです。
主な指示:
blueperiod_apply_artifact_aditツールを使用して思考や計画を保存blueperiod_create_artifactで新規メモ、blueperiod_apply_artifact_aditで既存メモの更新- 存在しないツールの使用を禁止
9. Adit編集ライブラリ
AIによる決定論的なテキスト編集を行うためのライブラリ。
ディレクトリ: next-app/src/lib/adit/
構成:
core.ts: Aditクラス本体。Structured Outputの試行とDelimiter形式へのフォールバックをオーケストレート。parser.ts:SEARCH/REPLACEブロックの抽出。engine.ts: 置換実行エンジン。Progressive Matchingによる曖昧一致とインデント自動維持を実装。schema.ts: Zodによる出力構造と内部型定義。
APIエンドポイント: /api/tools/adit
9.1. 基本理念:ハイブリッド・アプローチ
AIモデルの能力や接続状況に応じて、最適な編集方式を選択します:
- Structured Output (Primary): GPT-4o や Claude 3.5 Sonnet 等の高性能モデル向け。Zod スキーマにより JSON 形式で「どの部分を何に変えるか」を厳密に出力させます。トークン消費が最適化されます。
- Delimiter (Secondary/Fallback):
step-3.5-flash等の軽量モデルや、API側で Structured Output が拒否された(400エラー等)場合に使用。実績のあるSEARCH/REPLACEブロック形式で入力を受け取り、独自のパサーで処理します。
9.2. 動作フロー
9.3. 高度な置換エンジンの機能
1. Progressive Matching:
- ファイル内を走査し、完全一致する箇所を探索。
- 見つからない場合、改行コードの差異、行端の空白、行全体のインデント(トリム比較)を段階的に緩和して再探索します。これにより、AIが改行コードや空白を正確に再現できなくても編集が成功します。
2. Indentation Preservation:
- 置換対象がマッチした際、その箇所の実際のインデント(タブ/スペース)を保存。
- 置換後のテキストに対し、保存したインデントを自動適用します。AIに対し「インデントを正確に守れ」と指示するストレスを解消し、コードの崩れを防止します。
3. Safety Checks:
- スニペットがファイル内でユニークでない場合、意図しない箇所の置換(誤爆)を防ぐため、エラーとして処理を中断します。
10. ProxyChatModel
エージェントグラフからLLMを呼び出すためのプロキシモデルです。
役割: LangChainのBaseChatModelインターフェースを実装し、内部的に/api/chat APIを呼び出します。
利点:
- APIキー管理をサーバーサイドに集約
- 複数のLLMプロバイダー(Google、OpenAI、Anthropic等)を透過的に切り替え
10. Tool Useの安定化
10.1. Message Injectionの改善
LangChainの制約(「System message must be first」)を回避するため、コンテキスト注入を HumanMessage として行う設計に変更しました。
ツール使用時のみ厳格フォーマット適用:
- 厳格なフォーマットルール(
SEARCH_AGENT_SYSTEM_PROMPT)は、実際にツールを使用した場合のみ適用されます - 雑談の場合は不要なフォーマット制約を回避し、自然な会話を可能にします
// ツール使用したかを判定
const hasUsedToolsRecently = messages.slice(lastHumanIndex).some(m => m instanceof ToolMessage);
// 重複注入を防ぐチェック
const isContextInjected = messages.some(m =>
m instanceof HumanMessage &&
typeof m.content === 'string' &&
m.content.includes("## Session Context (Artifacts)")
);
if (!isContextInjected) {
const partsToInject = [];
// 1. 厳格フォーマット(ツール使用時のみ)
if (hasUsedToolsRecently) {
partsToInject.push(SEARCH_AGENT_SYSTEM_PROMPT);
}
// 2. Artifacts(常に利用可能)
if (artifactsText) {
partsToInject.push(artifactsText);
}
// ...
}10.2. チャット中断機能
AbortController による実行中のエージェント処理を中断できる機能を実装しました。
実装: src/stores/chat/atoms.ts、src/stores/chat/agent.ts
// Atom定義
export const chatAbortControllerAtom = atom<AbortController | null>(null);
// 使用例
const controller = new AbortController();
set(chatAbortControllerAtom, controller);
// ストリームにsignalを渡す
const stream = await graph.stream(
{ messages: inputMessages },
{ streamMode: "values", signal: controller.signal }
);
// 中断ボタン(ChatInput.tsx)
const handleStop = (e: React.MouseEvent) => {
if (abortController) {
abortController.abort();
}
};UI: ChatInputのドロップダウンメニューに「Stop Generating」ボタンを追加。
10.3. ThoughtLogの重複排除
エージェント実行中の思考ログが重複して表示されないよう、以下のロジックを強化しました:
activeToolがある場合のログを除外- 最後の純粋なテキストコンテンツログを検索
- 同一内容のログが連続しないよう判定
10.4. APIキー取得の強化
LocalStorageからのフォールバック処理を追加し、atomWithStorage のJSON形式("key")を適切に解析するようにしました。
const getApiKey = (atomValue: string, storageKey: string) => {
if (atomValue) return atomValue;
if (typeof window !== 'undefined') {
const stored = localStorage.getItem(storageKey);
if (stored) {
try {
return JSON.parse(stored); // atomWithStorageはJSON形式で保存
} catch {
return stored;
}
}
}
return undefined;
};10.5. ツールログの循環参照防止
エージェント実行中のツールログ保存時に、巨大なデータ構造(history、content フィールド等)が含まれていると、JSON.stringify によるクラッシュや循環参照エラーが発生する可能性があります。これを防ぐためのパターンを実装しました。
実装: src/stores/chat/agent.ts
// 重複チェック用のフィンガープリント生成(重いフィールドを除外)
const getArgsFingerprint = (args: Record<string, unknown> | undefined) => {
if (!args) return '';
// history, content を除外して比較用フィンガープリントを作成
const { history, content, ...rest } = args;
return JSON.stringify(rest);
};
// ログ保存用の安全な引数を作成(循環参照リスクのあるフィールドを除外)
const { history: _h, content: _c, ...safeArgs } = (tc.args || {});
thoughtLog.push({
phase: lastPhase,
content: toolLogContent,
toolName: tc.name,
toolArgs: safeArgs, // 安全な引数のみ保存
timestamp: Date.now()
});除外すべきフィールドのガイドライン:
history: メッセージ履歴全体(巨大かつ循環参照の可能性)content: 長文テキスト(Artifactの本文等)- 原則: 「ストリーミングで再取得可能なデータ」や「別途Artifactとして保存されているデータ」はツールログから除外
10.6. LangGraph永続化のためのthread_id設定
LangGraphのチェックポイント機能を有効にするため、グラフ実行時に thread_id を設定します。これにより、セッションごとの状態永続化が可能になります。
実装: src/stores/chat/agent.ts
const stream = await graph.stream(
{ messages: inputMessages },
{
streamMode: "values",
configurable: { thread_id: activeSession.id }, // セッションIDをthread_idとして設定
signal: controller.signal,
recursionLimit: 100,
}
);効果:
- セッションごとのグラフ状態を永続化可能
- 将来的な状態復帰やチェックポイント機能の活用に対応
11. UI統合
11.1. エージェントモードの切り替え
AIChatPanel コンポーネントに「エージェントモード」トグルを配置し、isAgentModeAtom で状態を管理します。
AIChatPanel コンポーネントに「エージェントモード」トグルを配置し、isAgentModeAtom で状態を管理します。
11.2. 思考プロセスの可視化
エージェントの実行中、以下の情報をリアルタイムに表示します。
- 現在のフェーズ:
agentPhaseAtom(planning → researching → answering) - アクティブツール:
agentActiveToolAtom(web_search、read_project_data) - 思考ログ: メッセージの
metadata.thoughtLogに保存される履歴
11.3. 記憶の可視化
新規記憶(memorizedFacts)をアコーディオン形式で表示します。
11.4. Artifactsパネル
ヘッダーの「📑 (Files)」ボタンからサイドパネルを開き、現在のセッションの資料を確認できます。
11.5. HITL UIの統合
Human-in-the-Loop(HITL)機能を提供するUIコンポーネントを、AI画面(AICenterPanel)に統合しました。
実装: next-app/src/components/AICenterPanel.tsx
export function AICenterPanel() {
return (
<div className="flex flex-col h-full bg-card min-w-0 relative">
{/* ...既存のチャットUI... */}
{/* HITL UIコンポーネント */}
<AgentConfirmationCard />
<AgentStatusIndicator />
</div>
);
}コンポーネントの役割:
| コンポーネント | 役割 | 配置 |
|---|---|---|
AgentConfirmationCard | エージェントが破壊的操作を行う前にユーザーの承認を求めるカード | 画面下部(オーバーレイ) |
AgentStatusIndicator | エージェントの現在の状態(フェーズ、アクティブツール)を表示するインジケーター | 画面上部 |
AgentConfirmationCard の特徴:
- オーバーレイ配置:
absolute inset-x-0 bottom-0で画面下部に配置 - バックドロップ付き: 背景をぼかして視認性を向上
- ツール名の表示: 承認を求められているツール名を明示
- プレビュー機能: ツール引数の詳細を確認可能
AgentStatusIndicator の特徴:
- リアルタイム更新: ストリーミング中のエージェント状態を表示
- フェーズ表示: planning → researching → answering の遷移を可視化
- アクティブツール表示: 現在実行中のツール名を表示
12. 設定管理
12.1. APIキー設定
エージェント機能を使用するには、以下のAPIキーが必要です。
| 設定項目 | Atom | 用途 |
|---|---|---|
| Tavily API Key | tavilyApiKeyAtom | Web検索機能 |
| Google API Key | geminiApiKeyAtom | Geminiモデル使用時 |
| OpenAI API Key | openaiApiKeyAtom | GPTモデル使用時 |
| Anthropic API Key | anthropicApiKeyAtom | Claudeモデル使用時 |
設定場所: ApiKeysSettingsPanel コンポーネント
12.2. チャット設定
エージェントは通常のチャット設定(プロバイダー、モデル、温度)を共有します。
chatLlmProviderAtom: 使用するLLMプロバイダーchatModelAtom: 使用するモデルchatTemperatureAtom: 生成の温度パラメータ
13. 実装状況
Phase 1: Assistant Agent (Chat) - 完了
- LangGraph.jsの導入
- ProxyChatModelの実装
- Web検索ツールの実装(Tavily連携)
- プロジェクトデータ参照ツールの実装
- エージェントモードのUI統合
- 思考プロセスの可視化
- Session Artifactsの実装 (2026-01-27)
-
sessionArtifactsテーブルの追加(Dexie Version 20) -
artifactWrapper.tsによる自動保存 - Context Injectionロジックの実装
- UIコンポーネント(ArtifactCard、ArtifactsList)
- ツールの保存制御(
shouldPersistオプション)
-
- メモリツールの実装 (2026-01-27)
-
list_memory_dates: 記憶が存在する日付の一覧取得 -
read_memories_by_date: 特定日付範囲の記憶取得 - Multi-hop Retrieval の実装
-
- Memory Nodesの実装 (2026-01-27)
-
memoryJudgeNode: 記憶判定ロジック -
memoryRefinerNode: 記憶の要約・タグ付け
-
- Router Nodeの実装 (2026-01-27)
-
routerNode.ts: 雑談/調査の分類 -
simpleChatNode.ts: ツールなしのシンプルチャット
-
- SubModel/SubTaskModel (2026-01-27)
- Router、Search Optimizer、Memory処理に軽量モデルを使用
-
useSubModelAtom、subLlmProviderAtom、subModelAtomによる制御
Phase 1.5: 機能強化 - 完了
- Web検索のBYOK(Bring Your Own Key)設定UI
- Web検索プロンプトの改善 (2026-01-27)
-
SEARCH_AGENT_SYSTEM_PROMPTによる回答フォーマットの統一 - ツール使用時のみ厳格フォーマットを適用
-
SEARCH_OPTIMIZER_PROMPTによる検索クエリ最適化 -
searchOptimizerNodeの実装 -
report_progressツールによる進捗報告 -
current_timeツールによる日時認識
-
- プロジェクトリーダーの詳細データ取得対応
- Tool Useの安定化 (2026-01-27)
- Message Injectionの改善
- ThoughtLogの重複排除
- APIキー取得の強化
- チャット中断機能 (2026-01-27)
-
AbortControllerによる実行中断 -
chatAbortControllerAtomの実装 - ChatInputに「Stop Generating」ボタンを追加
- ProxyChatModelにsignal対応
-
- LongTerm Memory制御 (2026-01-27)
-
memoryEnabledフラグによる制御 - simpleChat経由でもメモリ判定へ
-
- Artifact Editor Tool (2026-01-30)
-
artifact_editorツールの実装(→のちに原子的ツール群に統合) - Adit編集ライブラリの統合
- create, edit, overwrite, delete, list アクション
-
- Atomic Artifact Tools (2026-03-24)
-
blueperiod_apply_artifact_adit等の原子的ツール群に統合 - Deep MCPパターンへの移行
-
- Open URL Tool (2026-01-30)
-
open_urlツールの実装 -
/api/tools/open-urlAPIエンドポイント - cheerio + turndown によるHTML→Markdown変換
-
- Record Thought Tool (2026-01-30)
-
record_thoughtツールの実装 - 段階的思考プロセスの記録
-
- エージェント設定の管理UI
Phase 4: UI/UXのエージェント対応 - 一部完了
- エージェントチャットモードの追加
- ツール使用の可視化
- 記憶の可視化
- Artifact編集UI (2026-01-30)
-
ArtifactEditModalコンポーネント - 新規メモ作成ボタン
- アクティブArtifact数のバッジ表示
-
- 確認インラインUI(未実装)
- エージェント設定の管理UI(未実装)
Phase 5: Progressive Thinking & Self-Evaluation - 完了
- Record Thought Tool (2026-01-30)
- ツールファイルの作成
- グラフへの統合
- システムプロンプトの更新 (2026-01-30)
- 段階的思考ガイドラインの追加
- 自己評価と修正ガイドラインの追加
- ACTION OVER WORDS の強化
- Context Management ガイドラインの追加
Phase 6: Context Management Optimization - 完了 (2026-02-08)
目的: エージェントの長期動作安定性を根本的に改善し、トークン消費を最適化する。
実施内容:
-
履歴の再帰的増殖の解消
ProxyChatModelで送信前にhistory引数を削除- ツール引数がステートに永続化される問題を解決
- 効果: トークン消費を約 90% 削減
-
アーティファクトのインデックス化
- 全文ではなく ID・タイトル・300文字スニペットのみ注入
- AI には
readツールの使用を明示的に指示 - 効果: 初期注入トークンを 70% 削減
-
古い read 結果のパージング
ProxyChatModelで履歴を逆順スキャン- 同一アーティファクトの最新バージョン以外を自動削減
- 効果: Read → Edit サイクルでもトークンが線形増大しない
-
ReThink ノードの強化
- ツール呼び出し成功時に
loopCountをリセット - デバッグログの大幅強化(折りたたみグループ、カラー表示)
- プロンプトの命令形強化
- ツール呼び出し成功時に
-
Adit Hybrid Mode 実装
- Structured Output と Delimiter Mode の自動フォールバック
- プロンプトの強制力向上(会話禁止、厳格なフォーマット要求)
- エラー時の具体的なフィードバック実装
成果:
- 45+ ステップの長時間タスクでトークン消費を 124,823 → 約 15,000 に削減
- Adit 失敗率を 87% 改善(軽量モデルでも安定動作)
- エージェント強制終了をほぼゼロ化
技術的学び:
- LangGraph のステート内のツール引数は永続化されるため、送信直前でのサニタイジングが必須
- コンテキスト最適化の原則: 最小注入 + オンデマンド取得 + 履歴のパージング
- AI の自己修正には具体的な行動指示(「ツールを呼べ」)が必須
詳細: 2026-02-08_0150_report_adit-agent-comprehensive-optimization
Phase 7: Autonomous Loop Control & UI - 完了 (2026-02-10) → Phase 8で刷新
目的: ユーザーへの主要な回答(執筆本文等)と思考ログを UI 上で明確に分離し、AI が自身の回答プロセスを自律的に制御できるようにする。
- 戦略的ルーター (
routerNode.ts) の強化: 執筆タスクにおいて「まず回答し、その後に裏側で作業する」戦略を自律選択可能に。 - 先行・事後回答ノードの実装:
firstResponse,finalResponseノードを追加し、LangGraph による動的なフロー制御を実現。 - サンドイッチ・レイアウト UI (
ChatMessageCard.tsx): firstResponse → thoughtLog → finalResponse の順序で描画するレイアウトを導入。 - ノード識別ロジックの導入:
latestNodeNameに基づき、ストリーミング中の各メッセージを正しい表示レイヤーに自動振り分け。
注意: Phase 7 のサンドイッチ構造は Phase 8 で廃止され、「思考のストリーミング」モデルに移行した。
詳細: 2026-02-10_1630_report_autonomous-agent-loop-control
Phase 8: Graph設計リファクタリング — 思考のストリーミング - 完了 (2026-03-29)
目的: サンドイッチ構造を廃止し、Claude Code的なフロンティアエージェントモデルに近いUXを実現する。
- グラフ構造の簡素化:
firstResponse/finalResponseノードを削除。ルーティング戦略を3択に簡素化 - ツールセットの用途別分割:
generalTools(軽量 + artifact_tools)とwritingToolsFull(フル + editorial tools)に分離 - 新規ツールの作成:
response(メイン回答送信),plan_task(リッチなロードマップ提示)。record_thoughtはthoughtのみに簡略化 - ストリーミングロジックの全面的再構築 (
agent.ts): フェーズ依存ロジックを廃止し、メッセージ構造に基づく完全再構築に移行 → その後アキュムレータ方式に移行(Phase 2.8参照) - セマンティック・レンダリング (
MarkdownRenderer.tsx): 特殊コードブロック(thought/plan/progress/call)を専用UIコンポーネントに変換 - ChatMessageCard の大幅簡素化: 約150行の複雑な表示ロジックを単一の
MarkdownRendererに集約 - 脚注スコープ問題の解決:
suffixFootnotes+rehypePrefixIdsによる脚注ID衝突の完全防止 - Debounced DB書き込み: 500ms間隔でのIndexedDB書き込みによるI/O負荷軽減
詳細: 2026-03-29_1600_report_agent-graph-refactoring
Phase 2.8: ストリーミングのアキュムレータ移行 - 完了 (2026-04-08)
フルリビルド方式を廃止し、アキュムレータ(追加専用)方式に移行。LangGraphノードのメッセージ改変による内容消失を根本的に解決。
- アキュムレータ方式への移行 (
agent.ts):rebuiltContent = ""のチャンクごとリセットを廃止。processedToolCallKeys/processedMsgRawLengthによる差分検出で追加のみ行う - memoryRefinerのメッセージ置換廃止 (
memoryNodes.ts): AIMessageの同ID置換(tool_calls消失の原因)を廃止。memorizedFactsをAgentStateのカスタムフィールドで渡す - AgentState拡張 (
state.ts):memorizedFactsフィールドを追加 - finish_taskのUI隠蔽: ツール呼び出し分岐で
finish_taskをスキップ - コンテキスト注入チェック修正 (
assistantGraph.ts):isContextInjectedの検索文字列を実際の注入内容に一致 - 過去ツール履歴の可読フォーマット化 (
formatters.ts):call/progressブロックを人間可読なリスト形式に変換 - エラーハンドリング強化 (
agent.ts):finallyブロックで全エージェント関連アトムをリセット - セマンティックブロックの4バッククォート化 (
agent.ts,formatters.ts): ネストされたコードブロックによるレンダリング崩れを防止。フェンスを```→````に変更し、CommonMark仕様で内側の3バッククォートを安全に含める
詳細: 2026-04-08_0100_report_agent-streaming-accumulator-migration
Phase 3: Tauri V2 & Editorial Agent (Writing) - 完了 (2026-03-12)
- Editorial Agentの実装
-
assistantGraph.tsへのwritingAgentルートの追加 - 執筆専用システムプロンプトの統合
- プロット・原稿操作ツールの実装(Writing Tools)
-
- UI/UXの統合
-
AgentStatusIndicator,AgentConfirmationCardの共通化と執筆画面への配置 - 執筆画面でのエージェントモード有効化
-
14. 今後の展望
- MCP (Model Context Protocol) クライアント: 外部MCPサーバーとの連携
- メモリGatekeeper: 重要な会話のみを長期記憶に保存する判定ロジック(実装済み)
- マルチホップ検索: Semantic Search → Episodic Retrievalの多段階検索(実装済み)
- Artifactの管理機能強化:
- 複数セッション間でのArtifact共有
- Artifactの永続化(現在はセッション限定)
- Artifactのタグ付け・分類
関連ドキュメント:
-
02_technology_stack - LangGraph.js、Orama等の技術スタック
-
03_state_management - エージェント状態Atomsの説明
-
06_development_guidelines - 開発ガイドライン
-
09_design_system - デザイン哲学(静謐なアトリエ)
-
18_agent_tool_integration_guide - ツール統合ガイド
-
19_mcp_architecture - MCPアーキテクチャ
-
20_ai_agent_tool_architecture_overview - アーキテクチャと外部エージェント統合