basic-memory 0.8.0__py3-none-any.whl → 0.10.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 +1 -1
- basic_memory/alembic/migrations.py +4 -9
- basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py +106 -0
- basic_memory/api/app.py +9 -6
- basic_memory/api/routers/__init__.py +2 -1
- basic_memory/api/routers/knowledge_router.py +30 -4
- basic_memory/api/routers/memory_router.py +3 -2
- basic_memory/api/routers/project_info_router.py +274 -0
- basic_memory/api/routers/search_router.py +22 -4
- basic_memory/cli/app.py +54 -3
- basic_memory/cli/commands/__init__.py +15 -2
- basic_memory/cli/commands/db.py +9 -13
- basic_memory/cli/commands/import_chatgpt.py +31 -36
- basic_memory/cli/commands/import_claude_conversations.py +32 -35
- basic_memory/cli/commands/import_claude_projects.py +34 -37
- basic_memory/cli/commands/import_memory_json.py +26 -28
- basic_memory/cli/commands/mcp.py +7 -1
- basic_memory/cli/commands/project.py +119 -0
- basic_memory/cli/commands/project_info.py +167 -0
- basic_memory/cli/commands/status.py +7 -9
- basic_memory/cli/commands/sync.py +54 -9
- basic_memory/cli/commands/{tools.py → tool.py} +92 -19
- basic_memory/cli/main.py +40 -1
- basic_memory/config.py +157 -10
- basic_memory/db.py +19 -4
- basic_memory/deps.py +10 -3
- basic_memory/file_utils.py +34 -18
- basic_memory/markdown/markdown_processor.py +1 -1
- basic_memory/markdown/utils.py +5 -0
- basic_memory/mcp/main.py +1 -2
- basic_memory/mcp/prompts/__init__.py +6 -2
- basic_memory/mcp/prompts/ai_assistant_guide.py +9 -10
- basic_memory/mcp/prompts/continue_conversation.py +65 -126
- basic_memory/mcp/prompts/recent_activity.py +55 -13
- basic_memory/mcp/prompts/search.py +72 -17
- basic_memory/mcp/prompts/utils.py +139 -82
- basic_memory/mcp/server.py +1 -1
- basic_memory/mcp/tools/__init__.py +11 -22
- basic_memory/mcp/tools/build_context.py +85 -0
- basic_memory/mcp/tools/canvas.py +17 -19
- basic_memory/mcp/tools/delete_note.py +28 -0
- basic_memory/mcp/tools/project_info.py +51 -0
- basic_memory/mcp/tools/{resource.py → read_content.py} +42 -5
- basic_memory/mcp/tools/read_note.py +190 -0
- basic_memory/mcp/tools/recent_activity.py +100 -0
- basic_memory/mcp/tools/search.py +56 -17
- basic_memory/mcp/tools/utils.py +245 -17
- basic_memory/mcp/tools/write_note.py +124 -0
- basic_memory/models/search.py +2 -1
- basic_memory/repository/entity_repository.py +3 -2
- basic_memory/repository/project_info_repository.py +9 -0
- basic_memory/repository/repository.py +23 -6
- basic_memory/repository/search_repository.py +33 -10
- basic_memory/schemas/__init__.py +12 -0
- basic_memory/schemas/memory.py +3 -2
- basic_memory/schemas/project_info.py +96 -0
- basic_memory/schemas/search.py +27 -32
- basic_memory/services/context_service.py +3 -3
- basic_memory/services/entity_service.py +8 -2
- basic_memory/services/file_service.py +107 -57
- basic_memory/services/link_resolver.py +5 -45
- basic_memory/services/search_service.py +45 -16
- basic_memory/sync/sync_service.py +274 -39
- basic_memory/sync/watch_service.py +174 -34
- basic_memory/utils.py +40 -40
- basic_memory-0.10.0.dist-info/METADATA +386 -0
- basic_memory-0.10.0.dist-info/RECORD +99 -0
- basic_memory/mcp/prompts/json_canvas_spec.py +0 -25
- basic_memory/mcp/tools/knowledge.py +0 -68
- basic_memory/mcp/tools/memory.py +0 -177
- basic_memory/mcp/tools/notes.py +0 -201
- basic_memory-0.8.0.dist-info/METADATA +0 -379
- basic_memory-0.8.0.dist-info/RECORD +0 -91
- {basic_memory-0.8.0.dist-info → basic_memory-0.10.0.dist-info}/WHEEL +0 -0
- {basic_memory-0.8.0.dist-info → basic_memory-0.10.0.dist-info}/entry_points.txt +0 -0
- {basic_memory-0.8.0.dist-info → basic_memory-0.10.0.dist-info}/licenses/LICENSE +0 -0
basic_memory/mcp/tools/memory.py
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
"""Discussion context tools for Basic Memory MCP server."""
|
|
2
|
-
|
|
3
|
-
from typing import Optional, List
|
|
4
|
-
|
|
5
|
-
from loguru import logger
|
|
6
|
-
import logfire
|
|
7
|
-
|
|
8
|
-
from basic_memory.mcp.async_client import client
|
|
9
|
-
from basic_memory.mcp.server import mcp
|
|
10
|
-
from basic_memory.mcp.tools.utils import call_get
|
|
11
|
-
from basic_memory.schemas.memory import (
|
|
12
|
-
GraphContext,
|
|
13
|
-
MemoryUrl,
|
|
14
|
-
memory_url_path,
|
|
15
|
-
normalize_memory_url,
|
|
16
|
-
)
|
|
17
|
-
from basic_memory.schemas.base import TimeFrame
|
|
18
|
-
from basic_memory.schemas.search import SearchItemType
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@mcp.tool(
|
|
22
|
-
description="""Build context from a memory:// URI to continue conversations naturally.
|
|
23
|
-
|
|
24
|
-
Use this to follow up on previous discussions or explore related topics.
|
|
25
|
-
Timeframes support natural language like:
|
|
26
|
-
- "2 days ago"
|
|
27
|
-
- "last week"
|
|
28
|
-
- "today"
|
|
29
|
-
- "3 months ago"
|
|
30
|
-
Or standard formats like "7d", "24h"
|
|
31
|
-
""",
|
|
32
|
-
)
|
|
33
|
-
async def build_context(
|
|
34
|
-
url: MemoryUrl,
|
|
35
|
-
depth: Optional[int] = 1,
|
|
36
|
-
timeframe: Optional[TimeFrame] = "7d",
|
|
37
|
-
page: int = 1,
|
|
38
|
-
page_size: int = 10,
|
|
39
|
-
max_related: int = 10,
|
|
40
|
-
) -> GraphContext:
|
|
41
|
-
"""Get context needed to continue a discussion.
|
|
42
|
-
|
|
43
|
-
This tool enables natural continuation of discussions by loading relevant context
|
|
44
|
-
from memory:// URIs. It uses pattern matching to find relevant content and builds
|
|
45
|
-
a rich context graph of related information.
|
|
46
|
-
|
|
47
|
-
Args:
|
|
48
|
-
url: memory:// URI pointing to discussion content (e.g. memory://specs/search)
|
|
49
|
-
depth: How many relation hops to traverse (1-3 recommended for performance)
|
|
50
|
-
timeframe: How far back to look. Supports natural language like "2 days ago", "last week"
|
|
51
|
-
page: Page number of results to return (default: 1)
|
|
52
|
-
page_size: Number of results to return per page (default: 10)
|
|
53
|
-
max_related: Maximum number of related results to return (default: 10)
|
|
54
|
-
|
|
55
|
-
Returns:
|
|
56
|
-
GraphContext containing:
|
|
57
|
-
- primary_results: Content matching the memory:// URI
|
|
58
|
-
- related_results: Connected content via relations
|
|
59
|
-
- metadata: Context building details
|
|
60
|
-
|
|
61
|
-
Examples:
|
|
62
|
-
# Continue a specific discussion
|
|
63
|
-
build_context("memory://specs/search")
|
|
64
|
-
|
|
65
|
-
# Get deeper context about a component
|
|
66
|
-
build_context("memory://components/memory-service", depth=2)
|
|
67
|
-
|
|
68
|
-
# Look at recent changes to a specification
|
|
69
|
-
build_context("memory://specs/document-format", timeframe="today")
|
|
70
|
-
|
|
71
|
-
# Research the history of a feature
|
|
72
|
-
build_context("memory://features/knowledge-graph", timeframe="3 months ago")
|
|
73
|
-
"""
|
|
74
|
-
with logfire.span("Building context", url=url, depth=depth, timeframe=timeframe): # pyright: ignore [reportGeneralTypeIssues]
|
|
75
|
-
logger.info(f"Building context from {url}")
|
|
76
|
-
url = normalize_memory_url(url)
|
|
77
|
-
response = await call_get(
|
|
78
|
-
client,
|
|
79
|
-
f"/memory/{memory_url_path(url)}",
|
|
80
|
-
params={
|
|
81
|
-
"depth": depth,
|
|
82
|
-
"timeframe": timeframe,
|
|
83
|
-
"page": page,
|
|
84
|
-
"page_size": page_size,
|
|
85
|
-
"max_related": max_related,
|
|
86
|
-
},
|
|
87
|
-
)
|
|
88
|
-
return GraphContext.model_validate(response.json())
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
@mcp.tool(
|
|
92
|
-
description="""Get recent activity from across the knowledge base.
|
|
93
|
-
|
|
94
|
-
Timeframe supports natural language formats like:
|
|
95
|
-
- "2 days ago"
|
|
96
|
-
- "last week"
|
|
97
|
-
- "yesterday"
|
|
98
|
-
- "today"
|
|
99
|
-
- "3 weeks ago"
|
|
100
|
-
Or standard formats like "7d"
|
|
101
|
-
""",
|
|
102
|
-
)
|
|
103
|
-
async def recent_activity(
|
|
104
|
-
type: Optional[List[SearchItemType]] = None,
|
|
105
|
-
depth: Optional[int] = 1,
|
|
106
|
-
timeframe: Optional[TimeFrame] = "7d",
|
|
107
|
-
page: int = 1,
|
|
108
|
-
page_size: int = 10,
|
|
109
|
-
max_related: int = 10,
|
|
110
|
-
) -> GraphContext:
|
|
111
|
-
"""Get recent activity across the knowledge base.
|
|
112
|
-
|
|
113
|
-
Args:
|
|
114
|
-
type: Filter by content type(s). Valid options:
|
|
115
|
-
- ["entity"] for knowledge entities
|
|
116
|
-
- ["relation"] for connections between entities
|
|
117
|
-
- ["observation"] for notes and observations
|
|
118
|
-
Multiple types can be combined: ["entity", "relation"]
|
|
119
|
-
depth: How many relation hops to traverse (1-3 recommended)
|
|
120
|
-
timeframe: Time window to search. Supports natural language:
|
|
121
|
-
- Relative: "2 days ago", "last week", "yesterday"
|
|
122
|
-
- Points in time: "2024-01-01", "January 1st"
|
|
123
|
-
- Standard format: "7d", "24h"
|
|
124
|
-
page: Page number of results to return (default: 1)
|
|
125
|
-
page_size: Number of results to return per page (default: 10)
|
|
126
|
-
max_related: Maximum number of related results to return (default: 10)
|
|
127
|
-
|
|
128
|
-
Returns:
|
|
129
|
-
GraphContext containing:
|
|
130
|
-
- primary_results: Latest activities matching the filters
|
|
131
|
-
- related_results: Connected content via relations
|
|
132
|
-
- metadata: Query details and statistics
|
|
133
|
-
|
|
134
|
-
Examples:
|
|
135
|
-
# Get all entities for the last 10 days (default)
|
|
136
|
-
recent_activity()
|
|
137
|
-
|
|
138
|
-
# Get all entities from yesterday
|
|
139
|
-
recent_activity(type=["entity"], timeframe="yesterday")
|
|
140
|
-
|
|
141
|
-
# Get recent relations and observations
|
|
142
|
-
recent_activity(type=["relation", "observation"], timeframe="today")
|
|
143
|
-
|
|
144
|
-
# Look back further with more context
|
|
145
|
-
recent_activity(type=["entity"], depth=2, timeframe="2 weeks ago")
|
|
146
|
-
|
|
147
|
-
Notes:
|
|
148
|
-
- Higher depth values (>3) may impact performance with large result sets
|
|
149
|
-
- For focused queries, consider using build_context with a specific URI
|
|
150
|
-
- Max timeframe is 1 year in the past
|
|
151
|
-
"""
|
|
152
|
-
with logfire.span("Getting recent activity", type=type, depth=depth, timeframe=timeframe): # pyright: ignore [reportGeneralTypeIssues]
|
|
153
|
-
logger.info(
|
|
154
|
-
f"Getting recent activity from {type}, depth={depth}, timeframe={timeframe}, page={page}, page_size={page_size}, max_related={max_related}"
|
|
155
|
-
)
|
|
156
|
-
params = {
|
|
157
|
-
"page": page,
|
|
158
|
-
"page_size": page_size,
|
|
159
|
-
"max_related": max_related,
|
|
160
|
-
}
|
|
161
|
-
if depth:
|
|
162
|
-
params["depth"] = depth
|
|
163
|
-
if timeframe:
|
|
164
|
-
params["timeframe"] = timeframe # pyright: ignore
|
|
165
|
-
|
|
166
|
-
# send enum values if we have an enum, else send string value
|
|
167
|
-
if type:
|
|
168
|
-
params["type"] = [ # pyright: ignore
|
|
169
|
-
type.value if isinstance(type, SearchItemType) else type for type in type
|
|
170
|
-
]
|
|
171
|
-
|
|
172
|
-
response = await call_get(
|
|
173
|
-
client,
|
|
174
|
-
"/memory/recent",
|
|
175
|
-
params=params,
|
|
176
|
-
)
|
|
177
|
-
return GraphContext.model_validate(response.json())
|
basic_memory/mcp/tools/notes.py
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
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
|
-
import logfire
|
|
11
|
-
|
|
12
|
-
from basic_memory.mcp.server import mcp
|
|
13
|
-
from basic_memory.mcp.async_client import client
|
|
14
|
-
from basic_memory.schemas import EntityResponse, DeleteEntitiesResponse
|
|
15
|
-
from basic_memory.schemas.base import Entity
|
|
16
|
-
from basic_memory.mcp.tools.utils import call_get, call_put, call_delete
|
|
17
|
-
from basic_memory.schemas.memory import memory_url_path
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
@mcp.tool(
|
|
21
|
-
description="Create or update a markdown note. Returns a markdown formatted summary of the semantic content.",
|
|
22
|
-
)
|
|
23
|
-
async def write_note(
|
|
24
|
-
title: str,
|
|
25
|
-
content: str,
|
|
26
|
-
folder: str,
|
|
27
|
-
tags: Optional[List[str]] = None,
|
|
28
|
-
) -> str:
|
|
29
|
-
"""Write a markdown note to the knowledge base.
|
|
30
|
-
|
|
31
|
-
The content can include semantic observations and relations using markdown syntax.
|
|
32
|
-
Relations can be specified either explicitly or through inline wiki-style links:
|
|
33
|
-
|
|
34
|
-
Observations format:
|
|
35
|
-
`- [category] Observation text #tag1 #tag2 (optional context)`
|
|
36
|
-
|
|
37
|
-
Examples:
|
|
38
|
-
`- [design] Files are the source of truth #architecture (All state comes from files)`
|
|
39
|
-
`- [tech] Using SQLite for storage #implementation`
|
|
40
|
-
`- [note] Need to add error handling #todo`
|
|
41
|
-
|
|
42
|
-
Relations format:
|
|
43
|
-
- Explicit: `- relation_type [[Entity]] (optional context)`
|
|
44
|
-
- Inline: Any `[[Entity]]` reference creates a relation
|
|
45
|
-
|
|
46
|
-
Examples:
|
|
47
|
-
`- depends_on [[Content Parser]] (Need for semantic extraction)`
|
|
48
|
-
`- implements [[Search Spec]] (Initial implementation)`
|
|
49
|
-
`- This feature extends [[Base Design]] and uses [[Core Utils]]`
|
|
50
|
-
|
|
51
|
-
Args:
|
|
52
|
-
title: The title of the note
|
|
53
|
-
content: Markdown content for the note, can include observations and relations
|
|
54
|
-
folder: the folder where the file should be saved
|
|
55
|
-
tags: Optional list of tags to categorize the note
|
|
56
|
-
|
|
57
|
-
Returns:
|
|
58
|
-
A markdown formatted summary of the semantic content, including:
|
|
59
|
-
- Creation/update status
|
|
60
|
-
- File path and checksum
|
|
61
|
-
- Observation counts by category
|
|
62
|
-
- Relation counts (resolved/unresolved)
|
|
63
|
-
- Tags if present
|
|
64
|
-
"""
|
|
65
|
-
with logfire.span("Writing note", title=title, folder=folder): # pyright: ignore [reportGeneralTypeIssues]
|
|
66
|
-
logger.info(f"Writing note folder:'{folder}' title: '{title}'")
|
|
67
|
-
|
|
68
|
-
# Create the entity request
|
|
69
|
-
metadata = {"tags": [f"#{tag}" for tag in tags]} if tags else None
|
|
70
|
-
entity = Entity(
|
|
71
|
-
title=title,
|
|
72
|
-
folder=folder,
|
|
73
|
-
entity_type="note",
|
|
74
|
-
content_type="text/markdown",
|
|
75
|
-
content=content,
|
|
76
|
-
entity_metadata=metadata,
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
# Create or update via knowledge API
|
|
80
|
-
logger.info(f"Creating {entity.permalink}")
|
|
81
|
-
url = f"/knowledge/entities/{entity.permalink}"
|
|
82
|
-
response = await call_put(client, url, json=entity.model_dump())
|
|
83
|
-
result = EntityResponse.model_validate(response.json())
|
|
84
|
-
|
|
85
|
-
# Format semantic summary based on status code
|
|
86
|
-
action = "Created" if response.status_code == 201 else "Updated"
|
|
87
|
-
summary = [
|
|
88
|
-
f"# {action} {result.file_path} ({result.checksum[:8] if result.checksum else 'unknown'})",
|
|
89
|
-
f"permalink: {result.permalink}",
|
|
90
|
-
]
|
|
91
|
-
|
|
92
|
-
if result.observations:
|
|
93
|
-
categories = {}
|
|
94
|
-
for obs in result.observations:
|
|
95
|
-
categories[obs.category] = categories.get(obs.category, 0) + 1
|
|
96
|
-
|
|
97
|
-
summary.append("\n## Observations")
|
|
98
|
-
for category, count in sorted(categories.items()):
|
|
99
|
-
summary.append(f"- {category}: {count}")
|
|
100
|
-
|
|
101
|
-
if result.relations:
|
|
102
|
-
unresolved = sum(1 for r in result.relations if not r.to_id)
|
|
103
|
-
resolved = len(result.relations) - unresolved
|
|
104
|
-
|
|
105
|
-
summary.append("\n## Relations")
|
|
106
|
-
summary.append(f"- Resolved: {resolved}")
|
|
107
|
-
if unresolved:
|
|
108
|
-
summary.append(f"- Unresolved: {unresolved}")
|
|
109
|
-
summary.append("\nUnresolved relations will be retried on next sync.")
|
|
110
|
-
|
|
111
|
-
if tags:
|
|
112
|
-
summary.append(f"\n## Tags\n- {', '.join(tags)}")
|
|
113
|
-
|
|
114
|
-
return "\n".join(summary)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
@mcp.tool(description="Read note content by title, permalink, relation, or pattern")
|
|
118
|
-
async def read_note(identifier: str, page: int = 1, page_size: int = 10) -> str:
|
|
119
|
-
"""Get note content in unified diff format.
|
|
120
|
-
|
|
121
|
-
The content is returned in a unified diff inspired format:
|
|
122
|
-
```
|
|
123
|
-
--- memory://docs/example 2025-01-31T19:32:49 7d9f1c8b
|
|
124
|
-
<document content>
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Multiple documents (from relations or pattern matches) are separated by
|
|
128
|
-
additional headers.
|
|
129
|
-
|
|
130
|
-
Args:
|
|
131
|
-
identifier: Can be one of:
|
|
132
|
-
- Note title ("Project Planning")
|
|
133
|
-
- Note permalink ("docs/example")
|
|
134
|
-
- Relation path ("docs/example/depends-on/other-doc")
|
|
135
|
-
- Pattern match ("docs/*-architecture")
|
|
136
|
-
page: the page number of results to return (default 1)
|
|
137
|
-
page_size: the number of results to return per page (default 10)
|
|
138
|
-
|
|
139
|
-
Returns:
|
|
140
|
-
Document content in unified diff format. For single documents, returns
|
|
141
|
-
just that document's content. For relations or pattern matches, returns
|
|
142
|
-
multiple documents separated by unified diff headers.
|
|
143
|
-
|
|
144
|
-
Examples:
|
|
145
|
-
# Single document
|
|
146
|
-
content = await read_note("Project Planning")
|
|
147
|
-
|
|
148
|
-
# Read by permalink
|
|
149
|
-
content = await read_note("docs/architecture/file-first")
|
|
150
|
-
|
|
151
|
-
# Follow relation
|
|
152
|
-
content = await read_note("docs/architecture/depends-on/docs/content-parser")
|
|
153
|
-
|
|
154
|
-
# Pattern matching
|
|
155
|
-
content = await read_note("docs/*-architecture") # All architecture docs
|
|
156
|
-
content = await read_note("docs/*/implements/*") # Find implementations
|
|
157
|
-
|
|
158
|
-
Output format:
|
|
159
|
-
```
|
|
160
|
-
--- memory://docs/example 2025-01-31T19:32:49 7d9f1c8b
|
|
161
|
-
<first document content>
|
|
162
|
-
|
|
163
|
-
--- memory://docs/other 2025-01-30T15:45:22 a1b2c3d4
|
|
164
|
-
<second document content>
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
The headers include:
|
|
168
|
-
- Full memory:// URI for the document
|
|
169
|
-
- Last modified timestamp
|
|
170
|
-
- Content checksum
|
|
171
|
-
"""
|
|
172
|
-
with logfire.span("Reading note", identifier=identifier): # pyright: ignore [reportGeneralTypeIssues]
|
|
173
|
-
logger.info(f"Reading note {identifier}")
|
|
174
|
-
url = memory_url_path(identifier)
|
|
175
|
-
response = await call_get(
|
|
176
|
-
client, f"/resource/{url}", params={"page": page, "page_size": page_size}
|
|
177
|
-
)
|
|
178
|
-
return response.text
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
@mcp.tool(description="Delete a note by title or permalink")
|
|
182
|
-
async def delete_note(identifier: str) -> bool:
|
|
183
|
-
"""Delete a note from the knowledge base.
|
|
184
|
-
|
|
185
|
-
Args:
|
|
186
|
-
identifier: Note title or permalink
|
|
187
|
-
|
|
188
|
-
Returns:
|
|
189
|
-
True if note was deleted, False otherwise
|
|
190
|
-
|
|
191
|
-
Examples:
|
|
192
|
-
# Delete by title
|
|
193
|
-
delete_note("Meeting Notes: Project Planning")
|
|
194
|
-
|
|
195
|
-
# Delete by permalink
|
|
196
|
-
delete_note("notes/project-planning")
|
|
197
|
-
"""
|
|
198
|
-
with logfire.span("Deleting note", identifier=identifier): # pyright: ignore [reportGeneralTypeIssues]
|
|
199
|
-
response = await call_delete(client, f"/knowledge/entities/{identifier}")
|
|
200
|
-
result = DeleteEntitiesResponse.model_validate(response.json())
|
|
201
|
-
return result.deleted
|