basic-memory 0.0.0__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 +3 -0
- basic_memory/api/__init__.py +4 -0
- basic_memory/api/app.py +42 -0
- basic_memory/api/routers/__init__.py +8 -0
- basic_memory/api/routers/knowledge_router.py +168 -0
- basic_memory/api/routers/memory_router.py +123 -0
- basic_memory/api/routers/resource_router.py +34 -0
- basic_memory/api/routers/search_router.py +34 -0
- basic_memory/cli/__init__.py +1 -0
- basic_memory/cli/app.py +4 -0
- basic_memory/cli/commands/__init__.py +9 -0
- basic_memory/cli/commands/init.py +38 -0
- basic_memory/cli/commands/status.py +152 -0
- basic_memory/cli/commands/sync.py +254 -0
- basic_memory/cli/main.py +48 -0
- basic_memory/config.py +53 -0
- basic_memory/db.py +135 -0
- basic_memory/deps.py +182 -0
- basic_memory/file_utils.py +248 -0
- basic_memory/markdown/__init__.py +19 -0
- basic_memory/markdown/entity_parser.py +137 -0
- basic_memory/markdown/markdown_processor.py +153 -0
- basic_memory/markdown/plugins.py +236 -0
- basic_memory/markdown/schemas.py +73 -0
- basic_memory/markdown/utils.py +144 -0
- basic_memory/mcp/__init__.py +1 -0
- basic_memory/mcp/async_client.py +10 -0
- basic_memory/mcp/main.py +21 -0
- basic_memory/mcp/server.py +39 -0
- basic_memory/mcp/tools/__init__.py +34 -0
- basic_memory/mcp/tools/ai_edit.py +84 -0
- basic_memory/mcp/tools/knowledge.py +56 -0
- basic_memory/mcp/tools/memory.py +142 -0
- basic_memory/mcp/tools/notes.py +122 -0
- basic_memory/mcp/tools/search.py +28 -0
- basic_memory/mcp/tools/utils.py +154 -0
- basic_memory/models/__init__.py +12 -0
- basic_memory/models/base.py +9 -0
- basic_memory/models/knowledge.py +204 -0
- basic_memory/models/search.py +34 -0
- basic_memory/repository/__init__.py +7 -0
- basic_memory/repository/entity_repository.py +156 -0
- basic_memory/repository/observation_repository.py +40 -0
- basic_memory/repository/relation_repository.py +78 -0
- basic_memory/repository/repository.py +303 -0
- basic_memory/repository/search_repository.py +259 -0
- basic_memory/schemas/__init__.py +73 -0
- basic_memory/schemas/base.py +216 -0
- basic_memory/schemas/delete.py +38 -0
- basic_memory/schemas/discovery.py +25 -0
- basic_memory/schemas/memory.py +111 -0
- basic_memory/schemas/request.py +77 -0
- basic_memory/schemas/response.py +220 -0
- basic_memory/schemas/search.py +117 -0
- basic_memory/services/__init__.py +11 -0
- basic_memory/services/context_service.py +274 -0
- basic_memory/services/entity_service.py +281 -0
- basic_memory/services/exceptions.py +15 -0
- basic_memory/services/file_service.py +213 -0
- basic_memory/services/link_resolver.py +126 -0
- basic_memory/services/search_service.py +218 -0
- basic_memory/services/service.py +36 -0
- basic_memory/sync/__init__.py +5 -0
- basic_memory/sync/file_change_scanner.py +162 -0
- basic_memory/sync/sync_service.py +140 -0
- basic_memory/sync/utils.py +66 -0
- basic_memory/sync/watch_service.py +197 -0
- basic_memory/utils.py +78 -0
- basic_memory-0.0.0.dist-info/METADATA +71 -0
- basic_memory-0.0.0.dist-info/RECORD +73 -0
- basic_memory-0.0.0.dist-info/WHEEL +4 -0
- basic_memory-0.0.0.dist-info/entry_points.txt +2 -0
- basic_memory-0.0.0.dist-info/licenses/LICENSE +661 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Knowledge graph management tools for Basic Memory MCP server."""
|
|
2
|
+
|
|
3
|
+
from basic_memory.mcp.server import mcp
|
|
4
|
+
from basic_memory.mcp.tools.utils import call_get, call_post
|
|
5
|
+
from basic_memory.schemas.base import PathId
|
|
6
|
+
from basic_memory.schemas.request import (
|
|
7
|
+
GetEntitiesRequest,
|
|
8
|
+
)
|
|
9
|
+
from basic_memory.schemas.delete import (
|
|
10
|
+
DeleteEntitiesRequest,
|
|
11
|
+
)
|
|
12
|
+
from basic_memory.schemas.response import EntityListResponse, EntityResponse, DeleteEntitiesResponse
|
|
13
|
+
from basic_memory.mcp.async_client import client
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@mcp.tool(
|
|
17
|
+
description="Get complete information about a specific entity including observations and relations",
|
|
18
|
+
)
|
|
19
|
+
async def get_entity(permalink: PathId) -> EntityResponse:
|
|
20
|
+
"""Get a specific entity info by its permalink.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
permalink: Path identifier for the entity
|
|
24
|
+
"""
|
|
25
|
+
url = f"/knowledge/entities/{permalink}"
|
|
26
|
+
response = await call_get(client, url)
|
|
27
|
+
return EntityResponse.model_validate(response.json())
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@mcp.tool(
|
|
31
|
+
description="Load multiple entities by their permalinks in a single request",
|
|
32
|
+
)
|
|
33
|
+
async def get_entities(request: GetEntitiesRequest) -> EntityListResponse:
|
|
34
|
+
"""Load multiple entities by their permalinks.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
request: OpenNodesRequest containing list of permalinks to load
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
EntityListResponse containing complete details for each requested entity
|
|
41
|
+
"""
|
|
42
|
+
url = "/knowledge/entities"
|
|
43
|
+
response = await call_get(
|
|
44
|
+
client, url, params=[("permalink", permalink) for permalink in request.permalinks]
|
|
45
|
+
)
|
|
46
|
+
return EntityListResponse.model_validate(response.json())
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@mcp.tool(
|
|
50
|
+
description="Permanently delete entities and all related content (observations and relations)",
|
|
51
|
+
)
|
|
52
|
+
async def delete_entities(request: DeleteEntitiesRequest) -> DeleteEntitiesResponse:
|
|
53
|
+
"""Delete entities from the knowledge graph."""
|
|
54
|
+
url = "/knowledge/entities/delete"
|
|
55
|
+
response = await call_post(client, url, json=request.model_dump())
|
|
56
|
+
return DeleteEntitiesResponse.model_validate(response.json())
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"""Discussion context tools for Basic Memory MCP server."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Literal
|
|
4
|
+
|
|
5
|
+
from loguru import logger
|
|
6
|
+
|
|
7
|
+
from basic_memory.mcp.async_client import client
|
|
8
|
+
from basic_memory.mcp.server import mcp
|
|
9
|
+
from basic_memory.mcp.tools.utils import call_get
|
|
10
|
+
from basic_memory.schemas.memory import GraphContext, MemoryUrl, memory_url, memory_url_path, normalize_memory_url
|
|
11
|
+
from basic_memory.schemas.base import TimeFrame
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@mcp.tool(
|
|
15
|
+
description="""Build context from a memory:// URI to continue conversations naturally.
|
|
16
|
+
|
|
17
|
+
Use this to follow up on previous discussions or explore related topics.
|
|
18
|
+
Timeframes support natural language like:
|
|
19
|
+
- "2 days ago"
|
|
20
|
+
- "last week"
|
|
21
|
+
- "today"
|
|
22
|
+
- "3 months ago"
|
|
23
|
+
Or standard formats like "7d", "24h"
|
|
24
|
+
""",
|
|
25
|
+
)
|
|
26
|
+
async def build_context(
|
|
27
|
+
url: MemoryUrl,
|
|
28
|
+
depth: Optional[int] = 1,
|
|
29
|
+
timeframe: Optional[TimeFrame] = "7d",
|
|
30
|
+
max_results: int = 10,
|
|
31
|
+
) -> GraphContext:
|
|
32
|
+
"""Get context needed to continue a discussion.
|
|
33
|
+
|
|
34
|
+
This tool enables natural continuation of discussions by loading relevant context
|
|
35
|
+
from memory:// URIs. It uses pattern matching to find relevant content and builds
|
|
36
|
+
a rich context graph of related information.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
url: memory:// URI pointing to discussion content (e.g. memory://specs/search)
|
|
40
|
+
depth: How many relation hops to traverse (1-3 recommended for performance)
|
|
41
|
+
timeframe: How far back to look. Supports natural language like "2 days ago", "last week"
|
|
42
|
+
max_results: Maximum number of results to return (default: 10)
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
GraphContext containing:
|
|
46
|
+
- primary_results: Content matching the memory:// URI
|
|
47
|
+
- related_results: Connected content via relations
|
|
48
|
+
- metadata: Context building details
|
|
49
|
+
|
|
50
|
+
Examples:
|
|
51
|
+
# Continue a specific discussion
|
|
52
|
+
build_context("memory://specs/search")
|
|
53
|
+
|
|
54
|
+
# Get deeper context about a component
|
|
55
|
+
build_context("memory://components/memory-service", depth=2)
|
|
56
|
+
|
|
57
|
+
# Look at recent changes to a specification
|
|
58
|
+
build_context("memory://specs/document-format", timeframe="today")
|
|
59
|
+
|
|
60
|
+
# Research the history of a feature
|
|
61
|
+
build_context("memory://features/knowledge-graph", timeframe="3 months ago")
|
|
62
|
+
"""
|
|
63
|
+
logger.info(f"Building context from {url}")
|
|
64
|
+
url = normalize_memory_url(url)
|
|
65
|
+
response = await call_get(
|
|
66
|
+
client,
|
|
67
|
+
f"/memory/{memory_url_path(url)}",
|
|
68
|
+
params={"depth": depth, "timeframe": timeframe, "max_results": max_results},
|
|
69
|
+
)
|
|
70
|
+
return GraphContext.model_validate(response.json())
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@mcp.tool(
|
|
74
|
+
description="""Get recent activity from across the knowledge base.
|
|
75
|
+
|
|
76
|
+
Timeframe supports natural language formats like:
|
|
77
|
+
- "2 days ago"
|
|
78
|
+
- "last week"
|
|
79
|
+
- "yesterday"
|
|
80
|
+
- "today"
|
|
81
|
+
- "3 weeks ago"
|
|
82
|
+
Or standard formats like "7d"
|
|
83
|
+
""",
|
|
84
|
+
)
|
|
85
|
+
async def recent_activity(
|
|
86
|
+
type: Literal["entity", "observation", "relation"] = None,
|
|
87
|
+
depth: Optional[int] = 1,
|
|
88
|
+
timeframe: Optional[TimeFrame] = "7d",
|
|
89
|
+
max_results: int = 10,
|
|
90
|
+
) -> GraphContext:
|
|
91
|
+
"""Get recent activity across the knowledge base.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
type: Filter by content type(s). Valid options:
|
|
95
|
+
- ["entity"] for knowledge entities
|
|
96
|
+
- ["relation"] for connections between entities
|
|
97
|
+
- ["observation"] for notes and observations
|
|
98
|
+
Multiple types can be combined: ["entity", "relation"]
|
|
99
|
+
depth: How many relation hops to traverse (1-3 recommended)
|
|
100
|
+
timeframe: Time window to search. Supports natural language:
|
|
101
|
+
- Relative: "2 days ago", "last week", "yesterday"
|
|
102
|
+
- Points in time: "2024-01-01", "January 1st"
|
|
103
|
+
- Standard format: "7d", "24h"
|
|
104
|
+
max_results: Maximum number of results to return (default: 10)
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
GraphContext containing:
|
|
108
|
+
- primary_results: Latest activities matching the filters
|
|
109
|
+
- related_results: Connected content via relations
|
|
110
|
+
- metadata: Query details and statistics
|
|
111
|
+
|
|
112
|
+
Examples:
|
|
113
|
+
# Get all entities from yesterday
|
|
114
|
+
recent_activity(type=["entity"], timeframe="yesterday")
|
|
115
|
+
|
|
116
|
+
# Get recent relations and observations
|
|
117
|
+
recent_activity(type=["relation", "observation"], timeframe="today")
|
|
118
|
+
|
|
119
|
+
# Look back further with more context
|
|
120
|
+
recent_activity(type=["entity"], depth=2, timeframe="2 weeks ago")
|
|
121
|
+
|
|
122
|
+
Notes:
|
|
123
|
+
- Higher depth values (>3) may impact performance with large result sets
|
|
124
|
+
- For focused queries, consider using build_context with a specific URI
|
|
125
|
+
- Max timeframe is 1 year in the past
|
|
126
|
+
"""
|
|
127
|
+
logger.info(
|
|
128
|
+
f"Getting recent activity from {type}, depth={depth}, timeframe={timeframe}, max_results={max_results}"
|
|
129
|
+
)
|
|
130
|
+
params = {
|
|
131
|
+
"depth": depth,
|
|
132
|
+
"timeframe": timeframe,
|
|
133
|
+
"max_results": max_results,
|
|
134
|
+
"type": type if type else None,
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
response = await call_get(
|
|
138
|
+
client,
|
|
139
|
+
"/memory/recent",
|
|
140
|
+
params=params,
|
|
141
|
+
)
|
|
142
|
+
return GraphContext.model_validate(response.json())
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""Note management tools for Basic Memory MCP server.
|
|
2
|
+
|
|
3
|
+
These tools provide a natural interface for working with markdown notes
|
|
4
|
+
while leveraging the underlying knowledge graph structure.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Optional, List
|
|
8
|
+
|
|
9
|
+
from loguru import logger
|
|
10
|
+
|
|
11
|
+
from basic_memory.mcp.server import mcp
|
|
12
|
+
from basic_memory.mcp.async_client import client
|
|
13
|
+
from basic_memory.schemas import EntityResponse, DeleteEntitiesResponse
|
|
14
|
+
from basic_memory.schemas.base import Entity
|
|
15
|
+
from basic_memory.mcp.tools.utils import call_get, call_put, call_delete
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@mcp.tool(
|
|
19
|
+
description="Create or update a markdown note. Returns the permalink for referencing.",
|
|
20
|
+
)
|
|
21
|
+
async def write_note(
|
|
22
|
+
title: str,
|
|
23
|
+
content: str,
|
|
24
|
+
folder: str,
|
|
25
|
+
tags: Optional[List[str]] = None,
|
|
26
|
+
verbose: bool = False,
|
|
27
|
+
) -> EntityResponse | str:
|
|
28
|
+
"""Write a markdown note to the knowledge base.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
title: The title of the note
|
|
32
|
+
content: Markdown content for the note
|
|
33
|
+
folder: the folder where the file should be saved
|
|
34
|
+
tags: Optional list of tags to categorize the note
|
|
35
|
+
verbose: If True, returns full EntityResponse with semantic info
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
If verbose=False: Permalink that can be used to reference the note
|
|
39
|
+
If verbose=True: EntityResponse with full semantic details
|
|
40
|
+
|
|
41
|
+
Examples:
|
|
42
|
+
# Create a simple note
|
|
43
|
+
write_note(
|
|
44
|
+
tile="Meeting Notes: Project Planning.md",
|
|
45
|
+
content="# Key Points\\n\\n- Discussed timeline\\n- Set priorities"
|
|
46
|
+
folder="notes"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Create note with tags
|
|
50
|
+
write_note(
|
|
51
|
+
title="Security Review",
|
|
52
|
+
content="# Findings\\n\\n1. Updated auth flow\\n2. Added rate limiting",
|
|
53
|
+
folder="security",
|
|
54
|
+
tags=["security", "development"]
|
|
55
|
+
)
|
|
56
|
+
"""
|
|
57
|
+
logger.info(f"Writing note folder:'{folder}' title: '{title}'")
|
|
58
|
+
|
|
59
|
+
# Create the entity request
|
|
60
|
+
metadata = {"tags": [f"#{tag}" for tag in tags]} if tags else None
|
|
61
|
+
entity = Entity(
|
|
62
|
+
title=title,
|
|
63
|
+
folder=folder,
|
|
64
|
+
entity_type="note",
|
|
65
|
+
content_type="text/markdown",
|
|
66
|
+
content=content,
|
|
67
|
+
entity_metadata=metadata,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Use existing knowledge tool
|
|
71
|
+
logger.info(f"Creating {entity.permalink}")
|
|
72
|
+
url = f"/knowledge/entities/{entity.permalink}"
|
|
73
|
+
response = await call_put(client, url, json=entity.model_dump())
|
|
74
|
+
result = EntityResponse.model_validate(response.json())
|
|
75
|
+
return result if verbose else result.permalink
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@mcp.tool(description="Read a note's content by its title or permalink")
|
|
79
|
+
async def read_note(identifier: str) -> str:
|
|
80
|
+
"""Get the markdown content of a note.
|
|
81
|
+
Uses the resource router to return the actual file content.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
identifier: Note title or permalink
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
The note's markdown content
|
|
88
|
+
|
|
89
|
+
Examples:
|
|
90
|
+
# Read by title
|
|
91
|
+
read_note("Meeting Notes: Project Planning")
|
|
92
|
+
|
|
93
|
+
# Read by permalink
|
|
94
|
+
read_note("notes/project-planning")
|
|
95
|
+
|
|
96
|
+
Raises:
|
|
97
|
+
ValueError: If the note cannot be found
|
|
98
|
+
"""
|
|
99
|
+
response = await call_get(client, f"/resource/{identifier}")
|
|
100
|
+
return response.text
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@mcp.tool(description="Delete a note by title or permalink")
|
|
104
|
+
async def delete_note(identifier: str) -> bool:
|
|
105
|
+
"""Delete a note from the knowledge base.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
identifier: Note title or permalink
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
True if note was deleted, False otherwise
|
|
112
|
+
|
|
113
|
+
Examples:
|
|
114
|
+
# Delete by title
|
|
115
|
+
delete_note("Meeting Notes: Project Planning")
|
|
116
|
+
|
|
117
|
+
# Delete by permalink
|
|
118
|
+
delete_note("notes/project-planning")
|
|
119
|
+
"""
|
|
120
|
+
response = await call_delete(client, f"/knowledge/entities/{identifier}")
|
|
121
|
+
result = DeleteEntitiesResponse.model_validate(response.json())
|
|
122
|
+
return result.deleted
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Search tools for Basic Memory MCP server."""
|
|
2
|
+
from loguru import logger
|
|
3
|
+
|
|
4
|
+
from basic_memory.mcp.server import mcp
|
|
5
|
+
from basic_memory.mcp.tools.utils import call_post
|
|
6
|
+
from basic_memory.schemas.search import SearchQuery, SearchResponse
|
|
7
|
+
from basic_memory.mcp.async_client import client
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@mcp.tool(
|
|
11
|
+
description="Search across all content in basic-memory, including documents and entities",
|
|
12
|
+
)
|
|
13
|
+
async def search(query: SearchQuery) -> SearchResponse:
|
|
14
|
+
"""Search across all content in basic-memory.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
query: SearchQuery object with search parameters including:
|
|
18
|
+
- text: Search text (required)
|
|
19
|
+
- types: Optional list of content types to search ("document" or "entity")
|
|
20
|
+
- entity_types: Optional list of entity types to filter by
|
|
21
|
+
- after_date: Optional date filter for recent content
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
SearchResponse with search results and metadata
|
|
25
|
+
"""
|
|
26
|
+
logger.info(f"Searching for {query.text}")
|
|
27
|
+
response = await call_post(client,"/search/", json=query.model_dump())
|
|
28
|
+
return SearchResponse.model_validate(response.json())
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
|
|
3
|
+
from httpx import Response, URL, AsyncClient, HTTPStatusError
|
|
4
|
+
from httpx._client import UseClientDefault, USE_CLIENT_DEFAULT
|
|
5
|
+
from httpx._types import (
|
|
6
|
+
RequestContent,
|
|
7
|
+
RequestData,
|
|
8
|
+
RequestFiles,
|
|
9
|
+
QueryParamTypes,
|
|
10
|
+
HeaderTypes,
|
|
11
|
+
CookieTypes,
|
|
12
|
+
AuthTypes,
|
|
13
|
+
TimeoutTypes,
|
|
14
|
+
RequestExtensions,
|
|
15
|
+
)
|
|
16
|
+
from loguru import logger
|
|
17
|
+
from mcp.server.fastmcp.exceptions import ToolError
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
async def call_get(
|
|
21
|
+
client: AsyncClient,
|
|
22
|
+
url: URL | str,
|
|
23
|
+
*,
|
|
24
|
+
params: QueryParamTypes | None = None,
|
|
25
|
+
headers: HeaderTypes | None = None,
|
|
26
|
+
cookies: CookieTypes | None = None,
|
|
27
|
+
auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
|
|
28
|
+
follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
|
|
29
|
+
timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
|
|
30
|
+
extensions: RequestExtensions | None = None,
|
|
31
|
+
) -> Response:
|
|
32
|
+
logger.debug(f"Calling GET '{url}' params: '{params}'")
|
|
33
|
+
try:
|
|
34
|
+
response = await client.get(
|
|
35
|
+
url,
|
|
36
|
+
params=params,
|
|
37
|
+
headers=headers,
|
|
38
|
+
cookies=cookies,
|
|
39
|
+
auth=auth,
|
|
40
|
+
follow_redirects=follow_redirects,
|
|
41
|
+
timeout=timeout,
|
|
42
|
+
extensions=extensions,
|
|
43
|
+
)
|
|
44
|
+
response.raise_for_status()
|
|
45
|
+
return response
|
|
46
|
+
except HTTPStatusError as e:
|
|
47
|
+
logger.error(f"Error calling GET {url}: {e}")
|
|
48
|
+
raise ToolError(f"Error calling tool: {e}. Response: {response.text}") from e
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
async def call_put(
|
|
52
|
+
client: AsyncClient,
|
|
53
|
+
url: URL | str,
|
|
54
|
+
*,
|
|
55
|
+
content: RequestContent | None = None,
|
|
56
|
+
data: RequestData | None = None,
|
|
57
|
+
files: RequestFiles | None = None,
|
|
58
|
+
json: typing.Any | None = None,
|
|
59
|
+
params: QueryParamTypes | None = None,
|
|
60
|
+
headers: HeaderTypes | None = None,
|
|
61
|
+
cookies: CookieTypes | None = None,
|
|
62
|
+
auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
|
|
63
|
+
follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
|
|
64
|
+
timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
|
|
65
|
+
extensions: RequestExtensions | None = None,
|
|
66
|
+
) -> Response:
|
|
67
|
+
try:
|
|
68
|
+
response = await client.put(
|
|
69
|
+
url,
|
|
70
|
+
content=content,
|
|
71
|
+
data=data,
|
|
72
|
+
files=files,
|
|
73
|
+
json=json,
|
|
74
|
+
params=params,
|
|
75
|
+
headers=headers,
|
|
76
|
+
cookies=cookies,
|
|
77
|
+
auth=auth,
|
|
78
|
+
follow_redirects=follow_redirects,
|
|
79
|
+
timeout=timeout,
|
|
80
|
+
extensions=extensions,
|
|
81
|
+
)
|
|
82
|
+
response.raise_for_status()
|
|
83
|
+
return response
|
|
84
|
+
except HTTPStatusError as e:
|
|
85
|
+
logger.error(f"Error calling PUT {url}: {e}")
|
|
86
|
+
raise ToolError(f"Error calling tool: {e}") from e
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
async def call_post(
|
|
90
|
+
client: AsyncClient,
|
|
91
|
+
url: URL | str,
|
|
92
|
+
*,
|
|
93
|
+
content: RequestContent | None = None,
|
|
94
|
+
data: RequestData | None = None,
|
|
95
|
+
files: RequestFiles | None = None,
|
|
96
|
+
json: typing.Any | None = None,
|
|
97
|
+
params: QueryParamTypes | None = None,
|
|
98
|
+
headers: HeaderTypes | None = None,
|
|
99
|
+
cookies: CookieTypes | None = None,
|
|
100
|
+
auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
|
|
101
|
+
follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
|
|
102
|
+
timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
|
|
103
|
+
extensions: RequestExtensions | None = None,
|
|
104
|
+
) -> Response:
|
|
105
|
+
try:
|
|
106
|
+
response = await client.post(
|
|
107
|
+
url=url,
|
|
108
|
+
content=content,
|
|
109
|
+
data=data,
|
|
110
|
+
files=files,
|
|
111
|
+
json=json,
|
|
112
|
+
params=params,
|
|
113
|
+
headers=headers,
|
|
114
|
+
cookies=cookies,
|
|
115
|
+
auth=auth,
|
|
116
|
+
follow_redirects=follow_redirects,
|
|
117
|
+
timeout=timeout,
|
|
118
|
+
extensions=extensions,
|
|
119
|
+
)
|
|
120
|
+
response.raise_for_status()
|
|
121
|
+
return response
|
|
122
|
+
except HTTPStatusError as e:
|
|
123
|
+
logger.error(f"Error calling POST {url}: {e}")
|
|
124
|
+
raise ToolError(f"Error calling tool: {e}") from e
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
async def call_delete(
|
|
128
|
+
client: AsyncClient,
|
|
129
|
+
url: URL | str,
|
|
130
|
+
*,
|
|
131
|
+
params: QueryParamTypes | None = None,
|
|
132
|
+
headers: HeaderTypes | None = None,
|
|
133
|
+
cookies: CookieTypes | None = None,
|
|
134
|
+
auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
|
|
135
|
+
follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
|
|
136
|
+
timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
|
|
137
|
+
extensions: RequestExtensions | None = None,
|
|
138
|
+
) -> Response:
|
|
139
|
+
try:
|
|
140
|
+
response = await client.delete(
|
|
141
|
+
url=url,
|
|
142
|
+
params=params,
|
|
143
|
+
headers=headers,
|
|
144
|
+
cookies=cookies,
|
|
145
|
+
auth=auth,
|
|
146
|
+
follow_redirects=follow_redirects,
|
|
147
|
+
timeout=timeout,
|
|
148
|
+
extensions=extensions,
|
|
149
|
+
)
|
|
150
|
+
response.raise_for_status()
|
|
151
|
+
return response
|
|
152
|
+
except HTTPStatusError as e:
|
|
153
|
+
logger.error(f"Error calling DELETE {url}: {e}")
|
|
154
|
+
raise ToolError(f"Error calling tool: {e}") from e
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Models package for basic-memory."""
|
|
2
|
+
|
|
3
|
+
from basic_memory.models.base import Base
|
|
4
|
+
from basic_memory.models.knowledge import Entity, Observation, Relation, ObservationCategory
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
'Base',
|
|
8
|
+
'Entity',
|
|
9
|
+
'Observation',
|
|
10
|
+
'ObservationCategory',
|
|
11
|
+
'Relation'
|
|
12
|
+
]
|