codexa 0.4.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.
- codexa-0.4.0.dist-info/METADATA +650 -0
- codexa-0.4.0.dist-info/RECORD +189 -0
- codexa-0.4.0.dist-info/WHEEL +5 -0
- codexa-0.4.0.dist-info/entry_points.txt +2 -0
- codexa-0.4.0.dist-info/licenses/LICENSE +21 -0
- codexa-0.4.0.dist-info/top_level.txt +1 -0
- semantic_code_intelligence/__init__.py +5 -0
- semantic_code_intelligence/analysis/__init__.py +21 -0
- semantic_code_intelligence/analysis/ai_features.py +351 -0
- semantic_code_intelligence/bridge/__init__.py +28 -0
- semantic_code_intelligence/bridge/context_provider.py +245 -0
- semantic_code_intelligence/bridge/protocol.py +167 -0
- semantic_code_intelligence/bridge/server.py +348 -0
- semantic_code_intelligence/bridge/vscode.py +271 -0
- semantic_code_intelligence/ci/__init__.py +13 -0
- semantic_code_intelligence/ci/hooks.py +98 -0
- semantic_code_intelligence/ci/hotspots.py +272 -0
- semantic_code_intelligence/ci/impact.py +246 -0
- semantic_code_intelligence/ci/metrics.py +591 -0
- semantic_code_intelligence/ci/pr.py +412 -0
- semantic_code_intelligence/ci/quality.py +557 -0
- semantic_code_intelligence/ci/templates.py +164 -0
- semantic_code_intelligence/ci/trace.py +224 -0
- semantic_code_intelligence/cli/__init__.py +0 -0
- semantic_code_intelligence/cli/commands/__init__.py +0 -0
- semantic_code_intelligence/cli/commands/ask_cmd.py +153 -0
- semantic_code_intelligence/cli/commands/benchmark_cmd.py +303 -0
- semantic_code_intelligence/cli/commands/chat_cmd.py +252 -0
- semantic_code_intelligence/cli/commands/ci_gen_cmd.py +74 -0
- semantic_code_intelligence/cli/commands/context_cmd.py +120 -0
- semantic_code_intelligence/cli/commands/cross_refactor_cmd.py +113 -0
- semantic_code_intelligence/cli/commands/deps_cmd.py +91 -0
- semantic_code_intelligence/cli/commands/docs_cmd.py +101 -0
- semantic_code_intelligence/cli/commands/doctor_cmd.py +147 -0
- semantic_code_intelligence/cli/commands/evolve_cmd.py +171 -0
- semantic_code_intelligence/cli/commands/explain_cmd.py +112 -0
- semantic_code_intelligence/cli/commands/gate_cmd.py +135 -0
- semantic_code_intelligence/cli/commands/grep_cmd.py +234 -0
- semantic_code_intelligence/cli/commands/hotspots_cmd.py +119 -0
- semantic_code_intelligence/cli/commands/impact_cmd.py +131 -0
- semantic_code_intelligence/cli/commands/index_cmd.py +138 -0
- semantic_code_intelligence/cli/commands/init_cmd.py +152 -0
- semantic_code_intelligence/cli/commands/investigate_cmd.py +163 -0
- semantic_code_intelligence/cli/commands/languages_cmd.py +101 -0
- semantic_code_intelligence/cli/commands/lsp_cmd.py +49 -0
- semantic_code_intelligence/cli/commands/mcp_cmd.py +50 -0
- semantic_code_intelligence/cli/commands/metrics_cmd.py +264 -0
- semantic_code_intelligence/cli/commands/models_cmd.py +157 -0
- semantic_code_intelligence/cli/commands/plugin_cmd.py +275 -0
- semantic_code_intelligence/cli/commands/pr_summary_cmd.py +178 -0
- semantic_code_intelligence/cli/commands/quality_cmd.py +208 -0
- semantic_code_intelligence/cli/commands/refactor_cmd.py +103 -0
- semantic_code_intelligence/cli/commands/review_cmd.py +88 -0
- semantic_code_intelligence/cli/commands/search_cmd.py +236 -0
- semantic_code_intelligence/cli/commands/serve_cmd.py +117 -0
- semantic_code_intelligence/cli/commands/suggest_cmd.py +100 -0
- semantic_code_intelligence/cli/commands/summary_cmd.py +78 -0
- semantic_code_intelligence/cli/commands/tool_cmd.py +282 -0
- semantic_code_intelligence/cli/commands/trace_cmd.py +123 -0
- semantic_code_intelligence/cli/commands/tui_cmd.py +58 -0
- semantic_code_intelligence/cli/commands/viz_cmd.py +127 -0
- semantic_code_intelligence/cli/commands/watch_cmd.py +72 -0
- semantic_code_intelligence/cli/commands/web_cmd.py +61 -0
- semantic_code_intelligence/cli/commands/workspace_cmd.py +250 -0
- semantic_code_intelligence/cli/main.py +65 -0
- semantic_code_intelligence/cli/router.py +92 -0
- semantic_code_intelligence/config/__init__.py +0 -0
- semantic_code_intelligence/config/settings.py +260 -0
- semantic_code_intelligence/context/__init__.py +19 -0
- semantic_code_intelligence/context/engine.py +429 -0
- semantic_code_intelligence/context/memory.py +253 -0
- semantic_code_intelligence/daemon/__init__.py +1 -0
- semantic_code_intelligence/daemon/watcher.py +515 -0
- semantic_code_intelligence/docs/__init__.py +1080 -0
- semantic_code_intelligence/embeddings/__init__.py +0 -0
- semantic_code_intelligence/embeddings/enhanced.py +131 -0
- semantic_code_intelligence/embeddings/generator.py +149 -0
- semantic_code_intelligence/embeddings/model_registry.py +100 -0
- semantic_code_intelligence/evolution/__init__.py +1 -0
- semantic_code_intelligence/evolution/budget_guard.py +111 -0
- semantic_code_intelligence/evolution/commit_manager.py +88 -0
- semantic_code_intelligence/evolution/context_builder.py +131 -0
- semantic_code_intelligence/evolution/engine.py +249 -0
- semantic_code_intelligence/evolution/patch_generator.py +229 -0
- semantic_code_intelligence/evolution/task_selector.py +214 -0
- semantic_code_intelligence/evolution/test_runner.py +111 -0
- semantic_code_intelligence/indexing/__init__.py +0 -0
- semantic_code_intelligence/indexing/chunker.py +174 -0
- semantic_code_intelligence/indexing/parallel.py +86 -0
- semantic_code_intelligence/indexing/scanner.py +146 -0
- semantic_code_intelligence/indexing/semantic_chunker.py +337 -0
- semantic_code_intelligence/llm/__init__.py +62 -0
- semantic_code_intelligence/llm/cache.py +219 -0
- semantic_code_intelligence/llm/cached_provider.py +145 -0
- semantic_code_intelligence/llm/conversation.py +190 -0
- semantic_code_intelligence/llm/cross_refactor.py +272 -0
- semantic_code_intelligence/llm/investigation.py +274 -0
- semantic_code_intelligence/llm/mock_provider.py +77 -0
- semantic_code_intelligence/llm/ollama_provider.py +122 -0
- semantic_code_intelligence/llm/openai_provider.py +100 -0
- semantic_code_intelligence/llm/provider.py +92 -0
- semantic_code_intelligence/llm/rate_limiter.py +164 -0
- semantic_code_intelligence/llm/reasoning.py +438 -0
- semantic_code_intelligence/llm/safety.py +110 -0
- semantic_code_intelligence/llm/streaming.py +251 -0
- semantic_code_intelligence/lsp/__init__.py +609 -0
- semantic_code_intelligence/mcp/__init__.py +393 -0
- semantic_code_intelligence/parsing/__init__.py +19 -0
- semantic_code_intelligence/parsing/parser.py +375 -0
- semantic_code_intelligence/plugins/__init__.py +255 -0
- semantic_code_intelligence/plugins/examples/__init__.py +1 -0
- semantic_code_intelligence/plugins/examples/code_quality.py +73 -0
- semantic_code_intelligence/plugins/examples/search_annotator.py +56 -0
- semantic_code_intelligence/scalability/__init__.py +205 -0
- semantic_code_intelligence/search/__init__.py +0 -0
- semantic_code_intelligence/search/formatter.py +123 -0
- semantic_code_intelligence/search/grep.py +361 -0
- semantic_code_intelligence/search/hybrid_search.py +170 -0
- semantic_code_intelligence/search/keyword_search.py +311 -0
- semantic_code_intelligence/search/section_expander.py +103 -0
- semantic_code_intelligence/services/__init__.py +0 -0
- semantic_code_intelligence/services/indexing_service.py +630 -0
- semantic_code_intelligence/services/search_service.py +269 -0
- semantic_code_intelligence/storage/__init__.py +0 -0
- semantic_code_intelligence/storage/chunk_hash_store.py +86 -0
- semantic_code_intelligence/storage/hash_store.py +66 -0
- semantic_code_intelligence/storage/index_manifest.py +85 -0
- semantic_code_intelligence/storage/index_stats.py +138 -0
- semantic_code_intelligence/storage/query_history.py +160 -0
- semantic_code_intelligence/storage/symbol_registry.py +209 -0
- semantic_code_intelligence/storage/vector_store.py +297 -0
- semantic_code_intelligence/tests/__init__.py +0 -0
- semantic_code_intelligence/tests/test_ai_features.py +351 -0
- semantic_code_intelligence/tests/test_chunker.py +119 -0
- semantic_code_intelligence/tests/test_cli.py +188 -0
- semantic_code_intelligence/tests/test_config.py +154 -0
- semantic_code_intelligence/tests/test_context.py +381 -0
- semantic_code_intelligence/tests/test_embeddings.py +73 -0
- semantic_code_intelligence/tests/test_endtoend.py +1142 -0
- semantic_code_intelligence/tests/test_enhanced_embeddings.py +92 -0
- semantic_code_intelligence/tests/test_hash_store.py +79 -0
- semantic_code_intelligence/tests/test_logging.py +55 -0
- semantic_code_intelligence/tests/test_new_cli.py +138 -0
- semantic_code_intelligence/tests/test_parser.py +495 -0
- semantic_code_intelligence/tests/test_phase10.py +355 -0
- semantic_code_intelligence/tests/test_phase11.py +593 -0
- semantic_code_intelligence/tests/test_phase12.py +375 -0
- semantic_code_intelligence/tests/test_phase13.py +663 -0
- semantic_code_intelligence/tests/test_phase14.py +568 -0
- semantic_code_intelligence/tests/test_phase15.py +814 -0
- semantic_code_intelligence/tests/test_phase16.py +792 -0
- semantic_code_intelligence/tests/test_phase17.py +815 -0
- semantic_code_intelligence/tests/test_phase18.py +934 -0
- semantic_code_intelligence/tests/test_phase19.py +986 -0
- semantic_code_intelligence/tests/test_phase20.py +2753 -0
- semantic_code_intelligence/tests/test_phase20b.py +2058 -0
- semantic_code_intelligence/tests/test_phase20c.py +962 -0
- semantic_code_intelligence/tests/test_phase21.py +428 -0
- semantic_code_intelligence/tests/test_phase22.py +799 -0
- semantic_code_intelligence/tests/test_phase23.py +783 -0
- semantic_code_intelligence/tests/test_phase24.py +715 -0
- semantic_code_intelligence/tests/test_phase25.py +496 -0
- semantic_code_intelligence/tests/test_phase26.py +251 -0
- semantic_code_intelligence/tests/test_phase27.py +531 -0
- semantic_code_intelligence/tests/test_phase8.py +592 -0
- semantic_code_intelligence/tests/test_phase9.py +643 -0
- semantic_code_intelligence/tests/test_plugins.py +293 -0
- semantic_code_intelligence/tests/test_priority_features.py +727 -0
- semantic_code_intelligence/tests/test_router.py +41 -0
- semantic_code_intelligence/tests/test_scalability.py +138 -0
- semantic_code_intelligence/tests/test_scanner.py +125 -0
- semantic_code_intelligence/tests/test_search.py +160 -0
- semantic_code_intelligence/tests/test_semantic_chunker.py +255 -0
- semantic_code_intelligence/tests/test_tools.py +182 -0
- semantic_code_intelligence/tests/test_vector_store.py +151 -0
- semantic_code_intelligence/tests/test_watcher.py +211 -0
- semantic_code_intelligence/tools/__init__.py +442 -0
- semantic_code_intelligence/tools/executor.py +232 -0
- semantic_code_intelligence/tools/protocol.py +200 -0
- semantic_code_intelligence/tui/__init__.py +454 -0
- semantic_code_intelligence/utils/__init__.py +0 -0
- semantic_code_intelligence/utils/logging.py +112 -0
- semantic_code_intelligence/version.py +3 -0
- semantic_code_intelligence/web/__init__.py +11 -0
- semantic_code_intelligence/web/api.py +289 -0
- semantic_code_intelligence/web/server.py +397 -0
- semantic_code_intelligence/web/ui.py +659 -0
- semantic_code_intelligence/web/visualize.py +226 -0
- semantic_code_intelligence/workspace/__init__.py +427 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""Context memory — workspace memory, session context, and multi-step reasoning.
|
|
2
|
+
|
|
3
|
+
Provides persistent and session-scoped memory so that the AI assistant can:
|
|
4
|
+
- Remember previous interactions within a session
|
|
5
|
+
- Cache insights across sessions (workspace memory)
|
|
6
|
+
- Maintain multi-step reasoning chains
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import time
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
from semantic_code_intelligence.utils.logging import get_logger
|
|
18
|
+
|
|
19
|
+
logger = get_logger("context.memory")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
# Data types
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class MemoryEntry:
|
|
28
|
+
"""A single memory entry (question/answer, insight, or reasoning step)."""
|
|
29
|
+
|
|
30
|
+
key: str
|
|
31
|
+
content: str
|
|
32
|
+
kind: str = "general" # general | qa | reasoning | insight
|
|
33
|
+
timestamp: float = field(default_factory=time.time)
|
|
34
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
35
|
+
|
|
36
|
+
def to_dict(self) -> dict[str, Any]:
|
|
37
|
+
"""Serialize the memory entry to a plain dictionary."""
|
|
38
|
+
return {
|
|
39
|
+
"key": self.key,
|
|
40
|
+
"content": self.content,
|
|
41
|
+
"kind": self.kind,
|
|
42
|
+
"timestamp": self.timestamp,
|
|
43
|
+
"metadata": self.metadata,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def from_dict(cls, data: dict[str, Any]) -> "MemoryEntry":
|
|
48
|
+
"""Create a MemoryEntry from a dictionary."""
|
|
49
|
+
return cls(
|
|
50
|
+
key=data["key"],
|
|
51
|
+
content=data["content"],
|
|
52
|
+
kind=data.get("kind", "general"),
|
|
53
|
+
timestamp=data.get("timestamp", time.time()),
|
|
54
|
+
metadata=data.get("metadata", {}),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class ReasoningStep:
|
|
60
|
+
"""A single step in a multi-step reasoning chain."""
|
|
61
|
+
|
|
62
|
+
step_id: int
|
|
63
|
+
action: str # e.g. "search", "analyze", "ask_llm", "conclude"
|
|
64
|
+
input_text: str
|
|
65
|
+
output_text: str
|
|
66
|
+
timestamp: float = field(default_factory=time.time)
|
|
67
|
+
|
|
68
|
+
def to_dict(self) -> dict[str, Any]:
|
|
69
|
+
"""Serialize the reasoning step to a plain dictionary."""
|
|
70
|
+
return {
|
|
71
|
+
"step_id": self.step_id,
|
|
72
|
+
"action": self.action,
|
|
73
|
+
"input": self.input_text,
|
|
74
|
+
"output": self.output_text,
|
|
75
|
+
"timestamp": self.timestamp,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# ---------------------------------------------------------------------------
|
|
80
|
+
# Session Memory (in-process, per-session)
|
|
81
|
+
# ---------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
class SessionMemory:
|
|
84
|
+
"""In-process memory for the current session / conversation."""
|
|
85
|
+
|
|
86
|
+
def __init__(self, max_entries: int = 200) -> None:
|
|
87
|
+
self._entries: list[MemoryEntry] = []
|
|
88
|
+
self._reasoning_chains: dict[str, list[ReasoningStep]] = {}
|
|
89
|
+
self._max = max_entries
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def entries(self) -> list[MemoryEntry]:
|
|
93
|
+
"""Return a shallow copy of all session memory entries."""
|
|
94
|
+
return list(self._entries)
|
|
95
|
+
|
|
96
|
+
def add(self, key: str, content: str, kind: str = "general", **metadata: Any) -> MemoryEntry:
|
|
97
|
+
"""Add a memory entry to the session."""
|
|
98
|
+
entry = MemoryEntry(key=key, content=content, kind=kind, metadata=metadata)
|
|
99
|
+
self._entries.append(entry)
|
|
100
|
+
if len(self._entries) > self._max:
|
|
101
|
+
self._entries.pop(0)
|
|
102
|
+
return entry
|
|
103
|
+
|
|
104
|
+
def search(self, query: str, limit: int = 5) -> list[MemoryEntry]:
|
|
105
|
+
"""Simple keyword search over session memory."""
|
|
106
|
+
query_lower = query.lower()
|
|
107
|
+
scored = []
|
|
108
|
+
for entry in self._entries:
|
|
109
|
+
text = f"{entry.key} {entry.content}".lower()
|
|
110
|
+
if query_lower in text:
|
|
111
|
+
scored.append(entry)
|
|
112
|
+
return scored[-limit:]
|
|
113
|
+
|
|
114
|
+
def get_recent(self, limit: int = 10) -> list[MemoryEntry]:
|
|
115
|
+
"""Return the most recent entries."""
|
|
116
|
+
return self._entries[-limit:]
|
|
117
|
+
|
|
118
|
+
def clear(self) -> None:
|
|
119
|
+
"""Clear all session memory."""
|
|
120
|
+
self._entries.clear()
|
|
121
|
+
self._reasoning_chains.clear()
|
|
122
|
+
|
|
123
|
+
# --- Reasoning chains ---
|
|
124
|
+
|
|
125
|
+
def start_chain(self, chain_id: str) -> None:
|
|
126
|
+
"""Start a new reasoning chain."""
|
|
127
|
+
self._reasoning_chains[chain_id] = []
|
|
128
|
+
|
|
129
|
+
def add_step(
|
|
130
|
+
self,
|
|
131
|
+
chain_id: str,
|
|
132
|
+
action: str,
|
|
133
|
+
input_text: str,
|
|
134
|
+
output_text: str,
|
|
135
|
+
) -> ReasoningStep:
|
|
136
|
+
"""Add a step to an existing reasoning chain."""
|
|
137
|
+
chain = self._reasoning_chains.setdefault(chain_id, [])
|
|
138
|
+
step = ReasoningStep(
|
|
139
|
+
step_id=len(chain) + 1,
|
|
140
|
+
action=action,
|
|
141
|
+
input_text=input_text,
|
|
142
|
+
output_text=output_text,
|
|
143
|
+
)
|
|
144
|
+
chain.append(step)
|
|
145
|
+
return step
|
|
146
|
+
|
|
147
|
+
def get_chain(self, chain_id: str) -> list[ReasoningStep]:
|
|
148
|
+
"""Retrieve all steps in a reasoning chain."""
|
|
149
|
+
return list(self._reasoning_chains.get(chain_id, []))
|
|
150
|
+
|
|
151
|
+
def to_dict(self) -> dict[str, Any]:
|
|
152
|
+
"""Serialize all session memory and reasoning chains to a dictionary."""
|
|
153
|
+
return {
|
|
154
|
+
"entries": [e.to_dict() for e in self._entries],
|
|
155
|
+
"chains": {
|
|
156
|
+
cid: [s.to_dict() for s in steps]
|
|
157
|
+
for cid, steps in self._reasoning_chains.items()
|
|
158
|
+
},
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
def __repr__(self) -> str:
|
|
162
|
+
return (
|
|
163
|
+
f"SessionMemory(entries={len(self._entries)}, "
|
|
164
|
+
f"chains={len(self._reasoning_chains)})"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# ---------------------------------------------------------------------------
|
|
169
|
+
# Workspace Memory (persistent, stored in .codexa/)
|
|
170
|
+
# ---------------------------------------------------------------------------
|
|
171
|
+
|
|
172
|
+
MEMORY_FILE = "memory.json"
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class WorkspaceMemory:
|
|
176
|
+
"""Persistent memory stored in the project's .codexa/ directory.
|
|
177
|
+
|
|
178
|
+
Survives across sessions. Cached insights, frequently-asked questions,
|
|
179
|
+
and project-specific knowledge live here.
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
def __init__(self, project_root: Path) -> None:
|
|
183
|
+
from semantic_code_intelligence.config.settings import AppConfig
|
|
184
|
+
|
|
185
|
+
self._config_dir = AppConfig.config_dir(project_root)
|
|
186
|
+
self._path = self._config_dir / MEMORY_FILE
|
|
187
|
+
self._entries: dict[str, MemoryEntry] = {}
|
|
188
|
+
self._load()
|
|
189
|
+
|
|
190
|
+
def _load(self) -> None:
|
|
191
|
+
"""Load memory from disk."""
|
|
192
|
+
if self._path.exists():
|
|
193
|
+
try:
|
|
194
|
+
data = json.loads(self._path.read_text(encoding="utf-8"))
|
|
195
|
+
for entry_data in data.get("entries", []):
|
|
196
|
+
entry = MemoryEntry.from_dict(entry_data)
|
|
197
|
+
self._entries[entry.key] = entry
|
|
198
|
+
logger.debug("Loaded %d workspace memory entries", len(self._entries))
|
|
199
|
+
except (json.JSONDecodeError, KeyError, TypeError):
|
|
200
|
+
logger.warning("Corrupt workspace memory file; starting fresh.")
|
|
201
|
+
self._entries = {}
|
|
202
|
+
|
|
203
|
+
def _save(self) -> None:
|
|
204
|
+
"""Persist memory to disk."""
|
|
205
|
+
self._config_dir.mkdir(parents=True, exist_ok=True)
|
|
206
|
+
data = {"entries": [e.to_dict() for e in self._entries.values()]}
|
|
207
|
+
self._path.write_text(json.dumps(data, indent=2), encoding="utf-8")
|
|
208
|
+
|
|
209
|
+
@property
|
|
210
|
+
def entries(self) -> list[MemoryEntry]:
|
|
211
|
+
"""Return a list of all persisted workspace memory entries."""
|
|
212
|
+
return list(self._entries.values())
|
|
213
|
+
|
|
214
|
+
def add(self, key: str, content: str, kind: str = "general", **metadata: Any) -> MemoryEntry:
|
|
215
|
+
"""Add or update a memory entry."""
|
|
216
|
+
entry = MemoryEntry(key=key, content=content, kind=kind, metadata=metadata)
|
|
217
|
+
self._entries[key] = entry
|
|
218
|
+
self._save()
|
|
219
|
+
return entry
|
|
220
|
+
|
|
221
|
+
def get(self, key: str) -> MemoryEntry | None:
|
|
222
|
+
"""Retrieve a specific memory entry by key."""
|
|
223
|
+
return self._entries.get(key)
|
|
224
|
+
|
|
225
|
+
def search(self, query: str, limit: int = 5) -> list[MemoryEntry]:
|
|
226
|
+
"""Simple keyword search over workspace memory."""
|
|
227
|
+
query_lower = query.lower()
|
|
228
|
+
results = []
|
|
229
|
+
for entry in self._entries.values():
|
|
230
|
+
text = f"{entry.key} {entry.content}".lower()
|
|
231
|
+
if query_lower in text:
|
|
232
|
+
results.append(entry)
|
|
233
|
+
return results[:limit]
|
|
234
|
+
|
|
235
|
+
def remove(self, key: str) -> bool:
|
|
236
|
+
"""Remove a memory entry."""
|
|
237
|
+
if key in self._entries:
|
|
238
|
+
del self._entries[key]
|
|
239
|
+
self._save()
|
|
240
|
+
return True
|
|
241
|
+
return False
|
|
242
|
+
|
|
243
|
+
def clear(self) -> None:
|
|
244
|
+
"""Clear all workspace memory."""
|
|
245
|
+
self._entries.clear()
|
|
246
|
+
self._save()
|
|
247
|
+
|
|
248
|
+
def to_dict(self) -> dict[str, Any]:
|
|
249
|
+
"""Serialize all workspace memory entries to a dictionary."""
|
|
250
|
+
return {"entries": [e.to_dict() for e in self._entries.values()]}
|
|
251
|
+
|
|
252
|
+
def __repr__(self) -> str:
|
|
253
|
+
return f"WorkspaceMemory(entries={len(self._entries)})"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Daemon package — background intelligence subsystem."""
|