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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
|
+
from basic_memory.config import ConfigManager
|
|
3
4
|
from basic_memory.mcp.server import mcp
|
|
4
5
|
from loguru import logger
|
|
5
6
|
|
|
@@ -12,14 +13,58 @@ from loguru import logger
|
|
|
12
13
|
def ai_assistant_guide() -> str:
|
|
13
14
|
"""Return a concise guide on Basic Memory tools and how to use them.
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
Dynamically adapts instructions based on configuration:
|
|
17
|
+
- Default project mode: Simplified instructions with automatic project
|
|
18
|
+
- Regular mode: Project discovery and selection guidance
|
|
19
|
+
- CLI constraint mode: Single project constraint information
|
|
17
20
|
|
|
18
21
|
Returns:
|
|
19
22
|
A focused guide on Basic Memory usage.
|
|
20
23
|
"""
|
|
21
24
|
logger.info("Loading AI assistant guide resource")
|
|
25
|
+
|
|
26
|
+
# Load base guide content
|
|
22
27
|
guide_doc = Path(__file__).parent.parent / "resources" / "ai_assistant_guide.md"
|
|
23
28
|
content = guide_doc.read_text(encoding="utf-8")
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
|
|
30
|
+
# Check configuration for mode-specific instructions
|
|
31
|
+
config = ConfigManager().config
|
|
32
|
+
|
|
33
|
+
# Add mode-specific header
|
|
34
|
+
mode_info = ""
|
|
35
|
+
if config.default_project_mode:
|
|
36
|
+
mode_info = f"""
|
|
37
|
+
# 🎯 Default Project Mode Active
|
|
38
|
+
|
|
39
|
+
**Current Configuration**: All operations automatically use project '{config.default_project}'
|
|
40
|
+
|
|
41
|
+
**Simplified Usage**: You don't need to specify the project parameter in tool calls.
|
|
42
|
+
- `write_note(title="Note", content="...", folder="docs")` ✅
|
|
43
|
+
- Project parameter is optional and will default to '{config.default_project}'
|
|
44
|
+
- To use a different project, explicitly specify: `project="other-project"`
|
|
45
|
+
|
|
46
|
+
────────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
"""
|
|
49
|
+
else:
|
|
50
|
+
mode_info = """
|
|
51
|
+
# 🔧 Multi-Project Mode Active
|
|
52
|
+
|
|
53
|
+
**Current Configuration**: Project parameter required for all operations
|
|
54
|
+
|
|
55
|
+
**Project Discovery Required**: Use these tools to select a project:
|
|
56
|
+
- `list_memory_projects()` - See all available projects
|
|
57
|
+
- `recent_activity()` - Get project activity and recommendations
|
|
58
|
+
- Remember the user's project choice throughout the conversation
|
|
59
|
+
|
|
60
|
+
────────────────────────────────────────
|
|
61
|
+
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
# Prepend mode info to the guide
|
|
65
|
+
enhanced_content = mode_info + content
|
|
66
|
+
|
|
67
|
+
logger.info(
|
|
68
|
+
f"Loaded AI assistant guide ({len(enhanced_content)} chars) with mode: {'default_project' if config.default_project_mode else 'multi_project'}"
|
|
69
|
+
)
|
|
70
|
+
return enhanced_content
|
|
@@ -10,7 +10,7 @@ from loguru import logger
|
|
|
10
10
|
from pydantic import Field
|
|
11
11
|
|
|
12
12
|
from basic_memory.config import get_project_config
|
|
13
|
-
from basic_memory.mcp.async_client import
|
|
13
|
+
from basic_memory.mcp.async_client import get_client
|
|
14
14
|
from basic_memory.mcp.server import mcp
|
|
15
15
|
from basic_memory.mcp.tools.utils import call_post
|
|
16
16
|
from basic_memory.schemas.base import TimeFrame
|
|
@@ -18,7 +18,7 @@ from basic_memory.schemas.prompt import ContinueConversationRequest
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
@mcp.prompt(
|
|
21
|
-
name="
|
|
21
|
+
name="continue_conversation",
|
|
22
22
|
description="Continue a previous conversation",
|
|
23
23
|
)
|
|
24
24
|
async def continue_conversation(
|
|
@@ -42,20 +42,21 @@ async def continue_conversation(
|
|
|
42
42
|
"""
|
|
43
43
|
logger.info(f"Continuing session, topic: {topic}, timeframe: {timeframe}")
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
async with get_client() as client:
|
|
46
|
+
# Create request model
|
|
47
|
+
request = ContinueConversationRequest( # pyright: ignore [reportCallIssue]
|
|
48
|
+
topic=topic, timeframe=timeframe
|
|
49
|
+
)
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
project_url = get_project_config().project_url
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
# Call the prompt API endpoint
|
|
54
|
+
response = await call_post(
|
|
55
|
+
client,
|
|
56
|
+
f"{project_url}/prompt/continue-conversation",
|
|
57
|
+
json=request.model_dump(exclude_none=True),
|
|
58
|
+
)
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
# Extract the rendered prompt from the response
|
|
61
|
+
result = response.json()
|
|
62
|
+
return result["prompt"]
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
These prompts help users see what has changed in their knowledge base recently.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
from typing import Annotated
|
|
6
|
+
from typing import Annotated, Optional
|
|
7
7
|
|
|
8
8
|
from loguru import logger
|
|
9
9
|
from pydantic import Field
|
|
@@ -12,49 +12,83 @@ from basic_memory.mcp.prompts.utils import format_prompt_context, PromptContext,
|
|
|
12
12
|
from basic_memory.mcp.server import mcp
|
|
13
13
|
from basic_memory.mcp.tools.recent_activity import recent_activity
|
|
14
14
|
from basic_memory.schemas.base import TimeFrame
|
|
15
|
+
from basic_memory.schemas.memory import GraphContext, ProjectActivitySummary
|
|
15
16
|
from basic_memory.schemas.search import SearchItemType
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
@mcp.prompt(
|
|
19
|
-
name="
|
|
20
|
-
description="Get recent activity from across
|
|
20
|
+
name="recent_activity",
|
|
21
|
+
description="Get recent activity from a specific project or across all projects",
|
|
21
22
|
)
|
|
22
23
|
async def recent_activity_prompt(
|
|
23
24
|
timeframe: Annotated[
|
|
24
25
|
TimeFrame,
|
|
25
26
|
Field(description="How far back to look for activity (e.g. '1d', '1 week')"),
|
|
26
27
|
] = "7d",
|
|
28
|
+
project: Annotated[
|
|
29
|
+
Optional[str],
|
|
30
|
+
Field(
|
|
31
|
+
description="Specific project to get activity from (None for discovery across all projects)"
|
|
32
|
+
),
|
|
33
|
+
] = None,
|
|
27
34
|
) -> str:
|
|
28
|
-
"""Get recent activity from across
|
|
35
|
+
"""Get recent activity from a specific project or across all projects.
|
|
29
36
|
|
|
30
|
-
This prompt helps you see what's changed recently in the knowledge base
|
|
31
|
-
|
|
37
|
+
This prompt helps you see what's changed recently in the knowledge base.
|
|
38
|
+
In discovery mode (project=None), it shows activity across all projects.
|
|
39
|
+
In project-specific mode, it shows detailed activity for one project.
|
|
32
40
|
|
|
33
41
|
Args:
|
|
34
42
|
timeframe: How far back to look for activity (e.g. '1d', '1 week')
|
|
43
|
+
project: Specific project to get activity from (None for discovery across all projects)
|
|
35
44
|
|
|
36
45
|
Returns:
|
|
37
46
|
Formatted summary of recent activity
|
|
38
47
|
"""
|
|
39
|
-
logger.info(f"Getting recent activity, timeframe: {timeframe}")
|
|
48
|
+
logger.info(f"Getting recent activity, timeframe: {timeframe}, project: {project}")
|
|
40
49
|
|
|
41
|
-
recent = await recent_activity.fn(
|
|
50
|
+
recent = await recent_activity.fn(
|
|
51
|
+
project=project, timeframe=timeframe, type=[SearchItemType.ENTITY]
|
|
52
|
+
)
|
|
42
53
|
|
|
43
54
|
# Extract primary results from the hierarchical structure
|
|
44
55
|
primary_results = []
|
|
45
56
|
related_results = []
|
|
46
57
|
|
|
47
|
-
if recent
|
|
48
|
-
#
|
|
49
|
-
for
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
58
|
+
if isinstance(recent, ProjectActivitySummary):
|
|
59
|
+
# Discovery mode - extract results from all projects
|
|
60
|
+
for _, project_activity in recent.projects.items():
|
|
61
|
+
if project_activity.activity.results:
|
|
62
|
+
# Take up to 2 primary results per project
|
|
63
|
+
for item in project_activity.activity.results[:2]:
|
|
64
|
+
primary_results.append(item.primary_result)
|
|
65
|
+
# Add up to 1 related result per primary item
|
|
66
|
+
if item.related_results:
|
|
67
|
+
related_results.extend(item.related_results[:1])
|
|
68
|
+
|
|
69
|
+
# Limit total results for readability
|
|
70
|
+
primary_results = primary_results[:8]
|
|
71
|
+
related_results = related_results[:6]
|
|
72
|
+
|
|
73
|
+
elif isinstance(recent, GraphContext):
|
|
74
|
+
# Project-specific mode - use existing logic
|
|
75
|
+
if recent.results:
|
|
76
|
+
# Take up to 5 primary results
|
|
77
|
+
for item in recent.results[:5]:
|
|
78
|
+
primary_results.append(item.primary_result)
|
|
79
|
+
# Add up to 2 related results per primary item
|
|
80
|
+
if item.related_results:
|
|
81
|
+
related_results.extend(item.related_results[:2])
|
|
82
|
+
|
|
83
|
+
# Set topic based on mode
|
|
84
|
+
if project:
|
|
85
|
+
topic = f"Recent Activity in {project} ({timeframe})"
|
|
86
|
+
else:
|
|
87
|
+
topic = f"Recent Activity Across All Projects ({timeframe})"
|
|
54
88
|
|
|
55
89
|
prompt_context = format_prompt_context(
|
|
56
90
|
PromptContext(
|
|
57
|
-
topic=
|
|
91
|
+
topic=topic,
|
|
58
92
|
timeframe=timeframe,
|
|
59
93
|
results=[
|
|
60
94
|
PromptContextItem(
|
|
@@ -65,40 +99,90 @@ async def recent_activity_prompt(
|
|
|
65
99
|
)
|
|
66
100
|
)
|
|
67
101
|
|
|
68
|
-
# Add suggestions
|
|
102
|
+
# Add mode-specific suggestions
|
|
69
103
|
first_title = "Recent Topic"
|
|
70
104
|
if primary_results and len(primary_results) > 0:
|
|
71
105
|
first_title = primary_results[0].title
|
|
72
106
|
|
|
73
|
-
|
|
107
|
+
if project:
|
|
108
|
+
# Project-specific suggestions
|
|
109
|
+
capture_suggestions = f"""
|
|
74
110
|
## Opportunity to Capture Activity Summary
|
|
75
|
-
|
|
76
|
-
Consider creating a summary note of recent activity:
|
|
77
|
-
|
|
111
|
+
|
|
112
|
+
Consider creating a summary note of recent activity in {project}:
|
|
113
|
+
|
|
78
114
|
```python
|
|
79
115
|
await write_note(
|
|
116
|
+
"{project}",
|
|
80
117
|
title="Activity Summary {timeframe}",
|
|
81
118
|
content='''
|
|
82
|
-
# Activity Summary for {timeframe}
|
|
83
|
-
|
|
119
|
+
# Activity Summary for {project} ({timeframe})
|
|
120
|
+
|
|
84
121
|
## Overview
|
|
85
|
-
[Summary of key changes and developments over this period]
|
|
86
|
-
|
|
122
|
+
[Summary of key changes and developments in this project over this period]
|
|
123
|
+
|
|
87
124
|
## Key Updates
|
|
88
|
-
[List main updates and their significance]
|
|
89
|
-
|
|
125
|
+
[List main updates and their significance within this project]
|
|
126
|
+
|
|
90
127
|
## Observations
|
|
91
128
|
- [trend] [Observation about patterns in recent activity]
|
|
92
129
|
- [insight] [Connection between different activities]
|
|
93
|
-
|
|
130
|
+
|
|
94
131
|
## Relations
|
|
95
132
|
- summarizes [[{first_title}]]
|
|
96
|
-
- relates_to [[
|
|
97
|
-
'''
|
|
133
|
+
- relates_to [[{project} Overview]]
|
|
134
|
+
''',
|
|
135
|
+
folder="summaries"
|
|
98
136
|
)
|
|
99
137
|
```
|
|
100
|
-
|
|
101
|
-
Summarizing periodic activity helps create high-level insights and connections
|
|
138
|
+
|
|
139
|
+
Summarizing periodic activity helps create high-level insights and connections within the project.
|
|
140
|
+
"""
|
|
141
|
+
else:
|
|
142
|
+
# Discovery mode suggestions
|
|
143
|
+
project_count = len(recent.projects) if isinstance(recent, ProjectActivitySummary) else 0
|
|
144
|
+
most_active = (
|
|
145
|
+
getattr(recent.summary, "most_active_project", "Unknown")
|
|
146
|
+
if isinstance(recent, ProjectActivitySummary)
|
|
147
|
+
else "Unknown"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
capture_suggestions = f"""
|
|
151
|
+
## Cross-Project Activity Discovery
|
|
152
|
+
|
|
153
|
+
Found activity across {project_count} projects. Most active: **{most_active}**
|
|
154
|
+
|
|
155
|
+
Consider creating a cross-project summary:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
await write_note(
|
|
159
|
+
"{most_active if most_active != "Unknown" else "main"}",
|
|
160
|
+
title="Cross-Project Activity Summary {timeframe}",
|
|
161
|
+
content='''
|
|
162
|
+
# Cross-Project Activity Summary ({timeframe})
|
|
163
|
+
|
|
164
|
+
## Overview
|
|
165
|
+
Activity found across {project_count} projects, with {most_active} showing the most activity.
|
|
166
|
+
|
|
167
|
+
## Key Developments
|
|
168
|
+
[Summarize important changes across all projects]
|
|
169
|
+
|
|
170
|
+
## Project Insights
|
|
171
|
+
[Note patterns or connections between projects]
|
|
172
|
+
|
|
173
|
+
## Observations
|
|
174
|
+
- [trend] [Cross-project patterns observed]
|
|
175
|
+
- [insight] [Connections between different project activities]
|
|
176
|
+
|
|
177
|
+
## Relations
|
|
178
|
+
- summarizes [[{first_title}]]
|
|
179
|
+
- relates_to [[Project Portfolio Overview]]
|
|
180
|
+
''',
|
|
181
|
+
folder="summaries"
|
|
182
|
+
)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Cross-project summaries help identify broader trends and project interconnections.
|
|
102
186
|
"""
|
|
103
187
|
|
|
104
188
|
return prompt_context + capture_suggestions
|
|
@@ -9,7 +9,7 @@ from loguru import logger
|
|
|
9
9
|
from pydantic import Field
|
|
10
10
|
|
|
11
11
|
from basic_memory.config import get_project_config
|
|
12
|
-
from basic_memory.mcp.async_client import
|
|
12
|
+
from basic_memory.mcp.async_client import get_client
|
|
13
13
|
from basic_memory.mcp.server import mcp
|
|
14
14
|
from basic_memory.mcp.tools.utils import call_post
|
|
15
15
|
from basic_memory.schemas.base import TimeFrame
|
|
@@ -17,7 +17,7 @@ from basic_memory.schemas.prompt import SearchPromptRequest
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
@mcp.prompt(
|
|
20
|
-
name="
|
|
20
|
+
name="search_knowledge_base",
|
|
21
21
|
description="Search across all content in basic-memory",
|
|
22
22
|
)
|
|
23
23
|
async def search_prompt(
|
|
@@ -41,16 +41,17 @@ async def search_prompt(
|
|
|
41
41
|
"""
|
|
42
42
|
logger.info(f"Searching knowledge base, query: {query}, timeframe: {timeframe}")
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
async with get_client() as client:
|
|
45
|
+
# Create request model
|
|
46
|
+
request = SearchPromptRequest(query=query, timeframe=timeframe)
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
project_url = get_project_config().project_url
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
# Call the prompt API endpoint
|
|
51
|
+
response = await call_post(
|
|
52
|
+
client, f"{project_url}/prompt/search", json=request.model_dump(exclude_none=True)
|
|
53
|
+
)
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
# Extract the rendered prompt from the response
|
|
56
|
+
result = response.json()
|
|
57
|
+
return result["prompt"]
|
|
@@ -103,10 +103,17 @@ def format_prompt_context(context: PromptContext) -> str:
|
|
|
103
103
|
|
|
104
104
|
added_permalinks.add(primary_permalink)
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
# Use permalink if available, otherwise use file_path
|
|
107
|
+
if primary_permalink:
|
|
108
|
+
memory_url = normalize_memory_url(primary_permalink)
|
|
109
|
+
read_command = f'read_note("{primary_permalink}")'
|
|
110
|
+
else:
|
|
111
|
+
memory_url = f"file://{primary.file_path}"
|
|
112
|
+
read_command = f'read_file("{primary.file_path}")'
|
|
113
|
+
|
|
107
114
|
section = dedent(f"""
|
|
108
115
|
--- {memory_url}
|
|
109
|
-
|
|
116
|
+
|
|
110
117
|
## {primary.title}
|
|
111
118
|
- **Type**: {primary.type}
|
|
112
119
|
""")
|
|
@@ -121,8 +128,8 @@ def format_prompt_context(context: PromptContext) -> str:
|
|
|
121
128
|
section += f"\n**Excerpt**:\n{content}\n"
|
|
122
129
|
|
|
123
130
|
section += dedent(f"""
|
|
124
|
-
|
|
125
|
-
You can read this document with: `
|
|
131
|
+
|
|
132
|
+
You can read this document with: `{read_command}`
|
|
126
133
|
""")
|
|
127
134
|
sections.append(section)
|
|
128
135
|
|