emdash-core 0.1.7__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.
- emdash_core/__init__.py +3 -0
- emdash_core/agent/__init__.py +37 -0
- emdash_core/agent/agents.py +225 -0
- emdash_core/agent/code_reviewer.py +476 -0
- emdash_core/agent/compaction.py +143 -0
- emdash_core/agent/context_manager.py +140 -0
- emdash_core/agent/events.py +338 -0
- emdash_core/agent/handlers.py +224 -0
- emdash_core/agent/inprocess_subagent.py +377 -0
- emdash_core/agent/mcp/__init__.py +50 -0
- emdash_core/agent/mcp/client.py +346 -0
- emdash_core/agent/mcp/config.py +302 -0
- emdash_core/agent/mcp/manager.py +496 -0
- emdash_core/agent/mcp/tool_factory.py +213 -0
- emdash_core/agent/prompts/__init__.py +38 -0
- emdash_core/agent/prompts/main_agent.py +104 -0
- emdash_core/agent/prompts/subagents.py +131 -0
- emdash_core/agent/prompts/workflow.py +136 -0
- emdash_core/agent/providers/__init__.py +34 -0
- emdash_core/agent/providers/base.py +143 -0
- emdash_core/agent/providers/factory.py +80 -0
- emdash_core/agent/providers/models.py +220 -0
- emdash_core/agent/providers/openai_provider.py +463 -0
- emdash_core/agent/providers/transformers_provider.py +217 -0
- emdash_core/agent/research/__init__.py +81 -0
- emdash_core/agent/research/agent.py +143 -0
- emdash_core/agent/research/controller.py +254 -0
- emdash_core/agent/research/critic.py +428 -0
- emdash_core/agent/research/macros.py +469 -0
- emdash_core/agent/research/planner.py +449 -0
- emdash_core/agent/research/researcher.py +436 -0
- emdash_core/agent/research/state.py +523 -0
- emdash_core/agent/research/synthesizer.py +594 -0
- emdash_core/agent/reviewer_profile.py +475 -0
- emdash_core/agent/rules.py +123 -0
- emdash_core/agent/runner.py +601 -0
- emdash_core/agent/session.py +262 -0
- emdash_core/agent/spec_schema.py +66 -0
- emdash_core/agent/specification.py +479 -0
- emdash_core/agent/subagent.py +397 -0
- emdash_core/agent/subagent_prompts.py +13 -0
- emdash_core/agent/toolkit.py +482 -0
- emdash_core/agent/toolkits/__init__.py +64 -0
- emdash_core/agent/toolkits/base.py +96 -0
- emdash_core/agent/toolkits/explore.py +47 -0
- emdash_core/agent/toolkits/plan.py +55 -0
- emdash_core/agent/tools/__init__.py +141 -0
- emdash_core/agent/tools/analytics.py +436 -0
- emdash_core/agent/tools/base.py +131 -0
- emdash_core/agent/tools/coding.py +484 -0
- emdash_core/agent/tools/github_mcp.py +592 -0
- emdash_core/agent/tools/history.py +13 -0
- emdash_core/agent/tools/modes.py +153 -0
- emdash_core/agent/tools/plan.py +206 -0
- emdash_core/agent/tools/plan_write.py +135 -0
- emdash_core/agent/tools/search.py +412 -0
- emdash_core/agent/tools/spec.py +341 -0
- emdash_core/agent/tools/task.py +262 -0
- emdash_core/agent/tools/task_output.py +204 -0
- emdash_core/agent/tools/tasks.py +454 -0
- emdash_core/agent/tools/traversal.py +588 -0
- emdash_core/agent/tools/web.py +179 -0
- emdash_core/analytics/__init__.py +5 -0
- emdash_core/analytics/engine.py +1286 -0
- emdash_core/api/__init__.py +5 -0
- emdash_core/api/agent.py +308 -0
- emdash_core/api/agents.py +154 -0
- emdash_core/api/analyze.py +264 -0
- emdash_core/api/auth.py +173 -0
- emdash_core/api/context.py +77 -0
- emdash_core/api/db.py +121 -0
- emdash_core/api/embed.py +131 -0
- emdash_core/api/feature.py +143 -0
- emdash_core/api/health.py +93 -0
- emdash_core/api/index.py +162 -0
- emdash_core/api/plan.py +110 -0
- emdash_core/api/projectmd.py +210 -0
- emdash_core/api/query.py +320 -0
- emdash_core/api/research.py +122 -0
- emdash_core/api/review.py +161 -0
- emdash_core/api/router.py +76 -0
- emdash_core/api/rules.py +116 -0
- emdash_core/api/search.py +119 -0
- emdash_core/api/spec.py +99 -0
- emdash_core/api/swarm.py +223 -0
- emdash_core/api/tasks.py +109 -0
- emdash_core/api/team.py +120 -0
- emdash_core/auth/__init__.py +17 -0
- emdash_core/auth/github.py +389 -0
- emdash_core/config.py +74 -0
- emdash_core/context/__init__.py +52 -0
- emdash_core/context/models.py +50 -0
- emdash_core/context/providers/__init__.py +11 -0
- emdash_core/context/providers/base.py +74 -0
- emdash_core/context/providers/explored_areas.py +183 -0
- emdash_core/context/providers/touched_areas.py +360 -0
- emdash_core/context/registry.py +73 -0
- emdash_core/context/reranker.py +199 -0
- emdash_core/context/service.py +260 -0
- emdash_core/context/session.py +352 -0
- emdash_core/core/__init__.py +104 -0
- emdash_core/core/config.py +454 -0
- emdash_core/core/exceptions.py +55 -0
- emdash_core/core/models.py +265 -0
- emdash_core/core/review_config.py +57 -0
- emdash_core/db/__init__.py +67 -0
- emdash_core/db/auth.py +134 -0
- emdash_core/db/models.py +91 -0
- emdash_core/db/provider.py +222 -0
- emdash_core/db/providers/__init__.py +5 -0
- emdash_core/db/providers/supabase.py +452 -0
- emdash_core/embeddings/__init__.py +24 -0
- emdash_core/embeddings/indexer.py +534 -0
- emdash_core/embeddings/models.py +192 -0
- emdash_core/embeddings/providers/__init__.py +7 -0
- emdash_core/embeddings/providers/base.py +112 -0
- emdash_core/embeddings/providers/fireworks.py +141 -0
- emdash_core/embeddings/providers/openai.py +104 -0
- emdash_core/embeddings/registry.py +146 -0
- emdash_core/embeddings/service.py +215 -0
- emdash_core/graph/__init__.py +26 -0
- emdash_core/graph/builder.py +134 -0
- emdash_core/graph/connection.py +692 -0
- emdash_core/graph/schema.py +416 -0
- emdash_core/graph/writer.py +667 -0
- emdash_core/ingestion/__init__.py +7 -0
- emdash_core/ingestion/change_detector.py +150 -0
- emdash_core/ingestion/git/__init__.py +5 -0
- emdash_core/ingestion/git/commit_analyzer.py +196 -0
- emdash_core/ingestion/github/__init__.py +6 -0
- emdash_core/ingestion/github/pr_fetcher.py +296 -0
- emdash_core/ingestion/github/task_extractor.py +100 -0
- emdash_core/ingestion/orchestrator.py +540 -0
- emdash_core/ingestion/parsers/__init__.py +10 -0
- emdash_core/ingestion/parsers/base_parser.py +66 -0
- emdash_core/ingestion/parsers/call_graph_builder.py +121 -0
- emdash_core/ingestion/parsers/class_extractor.py +154 -0
- emdash_core/ingestion/parsers/function_extractor.py +202 -0
- emdash_core/ingestion/parsers/import_analyzer.py +119 -0
- emdash_core/ingestion/parsers/python_parser.py +123 -0
- emdash_core/ingestion/parsers/registry.py +72 -0
- emdash_core/ingestion/parsers/ts_ast_parser.js +313 -0
- emdash_core/ingestion/parsers/typescript_parser.py +278 -0
- emdash_core/ingestion/repository.py +346 -0
- emdash_core/models/__init__.py +38 -0
- emdash_core/models/agent.py +68 -0
- emdash_core/models/index.py +77 -0
- emdash_core/models/query.py +113 -0
- emdash_core/planning/__init__.py +7 -0
- emdash_core/planning/agent_api.py +413 -0
- emdash_core/planning/context_builder.py +265 -0
- emdash_core/planning/feature_context.py +232 -0
- emdash_core/planning/feature_expander.py +646 -0
- emdash_core/planning/llm_explainer.py +198 -0
- emdash_core/planning/similarity.py +509 -0
- emdash_core/planning/team_focus.py +821 -0
- emdash_core/server.py +153 -0
- emdash_core/sse/__init__.py +5 -0
- emdash_core/sse/stream.py +196 -0
- emdash_core/swarm/__init__.py +17 -0
- emdash_core/swarm/merge_agent.py +383 -0
- emdash_core/swarm/session_manager.py +274 -0
- emdash_core/swarm/swarm_runner.py +226 -0
- emdash_core/swarm/task_definition.py +137 -0
- emdash_core/swarm/worker_spawner.py +319 -0
- emdash_core/swarm/worktree_manager.py +278 -0
- emdash_core/templates/__init__.py +10 -0
- emdash_core/templates/defaults/agent-builder.md.template +82 -0
- emdash_core/templates/defaults/focus.md.template +115 -0
- emdash_core/templates/defaults/pr-review-enhanced.md.template +309 -0
- emdash_core/templates/defaults/pr-review.md.template +80 -0
- emdash_core/templates/defaults/project.md.template +85 -0
- emdash_core/templates/defaults/research_critic.md.template +112 -0
- emdash_core/templates/defaults/research_planner.md.template +85 -0
- emdash_core/templates/defaults/research_synthesizer.md.template +128 -0
- emdash_core/templates/defaults/reviewer.md.template +81 -0
- emdash_core/templates/defaults/spec.md.template +41 -0
- emdash_core/templates/defaults/tasks.md.template +78 -0
- emdash_core/templates/loader.py +296 -0
- emdash_core/utils/__init__.py +45 -0
- emdash_core/utils/git.py +84 -0
- emdash_core/utils/image.py +502 -0
- emdash_core/utils/logger.py +51 -0
- emdash_core-0.1.7.dist-info/METADATA +35 -0
- emdash_core-0.1.7.dist-info/RECORD +187 -0
- emdash_core-0.1.7.dist-info/WHEEL +4 -0
- emdash_core-0.1.7.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
"""Session context manager for Kuzu persistence."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import uuid
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
from .models import ContextItem, SessionContext
|
|
9
|
+
from ..graph.connection import KuzuConnection
|
|
10
|
+
from ..utils.logger import log
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SessionContextManager:
|
|
14
|
+
"""Manages session context persistence in Kuzu.
|
|
15
|
+
|
|
16
|
+
Handles:
|
|
17
|
+
- Creating and retrieving sessions by terminal ID
|
|
18
|
+
- Storing and updating context items
|
|
19
|
+
- Applying score decay to existing items
|
|
20
|
+
- Filtering items by minimum score
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, connection: KuzuConnection):
|
|
24
|
+
"""Initialize session context manager.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
connection: Kuzu database connection
|
|
28
|
+
"""
|
|
29
|
+
self.connection = connection
|
|
30
|
+
self._decay_factor = float(os.getenv("CONTEXT_DECAY_FACTOR", "0.8"))
|
|
31
|
+
self._ensure_schema()
|
|
32
|
+
|
|
33
|
+
def _ensure_schema(self):
|
|
34
|
+
"""Ensure Session and ContextItem tables exist."""
|
|
35
|
+
try:
|
|
36
|
+
# Try to create tables (IF NOT EXISTS handles idempotency)
|
|
37
|
+
log.debug("Ensuring Session table exists...")
|
|
38
|
+
self.connection.execute_write(
|
|
39
|
+
"""
|
|
40
|
+
CREATE NODE TABLE IF NOT EXISTS Session (
|
|
41
|
+
session_id STRING,
|
|
42
|
+
terminal_id STRING,
|
|
43
|
+
created_at TIMESTAMP,
|
|
44
|
+
last_active TIMESTAMP,
|
|
45
|
+
PRIMARY KEY (session_id)
|
|
46
|
+
)
|
|
47
|
+
"""
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
log.debug("Ensuring ContextItem table exists...")
|
|
51
|
+
self.connection.execute_write(
|
|
52
|
+
"""
|
|
53
|
+
CREATE NODE TABLE IF NOT EXISTS ContextItem (
|
|
54
|
+
id STRING,
|
|
55
|
+
session_id STRING,
|
|
56
|
+
qualified_name STRING,
|
|
57
|
+
entity_type STRING,
|
|
58
|
+
description STRING,
|
|
59
|
+
file_path STRING,
|
|
60
|
+
score DOUBLE,
|
|
61
|
+
touch_count INT64,
|
|
62
|
+
last_touched TIMESTAMP,
|
|
63
|
+
neighbors STRING[],
|
|
64
|
+
PRIMARY KEY (id)
|
|
65
|
+
)
|
|
66
|
+
"""
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
log.debug("Ensuring SESSION_HAS_CONTEXT relationship exists...")
|
|
70
|
+
self.connection.execute_write(
|
|
71
|
+
"""
|
|
72
|
+
CREATE REL TABLE IF NOT EXISTS SESSION_HAS_CONTEXT (
|
|
73
|
+
FROM Session TO ContextItem
|
|
74
|
+
)
|
|
75
|
+
"""
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
except Exception as e:
|
|
79
|
+
log.warning(f"Failed to ensure schema (may already exist): {e}")
|
|
80
|
+
|
|
81
|
+
def get_or_create_session(self, terminal_id: str) -> SessionContext:
|
|
82
|
+
"""Get existing session for terminal or create a new one.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
terminal_id: Unique identifier for the terminal
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
SessionContext for the terminal
|
|
89
|
+
"""
|
|
90
|
+
# Try to find existing session
|
|
91
|
+
results = self.connection.execute(
|
|
92
|
+
"""
|
|
93
|
+
MATCH (s:Session {terminal_id: $terminal_id})
|
|
94
|
+
RETURN s.session_id as session_id,
|
|
95
|
+
s.terminal_id as terminal_id,
|
|
96
|
+
s.created_at as created_at,
|
|
97
|
+
s.last_active as last_active
|
|
98
|
+
ORDER BY s.last_active DESC
|
|
99
|
+
LIMIT 1
|
|
100
|
+
""",
|
|
101
|
+
{"terminal_id": terminal_id},
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
if results:
|
|
105
|
+
row = results[0]
|
|
106
|
+
# Update last_active
|
|
107
|
+
self.connection.execute_write(
|
|
108
|
+
"""
|
|
109
|
+
MATCH (s:Session {session_id: $session_id})
|
|
110
|
+
SET s.last_active = timestamp($now)
|
|
111
|
+
""",
|
|
112
|
+
{"session_id": row["session_id"], "now": datetime.now().isoformat()},
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
return SessionContext(
|
|
116
|
+
session_id=row["session_id"],
|
|
117
|
+
terminal_id=row["terminal_id"],
|
|
118
|
+
created_at=row.get("created_at"),
|
|
119
|
+
last_active=datetime.now(),
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# Create new session
|
|
123
|
+
session_id = str(uuid.uuid4())
|
|
124
|
+
now = datetime.now()
|
|
125
|
+
|
|
126
|
+
self.connection.execute_write(
|
|
127
|
+
"""
|
|
128
|
+
CREATE (s:Session {
|
|
129
|
+
session_id: $session_id,
|
|
130
|
+
terminal_id: $terminal_id,
|
|
131
|
+
created_at: timestamp($created_at),
|
|
132
|
+
last_active: timestamp($last_active)
|
|
133
|
+
})
|
|
134
|
+
""",
|
|
135
|
+
{
|
|
136
|
+
"session_id": session_id,
|
|
137
|
+
"terminal_id": terminal_id,
|
|
138
|
+
"created_at": now.isoformat(),
|
|
139
|
+
"last_active": now.isoformat(),
|
|
140
|
+
},
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
log.info(f"Created new session {session_id} for terminal {terminal_id}")
|
|
144
|
+
|
|
145
|
+
return SessionContext(
|
|
146
|
+
session_id=session_id,
|
|
147
|
+
terminal_id=terminal_id,
|
|
148
|
+
created_at=now,
|
|
149
|
+
last_active=now,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
def add_context_items(self, session_id: str, items: list[ContextItem]):
|
|
153
|
+
"""Add new context items, applying decay to existing ones.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
session_id: Session to add items to
|
|
157
|
+
items: Context items to add
|
|
158
|
+
"""
|
|
159
|
+
if not items:
|
|
160
|
+
return
|
|
161
|
+
|
|
162
|
+
# First, decay existing items
|
|
163
|
+
self._decay_existing(session_id)
|
|
164
|
+
|
|
165
|
+
# Then upsert new items
|
|
166
|
+
for item in items:
|
|
167
|
+
self._upsert_item(session_id, item)
|
|
168
|
+
|
|
169
|
+
log.info(f"Added {len(items)} context items to session {session_id}")
|
|
170
|
+
|
|
171
|
+
def _decay_existing(self, session_id: str):
|
|
172
|
+
"""Apply decay factor to existing context items.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
session_id: Session to decay items for
|
|
176
|
+
"""
|
|
177
|
+
try:
|
|
178
|
+
self.connection.execute_write(
|
|
179
|
+
"""
|
|
180
|
+
MATCH (s:Session {session_id: $session_id})-[:SESSION_HAS_CONTEXT]->(c:ContextItem)
|
|
181
|
+
SET c.score = c.score * $factor
|
|
182
|
+
""",
|
|
183
|
+
{"session_id": session_id, "factor": self._decay_factor},
|
|
184
|
+
)
|
|
185
|
+
except Exception as e:
|
|
186
|
+
log.warning(f"Failed to decay existing items: {e}")
|
|
187
|
+
|
|
188
|
+
def _upsert_item(self, session_id: str, item: ContextItem):
|
|
189
|
+
"""Insert or update a context item.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
session_id: Session ID
|
|
193
|
+
item: Context item to upsert
|
|
194
|
+
"""
|
|
195
|
+
item_id = f"{session_id}:{item.qualified_name}"
|
|
196
|
+
now = datetime.now()
|
|
197
|
+
|
|
198
|
+
try:
|
|
199
|
+
# Check if item exists
|
|
200
|
+
existing = self.connection.execute(
|
|
201
|
+
"""
|
|
202
|
+
MATCH (c:ContextItem {id: $id})
|
|
203
|
+
RETURN c.touch_count as touch_count
|
|
204
|
+
""",
|
|
205
|
+
{"id": item_id},
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
if existing:
|
|
209
|
+
# Update existing - increment touch count and reset score
|
|
210
|
+
touch_count = (existing[0].get("touch_count") or 0) + 1
|
|
211
|
+
self.connection.execute_write(
|
|
212
|
+
"""
|
|
213
|
+
MATCH (c:ContextItem {id: $id})
|
|
214
|
+
SET c.score = 1.0,
|
|
215
|
+
c.touch_count = $touch_count,
|
|
216
|
+
c.last_touched = timestamp($now),
|
|
217
|
+
c.description = $description,
|
|
218
|
+
c.neighbors = $neighbors
|
|
219
|
+
""",
|
|
220
|
+
{
|
|
221
|
+
"id": item_id,
|
|
222
|
+
"touch_count": touch_count,
|
|
223
|
+
"now": now.isoformat(),
|
|
224
|
+
"description": item.description,
|
|
225
|
+
"neighbors": item.neighbors or [],
|
|
226
|
+
},
|
|
227
|
+
)
|
|
228
|
+
else:
|
|
229
|
+
# Create new item
|
|
230
|
+
self.connection.execute_write(
|
|
231
|
+
"""
|
|
232
|
+
CREATE (c:ContextItem {
|
|
233
|
+
id: $id,
|
|
234
|
+
session_id: $session_id,
|
|
235
|
+
qualified_name: $qualified_name,
|
|
236
|
+
entity_type: $entity_type,
|
|
237
|
+
description: $description,
|
|
238
|
+
file_path: $file_path,
|
|
239
|
+
score: $score,
|
|
240
|
+
touch_count: $touch_count,
|
|
241
|
+
last_touched: timestamp($last_touched),
|
|
242
|
+
neighbors: $neighbors
|
|
243
|
+
})
|
|
244
|
+
""",
|
|
245
|
+
{
|
|
246
|
+
"id": item_id,
|
|
247
|
+
"session_id": session_id,
|
|
248
|
+
"qualified_name": item.qualified_name,
|
|
249
|
+
"entity_type": item.entity_type,
|
|
250
|
+
"description": item.description,
|
|
251
|
+
"file_path": item.file_path,
|
|
252
|
+
"score": item.score,
|
|
253
|
+
"touch_count": item.touch_count,
|
|
254
|
+
"last_touched": now.isoformat(),
|
|
255
|
+
"neighbors": item.neighbors or [],
|
|
256
|
+
},
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
# Create relationship
|
|
260
|
+
self.connection.execute_write(
|
|
261
|
+
"""
|
|
262
|
+
MATCH (s:Session {session_id: $session_id})
|
|
263
|
+
MATCH (c:ContextItem {id: $item_id})
|
|
264
|
+
CREATE (s)-[:SESSION_HAS_CONTEXT]->(c)
|
|
265
|
+
""",
|
|
266
|
+
{"session_id": session_id, "item_id": item_id},
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
except Exception as e:
|
|
270
|
+
log.warning(f"Failed to upsert context item {item.qualified_name}: {e}")
|
|
271
|
+
|
|
272
|
+
def get_context(self, session_id: str, min_score: float = 0.3) -> list[ContextItem]:
|
|
273
|
+
"""Get context items above minimum score.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
session_id: Session to get items for
|
|
277
|
+
min_score: Minimum score threshold
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
List of context items
|
|
281
|
+
"""
|
|
282
|
+
try:
|
|
283
|
+
results = self.connection.execute(
|
|
284
|
+
"""
|
|
285
|
+
MATCH (s:Session {session_id: $session_id})-[:SESSION_HAS_CONTEXT]->(c:ContextItem)
|
|
286
|
+
WHERE c.score >= $min_score
|
|
287
|
+
RETURN c.qualified_name as qualified_name,
|
|
288
|
+
c.entity_type as entity_type,
|
|
289
|
+
c.description as description,
|
|
290
|
+
c.file_path as file_path,
|
|
291
|
+
c.score as score,
|
|
292
|
+
c.touch_count as touch_count,
|
|
293
|
+
c.last_touched as last_touched,
|
|
294
|
+
c.neighbors as neighbors
|
|
295
|
+
ORDER BY c.score DESC
|
|
296
|
+
""",
|
|
297
|
+
{"session_id": session_id, "min_score": min_score},
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
items = []
|
|
301
|
+
for row in results:
|
|
302
|
+
items.append(
|
|
303
|
+
ContextItem(
|
|
304
|
+
qualified_name=row["qualified_name"],
|
|
305
|
+
entity_type=row["entity_type"],
|
|
306
|
+
description=row.get("description"),
|
|
307
|
+
file_path=row.get("file_path"),
|
|
308
|
+
score=row.get("score", 0.0),
|
|
309
|
+
touch_count=row.get("touch_count", 1),
|
|
310
|
+
last_touched=row.get("last_touched"),
|
|
311
|
+
neighbors=row.get("neighbors") or [],
|
|
312
|
+
)
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
return items
|
|
316
|
+
|
|
317
|
+
except Exception as e:
|
|
318
|
+
log.warning(f"Failed to get context for session {session_id}: {e}")
|
|
319
|
+
return []
|
|
320
|
+
|
|
321
|
+
def clear_session(self, session_id: str):
|
|
322
|
+
"""Clear all context items for a session.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
session_id: Session to clear
|
|
326
|
+
"""
|
|
327
|
+
try:
|
|
328
|
+
# Delete context items
|
|
329
|
+
self.connection.execute_write(
|
|
330
|
+
"""
|
|
331
|
+
MATCH (s:Session {session_id: $session_id})-[:SESSION_HAS_CONTEXT]->(c:ContextItem)
|
|
332
|
+
DETACH DELETE c
|
|
333
|
+
""",
|
|
334
|
+
{"session_id": session_id},
|
|
335
|
+
)
|
|
336
|
+
log.info(f"Cleared context for session {session_id}")
|
|
337
|
+
except Exception as e:
|
|
338
|
+
log.warning(f"Failed to clear session {session_id}: {e}")
|
|
339
|
+
|
|
340
|
+
def cleanup_old_sessions(self, max_age_days: int = 7):
|
|
341
|
+
"""Remove sessions older than max_age_days.
|
|
342
|
+
|
|
343
|
+
Args:
|
|
344
|
+
max_age_days: Maximum age in days for sessions
|
|
345
|
+
"""
|
|
346
|
+
try:
|
|
347
|
+
# This is a simplified cleanup - proper implementation would use
|
|
348
|
+
# timestamp comparison, but Kuzu's timestamp handling varies
|
|
349
|
+
log.info(f"Cleaning up sessions older than {max_age_days} days")
|
|
350
|
+
# TODO: Implement proper date-based cleanup
|
|
351
|
+
except Exception as e:
|
|
352
|
+
log.warning(f"Failed to cleanup old sessions: {e}")
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Core module for EmDash - models, configuration, and exceptions."""
|
|
2
|
+
|
|
3
|
+
from .config import (
|
|
4
|
+
EmDashConfig,
|
|
5
|
+
KuzuConfig,
|
|
6
|
+
IngestionConfig,
|
|
7
|
+
AnalyticsConfig,
|
|
8
|
+
GitHubConfig,
|
|
9
|
+
OpenAIConfig,
|
|
10
|
+
AnthropicConfig,
|
|
11
|
+
FireworksConfig,
|
|
12
|
+
ContextConfig,
|
|
13
|
+
AgentConfig,
|
|
14
|
+
MCPConfig,
|
|
15
|
+
get_config,
|
|
16
|
+
set_config,
|
|
17
|
+
get_config_dir,
|
|
18
|
+
get_user_config_path,
|
|
19
|
+
get_local_env_path,
|
|
20
|
+
load_env_files,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
from .exceptions import (
|
|
24
|
+
EmDashException,
|
|
25
|
+
ConfigurationError,
|
|
26
|
+
DatabaseConnectionError,
|
|
27
|
+
RepositoryError,
|
|
28
|
+
ParsingError,
|
|
29
|
+
GraphBuildError,
|
|
30
|
+
QueryError,
|
|
31
|
+
AnalyticsError,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
from .models import (
|
|
35
|
+
FileEntity,
|
|
36
|
+
ClassEntity,
|
|
37
|
+
FunctionEntity,
|
|
38
|
+
ModuleEntity,
|
|
39
|
+
ImportStatement,
|
|
40
|
+
CommitEntity,
|
|
41
|
+
FileModification,
|
|
42
|
+
AuthorEntity,
|
|
43
|
+
PullRequestEntity,
|
|
44
|
+
TaskEntity,
|
|
45
|
+
RepositoryEntity,
|
|
46
|
+
ClusterEntity,
|
|
47
|
+
CodebaseEntities,
|
|
48
|
+
FileEntities,
|
|
49
|
+
GitData,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
from .review_config import (
|
|
53
|
+
ReviewConfig,
|
|
54
|
+
load_review_config,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
__all__ = [
|
|
58
|
+
# Config
|
|
59
|
+
"EmDashConfig",
|
|
60
|
+
"KuzuConfig",
|
|
61
|
+
"IngestionConfig",
|
|
62
|
+
"AnalyticsConfig",
|
|
63
|
+
"GitHubConfig",
|
|
64
|
+
"OpenAIConfig",
|
|
65
|
+
"AnthropicConfig",
|
|
66
|
+
"FireworksConfig",
|
|
67
|
+
"ContextConfig",
|
|
68
|
+
"AgentConfig",
|
|
69
|
+
"MCPConfig",
|
|
70
|
+
"get_config",
|
|
71
|
+
"set_config",
|
|
72
|
+
"get_config_dir",
|
|
73
|
+
"get_user_config_path",
|
|
74
|
+
"get_local_env_path",
|
|
75
|
+
"load_env_files",
|
|
76
|
+
# Exceptions
|
|
77
|
+
"EmDashException",
|
|
78
|
+
"ConfigurationError",
|
|
79
|
+
"DatabaseConnectionError",
|
|
80
|
+
"RepositoryError",
|
|
81
|
+
"ParsingError",
|
|
82
|
+
"GraphBuildError",
|
|
83
|
+
"QueryError",
|
|
84
|
+
"AnalyticsError",
|
|
85
|
+
# Models
|
|
86
|
+
"FileEntity",
|
|
87
|
+
"ClassEntity",
|
|
88
|
+
"FunctionEntity",
|
|
89
|
+
"ModuleEntity",
|
|
90
|
+
"ImportStatement",
|
|
91
|
+
"CommitEntity",
|
|
92
|
+
"FileModification",
|
|
93
|
+
"AuthorEntity",
|
|
94
|
+
"PullRequestEntity",
|
|
95
|
+
"TaskEntity",
|
|
96
|
+
"RepositoryEntity",
|
|
97
|
+
"ClusterEntity",
|
|
98
|
+
"CodebaseEntities",
|
|
99
|
+
"FileEntities",
|
|
100
|
+
"GitData",
|
|
101
|
+
# Review config
|
|
102
|
+
"ReviewConfig",
|
|
103
|
+
"load_review_config",
|
|
104
|
+
]
|