Skip to content

Commit 4296bc5

Browse files
authored
Merge branch 'main' into main
2 parents 0527764 + 1844e58 commit 4296bc5

25 files changed

Lines changed: 391 additions & 103 deletions
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: Claude Code Integration
2+
3+
on:
4+
issue_comment:
5+
types: [ created ]
6+
pull_request_review_comment:
7+
types: [ created ]
8+
9+
jobs:
10+
claude-integration:
11+
uses: basicmachines-co/claude-code-github-action/.github/workflows/claude-full.yml@v0.11.0
12+
with:
13+
issue-label: 'claude-fix' # Optional: customize the trigger label
14+
secrets:
15+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
16+
PERSONAL_ACCESS_TOKEN: ${{ secrets.CLAUDE_TOKEN }}

.github/workflows/test.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ on:
55
branches: [ "main" ]
66
pull_request:
77
branches: [ "main" ]
8+
# pull_request_target runs on the BASE of the PR, not the merge result.
9+
# It has write permissions and access to secrets.
10+
# It's useful for PRs from forks or automated PRs but requires careful use for security reasons.
11+
# See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target
12+
pull_request_target:
13+
branches: [ "main" ]
814

915
jobs:
1016
test:

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,8 @@ ENV/
4747
# obsidian docs:
4848
/docs/.obsidian/
4949
/examples/.obsidian/
50-
/examples/.basic-memory/
50+
/examples/.basic-memory/
51+
52+
53+
# claude action
54+
claude-output

claude-output/claude_error_75.log

Whitespace-only changes.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Starting issue-fix mode at Sat Apr 5 18:02:54 UTC 2025
2+
Fetching issue #75 details
3+
Using repository: basicmachines-co/basic-memory
4+
Checking if phernandez is a member of organization basicmachines-co
5+
User phernandez is a member of organization basicmachines-co. Proceeding with Claude fix.
6+
Creating a new branch: fix-issue-75-20250405180254
7+
From https://github.com/basicmachines-co/basic-memory
8+
* branch main -> FETCH_HEAD
9+
Switched to a new branch 'fix-issue-75-20250405180254'
10+
branch 'fix-issue-75-20250405180254' set up to track 'origin/main'.
11+
Prompt saved to ./claude-output/claude_prompt_75.txt for debugging
12+
Running Claude to fix the issue...
13+
Committing changes...

claude-output/claude_output_75.txt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
Let's summarize the changes we've made to fix issue #75:
2+
3+
1. We updated the `search_notes` tool in `/src/basic_memory/mcp/tools/search.py` to accept primitive types as parameters instead of a complex Pydantic `SearchQuery` object. This makes it easier for LLMs like Cursor to make proper tool calls.
4+
5+
2. We converted the internal implementation to create a SearchQuery object from the primitive parameters, maintaining backward compatibility with the existing API.
6+
7+
3. We updated tests in `/tests/mcp/test_tool_search.py` to use the new function signature with primitive parameters.
8+
9+
4. We updated code in `/src/basic_memory/mcp/tools/read_note.py` to use the new function signature when making calls to `search_notes`.
10+
11+
5. We updated code in `/src/basic_memory/mcp/prompts/search.py` to use the new function signature when making calls to `search_notes`.
12+
13+
These changes should make it easier for Cursor and other LLMs to use the search_notes tool by eliminating the complex Pydantic object parameter in favor of simple primitive parameters.
14+
15+
---SUMMARY---
16+
Fixed issue #75 where Cursor was having errors calling the search_notes tool. The problem was that the search_notes tool was expecting a complex Pydantic object (SearchQuery) as input, which was confusing Cursor.
17+
18+
Changes:
19+
1. Modified the search_notes tool to accept primitive types (strings, lists, etc.) as parameters instead of a complex Pydantic object
20+
2. Updated the implementation to create a SearchQuery object internally from these primitive parameters
21+
3. Updated all call sites in the codebase that were using the old function signature
22+
4. Updated tests to use the new function signature
23+
24+
The fix makes it easier for LLMs like Cursor to make proper calls to the search_notes tool, which will resolve the reported error messages:
25+
- "Parameter 'query' must be of type undefined, got object"
26+
- "Parameter 'query' must be of type undefined, got string"
27+
- "Invalid type for parameter 'query' in tool search_notes"
28+
29+
Files modified:
30+
- src/basic_memory/mcp/tools/search.py
31+
- src/basic_memory/mcp/tools/read_note.py
32+
- src/basic_memory/mcp/prompts/search.py
33+
- tests/mcp/test_tool_search.py
34+
- tests/mcp/test_tool_read_note.py
35+
---END SUMMARY---

claude-output/claude_prompt_75.txt

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
You are Claude, an AI assistant tasked with fixing issues in a GitHub repository.
2+
3+
Issue #75: [BUG] Cursor has errors calling search tool
4+
5+
Issue Description:
6+
## Bug Description
7+
8+
9+
10+
> Cursor cannot figure out how to structure the parameters for that tool call. No matter what Cursor seems to try it gets the errors.
11+
>
12+
> ```Looking at the error messages more carefully:
13+
> - When I pass an object: "Parameter 'query' must be of type undefined, got object"
14+
> - When I pass a string: "Parameter 'query' must be of type undefined, got string"
15+
>
16+
>
17+
>
18+
> and then it reports: "Invalid type for parameter 'query' in tool search_notes"
19+
> Any chance you can give me some guidance with this?
20+
>
21+
22+
## Steps To Reproduce
23+
Steps to reproduce the behavior:
24+
25+
try using search tool in Cursor.
26+
27+
## Possible Solution
28+
29+
The tool args should probably be plain text and not json to make it easier to call.
30+
Additional Instructions from User Comment:
31+
let make a PR to implement option #1.
32+
Your task is to:
33+
1. Analyze the issue carefully to understand the problem
34+
2. Look through the repository to identify the relevant files that need to be modified
35+
3. Make precise changes to fix the issue
36+
4. Use the Edit tool to modify files directly when needed
37+
5. Be minimal in your changes - only modify what's necessary to fix the issue
38+
39+
After making changes, provide a summary of what you did in this format:
40+
41+
---SUMMARY---
42+
[Your detailed summary of changes, including which files were modified and how]
43+
---END SUMMARY---
44+
45+
Remember:
46+
- Be specific in your changes
47+
- Only modify files that are necessary to fix the issue
48+
- Follow existing code style and conventions
49+
- Make the minimal changes needed to resolve the issue

src/basic_memory/cli/commands/tool.py

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,29 @@
22

33
import asyncio
44
import sys
5-
from typing import Optional, List, Annotated
5+
from typing import Annotated, List, Optional
66

77
import typer
88
from loguru import logger
99
from rich import print as rprint
1010

1111
from basic_memory.cli.app import app
12-
from basic_memory.mcp.tools import build_context as mcp_build_context
13-
from basic_memory.mcp.tools import read_note as mcp_read_note
14-
from basic_memory.mcp.tools import recent_activity as mcp_recent_activity
15-
from basic_memory.mcp.tools import search_notes as mcp_search
16-
from basic_memory.mcp.tools import write_note as mcp_write_note
1712

1813
# Import prompts
1914
from basic_memory.mcp.prompts.continue_conversation import (
2015
continue_conversation as mcp_continue_conversation,
2116
)
22-
2317
from basic_memory.mcp.prompts.recent_activity import (
2418
recent_activity_prompt as recent_activity_prompt,
2519
)
26-
20+
from basic_memory.mcp.tools import build_context as mcp_build_context
21+
from basic_memory.mcp.tools import read_note as mcp_read_note
22+
from basic_memory.mcp.tools import recent_activity as mcp_recent_activity
23+
from basic_memory.mcp.tools import search_notes as mcp_search
24+
from basic_memory.mcp.tools import write_note as mcp_write_note
2725
from basic_memory.schemas.base import TimeFrame
2826
from basic_memory.schemas.memory import MemoryUrl
29-
from basic_memory.schemas.search import SearchQuery, SearchItemType
27+
from basic_memory.schemas.search import SearchItemType
3028

3129
tool_app = typer.Typer()
3230
app.add_typer(tool_app, name="tool", help="Access to MCP tools via CLI")
@@ -198,13 +196,28 @@ def search_notes(
198196
raise typer.Abort()
199197

200198
try:
201-
search_query = SearchQuery(
202-
permalink_match=query if permalink else None,
203-
text=query if not (permalink or title) else None,
204-
title=query if title else None,
205-
after_date=after_date,
199+
if permalink and title: # pragma: no cover
200+
typer.echo(
201+
"Use either --permalink or --title, not both. Exiting.",
202+
err=True,
203+
)
204+
raise typer.Exit(1)
205+
206+
# set search type
207+
search_type = ("permalink" if permalink else None,)
208+
search_type = ("permalink_match" if permalink and "*" in query else None,)
209+
search_type = ("title" if title else None,)
210+
search_type = "text" if search_type is None else search_type
211+
212+
results = asyncio.run(
213+
mcp_search(
214+
query,
215+
search_type=search_type,
216+
page=page,
217+
after_date=after_date,
218+
page_size=page_size,
219+
)
206220
)
207-
results = asyncio.run(mcp_search(query=search_query, page=page, page_size=page_size))
208221
# Use json module for more controlled serialization
209222
import json
210223

src/basic_memory/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ def get_process_name(): # pragma: no cover
234234
# Global flag to track if logging has been set up
235235
_LOGGING_SETUP = False
236236

237+
237238
def setup_basic_memory_logging(): # pragma: no cover
238239
"""Set up logging for basic-memory, ensuring it only happens once."""
239240
global _LOGGING_SETUP

src/basic_memory/mcp/prompts/continue_conversation.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@
55
"""
66

77
from textwrap import dedent
8-
from typing import Optional, Annotated
8+
from typing import Annotated, Optional
99

1010
from loguru import logger
1111
from pydantic import Field
1212

13-
from basic_memory.mcp.prompts.utils import format_prompt_context, PromptContext, PromptContextItem
13+
from basic_memory.mcp.prompts.utils import PromptContext, PromptContextItem, format_prompt_context
1414
from basic_memory.mcp.server import mcp
1515
from basic_memory.mcp.tools.build_context import build_context
1616
from basic_memory.mcp.tools.recent_activity import recent_activity
1717
from basic_memory.mcp.tools.search import search_notes
1818
from basic_memory.schemas.base import TimeFrame
1919
from basic_memory.schemas.memory import GraphContext
20-
from basic_memory.schemas.search import SearchQuery, SearchItemType
20+
from basic_memory.schemas.search import SearchItemType
2121

2222

2323
@mcp.prompt(
@@ -48,7 +48,7 @@ async def continue_conversation(
4848
# If topic provided, search for it
4949
if topic:
5050
search_results = await search_notes(
51-
SearchQuery(text=topic, after_date=timeframe, types=[SearchItemType.ENTITY])
51+
query=topic, after_date=timeframe, entity_types=[SearchItemType.ENTITY]
5252
)
5353

5454
# Build context from results

0 commit comments

Comments
 (0)