obsidian-brain-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +112 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +304 -0
- package/dist/tools/agent-dialogue.d.ts +5 -0
- package/dist/tools/agent-dialogue.js +121 -0
- package/dist/tools/consolidate-memory.d.ts +6 -0
- package/dist/tools/consolidate-memory.js +87 -0
- package/dist/tools/create-agent.d.ts +6 -0
- package/dist/tools/create-agent.js +47 -0
- package/dist/tools/detect-conflicts.d.ts +4 -0
- package/dist/tools/detect-conflicts.js +75 -0
- package/dist/tools/evolve-belief.d.ts +8 -0
- package/dist/tools/evolve-belief.js +57 -0
- package/dist/tools/get-agent-context.d.ts +2 -0
- package/dist/tools/get-agent-context.js +70 -0
- package/dist/tools/import-notes.d.ts +7 -0
- package/dist/tools/import-notes.js +64 -0
- package/dist/tools/link-knowledge.d.ts +8 -0
- package/dist/tools/link-knowledge.js +31 -0
- package/dist/tools/list-agents.d.ts +2 -0
- package/dist/tools/list-agents.js +22 -0
- package/dist/tools/promote-pattern.d.ts +9 -0
- package/dist/tools/promote-pattern.js +36 -0
- package/dist/tools/query-agent.d.ts +5 -0
- package/dist/tools/query-agent.js +109 -0
- package/dist/tools/record-decision.d.ts +9 -0
- package/dist/tools/record-decision.js +55 -0
- package/dist/tools/search-across-agents.d.ts +4 -0
- package/dist/tools/search-across-agents.js +77 -0
- package/dist/tools/suggest-agents.d.ts +4 -0
- package/dist/tools/suggest-agents.js +28 -0
- package/dist/types.d.ts +70 -0
- package/dist/types.js +1 -0
- package/dist/vault.d.ts +13 -0
- package/dist/vault.js +131 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 HikaruHonda
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# obsidian-brain-mcp
|
|
2
|
+
|
|
3
|
+
Turn your Obsidian vault into a domain-specific AI brain. An MCP (Model Context Protocol) server that enables dynamic agent creation, knowledge management, and cross-agent intelligence.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Dynamic Agent Creation** — Create specialized domain agents that accumulate knowledge over time
|
|
8
|
+
- **Belief Evolution** — Track how understanding changes with confidence scoring and supersede chains
|
|
9
|
+
- **Decision Recording** — Capture decisions with context, reasoning, and outcomes
|
|
10
|
+
- **Pattern Recognition** — Promote recurring patterns from accumulated decisions
|
|
11
|
+
- **Cross-Agent Search** — Search knowledge across all agents simultaneously
|
|
12
|
+
- **Knowledge Linking** — Create typed relationships between knowledge nodes across agents
|
|
13
|
+
- **Conflict Detection** — Surface contradictory beliefs within and across agents
|
|
14
|
+
- **Memory Consolidation** — Automatically archive and summarize aging knowledge
|
|
15
|
+
- **Agent Dialogue** — Generate structured dialogue material between two agents on a topic
|
|
16
|
+
- **Note Import** — Import existing Obsidian notes into agent knowledge bases
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g obsidian-brain-mcp
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Configuration
|
|
25
|
+
|
|
26
|
+
Set the environment variable to point to your Obsidian vault directory where agent brains will be stored:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
export OBSIDIAN_BRAIN_VAULT_PATH="/path/to/your/obsidian-vault/AI Brain"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage with Claude Code
|
|
33
|
+
|
|
34
|
+
Add to your `~/.claude/settings.json`:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"mcpServers": {
|
|
39
|
+
"obsidian-brain": {
|
|
40
|
+
"command": "obsidian-brain-mcp",
|
|
41
|
+
"env": {
|
|
42
|
+
"OBSIDIAN_BRAIN_VAULT_PATH": "/path/to/your/obsidian-vault/AI Brain"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Tools
|
|
50
|
+
|
|
51
|
+
| Tool | Description | Key Parameters |
|
|
52
|
+
|------|-------------|----------------|
|
|
53
|
+
| `create_agent` | Create a new domain agent | `name`, `description`, `scope` |
|
|
54
|
+
| `list_agents` | List all agents with statistics | _(none)_ |
|
|
55
|
+
| `get_agent_context` | Get full knowledge context for an agent (for prompt injection) | `agent` |
|
|
56
|
+
| `suggest_agents` | Suggest relevant agents for a given task | `task` |
|
|
57
|
+
| `record_decision` | Record a decision with context and reasoning | `agent`, `title`, `context`, `decision`, `reasoning`, `tags` |
|
|
58
|
+
| `query_agent` | Search an agent's knowledge base | `agent`, `question` |
|
|
59
|
+
| `evolve_belief` | Record or evolve a belief with confidence tracking | `agent`, `title`, `content`, `reasoning`, `supersedes?` |
|
|
60
|
+
| `promote_pattern` | Promote a recurring pattern from decisions | `agent`, `title`, `description`, `conditions`, `decision_refs`, `confidence` |
|
|
61
|
+
| `search_across_agents` | Search knowledge across all agents | `query` |
|
|
62
|
+
| `link_knowledge` | Create typed links between knowledge across agents | `source_agent`, `source_file`, `target_agent`, `target_file`, `relationship` |
|
|
63
|
+
| `detect_conflicts` | Detect contradictory beliefs within/across agents | `agent?` |
|
|
64
|
+
| `consolidate_memory` | Archive and summarize aging knowledge | `agent`, `before_date?`, `dry_run?` |
|
|
65
|
+
| `agent_dialogue` | Generate dialogue material between two agents on a topic | `agents` (array of 2), `topic` |
|
|
66
|
+
| `import_notes` | Import existing Obsidian notes into an agent's knowledge base | `agent`, `note_path`, `import_as`, `title?` |
|
|
67
|
+
|
|
68
|
+
## Vault Structure
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
{OBSIDIAN_BRAIN_VAULT_PATH}/
|
|
72
|
+
├── _registry.md # Agent registry
|
|
73
|
+
├── master/ # Default root agent
|
|
74
|
+
│ ├── _agent.md
|
|
75
|
+
│ ├── beliefs/
|
|
76
|
+
│ ├── decisions/
|
|
77
|
+
│ ├── patterns/
|
|
78
|
+
│ ├── knowledge-links/
|
|
79
|
+
│ └── consolidations/
|
|
80
|
+
├── {agent-name}/
|
|
81
|
+
│ ├── _agent.md
|
|
82
|
+
│ ├── beliefs/
|
|
83
|
+
│ │ └── {slug}.md # Frontmatter: confidence, formed, supersedes
|
|
84
|
+
│ ├── decisions/
|
|
85
|
+
│ │ └── {date}-{slug}.md # Frontmatter: tags, outcome
|
|
86
|
+
│ ├── patterns/
|
|
87
|
+
│ │ └── {slug}.md # Frontmatter: confidence, derived_from
|
|
88
|
+
│ ├── knowledge-links/
|
|
89
|
+
│ │ └── {slug}.md # Cross-agent relationship links
|
|
90
|
+
│ └── consolidations/
|
|
91
|
+
│ └── {date}-consolidated-{timestamp}.md
|
|
92
|
+
└── ...
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## How It Works
|
|
96
|
+
|
|
97
|
+
Each agent lives as a directory in your Obsidian vault. Knowledge is stored as Markdown files with YAML frontmatter for metadata (confidence scores, timestamps, relationships, tags).
|
|
98
|
+
|
|
99
|
+
When you create an agent, it gets its own directory with subdirectories for beliefs, decisions, patterns, knowledge-links, and consolidations. As you record decisions and evolve beliefs, the agent accumulates structured knowledge that can be queried, searched, and linked across agents.
|
|
100
|
+
|
|
101
|
+
The frontmatter-based metadata system enables features like belief evolution (tracking how understanding changes over time via supersede chains), pattern promotion (elevating recurring decision patterns), and conflict detection (surfacing contradictory beliefs by comparing content across agents).
|
|
102
|
+
|
|
103
|
+
Because everything is plain Markdown, you can browse, edit, and link your agent knowledge directly in Obsidian — or any text editor.
|
|
104
|
+
|
|
105
|
+
## Requirements
|
|
106
|
+
|
|
107
|
+
- Node.js >= 18.0.0
|
|
108
|
+
- An Obsidian vault (or any directory — Obsidian is optional but recommended for browsing)
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
MIT
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { ensureBrainDir } from "./vault.js";
|
|
6
|
+
import { createAgent } from "./tools/create-agent.js";
|
|
7
|
+
import { listAgents } from "./tools/list-agents.js";
|
|
8
|
+
import { getAgentContext } from "./tools/get-agent-context.js";
|
|
9
|
+
import { suggestAgents } from "./tools/suggest-agents.js";
|
|
10
|
+
import { recordDecision } from "./tools/record-decision.js";
|
|
11
|
+
import { queryAgent } from "./tools/query-agent.js";
|
|
12
|
+
import { evolveBelief } from "./tools/evolve-belief.js";
|
|
13
|
+
import { promotePattern } from "./tools/promote-pattern.js";
|
|
14
|
+
import { searchAcrossAgents } from "./tools/search-across-agents.js";
|
|
15
|
+
import { linkKnowledge } from "./tools/link-knowledge.js";
|
|
16
|
+
import { detectConflicts } from "./tools/detect-conflicts.js";
|
|
17
|
+
import { consolidateMemory } from "./tools/consolidate-memory.js";
|
|
18
|
+
import { agentDialogue } from "./tools/agent-dialogue.js";
|
|
19
|
+
import { importNotes } from "./tools/import-notes.js";
|
|
20
|
+
const server = new Server({ name: "obsidian-brain-mcp", version: "0.1.0" }, { capabilities: { tools: {} } });
|
|
21
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
22
|
+
tools: [
|
|
23
|
+
{
|
|
24
|
+
name: "create_agent",
|
|
25
|
+
description: "新しいドメインエージェントを作成",
|
|
26
|
+
inputSchema: {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {
|
|
29
|
+
name: { type: "string", description: "エージェント名" },
|
|
30
|
+
description: { type: "string", description: "エージェントの説明" },
|
|
31
|
+
scope: { type: "string", description: "担当スコープ" },
|
|
32
|
+
},
|
|
33
|
+
required: ["name", "description", "scope"],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "list_agents",
|
|
38
|
+
description: "全エージェント一覧と統計",
|
|
39
|
+
inputSchema: {
|
|
40
|
+
type: "object",
|
|
41
|
+
properties: {},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "get_agent_context",
|
|
46
|
+
description: "特定エージェントの全知識を取得(prompt注入用)",
|
|
47
|
+
inputSchema: {
|
|
48
|
+
type: "object",
|
|
49
|
+
properties: {
|
|
50
|
+
agent: { type: "string", description: "エージェント名" },
|
|
51
|
+
},
|
|
52
|
+
required: ["agent"],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "suggest_agents",
|
|
57
|
+
description: "タスクに関連するエージェントを提案",
|
|
58
|
+
inputSchema: {
|
|
59
|
+
type: "object",
|
|
60
|
+
properties: {
|
|
61
|
+
task: { type: "string", description: "タスクの説明" },
|
|
62
|
+
},
|
|
63
|
+
required: ["task"],
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "record_decision",
|
|
68
|
+
description: "判断を記録",
|
|
69
|
+
inputSchema: {
|
|
70
|
+
type: "object",
|
|
71
|
+
properties: {
|
|
72
|
+
agent: { type: "string", description: "エージェント名" },
|
|
73
|
+
title: { type: "string", description: "判断のタイトル" },
|
|
74
|
+
context: { type: "string", description: "状況・背景" },
|
|
75
|
+
decision: { type: "string", description: "判断内容" },
|
|
76
|
+
reasoning: { type: "string", description: "理由" },
|
|
77
|
+
tags: {
|
|
78
|
+
type: "array",
|
|
79
|
+
items: { type: "string" },
|
|
80
|
+
description: "タグ",
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
required: ["agent", "title", "context", "decision", "reasoning", "tags"],
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "query_agent",
|
|
88
|
+
description: "エージェントの知識を検索",
|
|
89
|
+
inputSchema: {
|
|
90
|
+
type: "object",
|
|
91
|
+
properties: {
|
|
92
|
+
agent: { type: "string", description: "エージェント名" },
|
|
93
|
+
question: { type: "string", description: "検索クエリ" },
|
|
94
|
+
},
|
|
95
|
+
required: ["agent", "question"],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: "evolve_belief",
|
|
100
|
+
description: "信念を記録・進化",
|
|
101
|
+
inputSchema: {
|
|
102
|
+
type: "object",
|
|
103
|
+
properties: {
|
|
104
|
+
agent: { type: "string", description: "エージェント名" },
|
|
105
|
+
title: { type: "string", description: "信念のタイトル" },
|
|
106
|
+
content: { type: "string", description: "信念の内容" },
|
|
107
|
+
reasoning: { type: "string", description: "根拠" },
|
|
108
|
+
supersedes: {
|
|
109
|
+
type: "string",
|
|
110
|
+
description: "置き換える信念のファイル名(任意)",
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
required: ["agent", "title", "content", "reasoning"],
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: "promote_pattern",
|
|
118
|
+
description: "パターンを昇格",
|
|
119
|
+
inputSchema: {
|
|
120
|
+
type: "object",
|
|
121
|
+
properties: {
|
|
122
|
+
agent: { type: "string", description: "エージェント名" },
|
|
123
|
+
title: { type: "string", description: "パターンのタイトル" },
|
|
124
|
+
description: { type: "string", description: "パターンの説明" },
|
|
125
|
+
conditions: { type: "string", description: "適用条件" },
|
|
126
|
+
decision_refs: {
|
|
127
|
+
type: "array",
|
|
128
|
+
items: { type: "string" },
|
|
129
|
+
description: "根拠となる判断のファイル名",
|
|
130
|
+
},
|
|
131
|
+
confidence: { type: "number", description: "確信度(0-1)" },
|
|
132
|
+
},
|
|
133
|
+
required: ["agent", "title", "description", "conditions", "decision_refs", "confidence"],
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: "search_across_agents",
|
|
138
|
+
description: "全エージェントの知識を横断検索します",
|
|
139
|
+
inputSchema: {
|
|
140
|
+
type: "object",
|
|
141
|
+
properties: {
|
|
142
|
+
query: { type: "string", description: "検索キーワード" },
|
|
143
|
+
},
|
|
144
|
+
required: ["query"],
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: "link_knowledge",
|
|
149
|
+
description: "エージェント間の知識をリンクで接続します",
|
|
150
|
+
inputSchema: {
|
|
151
|
+
type: "object",
|
|
152
|
+
properties: {
|
|
153
|
+
source_agent: { type: "string", description: "リンク元エージェント名" },
|
|
154
|
+
source_file: { type: "string", description: "リンク元ファイル名" },
|
|
155
|
+
target_agent: { type: "string", description: "リンク先エージェント名" },
|
|
156
|
+
target_file: { type: "string", description: "リンク先ファイル名" },
|
|
157
|
+
relationship: {
|
|
158
|
+
type: "string",
|
|
159
|
+
enum: ["supports", "contradicts", "extends", "related"],
|
|
160
|
+
description: "リンクの関係性",
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
required: ["source_agent", "source_file", "target_agent", "target_file", "relationship"],
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: "detect_conflicts",
|
|
168
|
+
description: "エージェント内・エージェント間の信念の矛盾候補を検出します",
|
|
169
|
+
inputSchema: {
|
|
170
|
+
type: "object",
|
|
171
|
+
properties: {
|
|
172
|
+
agent: { type: "string", description: "対象エージェント(省略時は全エージェント)" },
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: "consolidate_memory",
|
|
178
|
+
description: "古い記憶を統合・整理します",
|
|
179
|
+
inputSchema: {
|
|
180
|
+
type: "object",
|
|
181
|
+
properties: {
|
|
182
|
+
agent: { type: "string" },
|
|
183
|
+
before_date: { type: "string", description: "この日付以前の記憶を対象(YYYY-MM-DD、デフォルト30日前)" },
|
|
184
|
+
dry_run: { type: "boolean", description: "trueなら対象一覧のみ返す(デフォルトtrue)" },
|
|
185
|
+
},
|
|
186
|
+
required: ["agent"],
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: "agent_dialogue",
|
|
191
|
+
description: "2つのエージェント間でトピックについての対話素材を生成します",
|
|
192
|
+
inputSchema: {
|
|
193
|
+
type: "object",
|
|
194
|
+
properties: {
|
|
195
|
+
agents: {
|
|
196
|
+
type: "array",
|
|
197
|
+
items: { type: "string" },
|
|
198
|
+
minItems: 2,
|
|
199
|
+
maxItems: 2,
|
|
200
|
+
description: "対話させる2つのエージェント名",
|
|
201
|
+
},
|
|
202
|
+
topic: { type: "string", description: "対話のトピック" },
|
|
203
|
+
},
|
|
204
|
+
required: ["agents", "topic"],
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: "import_notes",
|
|
209
|
+
description: "既存のObsidianノートをエージェントの知識として取り込みます",
|
|
210
|
+
inputSchema: {
|
|
211
|
+
type: "object",
|
|
212
|
+
properties: {
|
|
213
|
+
agent: { type: "string" },
|
|
214
|
+
note_path: { type: "string", description: "ノートのパス(絶対パスまたはVault相対パス)" },
|
|
215
|
+
import_as: {
|
|
216
|
+
type: "string",
|
|
217
|
+
enum: ["belief", "decision", "pattern"],
|
|
218
|
+
description: "取り込む知識の種類",
|
|
219
|
+
},
|
|
220
|
+
title: { type: "string", description: "タイトル(省略時はファイル名)" },
|
|
221
|
+
},
|
|
222
|
+
required: ["agent", "note_path", "import_as"],
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
}));
|
|
227
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
228
|
+
const { name, arguments: args } = request.params;
|
|
229
|
+
try {
|
|
230
|
+
switch (name) {
|
|
231
|
+
case "create_agent": {
|
|
232
|
+
const result = await createAgent(args);
|
|
233
|
+
return { content: [{ type: "text", text: result }] };
|
|
234
|
+
}
|
|
235
|
+
case "list_agents": {
|
|
236
|
+
const result = await listAgents();
|
|
237
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
238
|
+
}
|
|
239
|
+
case "get_agent_context": {
|
|
240
|
+
const result = await getAgentContext(args.agent);
|
|
241
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
242
|
+
}
|
|
243
|
+
case "suggest_agents": {
|
|
244
|
+
const result = await suggestAgents(args);
|
|
245
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
246
|
+
}
|
|
247
|
+
case "record_decision": {
|
|
248
|
+
const result = await recordDecision(args);
|
|
249
|
+
return { content: [{ type: "text", text: result }] };
|
|
250
|
+
}
|
|
251
|
+
case "query_agent": {
|
|
252
|
+
const result = await queryAgent(args);
|
|
253
|
+
return { content: [{ type: "text", text: result }] };
|
|
254
|
+
}
|
|
255
|
+
case "evolve_belief": {
|
|
256
|
+
const result = await evolveBelief(args);
|
|
257
|
+
return { content: [{ type: "text", text: result }] };
|
|
258
|
+
}
|
|
259
|
+
case "promote_pattern": {
|
|
260
|
+
const result = await promotePattern(args);
|
|
261
|
+
return { content: [{ type: "text", text: result }] };
|
|
262
|
+
}
|
|
263
|
+
case "search_across_agents": {
|
|
264
|
+
const result = await searchAcrossAgents(args);
|
|
265
|
+
return { content: [{ type: "text", text: result }] };
|
|
266
|
+
}
|
|
267
|
+
case "link_knowledge": {
|
|
268
|
+
const result = await linkKnowledge(args);
|
|
269
|
+
return { content: [{ type: "text", text: result }] };
|
|
270
|
+
}
|
|
271
|
+
case "detect_conflicts": {
|
|
272
|
+
const result = await detectConflicts(args);
|
|
273
|
+
return { content: [{ type: "text", text: result }] };
|
|
274
|
+
}
|
|
275
|
+
case "consolidate_memory": {
|
|
276
|
+
const result = await consolidateMemory(args);
|
|
277
|
+
return { content: [{ type: "text", text: result }] };
|
|
278
|
+
}
|
|
279
|
+
case "agent_dialogue": {
|
|
280
|
+
const result = await agentDialogue(args);
|
|
281
|
+
return { content: [{ type: "text", text: result }] };
|
|
282
|
+
}
|
|
283
|
+
case "import_notes": {
|
|
284
|
+
const result = await importNotes(args);
|
|
285
|
+
return { content: [{ type: "text", text: result }] };
|
|
286
|
+
}
|
|
287
|
+
default:
|
|
288
|
+
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
293
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
async function main() {
|
|
297
|
+
await ensureBrainDir();
|
|
298
|
+
const transport = new StdioServerTransport();
|
|
299
|
+
await server.connect(transport);
|
|
300
|
+
}
|
|
301
|
+
main().catch((error) => {
|
|
302
|
+
console.error("Fatal error:", error);
|
|
303
|
+
process.exit(1);
|
|
304
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { agentDir, agentExists, readMarkdown, listFiles } from "../vault.js";
|
|
3
|
+
export async function agentDialogue(input) {
|
|
4
|
+
const { agents, topic } = input;
|
|
5
|
+
if (agents.length !== 2) {
|
|
6
|
+
throw new Error(`agents must be exactly 2, got ${agents.length}.`);
|
|
7
|
+
}
|
|
8
|
+
for (const agent of agents) {
|
|
9
|
+
if (!(await agentExists(agent))) {
|
|
10
|
+
throw new Error(`Agent "${agent}" not found.`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const keywords = topic
|
|
14
|
+
.toLowerCase()
|
|
15
|
+
.split(/\s+/)
|
|
16
|
+
.filter((w) => w.length > 1);
|
|
17
|
+
function matchesKeywords(text) {
|
|
18
|
+
const lower = text.toLowerCase();
|
|
19
|
+
return keywords.some((kw) => lower.includes(kw));
|
|
20
|
+
}
|
|
21
|
+
const sections = [];
|
|
22
|
+
const allAgentBeliefs = [];
|
|
23
|
+
const allAgentDecisions = [];
|
|
24
|
+
const allAgentPatterns = [];
|
|
25
|
+
for (const agent of agents) {
|
|
26
|
+
const dir = agentDir(agent);
|
|
27
|
+
// Beliefs (exclude superseded)
|
|
28
|
+
const beliefFiles = await listFiles(path.join(dir, "beliefs"), ".md");
|
|
29
|
+
const relevantBeliefs = [];
|
|
30
|
+
for (const file of beliefFiles) {
|
|
31
|
+
const { data, content } = await readMarkdown(path.join(dir, "beliefs", file));
|
|
32
|
+
if (data.superseded_by)
|
|
33
|
+
continue;
|
|
34
|
+
const title = data.title ?? "";
|
|
35
|
+
if (matchesKeywords(title) || matchesKeywords(content)) {
|
|
36
|
+
relevantBeliefs.push({
|
|
37
|
+
title,
|
|
38
|
+
content: content.trim(),
|
|
39
|
+
agent: data.agent ?? agent,
|
|
40
|
+
confidence: data.confidence ?? 0,
|
|
41
|
+
formed: data.formed ?? "",
|
|
42
|
+
reasoning: data.reasoning ?? "",
|
|
43
|
+
supersedes: data.supersedes,
|
|
44
|
+
superseded_by: data.superseded_by,
|
|
45
|
+
evidence_count: data.evidence_count ?? 0,
|
|
46
|
+
filename: file,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Decisions
|
|
51
|
+
const decisionFiles = await listFiles(path.join(dir, "decisions"), ".md");
|
|
52
|
+
const relevantDecisions = [];
|
|
53
|
+
for (const file of decisionFiles) {
|
|
54
|
+
const { data, content } = await readMarkdown(path.join(dir, "decisions", file));
|
|
55
|
+
const title = data.title ?? "";
|
|
56
|
+
if (matchesKeywords(title) || matchesKeywords(content)) {
|
|
57
|
+
relevantDecisions.push({
|
|
58
|
+
title,
|
|
59
|
+
agent: data.agent ?? agent,
|
|
60
|
+
context: data.context ?? "",
|
|
61
|
+
decision: data.decision ?? "",
|
|
62
|
+
reasoning: data.reasoning ?? "",
|
|
63
|
+
tags: data.tags ?? [],
|
|
64
|
+
date: data.date ?? "",
|
|
65
|
+
outcome: data.outcome ?? "",
|
|
66
|
+
filename: file,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Patterns
|
|
71
|
+
const patternFiles = await listFiles(path.join(dir, "patterns"), ".md");
|
|
72
|
+
const relevantPatterns = [];
|
|
73
|
+
for (const file of patternFiles) {
|
|
74
|
+
const { data, content } = await readMarkdown(path.join(dir, "patterns", file));
|
|
75
|
+
const title = data.title ?? "";
|
|
76
|
+
const description = data.description ?? "";
|
|
77
|
+
if (matchesKeywords(title) ||
|
|
78
|
+
matchesKeywords(description) ||
|
|
79
|
+
matchesKeywords(content)) {
|
|
80
|
+
relevantPatterns.push({
|
|
81
|
+
title,
|
|
82
|
+
agent: data.agent ?? agent,
|
|
83
|
+
description,
|
|
84
|
+
conditions: data.conditions ?? "",
|
|
85
|
+
confidence: data.confidence ?? 0,
|
|
86
|
+
derived_from: data.derived_from ?? [],
|
|
87
|
+
min_evidence: data.min_evidence ?? 0,
|
|
88
|
+
filename: file,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Build section
|
|
93
|
+
const beliefLines = relevantBeliefs.map((b) => {
|
|
94
|
+
const snippet = b.content.slice(0, 80).replace(/\n/g, " ");
|
|
95
|
+
return `- ${b.title} (confidence: ${b.confidence}): ${snippet}`;
|
|
96
|
+
});
|
|
97
|
+
const decisionLines = relevantDecisions.map((d) => {
|
|
98
|
+
const snippet = (d.decision || d.context).slice(0, 80).replace(/\n/g, " ");
|
|
99
|
+
return `- ${d.title}: ${snippet}`;
|
|
100
|
+
});
|
|
101
|
+
const patternLines = relevantPatterns.map((p) => {
|
|
102
|
+
return `- ${p.title}: ${p.description}`;
|
|
103
|
+
});
|
|
104
|
+
allAgentBeliefs.push(beliefLines);
|
|
105
|
+
allAgentDecisions.push(decisionLines);
|
|
106
|
+
allAgentPatterns.push(patternLines);
|
|
107
|
+
let section = `## ${agent} の視点\n`;
|
|
108
|
+
section += `\n### 信念\n${beliefLines.length > 0 ? beliefLines.join("\n") : "該当なし"}\n`;
|
|
109
|
+
section += `\n### 意思決定\n${decisionLines.length > 0 ? decisionLines.join("\n") : "該当なし"}\n`;
|
|
110
|
+
section += `\n### パターン\n${patternLines.length > 0 ? patternLines.join("\n") : "該当なし"}\n`;
|
|
111
|
+
sections.push(section);
|
|
112
|
+
}
|
|
113
|
+
const totalItems = allAgentBeliefs.flat().length + allAgentDecisions.flat().length + allAgentPatterns.flat().length;
|
|
114
|
+
if (totalItems === 0) {
|
|
115
|
+
return `トピック「${topic}」に関連する信念・意思決定・パターンは両エージェントとも見つかりませんでした。`;
|
|
116
|
+
}
|
|
117
|
+
// Dialogue points
|
|
118
|
+
const hasShared = allAgentBeliefs[0].length > 0 && allAgentBeliefs[1].length > 0;
|
|
119
|
+
const dialoguePoints = `## 対話のための論点\n- 共通するテーマ: ${hasShared ? "両エージェントがこのトピックについて信念を持っています" : "一方のみがこのトピックに関連する信念を持っています"}\n- 異なる視点: 各エージェントのconfidence値や推論の違いを比較してください`;
|
|
120
|
+
return `# エージェント対話: ${topic}\n\n${sections.join("\n")}\n${dialoguePoints}`;
|
|
121
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { agentDir, agentExists, readMarkdown, writeMarkdown, listFiles, } from "../vault.js";
|
|
4
|
+
export async function consolidateMemory(input) {
|
|
5
|
+
const { agent, dry_run = true } = input;
|
|
6
|
+
if (!(await agentExists(agent))) {
|
|
7
|
+
throw new Error(`Agent "${agent}" not found.`);
|
|
8
|
+
}
|
|
9
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
10
|
+
const beforeDate = input.before_date ??
|
|
11
|
+
new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
|
|
12
|
+
const dir = agentDir(agent);
|
|
13
|
+
// Collect beliefs before the date
|
|
14
|
+
const beliefFiles = await listFiles(path.join(dir, "beliefs"), ".md");
|
|
15
|
+
const targets = [];
|
|
16
|
+
for (const file of beliefFiles) {
|
|
17
|
+
const { data, content } = await readMarkdown(path.join(dir, "beliefs", file));
|
|
18
|
+
const formed = data.formed ?? "";
|
|
19
|
+
if (formed && formed < beforeDate) {
|
|
20
|
+
targets.push({
|
|
21
|
+
file: path.join(dir, "beliefs", file),
|
|
22
|
+
type: "belief",
|
|
23
|
+
title: data.title ?? file,
|
|
24
|
+
content: content.trim(),
|
|
25
|
+
date: formed,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Collect decisions before the date
|
|
30
|
+
const decisionFiles = await listFiles(path.join(dir, "decisions"), ".md");
|
|
31
|
+
for (const file of decisionFiles) {
|
|
32
|
+
const { data, content } = await readMarkdown(path.join(dir, "decisions", file));
|
|
33
|
+
const date = data.date ?? "";
|
|
34
|
+
if (date && date < beforeDate) {
|
|
35
|
+
targets.push({
|
|
36
|
+
file: path.join(dir, "decisions", file),
|
|
37
|
+
type: "decision",
|
|
38
|
+
title: data.title ?? file,
|
|
39
|
+
content: content.trim(),
|
|
40
|
+
date,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (targets.length === 0) {
|
|
45
|
+
return `対象なし: ${beforeDate} 以前のbelief/decisionはありません。`;
|
|
46
|
+
}
|
|
47
|
+
// dry_run: list only
|
|
48
|
+
if (dry_run) {
|
|
49
|
+
const lines = targets.map((t) => `- **${t.title}** (${t.type}, ${t.date})`);
|
|
50
|
+
return `## 統合候補 (dry_run)\n\nagent: ${agent}\nbefore: ${beforeDate}\n対象: ${targets.length}件\n\n${lines.join("\n")}`;
|
|
51
|
+
}
|
|
52
|
+
// Execute consolidation
|
|
53
|
+
const consolidationsDir = path.join(dir, "consolidations");
|
|
54
|
+
await fs.mkdir(consolidationsDir, { recursive: true });
|
|
55
|
+
const dates = targets.map((t) => t.date).sort();
|
|
56
|
+
const oldest = dates[0];
|
|
57
|
+
const newest = dates[dates.length - 1];
|
|
58
|
+
const dateRange = `${oldest}~${newest}`;
|
|
59
|
+
const entryLines = targets.map((t) => {
|
|
60
|
+
const snippet = t.content.slice(0, 100).replace(/\n/g, " ");
|
|
61
|
+
return `- **${t.title}** (${t.type}): ${snippet}`;
|
|
62
|
+
});
|
|
63
|
+
const body = `# 統合メモリ: ${agent}
|
|
64
|
+
|
|
65
|
+
## 対象期間
|
|
66
|
+
${dateRange}
|
|
67
|
+
|
|
68
|
+
## エントリ一覧
|
|
69
|
+
${entryLines.join("\n")}
|
|
70
|
+
`;
|
|
71
|
+
const filename = `${today}-consolidated-${Date.now()}.md`;
|
|
72
|
+
const filePath = path.join(consolidationsDir, filename);
|
|
73
|
+
await writeMarkdown(filePath, {
|
|
74
|
+
type: "consolidation",
|
|
75
|
+
agent,
|
|
76
|
+
source_count: targets.length,
|
|
77
|
+
date_range: dateRange,
|
|
78
|
+
created: today,
|
|
79
|
+
}, body);
|
|
80
|
+
// Mark originals as archived
|
|
81
|
+
for (const t of targets) {
|
|
82
|
+
const { data, content } = await readMarkdown(t.file);
|
|
83
|
+
data.archived = true;
|
|
84
|
+
await writeMarkdown(t.file, data, content);
|
|
85
|
+
}
|
|
86
|
+
return `統合完了: ${targets.length}件を ${filename} に統合しました。元ファイルに archived: true を追記済み。`;
|
|
87
|
+
}
|