basic-memory 0.14.4__py3-none-any.whl → 0.15.1__py3-none-any.whl
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.
Potentially problematic release.
This version of basic-memory might be problematic. Click here for more details.
- basic_memory/__init__.py +1 -1
- basic_memory/alembic/versions/a1b2c3d4e5f6_fix_project_foreign_keys.py +5 -9
- basic_memory/api/app.py +10 -4
- basic_memory/api/routers/directory_router.py +23 -2
- basic_memory/api/routers/knowledge_router.py +25 -8
- basic_memory/api/routers/project_router.py +100 -4
- basic_memory/cli/app.py +9 -28
- basic_memory/cli/auth.py +277 -0
- basic_memory/cli/commands/cloud/__init__.py +5 -0
- basic_memory/cli/commands/cloud/api_client.py +112 -0
- basic_memory/cli/commands/cloud/bisync_commands.py +818 -0
- basic_memory/cli/commands/cloud/core_commands.py +288 -0
- basic_memory/cli/commands/cloud/mount_commands.py +295 -0
- basic_memory/cli/commands/cloud/rclone_config.py +288 -0
- basic_memory/cli/commands/cloud/rclone_installer.py +198 -0
- basic_memory/cli/commands/command_utils.py +43 -0
- basic_memory/cli/commands/import_memory_json.py +0 -4
- basic_memory/cli/commands/mcp.py +77 -60
- basic_memory/cli/commands/project.py +154 -152
- basic_memory/cli/commands/status.py +25 -22
- basic_memory/cli/commands/sync.py +45 -228
- basic_memory/cli/commands/tool.py +87 -16
- basic_memory/cli/main.py +1 -0
- basic_memory/config.py +131 -21
- basic_memory/db.py +104 -3
- basic_memory/deps.py +27 -8
- basic_memory/file_utils.py +37 -13
- basic_memory/ignore_utils.py +295 -0
- basic_memory/markdown/plugins.py +9 -7
- basic_memory/mcp/async_client.py +124 -14
- basic_memory/mcp/project_context.py +141 -0
- basic_memory/mcp/prompts/ai_assistant_guide.py +49 -4
- basic_memory/mcp/prompts/continue_conversation.py +17 -16
- basic_memory/mcp/prompts/recent_activity.py +116 -32
- basic_memory/mcp/prompts/search.py +13 -12
- basic_memory/mcp/prompts/utils.py +11 -4
- basic_memory/mcp/resources/ai_assistant_guide.md +211 -341
- basic_memory/mcp/resources/project_info.py +27 -11
- basic_memory/mcp/server.py +0 -37
- basic_memory/mcp/tools/__init__.py +5 -6
- basic_memory/mcp/tools/build_context.py +67 -56
- basic_memory/mcp/tools/canvas.py +38 -26
- basic_memory/mcp/tools/chatgpt_tools.py +187 -0
- basic_memory/mcp/tools/delete_note.py +81 -47
- basic_memory/mcp/tools/edit_note.py +155 -138
- basic_memory/mcp/tools/list_directory.py +112 -99
- basic_memory/mcp/tools/move_note.py +181 -101
- basic_memory/mcp/tools/project_management.py +113 -277
- basic_memory/mcp/tools/read_content.py +91 -74
- basic_memory/mcp/tools/read_note.py +152 -115
- basic_memory/mcp/tools/recent_activity.py +471 -68
- basic_memory/mcp/tools/search.py +105 -92
- basic_memory/mcp/tools/sync_status.py +136 -130
- basic_memory/mcp/tools/utils.py +4 -0
- basic_memory/mcp/tools/view_note.py +44 -33
- basic_memory/mcp/tools/write_note.py +151 -90
- basic_memory/models/knowledge.py +12 -6
- basic_memory/models/project.py +6 -2
- basic_memory/repository/entity_repository.py +89 -82
- basic_memory/repository/relation_repository.py +13 -0
- basic_memory/repository/repository.py +18 -5
- basic_memory/repository/search_repository.py +46 -2
- basic_memory/schemas/__init__.py +6 -0
- basic_memory/schemas/base.py +39 -11
- basic_memory/schemas/cloud.py +46 -0
- basic_memory/schemas/memory.py +90 -21
- basic_memory/schemas/project_info.py +9 -10
- basic_memory/schemas/sync_report.py +48 -0
- basic_memory/services/context_service.py +25 -11
- basic_memory/services/directory_service.py +124 -3
- basic_memory/services/entity_service.py +100 -48
- basic_memory/services/initialization.py +30 -11
- basic_memory/services/project_service.py +101 -24
- basic_memory/services/search_service.py +16 -8
- basic_memory/sync/sync_service.py +173 -34
- basic_memory/sync/watch_service.py +101 -40
- basic_memory/utils.py +14 -4
- {basic_memory-0.14.4.dist-info → basic_memory-0.15.1.dist-info}/METADATA +57 -9
- basic_memory-0.15.1.dist-info/RECORD +146 -0
- basic_memory/mcp/project_session.py +0 -120
- basic_memory-0.14.4.dist-info/RECORD +0 -133
- {basic_memory-0.14.4.dist-info → basic_memory-0.15.1.dist-info}/WHEEL +0 -0
- {basic_memory-0.14.4.dist-info → basic_memory-0.15.1.dist-info}/entry_points.txt +0 -0
- {basic_memory-0.14.4.dist-info → basic_memory-0.15.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
from typing import Optional
|
|
4
4
|
|
|
5
5
|
from loguru import logger
|
|
6
|
+
from fastmcp import Context
|
|
6
7
|
|
|
7
8
|
from basic_memory.config import ConfigManager
|
|
9
|
+
from basic_memory.mcp.async_client import get_client
|
|
8
10
|
from basic_memory.mcp.server import mcp
|
|
9
|
-
from basic_memory.mcp.
|
|
11
|
+
from basic_memory.mcp.project_context import get_active_project
|
|
10
12
|
from basic_memory.services.sync_status_service import sync_status_tracker
|
|
11
13
|
|
|
12
14
|
|
|
@@ -79,7 +81,7 @@ def _get_all_projects_status() -> list[str]:
|
|
|
79
81
|
- Background processing of knowledge graphs
|
|
80
82
|
""",
|
|
81
83
|
)
|
|
82
|
-
async def sync_status(project: Optional[str] = None) -> str:
|
|
84
|
+
async def sync_status(project: Optional[str] = None, context: Context | None = None) -> str:
|
|
83
85
|
"""Get current sync status and system readiness information.
|
|
84
86
|
|
|
85
87
|
This tool provides detailed information about any ongoing or completed
|
|
@@ -93,163 +95,167 @@ async def sync_status(project: Optional[str] = None) -> str:
|
|
|
93
95
|
"""
|
|
94
96
|
logger.info("MCP tool call tool=sync_status")
|
|
95
97
|
|
|
96
|
-
|
|
98
|
+
async with get_client() as client:
|
|
99
|
+
status_lines = []
|
|
97
100
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
status_lines.extend(
|
|
107
|
-
[
|
|
108
|
-
"# Basic Memory Sync Status",
|
|
109
|
-
"",
|
|
110
|
-
f"**Current Status**: {summary}",
|
|
111
|
-
f"**System Ready**: {'✅ Yes' if is_ready else '🔄 Processing'}",
|
|
112
|
-
"",
|
|
113
|
-
]
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
if is_ready:
|
|
101
|
+
try:
|
|
102
|
+
from basic_memory.services.sync_status_service import sync_status_tracker
|
|
103
|
+
|
|
104
|
+
# Get overall summary
|
|
105
|
+
summary = sync_status_tracker.get_summary()
|
|
106
|
+
is_ready = sync_status_tracker.is_ready
|
|
107
|
+
|
|
108
|
+
# Header
|
|
117
109
|
status_lines.extend(
|
|
118
110
|
[
|
|
119
|
-
"
|
|
111
|
+
"# Basic Memory Sync Status",
|
|
120
112
|
"",
|
|
121
|
-
"
|
|
122
|
-
"
|
|
123
|
-
"- All Basic Memory tools are fully operational",
|
|
113
|
+
f"**Current Status**: {summary}",
|
|
114
|
+
f"**System Ready**: {'✅ Yes' if is_ready else '🔄 Processing'}",
|
|
124
115
|
"",
|
|
125
|
-
"Your knowledge base is ready for use!",
|
|
126
116
|
]
|
|
127
117
|
)
|
|
128
118
|
|
|
129
|
-
|
|
130
|
-
status_lines.extend(_get_all_projects_status())
|
|
131
|
-
else:
|
|
132
|
-
# System is still processing - show both active and all projects
|
|
133
|
-
all_sync_projects = sync_status_tracker.get_all_projects()
|
|
134
|
-
|
|
135
|
-
active_projects = [
|
|
136
|
-
p for p in all_sync_projects.values() if p.status.value in ["scanning", "syncing"]
|
|
137
|
-
]
|
|
138
|
-
failed_projects = [p for p in all_sync_projects.values() if p.status.value == "failed"]
|
|
139
|
-
|
|
140
|
-
if active_projects:
|
|
119
|
+
if is_ready:
|
|
141
120
|
status_lines.extend(
|
|
142
121
|
[
|
|
143
|
-
"
|
|
122
|
+
"✅ **All sync operations completed**",
|
|
144
123
|
"",
|
|
145
|
-
"
|
|
146
|
-
"
|
|
124
|
+
"- File indexing is complete",
|
|
125
|
+
"- Knowledge graphs are up to date",
|
|
126
|
+
"- All Basic Memory tools are fully operational",
|
|
147
127
|
"",
|
|
148
|
-
"
|
|
128
|
+
"Your knowledge base is ready for use!",
|
|
149
129
|
]
|
|
150
130
|
)
|
|
151
131
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
) * 100
|
|
158
|
-
progress = f" ({project_status.files_processed}/{project_status.files_total}, {progress_pct:.0f}%)"
|
|
132
|
+
# Show all projects status even when ready
|
|
133
|
+
status_lines.extend(_get_all_projects_status())
|
|
134
|
+
else:
|
|
135
|
+
# System is still processing - show both active and all projects
|
|
136
|
+
all_sync_projects = sync_status_tracker.get_all_projects()
|
|
159
137
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
"- Scanning and indexing markdown files",
|
|
169
|
-
"- Building entity and relationship graphs",
|
|
170
|
-
"- Setting up full-text search indexes",
|
|
171
|
-
"- Processing file changes and updates",
|
|
172
|
-
"",
|
|
173
|
-
"**What you can do:**",
|
|
174
|
-
"- Wait for automatic processing to complete - no action needed",
|
|
175
|
-
"- Use this tool again to check progress",
|
|
176
|
-
"- Simple operations may work already",
|
|
177
|
-
"- All projects will be available once sync finishes",
|
|
178
|
-
]
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
# Handle failed projects (independent of active projects)
|
|
182
|
-
if failed_projects:
|
|
183
|
-
status_lines.extend(["", "❌ **Some projects failed to sync:**", ""])
|
|
138
|
+
active_projects = [
|
|
139
|
+
p
|
|
140
|
+
for p in all_sync_projects.values()
|
|
141
|
+
if p.status.value in ["scanning", "syncing"]
|
|
142
|
+
]
|
|
143
|
+
failed_projects = [
|
|
144
|
+
p for p in all_sync_projects.values() if p.status.value == "failed"
|
|
145
|
+
]
|
|
184
146
|
|
|
185
|
-
|
|
186
|
-
status_lines.
|
|
187
|
-
|
|
147
|
+
if active_projects:
|
|
148
|
+
status_lines.extend(
|
|
149
|
+
[
|
|
150
|
+
"🔄 **File synchronization in progress**",
|
|
151
|
+
"",
|
|
152
|
+
"Basic Memory is automatically processing all configured projects and building knowledge graphs.",
|
|
153
|
+
"This typically takes 1-3 minutes depending on the amount of content.",
|
|
154
|
+
"",
|
|
155
|
+
"**Currently Processing:**",
|
|
156
|
+
]
|
|
188
157
|
)
|
|
189
158
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
159
|
+
for project_status in active_projects:
|
|
160
|
+
progress = ""
|
|
161
|
+
if project_status.files_total > 0:
|
|
162
|
+
progress_pct = (
|
|
163
|
+
project_status.files_processed / project_status.files_total
|
|
164
|
+
) * 100
|
|
165
|
+
progress = f" ({project_status.files_processed}/{project_status.files_total}, {progress_pct:.0f}%)"
|
|
166
|
+
|
|
167
|
+
status_lines.append(
|
|
168
|
+
f"- **{project_status.project_name}**: {project_status.message}{progress}"
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
status_lines.extend(
|
|
172
|
+
[
|
|
173
|
+
"",
|
|
174
|
+
"**What's happening:**",
|
|
175
|
+
"- Scanning and indexing markdown files",
|
|
176
|
+
"- Building entity and relationship graphs",
|
|
177
|
+
"- Settings up full-text search indexes",
|
|
178
|
+
"- Processing file changes and updates",
|
|
179
|
+
"",
|
|
180
|
+
"**What you can do:**",
|
|
181
|
+
"- Wait for automatic processing to complete - no action needed",
|
|
182
|
+
"- Use this tool again to check progress",
|
|
183
|
+
"- Simple operations may work already",
|
|
184
|
+
"- All projects will be available once sync finishes",
|
|
185
|
+
]
|
|
186
|
+
)
|
|
210
187
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
188
|
+
# Handle failed projects (independent of active projects)
|
|
189
|
+
if failed_projects:
|
|
190
|
+
status_lines.extend(["", "❌ **Some projects failed to sync:**", ""])
|
|
191
|
+
|
|
192
|
+
for project_status in failed_projects:
|
|
193
|
+
status_lines.append(
|
|
194
|
+
f"- **{project_status.project_name}**: {project_status.error or 'Unknown error'}"
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
status_lines.extend(
|
|
198
|
+
[
|
|
199
|
+
"",
|
|
200
|
+
"**Next steps:**",
|
|
201
|
+
"1. Check the logs for detailed error information",
|
|
202
|
+
"2. Ensure file permissions allow read/write access",
|
|
203
|
+
"3. Try restarting the MCP server",
|
|
204
|
+
"4. If issues persist, consider filing a support issue",
|
|
205
|
+
]
|
|
206
|
+
)
|
|
207
|
+
elif not active_projects:
|
|
208
|
+
# No active or failed projects - must be pending
|
|
209
|
+
status_lines.extend(
|
|
210
|
+
[
|
|
211
|
+
"⏳ **Sync operations pending**",
|
|
212
|
+
"",
|
|
213
|
+
"File synchronization has been queued but hasn't started yet.",
|
|
214
|
+
"This usually resolves automatically within a few seconds.",
|
|
215
|
+
]
|
|
216
|
+
)
|
|
215
217
|
|
|
216
|
-
# Add
|
|
217
|
-
|
|
218
|
-
if
|
|
219
|
-
status_lines.extend(
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
218
|
+
# Add comprehensive project status for all configured projects
|
|
219
|
+
all_projects_status = _get_all_projects_status()
|
|
220
|
+
if all_projects_status:
|
|
221
|
+
status_lines.extend(all_projects_status)
|
|
222
|
+
|
|
223
|
+
# Add explanation about automatic syncing if there are unsynced projects
|
|
224
|
+
unsynced_count = sum(1 for line in all_projects_status if "⏳" in line)
|
|
225
|
+
if unsynced_count > 0 and not is_ready:
|
|
226
|
+
status_lines.extend(
|
|
227
|
+
[
|
|
228
|
+
"",
|
|
229
|
+
"**Note**: All configured projects will be automatically synced during startup.",
|
|
230
|
+
]
|
|
231
|
+
)
|
|
226
232
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
233
|
+
# Add project context if provided
|
|
234
|
+
if project:
|
|
235
|
+
try:
|
|
236
|
+
active_project = await get_active_project(client, project, context)
|
|
237
|
+
status_lines.extend(
|
|
238
|
+
[
|
|
239
|
+
"",
|
|
240
|
+
"---",
|
|
241
|
+
"",
|
|
242
|
+
f"**Active Project**: {active_project.name}",
|
|
243
|
+
f"**Project Path**: {active_project.home}",
|
|
244
|
+
]
|
|
245
|
+
)
|
|
246
|
+
except Exception as e:
|
|
247
|
+
logger.debug(f"Could not get project info: {e}")
|
|
242
248
|
|
|
243
|
-
|
|
249
|
+
return "\n".join(status_lines)
|
|
244
250
|
|
|
245
|
-
|
|
246
|
-
|
|
251
|
+
except Exception as e:
|
|
252
|
+
return f"""# Sync Status - Error
|
|
247
253
|
|
|
248
254
|
❌ **Unable to check sync status**: {str(e)}
|
|
249
255
|
|
|
250
256
|
**Troubleshooting:**
|
|
251
257
|
- The system may still be starting up
|
|
252
|
-
- Try waiting a few seconds and checking again
|
|
258
|
+
- Try waiting a few seconds and checking again
|
|
253
259
|
- Check logs for detailed error information
|
|
254
260
|
- Consider restarting if the issue persists
|
|
255
261
|
"""
|
basic_memory/mcp/tools/utils.py
CHANGED
|
@@ -107,6 +107,7 @@ async def call_get(
|
|
|
107
107
|
"""
|
|
108
108
|
logger.debug(f"Calling GET '{url}' params: '{params}'")
|
|
109
109
|
error_message = None
|
|
110
|
+
|
|
110
111
|
try:
|
|
111
112
|
response = await client.get(
|
|
112
113
|
url,
|
|
@@ -280,6 +281,7 @@ async def call_patch(
|
|
|
280
281
|
ToolError: If the request fails with an appropriate error message
|
|
281
282
|
"""
|
|
282
283
|
logger.debug(f"Calling PATCH '{url}'")
|
|
284
|
+
|
|
283
285
|
try:
|
|
284
286
|
response = await client.patch(
|
|
285
287
|
url,
|
|
@@ -384,6 +386,7 @@ async def call_post(
|
|
|
384
386
|
"""
|
|
385
387
|
logger.debug(f"Calling POST '{url}'")
|
|
386
388
|
error_message = None
|
|
389
|
+
|
|
387
390
|
try:
|
|
388
391
|
response = await client.post(
|
|
389
392
|
url=url,
|
|
@@ -465,6 +468,7 @@ async def call_delete(
|
|
|
465
468
|
"""
|
|
466
469
|
logger.debug(f"Calling DELETE '{url}'")
|
|
467
470
|
error_message = None
|
|
471
|
+
|
|
468
472
|
try:
|
|
469
473
|
response = await client.delete(
|
|
470
474
|
url=url,
|
|
@@ -4,6 +4,7 @@ from textwrap import dedent
|
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
6
6
|
from loguru import logger
|
|
7
|
+
from fastmcp import Context
|
|
7
8
|
|
|
8
9
|
from basic_memory.mcp.server import mcp
|
|
9
10
|
from basic_memory.mcp.tools.read_note import read_note
|
|
@@ -13,54 +14,64 @@ from basic_memory.mcp.tools.read_note import read_note
|
|
|
13
14
|
description="View a note as a formatted artifact for better readability.",
|
|
14
15
|
)
|
|
15
16
|
async def view_note(
|
|
16
|
-
identifier: str,
|
|
17
|
+
identifier: str,
|
|
18
|
+
project: Optional[str] = None,
|
|
19
|
+
page: int = 1,
|
|
20
|
+
page_size: int = 10,
|
|
21
|
+
context: Context | None = None,
|
|
17
22
|
) -> str:
|
|
18
23
|
"""View a markdown note as a formatted artifact.
|
|
19
24
|
|
|
20
|
-
This tool reads a note using the same logic as read_note but
|
|
21
|
-
as a markdown artifact
|
|
22
|
-
|
|
23
|
-
After calling this tool, create an artifact using the returned content to display
|
|
24
|
-
the note in a readable format. The tool returns the note content that should be
|
|
25
|
-
used to create a markdown artifact.
|
|
25
|
+
This tool reads a note using the same logic as read_note but instructs Claude
|
|
26
|
+
to display the content as a markdown artifact in the Claude Desktop app.
|
|
27
|
+
Project parameter optional with server resolution.
|
|
26
28
|
|
|
27
29
|
Args:
|
|
28
30
|
identifier: The title or permalink of the note to view
|
|
31
|
+
project: Project name to read from. Optional - server will resolve using hierarchy.
|
|
32
|
+
If unknown, use list_memory_projects() to discover available projects.
|
|
29
33
|
page: Page number for paginated results (default: 1)
|
|
30
34
|
page_size: Number of items per page (default: 10)
|
|
31
|
-
|
|
35
|
+
context: Optional FastMCP context for performance caching.
|
|
32
36
|
|
|
33
37
|
Returns:
|
|
34
|
-
|
|
38
|
+
Instructions for Claude to create a markdown artifact with the note content.
|
|
39
|
+
|
|
40
|
+
Examples:
|
|
41
|
+
# View a note by title
|
|
42
|
+
view_note("Meeting Notes")
|
|
43
|
+
|
|
44
|
+
# View a note by permalink
|
|
45
|
+
view_note("meetings/weekly-standup")
|
|
46
|
+
|
|
47
|
+
# View with pagination
|
|
48
|
+
view_note("large-document", page=2, page_size=5)
|
|
49
|
+
|
|
50
|
+
# Explicit project specification
|
|
51
|
+
view_note("Meeting Notes", project="my-project")
|
|
52
|
+
|
|
53
|
+
Raises:
|
|
54
|
+
HTTPError: If project doesn't exist or is inaccessible
|
|
55
|
+
SecurityError: If identifier attempts path traversal
|
|
35
56
|
"""
|
|
36
57
|
|
|
37
|
-
logger.info(f"Viewing note: {identifier}")
|
|
58
|
+
logger.info(f"Viewing note: {identifier} in project: {project}")
|
|
38
59
|
|
|
39
60
|
# Call the existing read_note logic
|
|
40
|
-
content = await read_note.fn(identifier, page, page_size,
|
|
61
|
+
content = await read_note.fn(identifier, project, page, page_size, context)
|
|
41
62
|
|
|
42
63
|
# Check if this is an error message (note not found)
|
|
43
|
-
if "# Note Not Found
|
|
44
|
-
return content # Return error message directly
|
|
45
|
-
|
|
46
|
-
# Extract title from content if possible
|
|
47
|
-
title = identifier
|
|
48
|
-
lines = content.split("\n")
|
|
49
|
-
for line in lines:
|
|
50
|
-
if line.startswith("title:"):
|
|
51
|
-
# Extract title from frontmatter
|
|
52
|
-
title = line.split("title:", 1)[1].strip().strip('"').strip("'")
|
|
53
|
-
break
|
|
54
|
-
elif line.startswith("# "):
|
|
55
|
-
# Extract title from first heading
|
|
56
|
-
title = line[2:].strip()
|
|
57
|
-
break
|
|
58
|
-
|
|
59
|
-
# Return the artifact XML as part of the response
|
|
60
|
-
artifact = f'<artifact identifier="note-{hash(identifier) & 0x7FFFFFFF}" type="text/markdown" title="{title}">\n{content}\n</artifact>'
|
|
64
|
+
if "# Note Not Found" in content:
|
|
65
|
+
return content # Return error message directly
|
|
61
66
|
|
|
67
|
+
# Return instructions for Claude to create an artifact
|
|
62
68
|
return dedent(f"""
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
Note retrieved: "{identifier}"
|
|
70
|
+
|
|
71
|
+
Display this note as a markdown artifact for the user.
|
|
72
|
+
|
|
73
|
+
Content:
|
|
74
|
+
---
|
|
75
|
+
{content}
|
|
76
|
+
---
|
|
77
|
+
""").strip()
|