Skip to content

Commit 3c4617e

Browse files
committed
format code
Signed-off-by: phernandez <paul@basicmachines.co>
1 parent 38aac1c commit 3c4617e

5 files changed

Lines changed: 44 additions & 71 deletions

File tree

src/basic_memory/mcp/tools/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
create_memory_project,
2525
delete_project,
2626
)
27+
2728
# ChatGPT-compatible tools
2829
from basic_memory.mcp.tools.chatgpt_tools import search, fetch
2930

src/basic_memory/mcp/tools/chatgpt_tools.py

Lines changed: 18 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def _format_search_results_for_chatgpt(results: SearchResponse) -> List[Dict[str
2727
formatted_result = {
2828
"id": result.permalink or f"doc-{len(formatted_results)}",
2929
"title": result.title if result.title and result.title.strip() else "Untitled",
30-
"url": result.permalink or ""
30+
"url": result.permalink or "",
3131
}
3232
formatted_results.append(formatted_result)
3333

@@ -43,11 +43,11 @@ def _format_document_for_chatgpt(
4343
"""
4444
# Extract title from markdown content if not provided
4545
if not title and isinstance(content, str):
46-
lines = content.split('\n')
47-
if lines and lines[0].startswith('# '):
46+
lines = content.split("\n")
47+
if lines and lines[0].startswith("# "):
4848
title = lines[0][2:].strip()
4949
else:
50-
title = identifier.split('/')[-1].replace('-', ' ').title()
50+
title = identifier.split("/")[-1].replace("-", " ").title()
5151

5252
# Ensure title is never None
5353
if not title:
@@ -60,21 +60,19 @@ def _format_document_for_chatgpt(
6060
"title": title or "Document Not Found",
6161
"text": content,
6262
"url": identifier,
63-
"metadata": {"error": "Document not found"}
63+
"metadata": {"error": "Document not found"},
6464
}
6565

6666
return {
6767
"id": identifier,
6868
"title": title or "Untitled Document",
6969
"text": content,
7070
"url": identifier,
71-
"metadata": {"format": "markdown"}
71+
"metadata": {"format": "markdown"},
7272
}
7373

7474

75-
@mcp.tool(
76-
description="Search for content across the knowledge base"
77-
)
75+
@mcp.tool(description="Search for content across the knowledge base")
7876
async def search(
7977
query: str,
8078
context: Context | None = None,
@@ -99,7 +97,7 @@ async def search(
9997
page=1,
10098
page_size=10, # Reasonable default for ChatGPT consumption
10199
search_type="text", # Default to full-text search
102-
context=context
100+
context=context,
103101
)
104102

105103
# Handle string error responses from search_notes
@@ -108,44 +106,32 @@ async def search(
108106
search_results = {
109107
"results": [],
110108
"error": "Search failed",
111-
"error_details": results[:500] # Truncate long error messages
109+
"error_details": results[:500], # Truncate long error messages
112110
}
113111
else:
114112
# Format successful results for ChatGPT
115113
formatted_results = _format_search_results_for_chatgpt(results)
116114
search_results = {
117115
"results": formatted_results,
118116
"total_count": len(results.results), # Use actual count from results
119-
"query": query
117+
"query": query,
120118
}
121119
logger.info(f"Search completed: {len(formatted_results)} results returned")
122120

123121
# Return in MCP content array format as required by OpenAI
124-
return [
125-
{
126-
"type": "text",
127-
"text": json.dumps(search_results, ensure_ascii=False)
128-
}
129-
]
122+
return [{"type": "text", "text": json.dumps(search_results, ensure_ascii=False)}]
130123

131124
except Exception as e:
132125
logger.error(f"ChatGPT search failed for query '{query}': {e}")
133126
error_results = {
134127
"results": [],
135128
"error": "Internal search error",
136-
"error_message": str(e)[:200]
129+
"error_message": str(e)[:200],
137130
}
138-
return [
139-
{
140-
"type": "text",
141-
"text": json.dumps(error_results, ensure_ascii=False)
142-
}
143-
]
131+
return [{"type": "text", "text": json.dumps(error_results, ensure_ascii=False)}]
144132

145133

146-
@mcp.tool(
147-
description="Fetch the full contents of a search result document"
148-
)
134+
@mcp.tool(description="Fetch the full contents of a search result document")
149135
async def fetch(
150136
id: str,
151137
context: Context | None = None,
@@ -169,7 +155,7 @@ async def fetch(
169155
project=None, # Let project resolution happen automatically
170156
page=1,
171157
page_size=10, # Default pagination
172-
context=context
158+
context=context,
173159
)
174160

175161
# Format the document for ChatGPT
@@ -178,12 +164,7 @@ async def fetch(
178164
logger.info(f"Fetch completed: id='{id}', content_length={len(document.get('text', ''))}")
179165

180166
# Return in MCP content array format as required by OpenAI
181-
return [
182-
{
183-
"type": "text",
184-
"text": json.dumps(document, ensure_ascii=False)
185-
}
186-
]
167+
return [{"type": "text", "text": json.dumps(document, ensure_ascii=False)}]
187168

188169
except Exception as e:
189170
logger.error(f"ChatGPT fetch failed for id '{id}': {e}")
@@ -192,11 +173,6 @@ async def fetch(
192173
"title": "Fetch Error",
193174
"text": f"Failed to fetch document: {str(e)[:200]}",
194175
"url": id,
195-
"metadata": {"error": "Fetch failed"}
176+
"metadata": {"error": "Fetch failed"},
196177
}
197-
return [
198-
{
199-
"type": "text",
200-
"text": json.dumps(error_document, ensure_ascii=False)
201-
}
202-
]
178+
return [{"type": "text", "text": json.dumps(error_document, ensure_ascii=False)}]

test-int/mcp/test_chatgpt_tools_integration.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ async def test_chatgpt_search_basic(mcp_server, app, test_project):
3838
"title": "Machine Learning Fundamentals",
3939
"folder": "ai",
4040
"content": (
41-
"# Machine Learning Fundamentals\n\n"
42-
"Introduction to ML concepts and algorithms."
41+
"# Machine Learning Fundamentals\n\nIntroduction to ML concepts and algorithms."
4342
),
4443
"tags": "ml,ai,fundamentals",
4544
},
@@ -66,8 +65,7 @@ async def test_chatgpt_search_basic(mcp_server, app, test_project):
6665
"title": "Data Visualization Guide",
6766
"folder": "data",
6867
"content": (
69-
"# Data Visualization Guide\n\n"
70-
"Creating charts and graphs for data analysis."
68+
"# Data Visualization Guide\n\nCreating charts and graphs for data analysis."
7169
),
7270
"tags": "visualization,data,charts",
7371
},
@@ -131,8 +129,7 @@ async def test_chatgpt_search_with_boolean_operators(mcp_server, app, test_proje
131129
"title": "Python Web Frameworks",
132130
"folder": "dev",
133131
"content": (
134-
"# Python Web Frameworks\n\n"
135-
"Comparing Django and Flask for web development."
132+
"# Python Web Frameworks\n\nComparing Django and Flask for web development."
136133
),
137134
"tags": "python,web,frameworks",
138135
},
@@ -376,7 +373,7 @@ async def test_chatgpt_tools_error_handling(mcp_server, app, test_project):
376373
)
377374

378375
# Should still return MCP content array format
379-
assert hasattr(search_result, 'content')
376+
assert hasattr(search_result, "content")
380377
content_list = search_result.content
381378
assert isinstance(content_list, list)
382379
assert len(content_list) == 1
@@ -397,8 +394,7 @@ async def test_chatgpt_integration_workflow(mcp_server, app, test_project):
397394
{
398395
"title": "API Design Best Practices",
399396
"content": (
400-
"# API Design Best Practices\n\n"
401-
"RESTful API design principles and patterns."
397+
"# API Design Best Practices\n\nRESTful API design principles and patterns."
402398
),
403399
"tags": "api,rest,design",
404400
},
@@ -456,4 +452,4 @@ async def test_chatgpt_integration_workflow(mcp_server, app, test_project):
456452
assert "API" in document_json["text"] or "api" in document_json["text"].lower()
457453

458454
# Verify document has expected structure
459-
assert document_json["metadata"]["format"] == "markdown"
455+
assert document_json["metadata"]["format"] == "markdown"

tests/mcp/tools/test_chatgpt_tools.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,29 @@ async def test_search_successful_results():
1919
content="This is test content for document 1",
2020
type=SearchItemType.ENTITY,
2121
score=1.0,
22-
file_path="/test/docs/test-doc-1.md"
22+
file_path="/test/docs/test-doc-1.md",
2323
),
2424
SearchResult(
2525
title="Test Document 2",
2626
permalink="docs/test-doc-2",
2727
content="This is test content for document 2",
2828
type=SearchItemType.ENTITY,
2929
score=0.9,
30-
file_path="/test/docs/test-doc-2.md"
31-
)
30+
file_path="/test/docs/test-doc-2.md",
31+
),
3232
],
3333
current_page=1,
34-
page_size=10
34+
page_size=10,
3535
)
3636

3737
with patch(
38-
'basic_memory.mcp.tools.chatgpt_tools.search_notes.fn',
39-
new_callable=AsyncMock
38+
"basic_memory.mcp.tools.chatgpt_tools.search_notes.fn", new_callable=AsyncMock
4039
) as mock_search:
4140
mock_search.return_value = mock_results
4241

4342
# Import and call the actual function
4443
from basic_memory.mcp.tools.chatgpt_tools import search
44+
4545
result = await search.fn("test query")
4646

4747
# Verify MCP content array format
@@ -71,12 +71,12 @@ async def test_search_with_error_response():
7171
error_message = "# Search Failed - Invalid Syntax\n\nThe search query contains errors..."
7272

7373
with patch(
74-
'basic_memory.mcp.tools.chatgpt_tools.search_notes.fn',
75-
new_callable=AsyncMock
74+
"basic_memory.mcp.tools.chatgpt_tools.search_notes.fn", new_callable=AsyncMock
7675
) as mock_search:
7776
mock_search.return_value = error_message
7877

7978
from basic_memory.mcp.tools.chatgpt_tools import search
79+
8080
result = await search.fn("invalid query")
8181

8282
# Verify MCP content array format
@@ -109,12 +109,12 @@ async def test_fetch_successful_document():
109109
"""
110110

111111
with patch(
112-
'basic_memory.mcp.tools.chatgpt_tools.read_note.fn',
113-
new_callable=AsyncMock
112+
"basic_memory.mcp.tools.chatgpt_tools.read_note.fn", new_callable=AsyncMock
114113
) as mock_read:
115114
mock_read.return_value = document_content
116115

117116
from basic_memory.mcp.tools.chatgpt_tools import fetch
117+
118118
result = await fetch.fn("docs/test-document")
119119

120120
# Verify MCP content array format
@@ -143,12 +143,12 @@ async def test_fetch_document_not_found():
143143
"""
144144

145145
with patch(
146-
'basic_memory.mcp.tools.chatgpt_tools.read_note.fn',
147-
new_callable=AsyncMock
146+
"basic_memory.mcp.tools.chatgpt_tools.read_note.fn", new_callable=AsyncMock
148147
) as mock_read:
149148
mock_read.return_value = error_content
150149

151150
from basic_memory.mcp.tools.chatgpt_tools import fetch
151+
152152
result = await fetch.fn("nonexistent-doc")
153153

154154
# Verify MCP content array format
@@ -175,19 +175,19 @@ def test_format_search_results_for_chatgpt():
175175
content="Content for document one",
176176
type=SearchItemType.ENTITY,
177177
score=1.0,
178-
file_path="/test/docs/doc-one.md"
178+
file_path="/test/docs/doc-one.md",
179179
),
180180
SearchResult(
181181
title="", # Test empty title handling
182182
permalink="docs/untitled",
183183
content="Content without title",
184184
type=SearchItemType.ENTITY,
185185
score=0.8,
186-
file_path="/test/docs/untitled.md"
187-
)
186+
file_path="/test/docs/untitled.md",
187+
),
188188
],
189189
current_page=1,
190-
page_size=10
190+
page_size=10,
191191
)
192192

193193
formatted = _format_search_results_for_chatgpt(mock_results)
@@ -219,10 +219,10 @@ def test_format_document_error_handling():
219219
"""Test document formatting with error content."""
220220
from basic_memory.mcp.tools.chatgpt_tools import _format_document_for_chatgpt
221221

222-
error_content = "# Note Not Found: \"missing-doc\"\n\nDocument not found."
222+
error_content = '# Note Not Found: "missing-doc"\n\nDocument not found.'
223223
result = _format_document_for_chatgpt(error_content, "missing-doc", "Missing Doc")
224224

225225
assert result["id"] == "missing-doc"
226226
assert result["title"] == "Missing Doc"
227227
assert result["text"] == error_content
228-
assert result["metadata"]["error"] == "Document not found"
228+
assert result["metadata"]["error"] == "Document not found"

tests/sync/test_sync_service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ async def test_sync_preserves_timestamps(
639639
entity_updated_epoch = file_entity.updated_at.timestamp()
640640

641641
# Allow 2s difference on Windows due to filesystem timing precision
642-
tolerance = 2 if os.name == 'nt' else 1
642+
tolerance = 2 if os.name == "nt" else 1
643643
assert abs(entity_created_epoch - file_stats.st_ctime) < tolerance
644644
assert abs(entity_updated_epoch - file_stats.st_mtime) < tolerance # Allow tolerance difference
645645

0 commit comments

Comments
 (0)