-
Notifications
You must be signed in to change notification settings - Fork 191
Expand file tree
/
Copy pathproject_info.py
More file actions
211 lines (158 loc) · 6.67 KB
/
project_info.py
File metadata and controls
211 lines (158 loc) · 6.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
"""Schema for project info response."""
import os
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional, Any
from pydantic import Field, BaseModel
from basic_memory.utils import generate_permalink
class ProjectStatistics(BaseModel):
"""Statistics about the current project."""
# Basic counts
total_entities: int = Field(description="Total number of entities in the knowledge base")
total_observations: int = Field(description="Total number of observations across all entities")
total_relations: int = Field(description="Total number of relations between entities")
total_unresolved_relations: int = Field(
description="Number of relations with unresolved targets"
)
# Entity counts by type
entity_types: Dict[str, int] = Field(
description="Count of entities by type (e.g., note, conversation)"
)
# Observation counts by category
observation_categories: Dict[str, int] = Field(
description="Count of observations by category (e.g., tech, decision)"
)
# Relation counts by type
relation_types: Dict[str, int] = Field(
description="Count of relations by type (e.g., implements, relates_to)"
)
# Graph metrics
most_connected_entities: List[Dict[str, Any]] = Field(
description="Entities with the most relations, including their titles and permalinks"
)
isolated_entities: int = Field(description="Number of entities with no relations")
class ActivityMetrics(BaseModel):
"""Activity metrics for the current project."""
# Recent activity
recently_created: List[Dict[str, Any]] = Field(
description="Recently created entities with timestamps"
)
recently_updated: List[Dict[str, Any]] = Field(
description="Recently updated entities with timestamps"
)
# Growth over time (last 6 months)
monthly_growth: Dict[str, Dict[str, int]] = Field(
description="Monthly growth statistics for entities, observations, and relations"
)
class SystemStatus(BaseModel):
"""System status information."""
# Version information
version: str = Field(description="Basic Memory version")
# Database status
database_path: str = Field(description="Path to the SQLite database")
database_size: str = Field(description="Size of the database in human-readable format")
# Watch service status
watch_status: Optional[Dict[str, Any]] = Field(
default=None, description="Watch service status information (if running)"
)
# System information
timestamp: datetime = Field(description="Timestamp when the information was collected")
class ProjectInfoResponse(BaseModel):
"""Response for the project_info tool."""
# Project configuration
project_name: str = Field(description="Name of the current project")
project_path: str = Field(description="Path to the current project files")
available_projects: Dict[str, Dict[str, Any]] = Field(
description="Map of configured project names to detailed project information"
)
default_project: str = Field(description="Name of the default project")
# Statistics
statistics: ProjectStatistics = Field(description="Statistics about the knowledge base")
# Activity metrics
activity: ActivityMetrics = Field(description="Activity and growth metrics")
# System status
system: SystemStatus = Field(description="System and service status information")
class ProjectInfoRequest(BaseModel):
"""Request model for switching projects."""
name: str = Field(..., description="Name of the project to switch to")
path: str = Field(..., description="Path to the project directory")
set_default: bool = Field(..., description="Set the project as the default")
class WatchEvent(BaseModel):
timestamp: datetime
path: str
action: str # new, delete, etc
status: str # success, error
checksum: Optional[str]
error: Optional[str] = None
class WatchServiceState(BaseModel):
# Service status
running: bool = False
start_time: datetime = datetime.now() # Use directly with Pydantic model
pid: int = os.getpid() # Use directly with Pydantic model
# Stats
error_count: int = 0
last_error: Optional[datetime] = None
last_scan: Optional[datetime] = None
# File counts
synced_files: int = 0
# Recent activity
recent_events: List[WatchEvent] = [] # Use directly with Pydantic model
def add_event(
self,
path: str,
action: str,
status: str,
checksum: Optional[str] = None,
error: Optional[str] = None,
) -> WatchEvent: # pragma: no cover
event = WatchEvent(
timestamp=datetime.now(),
path=path,
action=action,
status=status,
checksum=checksum,
error=error,
)
self.recent_events.insert(0, event)
self.recent_events = self.recent_events[:100] # Keep last 100
return event
def record_error(self, error: str): # pragma: no cover
self.error_count += 1
self.add_event(path="", action="sync", status="error", error=error)
self.last_error = datetime.now()
class ProjectWatchStatus(BaseModel):
"""Project with its watch status."""
name: str = Field(..., description="Name of the project")
path: str = Field(..., description="Path to the project")
watch_status: Optional[WatchServiceState] = Field(
None, description="Watch status information for the project"
)
class ProjectItem(BaseModel):
"""Simple representation of a project."""
name: str
path: str
is_default: bool = False
@property
def permalink(self) -> str: # pragma: no cover
return generate_permalink(self.name)
@property
def home(self) -> Path: # pragma: no cover
return Path(self.path).expanduser()
@property
def project_url(self) -> str: # pragma: no cover
return f"/{generate_permalink(self.name)}"
class ProjectList(BaseModel):
"""Response model for listing projects."""
projects: List[ProjectItem]
default_project: str
class ProjectStatusResponse(BaseModel):
"""Response model for switching projects."""
message: str = Field(..., description="Status message about the project switch")
status: str = Field(..., description="Status of the switch (success or error)")
default: bool = Field(..., description="True if the project was set as the default")
old_project: Optional[ProjectItem] = Field(
None, description="Information about the project being switched from"
)
new_project: Optional[ProjectItem] = Field(
None, description="Information about the project being switched to"
)