BluePeriod Docs
開発

内製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)はクライアントサイド(ブラウザ内)で実行します。これにより、エージェントはローカルのプロジェクトデータに遅延なくアクセスでき、セキュリティとレスポンス性を両立します。

Browser (Client Side) Tools Session Artifacts (Dexie) Next.js Server External Services Inference Fetch AI Chat Panel LangGraph Agent web_search blueperiod_get_project blueperiod_get_outline Search Results Project Information /api/chat (LLM) /api/tools/web-search (Tavily) Tavily Search API

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. ライフサイクル

質問 web_search / read_project_data 結果を返す 結果を保存 (isActive=true) 結果を返す 結果 次回のためにArtifactsを取得 セッションの資料一覧 回答(資料を参照) 資料を無効化/削除 isActive=false / DELETE ユーザーがArtifactsPanelで確認 User Agent ツール実行 ArtifactWrapper Dexie (sessionArtifacts) ArtifactsPanel

2.3. ReActパターンとグラフ構造

エージェントは ReAct (Reason + Act) パターンを採用し、Router Patternによる分岐構造を持っています。

2.3.1. Router Pattern(分岐パターン)

「雑談(chat)」と「調査・執筆支援」を分類し、適切な処理ルートに振り分けます。

問題: 単一のReActパターンで全てを処理すると、挨拶などの雑談でもツールを使おうとする「過剰反応」が発生します。

解決: Router Nodeを導入し、役割分担を行います。

chat general_agent writing memory enabled memory disabled ツール必要 ツール必要 web_search その他 finish_task finish_task Yes No 記憶必要 記憶不要 __start__ Router SimpleChat Agent WritingAgent MemoryJudge END ToolCheck SearchOptimizer Tools メモリ有効? MemoryRefiner

: 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ツールを使わないシンプルな会話MainModelnodes/simpleChatNode.ts
agent一般調査・クリエイティブタスク。軽量ツールセットMainModelassistantGraph.ts
writingAgent執筆・プロット操作に特化。フルツールセットMainModelassistantGraph.ts
rethinkツール未使用時の再考を促すガード-assistantGraph.ts
searchOptimizerWeb検索クエリを最適化SubModelnodes/searchOptimizerNode.ts
tools実際のツールを実行するLangChain ToolNode-(標準コンポーネント)
memoryJudge記憶すべきかを判定SubModelnodes/memoryNodes.ts
memoryRefiner記憶を要約・タグ付けして保存SubModelnodes/memoryNodes.ts

2.3.3. SubModel / SubTaskModel

軽量モデル(例: Gemini Flash)を使用して、以下のユーティリティタスクを効率化します:

  • Router: 入力の分類
  • Search Optimizer: クエリの最適化
  • Memory Judge/Refiner: 記憶の判定・精製

メリット:

  • メインモデルのトークン消費量を削減
  • レスポンス速度の向上
  • コストの削減

設定: useSubModelAtomsubLlmProviderAtomsubModelAtom で制御。

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_thoughtReasoning アコーディオン(折りたたみ)
```plan```plan_taskExecution Plan カード(常時展開)
```progress```report_progressProgress ピル(パルスアニメ付き)
```call```技術ツール全般Tool Executed ピル(アイコン付き)
直接テキストresponse / 生テキストメイン回答(Markdown)

2.4.2. セマンティック・レンダリング

MarkdownRenderer.tsx が特殊コードブロックを検知し、専用のUIコンポーネントに変換して表示します。ChatMessageCard.tsx は単一の MarkdownRenderermessage.content を渡すだけで済むようになりました。

2.4.3. ツールセットの分離

エージェントの用途に応じてツールセットを分離しています:

ツールgeneral_agentwritingAgent
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_aditblueperiod_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ツール未使用時に再考を促すガードノード
toolsToolNode(LangChain付属)を使用し、実際のツールを実行

4.3. エッジ定義

エッジ条件
__start__router常にRouterへ
routersimpleChat戦略が chat_only の場合
routeragent戦略が general_agent の場合
routerwritingAgent戦略が writing の場合
simpleChatmemoryJudgeメモリ有効時
simpleChatENDメモリ無効時
agentsearchOptimizerweb_search ツール使用時
agenttoolsその他のツール使用時
agentrethinkツール未使用・回答未完了時
agentmemoryJudgefinish_task 完了、メモリ有効時
agentENDfinish_task 完了、メモリ無効時
writingAgenttools執筆ツールの使用時
writingAgentmemoryJudgefinish_task 完了、メモリ有効時
writingAgentENDfinish_task 完了、メモリ無効時
toolsagentgeneral_agent 実行中
toolswritingAgentwriting 実行中
searchOptimizertools常に(最適化後にツール実行)

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.tsagentNode

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)

設定: tavilyApiKeyAtomsrc/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_editsAdit形式による精密編集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 の実装:

  1. ユーザーが「あの時の話」と曖昧に言及
  2. エージェントが list_memory_dates で日付の一覧を取得
  3. read_memories_by_date で該当期間の記憶を読み取り
  4. 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新しいメモを作成
editAdit(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への変換

処理フロー:

  1. ユーザーがURLを提供(またはエージェントが検索結果からURLを取得)
  2. サーバーサイドでHTMLをフェッチ(User-Agent設定済み)
  3. 不要な要素を削除
  4. Markdownに変換して返却
  5. 結果は自動的に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
Plotget_structured_plot現在のプロット階層を取得structuredPlotAtom
Plotparse_plot_to_structureテキストを解析してプロット化structurePlotAtom
Plotrefine_plot_itemプロット項目をAIでブラッシュアップrefinePlotItemAtom
Plotadd_plot_structure新しいプロット項目を追加structurePlotAtom
Plotedit_plot_item既存のプロット項目を編集structurePlotAtom
Manuscriptgenerate_manuscript指定された節の本文を生成generateSectionAtom
Manuscriptrewrite_manuscript原稿の部分書き直し・推敲rewriteSectionAtom
Manuscripttranslate_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.tshitlToolsNode および AgentToolReviewDialog コンポーネント。

対象ツール:

  • blueperiod_apply_artifact_adit, blueperiod_apply_artifact_delimiter, blueperiod_overwrite_artifact
  • blueperiod_apply_manuscript_adit, blueperiod_apply_manuscript_delimiter, blueperiod_overwrite_manuscript

フロー:

  1. AIが blueperiod_apply_artifact_adit などの編集ツールを呼び出す。
  2. グラフが hitlToolsNode に到達し、ツール実行を一時停止。
  3. UI側で AgentToolReviewDialog が表示され、ユーザーに「差分(Diff)」を提示。
  4. ユーザーが承認(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モデルの能力や接続状況に応じて、最適な編集方式を選択します:

  1. Structured Output (Primary): GPT-4o や Claude 3.5 Sonnet 等の高性能モデル向け。Zod スキーマにより JSON 形式で「どの部分を何に変えるか」を厳密に出力させます。トークン消費が最適化されます。
  2. Delimiter (Secondary/Fallback): step-3.5-flash 等の軽量モデルや、API側で Structured Output が拒否された(400エラー等)場合に使用。実績のある SEARCH/REPLACE ブロック形式で入力を受け取り、独自のパサーで処理します。

9.2. 動作フロー

alt [Success] [400 Error / Failure] edit(content, instruction) JSON Output SEARCH/REPLACE Block Request Text + Blocks Progressive Matching & Apply 更新後のテキスト {success, updatedContent, thoughtProcess} Attempt Structured Output (v1) Fallback to Delimiter Mode (v2) AI Agent Adit LLM Engine

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.tssrc/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. ツールログの循環参照防止

エージェント実行中のツールログ保存時に、巨大なデータ構造(historycontent フィールド等)が含まれていると、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 KeytavilyApiKeyAtomWeb検索機能
Google API KeygeminiApiKeyAtomGeminiモデル使用時
OpenAI API KeyopenaiApiKeyAtomGPTモデル使用時
Anthropic API KeyanthropicApiKeyAtomClaudeモデル使用時

設定場所: 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処理に軽量モデルを使用
    • useSubModelAtomsubLlmProviderAtomsubModelAtom による制御

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-url APIエンドポイント
    • 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_thoughtthought のみに簡略化
  • ストリーミングロジックの全面的再構築 (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のタグ付け・分類

関連ドキュメント:

On this page

12. 内製AIエージェントアーキテクチャ (Internal AI Agent)
1. 概要
2. アーキテクチャ設計
2.1. Client-Side LangGraph
2.2. Session Artifacts(資料管理)
2.2.1. 設計哲学
2.2.2. データ構造
2.2.3. ライフサイクル
2.3. ReActパターンとグラフ構造
2.3.1. Router Pattern(分岐パターン)
2.3.2. ノード詳細
2.3.3. SubModel / SubTaskModel
2.3.4. フェーズ遷移
2.4. 思考のストリーミング (Thought Streaming)
2.4.1. メインストリーム統合
2.4.2. セマンティック・レンダリング
2.4.3. ツールセットの分離
3. ディレクトリ構成
4. グラフ定義 (assistantGraph.ts)
4.1. AgentState
4.4. 履歴の再構築とコンテキストの維持 (Context Consistency)
思考ログの埋め込み (formatMessageWithThoughts)
4.2. ノード定義
4.3. エッジ定義
5. Session Artifactsの仕組み
5.1. Artifact Wrapper(ツール結果の自動保存)
5.2. Context Injection(コンテキスト注入)
5.2.1. インデックス化とスニペット(Snippet-based Injection)
5.2.2. 特徴とメリット
5.2.3. 通常チャット(Agent: OFF)での動作
5.3. システムステータスの知覚 (System Status Awareness)
5.4. UIコンポーネント
6. エージェンツール
6.1. Web検索ツール (webSearchTool)
6.2. プロジェクト参照ツール (Standardized Project Tools)
6.3. プロット&原稿操作ツール (Editorial Tools)
6.3. メモリツール (memoryTools)
6.3.1. list_memory_dates
6.3.2. read_memories_by_date
6.4. 補助ツール
6.4.1. current_time
6.4.2. report_progress
6.5. Artifact Editor Tool (artifactEditorTool)
6.6. Open URL Tool (openUrlTool)
6.7. Record Thought Tool (recordThoughtTool)
6.7b. Plan Task Tool (planTool) — 新設 (2026-03-28)
6.7c. Response Tool (responseTool) — 新設 (2026-03-28)
6.8. Writing Tools (writingTools)
7. 専用ノード
7.1. Routerノード
7.2. SimpleChatノード
7.3. Search Optimizerノード
7.4. Memory Judgeノード
7.5. Memory Refinerノード
7.6. Human-in-the-Loop (HITL) Integration
8. エージェント設定 (AgentSettingsPanel)
8.1. ツールの分類管理
8.2. Human-in-the-Loop (HITL) 設定
8.3. その他の設定
8.1. AGENT_AUTONOMY_GUIDELINE
8.2. SEARCH_AGENT_SYSTEM_PROMPT
8.4. AGENT_AUTONOMY_GUIDELINE(改善点)
8.5. ROUTER_SYSTEM_PROMPT
8.6. SEARCH_OPTIMIZER_PROMPT
8.7. Progressive Thinking(段階的思考)
8.8. Context Management(コンテキスト管理)
9. Adit編集ライブラリ
9.1. 基本理念:ハイブリッド・アプローチ
9.2. 動作フロー
9.3. 高度な置換エンジンの機能
10. ProxyChatModel
10. Tool Useの安定化
10.1. Message Injectionの改善
10.2. チャット中断機能
10.3. ThoughtLogの重複排除
10.4. APIキー取得の強化
10.5. ツールログの循環参照防止
10.6. LangGraph永続化のためのthread_id設定
11. UI統合
11.1. エージェントモードの切り替え
11.2. 思考プロセスの可視化
11.3. 記憶の可視化
11.4. Artifactsパネル
11.5. HITL UIの統合
12. 設定管理
12.1. APIキー設定
12.2. チャット設定
13. 実装状況
Phase 1: Assistant Agent (Chat) - 完了
Phase 1.5: 機能強化 - 完了
Phase 4: UI/UXのエージェント対応 - 一部完了
Phase 5: Progressive Thinking & Self-Evaluation - 完了
Phase 6: Context Management Optimization - 完了 (2026-02-08)
実施内容:
Phase 7: Autonomous Loop Control & UI - 完了 (2026-02-10) → Phase 8で刷新
Phase 8: Graph設計リファクタリング — 思考のストリーミング - 完了 (2026-03-29)
Phase 2.8: ストリーミングのアキュムレータ移行 - 完了 (2026-04-08)
Phase 3: Tauri V2 & Editorial Agent (Writing) - 完了 (2026-03-12)
14. 今後の展望