memor-cli 0.6.1__tar.gz → 0.7.0__tar.gz
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.
- {memor_cli-0.6.1/memor_cli.egg-info → memor_cli-0.7.0}/PKG-INFO +33 -16
- {memor_cli-0.6.1 → memor_cli-0.7.0}/README.md +32 -15
- memor_cli-0.7.0/memor/__init__.py +1 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/cli.py +101 -10
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/dashboard/server.py +5 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/dashboard/static/index.html +50 -2
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/hook_cli.py +3 -7
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/hook_server.py +29 -20
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/store/sqlite_store.py +28 -4
- {memor_cli-0.6.1 → memor_cli-0.7.0/memor_cli.egg-info}/PKG-INFO +33 -16
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor_cli.egg-info/SOURCES.txt +1 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/pyproject.toml +1 -1
- memor_cli-0.7.0/tests/test_multi_agent_hook.py +199 -0
- memor_cli-0.6.1/memor/__init__.py +0 -1
- {memor_cli-0.6.1 → memor_cli-0.7.0}/LICENSE +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/daemon.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/dashboard/__init__.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/distill/__init__.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/distill/distiller.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/distill/extractive.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/embed/__init__.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/embed/api.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/embed/fake.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/embed/local.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/eval/__init__.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/eval/baselines/__init__.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/eval/baselines/base.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/eval/baselines/claude_mem.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/eval/baselines/graphiti.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/eval/counterfactual.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/eval/dataset.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/eval/embed_benchmark.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/eval/judge.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/eval/metrics.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/eval/runner.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/feedback.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/global_memories.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/ingest/__init__.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/ingest/claude_code.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/ingest/documents.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/interfaces.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/llm/__init__.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/llm/anthropic.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/llm/base.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/llm/openai_compat.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/project.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/query_complexity.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/recall.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/redact.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/retrieve/__init__.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/retrieve/retriever.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/service.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/session_context.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/store/__init__.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/tokencount.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/turn_metrics.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor/types.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor_cli.egg-info/dependency_links.txt +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor_cli.egg-info/entry_points.txt +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor_cli.egg-info/requires.txt +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/memor_cli.egg-info/top_level.txt +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/setup.cfg +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_cli_smoke.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_counterfactual.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_daemon.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_dashboard.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_dashboard_quality.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_dataset_builder.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_dimension_safety.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_distiller.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_embed.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_embed_benchmark.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_eval_ablation.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_eval_runner.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_external_baselines.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_extractive.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_feedback.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_global_memories.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_hook.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_hook_server.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_hybrid_retrieval.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_ingest_claude_code.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_ingest_documents.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_install_hook.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_interfaces.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_judge.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_metrics.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_negative_feedback.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_noise_filter.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_project_resolver.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_quality_gate.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_query_complexity.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_recall_core.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_redact.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_retriever.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_roi_trend.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_semantic_feedback.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_service.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_session_context.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_skill_recall.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_store.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_supersession.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_tokencount.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_turn_metrics.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_types.py +0 -0
- {memor_cli-0.6.1 → memor_cli-0.7.0}/tests/test_vec_compaction.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memor-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Measured memory for coding agents. Fire and forget — no API keys needed.
|
|
5
5
|
Author-email: Nimit Bhandari <nimitbhandari17@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -46,13 +46,13 @@ Dynamic: license-file
|
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
[](LICENSE)
|
|
49
|
-
[]()
|
|
50
50
|
[]()
|
|
51
51
|
[](https://pypi.org/project/memor-cli/)
|
|
52
52
|
|
|
53
|
-
**Automatic background memory for Claude Code.** Fire and forget — no API keys needed.
|
|
53
|
+
**Automatic background memory for Claude Code, Codex, and Copilot.** Fire and forget — no API keys needed.
|
|
54
54
|
|
|
55
|
-
Memor watches your coding sessions, extracts decisions and patterns, and recalls relevant context on every prompt. Zero configuration. One install. Your agent remembers everything.
|
|
55
|
+
Memor watches your coding sessions, extracts decisions and patterns, and recalls relevant context on every prompt. Works with Claude Code, OpenAI Codex CLI, and GitHub Copilot CLI. Zero configuration. One install. Your agent remembers everything.
|
|
56
56
|
|
|
57
57
|
---
|
|
58
58
|
|
|
@@ -62,8 +62,9 @@ Memor watches your coding sessions, extracts decisions and patterns, and recalls
|
|
|
62
62
|
# Install globally (recommended)
|
|
63
63
|
pipx install memor-cli
|
|
64
64
|
|
|
65
|
-
# Install the
|
|
66
|
-
memor install-hook
|
|
65
|
+
# Install the hook + download embedding model (~60MB)
|
|
66
|
+
memor install-hook # interactive — pick Claude Code, Codex, or Copilot
|
|
67
|
+
memor install-hook --agent claude # or pass directly
|
|
67
68
|
|
|
68
69
|
# Start as a background service (macOS/Linux)
|
|
69
70
|
memor service install
|
|
@@ -72,7 +73,7 @@ memor service install
|
|
|
72
73
|
memor daemon
|
|
73
74
|
```
|
|
74
75
|
|
|
75
|
-
That's it. Every
|
|
76
|
+
That's it. Every prompt now gets automatic context recall. Open the dashboard to see it working:
|
|
76
77
|
|
|
77
78
|
```bash
|
|
78
79
|
memor dashboard
|
|
@@ -86,10 +87,10 @@ memor dashboard
|
|
|
86
87
|
## How It Works
|
|
87
88
|
|
|
88
89
|
```
|
|
89
|
-
You type a prompt
|
|
90
|
+
You type a prompt (Claude Code / Codex / Copilot)
|
|
90
91
|
|
|
|
91
92
|
v
|
|
92
|
-
Hook fires
|
|
93
|
+
Hook fires — auto-detects which agent
|
|
93
94
|
|
|
|
94
95
|
v
|
|
95
96
|
Embed query locally (model2vec, ~2ms)
|
|
@@ -107,14 +108,26 @@ memor dashboard
|
|
|
107
108
|
Inject relevant context into prompt
|
|
108
109
|
|
|
|
109
110
|
v
|
|
110
|
-
|
|
111
|
+
Your agent sees past decisions, bugfixes,
|
|
111
112
|
architecture choices — without you re-explaining
|
|
112
113
|
```
|
|
113
114
|
|
|
115
|
+
### Supported Agents
|
|
116
|
+
|
|
117
|
+
| Agent | Hook protocol | Config location | Install |
|
|
118
|
+
|---|---|---|---|
|
|
119
|
+
| **Claude Code** | `UserPromptSubmit` + `additionalContext` | `~/.claude/settings.json` | `memor install-hook --agent claude` |
|
|
120
|
+
| **Codex CLI** | `UserPromptSubmit` + `additionalContext` | `~/.codex/hooks/hooks.json` | `memor install-hook --agent codex` |
|
|
121
|
+
| **Copilot CLI** | `userPromptSubmitted` + `additionalContext` | `~/.copilot/hooks/memor.json` | `memor install-hook --agent copilot` |
|
|
122
|
+
|
|
123
|
+
A single `memor-hook` binary auto-detects which agent is calling it — no separate entry points needed. The dashboard tracks recalls per agent so you can see usage across all your environments.
|
|
124
|
+
|
|
125
|
+
> **Note:** Cloud-hosted agents (Codex cloud, Copilot cloud agent) run in remote sandboxes and cannot reach local hooks. MCP server support for sandboxed agents is planned ([#26](https://github.com/bnimit/memor-ai/issues/26)).
|
|
126
|
+
|
|
114
127
|
**Two background processes:**
|
|
115
128
|
|
|
116
|
-
1. **Daemon** — polls `~/.claude/projects/` for transcripts, embeds chunks, runs distillation, analyzes feedback (positive and negative), promotes cross-project patterns to global scope, compacts duplicates, tracks session-level token usage. All local.
|
|
117
|
-
2. **Hook** — fires on every prompt, recalls relevant memories, injects them as context. Sub-15ms.
|
|
129
|
+
1. **Daemon** — polls `~/.claude/projects/` for transcripts, embeds chunks, runs distillation, analyzes feedback (positive and negative), promotes cross-project patterns to global scope, compacts duplicates, auto-compacts the vector index when bloated, tracks session-level token usage. All local.
|
|
130
|
+
2. **Hook** — fires on every prompt, recalls relevant memories, injects them as context. Sub-15ms. Works across Claude Code, Codex, and Copilot.
|
|
118
131
|
|
|
119
132
|
**No API keys required.** Embeddings run locally via [model2vec](https://github.com/MinishLab/model2vec) (potion-base-8M, 256-dim). Vectors stored in [sqlite-vec](https://github.com/asg017/sqlite-vec). Everything runs on your machine.
|
|
120
133
|
|
|
@@ -188,10 +201,11 @@ memor dashboard
|
|
|
188
201
|
|
|
189
202
|
Dark fintech-inspired UI showing:
|
|
190
203
|
- **Hero metrics** — total memories, recall count, avg latency, coverage — with sparkline bars
|
|
204
|
+
- **Agent breakdown** — per-agent recall stats (Claude, Codex, Copilot) with hit rates
|
|
191
205
|
- **Daily recall activity** — stacked bar chart of hits vs misses over time
|
|
192
206
|
- **Session efficiency** — real token savings measured from API usage data (avg tokens/turn with vs without recall)
|
|
193
207
|
- **Per-project breakdown** — artifact counts, token totals, last activity
|
|
194
|
-
- **Recent recalls** — every hook event with scores, latency, and status
|
|
208
|
+
- **Recent recalls** — every hook event with agent badge, scores, latency, and status
|
|
195
209
|
|
|
196
210
|
---
|
|
197
211
|
|
|
@@ -199,7 +213,8 @@ Dark fintech-inspired UI showing:
|
|
|
199
213
|
|
|
200
214
|
```
|
|
201
215
|
memor help Print the full manual
|
|
202
|
-
memor install-hook Install
|
|
216
|
+
memor install-hook Install hook + download model (interactive agent picker)
|
|
217
|
+
--agent claude|codex|copilot Choose agent directly
|
|
203
218
|
memor daemon Auto-ingest + distill (background watcher)
|
|
204
219
|
memor dashboard Web dashboard on localhost:8420
|
|
205
220
|
memor version Print installed version
|
|
@@ -211,6 +226,7 @@ memor query <text> Search memories from the CLI
|
|
|
211
226
|
memor reingest Wipe DB and re-ingest everything
|
|
212
227
|
memor reingest --project <name> Re-ingest only one project
|
|
213
228
|
memor forget-stale Deactivate memories unused for 30+ days
|
|
229
|
+
memor compact Rebuild vector index, reclaim wasted space
|
|
214
230
|
memor scan Audit DB for leaked secrets
|
|
215
231
|
memor scan --purge Redact secrets in place
|
|
216
232
|
memor setup-model Download/retry the embedding model
|
|
@@ -264,7 +280,8 @@ memor/
|
|
|
264
280
|
+-- judge.py LLM-as-judge evaluation
|
|
265
281
|
+-- embed_benchmark.py Embedding model comparison
|
|
266
282
|
|
|
267
|
-
memor/hook_cli.py
|
|
283
|
+
memor/hook_cli.py Hook entry point — auto-detects Claude/Codex/Copilot
|
|
284
|
+
memor/hook_server.py Hook server with agent detection + response formatting
|
|
268
285
|
skill/recall.py Standalone recall script
|
|
269
286
|
```
|
|
270
287
|
|
|
@@ -311,7 +328,7 @@ cd memor-ai
|
|
|
311
328
|
python3 -m venv .venv && source .venv/bin/activate
|
|
312
329
|
pip install -e ".[dev]"
|
|
313
330
|
|
|
314
|
-
pytest #
|
|
331
|
+
pytest # 285 tests
|
|
315
332
|
```
|
|
316
333
|
|
|
317
334
|
---
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
[](LICENSE)
|
|
12
|
-
[]()
|
|
13
13
|
[]()
|
|
14
14
|
[](https://pypi.org/project/memor-cli/)
|
|
15
15
|
|
|
16
|
-
**Automatic background memory for Claude Code.** Fire and forget — no API keys needed.
|
|
16
|
+
**Automatic background memory for Claude Code, Codex, and Copilot.** Fire and forget — no API keys needed.
|
|
17
17
|
|
|
18
|
-
Memor watches your coding sessions, extracts decisions and patterns, and recalls relevant context on every prompt. Zero configuration. One install. Your agent remembers everything.
|
|
18
|
+
Memor watches your coding sessions, extracts decisions and patterns, and recalls relevant context on every prompt. Works with Claude Code, OpenAI Codex CLI, and GitHub Copilot CLI. Zero configuration. One install. Your agent remembers everything.
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
@@ -25,8 +25,9 @@ Memor watches your coding sessions, extracts decisions and patterns, and recalls
|
|
|
25
25
|
# Install globally (recommended)
|
|
26
26
|
pipx install memor-cli
|
|
27
27
|
|
|
28
|
-
# Install the
|
|
29
|
-
memor install-hook
|
|
28
|
+
# Install the hook + download embedding model (~60MB)
|
|
29
|
+
memor install-hook # interactive — pick Claude Code, Codex, or Copilot
|
|
30
|
+
memor install-hook --agent claude # or pass directly
|
|
30
31
|
|
|
31
32
|
# Start as a background service (macOS/Linux)
|
|
32
33
|
memor service install
|
|
@@ -35,7 +36,7 @@ memor service install
|
|
|
35
36
|
memor daemon
|
|
36
37
|
```
|
|
37
38
|
|
|
38
|
-
That's it. Every
|
|
39
|
+
That's it. Every prompt now gets automatic context recall. Open the dashboard to see it working:
|
|
39
40
|
|
|
40
41
|
```bash
|
|
41
42
|
memor dashboard
|
|
@@ -49,10 +50,10 @@ memor dashboard
|
|
|
49
50
|
## How It Works
|
|
50
51
|
|
|
51
52
|
```
|
|
52
|
-
You type a prompt
|
|
53
|
+
You type a prompt (Claude Code / Codex / Copilot)
|
|
53
54
|
|
|
|
54
55
|
v
|
|
55
|
-
Hook fires
|
|
56
|
+
Hook fires — auto-detects which agent
|
|
56
57
|
|
|
|
57
58
|
v
|
|
58
59
|
Embed query locally (model2vec, ~2ms)
|
|
@@ -70,14 +71,26 @@ memor dashboard
|
|
|
70
71
|
Inject relevant context into prompt
|
|
71
72
|
|
|
|
72
73
|
v
|
|
73
|
-
|
|
74
|
+
Your agent sees past decisions, bugfixes,
|
|
74
75
|
architecture choices — without you re-explaining
|
|
75
76
|
```
|
|
76
77
|
|
|
78
|
+
### Supported Agents
|
|
79
|
+
|
|
80
|
+
| Agent | Hook protocol | Config location | Install |
|
|
81
|
+
|---|---|---|---|
|
|
82
|
+
| **Claude Code** | `UserPromptSubmit` + `additionalContext` | `~/.claude/settings.json` | `memor install-hook --agent claude` |
|
|
83
|
+
| **Codex CLI** | `UserPromptSubmit` + `additionalContext` | `~/.codex/hooks/hooks.json` | `memor install-hook --agent codex` |
|
|
84
|
+
| **Copilot CLI** | `userPromptSubmitted` + `additionalContext` | `~/.copilot/hooks/memor.json` | `memor install-hook --agent copilot` |
|
|
85
|
+
|
|
86
|
+
A single `memor-hook` binary auto-detects which agent is calling it — no separate entry points needed. The dashboard tracks recalls per agent so you can see usage across all your environments.
|
|
87
|
+
|
|
88
|
+
> **Note:** Cloud-hosted agents (Codex cloud, Copilot cloud agent) run in remote sandboxes and cannot reach local hooks. MCP server support for sandboxed agents is planned ([#26](https://github.com/bnimit/memor-ai/issues/26)).
|
|
89
|
+
|
|
77
90
|
**Two background processes:**
|
|
78
91
|
|
|
79
|
-
1. **Daemon** — polls `~/.claude/projects/` for transcripts, embeds chunks, runs distillation, analyzes feedback (positive and negative), promotes cross-project patterns to global scope, compacts duplicates, tracks session-level token usage. All local.
|
|
80
|
-
2. **Hook** — fires on every prompt, recalls relevant memories, injects them as context. Sub-15ms.
|
|
92
|
+
1. **Daemon** — polls `~/.claude/projects/` for transcripts, embeds chunks, runs distillation, analyzes feedback (positive and negative), promotes cross-project patterns to global scope, compacts duplicates, auto-compacts the vector index when bloated, tracks session-level token usage. All local.
|
|
93
|
+
2. **Hook** — fires on every prompt, recalls relevant memories, injects them as context. Sub-15ms. Works across Claude Code, Codex, and Copilot.
|
|
81
94
|
|
|
82
95
|
**No API keys required.** Embeddings run locally via [model2vec](https://github.com/MinishLab/model2vec) (potion-base-8M, 256-dim). Vectors stored in [sqlite-vec](https://github.com/asg017/sqlite-vec). Everything runs on your machine.
|
|
83
96
|
|
|
@@ -151,10 +164,11 @@ memor dashboard
|
|
|
151
164
|
|
|
152
165
|
Dark fintech-inspired UI showing:
|
|
153
166
|
- **Hero metrics** — total memories, recall count, avg latency, coverage — with sparkline bars
|
|
167
|
+
- **Agent breakdown** — per-agent recall stats (Claude, Codex, Copilot) with hit rates
|
|
154
168
|
- **Daily recall activity** — stacked bar chart of hits vs misses over time
|
|
155
169
|
- **Session efficiency** — real token savings measured from API usage data (avg tokens/turn with vs without recall)
|
|
156
170
|
- **Per-project breakdown** — artifact counts, token totals, last activity
|
|
157
|
-
- **Recent recalls** — every hook event with scores, latency, and status
|
|
171
|
+
- **Recent recalls** — every hook event with agent badge, scores, latency, and status
|
|
158
172
|
|
|
159
173
|
---
|
|
160
174
|
|
|
@@ -162,7 +176,8 @@ Dark fintech-inspired UI showing:
|
|
|
162
176
|
|
|
163
177
|
```
|
|
164
178
|
memor help Print the full manual
|
|
165
|
-
memor install-hook Install
|
|
179
|
+
memor install-hook Install hook + download model (interactive agent picker)
|
|
180
|
+
--agent claude|codex|copilot Choose agent directly
|
|
166
181
|
memor daemon Auto-ingest + distill (background watcher)
|
|
167
182
|
memor dashboard Web dashboard on localhost:8420
|
|
168
183
|
memor version Print installed version
|
|
@@ -174,6 +189,7 @@ memor query <text> Search memories from the CLI
|
|
|
174
189
|
memor reingest Wipe DB and re-ingest everything
|
|
175
190
|
memor reingest --project <name> Re-ingest only one project
|
|
176
191
|
memor forget-stale Deactivate memories unused for 30+ days
|
|
192
|
+
memor compact Rebuild vector index, reclaim wasted space
|
|
177
193
|
memor scan Audit DB for leaked secrets
|
|
178
194
|
memor scan --purge Redact secrets in place
|
|
179
195
|
memor setup-model Download/retry the embedding model
|
|
@@ -227,7 +243,8 @@ memor/
|
|
|
227
243
|
+-- judge.py LLM-as-judge evaluation
|
|
228
244
|
+-- embed_benchmark.py Embedding model comparison
|
|
229
245
|
|
|
230
|
-
memor/hook_cli.py
|
|
246
|
+
memor/hook_cli.py Hook entry point — auto-detects Claude/Codex/Copilot
|
|
247
|
+
memor/hook_server.py Hook server with agent detection + response formatting
|
|
231
248
|
skill/recall.py Standalone recall script
|
|
232
249
|
```
|
|
233
250
|
|
|
@@ -274,7 +291,7 @@ cd memor-ai
|
|
|
274
291
|
python3 -m venv .venv && source .venv/bin/activate
|
|
275
292
|
pip install -e ".[dev]"
|
|
276
293
|
|
|
277
|
-
pytest #
|
|
294
|
+
pytest # 285 tests
|
|
278
295
|
```
|
|
279
296
|
|
|
280
297
|
---
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.7.0"
|
|
@@ -44,9 +44,10 @@ HELP_TEXT = """\
|
|
|
44
44
|
memor — measured memory for coding agents
|
|
45
45
|
|
|
46
46
|
GETTING STARTED
|
|
47
|
-
memor install-hook
|
|
48
|
-
|
|
49
|
-
memor
|
|
47
|
+
memor install-hook Install the recall hook + download model
|
|
48
|
+
--agent claude|codex|copilot Choose your agent (default: claude)
|
|
49
|
+
memor service install Start the daemon as a background service
|
|
50
|
+
memor dashboard Open the web dashboard at localhost:8420
|
|
50
51
|
|
|
51
52
|
SERVICE MANAGEMENT
|
|
52
53
|
memor service install Install and start as a background service (survives reboots)
|
|
@@ -89,7 +90,9 @@ CONFIGURATION
|
|
|
89
90
|
No configuration needed — just install, hook, and run the daemon.
|
|
90
91
|
|
|
91
92
|
EXAMPLES
|
|
92
|
-
memor install-hook && memor service install
|
|
93
|
+
memor install-hook && memor service install # Claude Code (default)
|
|
94
|
+
memor install-hook --agent codex && memor service install # Codex CLI
|
|
95
|
+
memor install-hook --agent copilot && memor service install # Copilot CLI
|
|
93
96
|
memor query "auth flow" --project my-app
|
|
94
97
|
memor reingest --project my-app -y # refresh one project
|
|
95
98
|
memor dashboard # see stats at localhost:8420
|
|
@@ -487,20 +490,108 @@ def _install_hook_logic(settings_path: Path, hook_command: str) -> None:
|
|
|
487
490
|
settings_path.write_text(json.dumps(data, indent=2))
|
|
488
491
|
|
|
489
492
|
|
|
493
|
+
def _install_hook_logic_codex(hooks_path: Path, hook_command: str) -> None:
|
|
494
|
+
if hooks_path.exists():
|
|
495
|
+
data = json.loads(hooks_path.read_text())
|
|
496
|
+
else:
|
|
497
|
+
data = {}
|
|
498
|
+
hooks = data.setdefault("hooks", {})
|
|
499
|
+
prompt_hooks = hooks.setdefault("UserPromptSubmit", [])
|
|
500
|
+
entry = {"command": hook_command, "timeout": 5}
|
|
501
|
+
existing_idx = None
|
|
502
|
+
for i, h in enumerate(prompt_hooks):
|
|
503
|
+
if "memor-hook" in h.get("command", ""):
|
|
504
|
+
existing_idx = i
|
|
505
|
+
break
|
|
506
|
+
if existing_idx is not None:
|
|
507
|
+
prompt_hooks[existing_idx] = entry
|
|
508
|
+
else:
|
|
509
|
+
prompt_hooks.append(entry)
|
|
510
|
+
hooks_path.parent.mkdir(parents=True, exist_ok=True)
|
|
511
|
+
hooks_path.write_text(json.dumps(data, indent=2))
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def _install_hook_logic_copilot(hooks_path: Path, hook_command: str) -> None:
|
|
515
|
+
if hooks_path.exists():
|
|
516
|
+
data = json.loads(hooks_path.read_text())
|
|
517
|
+
else:
|
|
518
|
+
data = {"version": 1, "hooks": {}}
|
|
519
|
+
data.setdefault("version", 1)
|
|
520
|
+
hooks = data.setdefault("hooks", {})
|
|
521
|
+
prompt_hooks = hooks.setdefault("userPromptSubmitted", [])
|
|
522
|
+
entry = {"type": "command", "bash": hook_command, "timeoutSec": 5}
|
|
523
|
+
existing_idx = None
|
|
524
|
+
for i, h in enumerate(prompt_hooks):
|
|
525
|
+
if "memor-hook" in h.get("bash", ""):
|
|
526
|
+
existing_idx = i
|
|
527
|
+
break
|
|
528
|
+
if existing_idx is not None:
|
|
529
|
+
prompt_hooks[existing_idx] = entry
|
|
530
|
+
else:
|
|
531
|
+
prompt_hooks.append(entry)
|
|
532
|
+
hooks_path.parent.mkdir(parents=True, exist_ok=True)
|
|
533
|
+
hooks_path.write_text(json.dumps(data, indent=2))
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
AGENT_CHOICES = [
|
|
537
|
+
("claude", "~/.claude/settings.json", "Claude Code"),
|
|
538
|
+
("codex", "~/.codex/hooks/hooks.json", "Codex CLI"),
|
|
539
|
+
("copilot", "~/.copilot/hooks/memor.json", "Copilot CLI"),
|
|
540
|
+
]
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
def _prompt_agent() -> str:
|
|
544
|
+
typer.echo("Which agent do you want to install the recall hook for?\n")
|
|
545
|
+
for i, (key, _, label) in enumerate(AGENT_CHOICES, 1):
|
|
546
|
+
typer.echo(f" {i}. {label}")
|
|
547
|
+
typer.echo()
|
|
548
|
+
while True:
|
|
549
|
+
choice = typer.prompt("Choose (1-3)", default="1")
|
|
550
|
+
try:
|
|
551
|
+
idx = int(choice) - 1
|
|
552
|
+
if 0 <= idx < len(AGENT_CHOICES):
|
|
553
|
+
return AGENT_CHOICES[idx][0]
|
|
554
|
+
except ValueError:
|
|
555
|
+
pass
|
|
556
|
+
typer.echo("Invalid choice. Enter 1, 2, or 3.")
|
|
557
|
+
|
|
558
|
+
|
|
490
559
|
@app.command("install-hook")
|
|
491
|
-
def install_hook():
|
|
492
|
-
"""Install the Claude Code
|
|
560
|
+
def install_hook(agent: str | None = typer.Option(None, help="Agent: claude, codex, copilot (interactive if omitted)")):
|
|
561
|
+
"""Install the recall hook for Claude Code, Codex, or Copilot."""
|
|
493
562
|
import shutil
|
|
563
|
+
agent_keys = {key for key, _, _ in AGENT_CHOICES}
|
|
564
|
+
|
|
565
|
+
if agent is None:
|
|
566
|
+
agent = _prompt_agent()
|
|
567
|
+
else:
|
|
568
|
+
agent = agent.lower()
|
|
569
|
+
|
|
570
|
+
if agent not in agent_keys:
|
|
571
|
+
typer.echo(f"Unknown agent '{agent}'. Choose: claude, codex, copilot", err=True)
|
|
572
|
+
raise typer.Exit(1)
|
|
573
|
+
|
|
494
574
|
hook_bin = shutil.which("memor-hook")
|
|
495
575
|
if not hook_bin:
|
|
496
576
|
typer.echo("Error: 'memor-hook' not found on PATH.", err=True)
|
|
497
577
|
typer.echo(" If you installed with pipx: pipx install memor-cli", err=True)
|
|
498
578
|
typer.echo(" If developing locally: pip install -e .", err=True)
|
|
499
579
|
raise typer.Exit(1)
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
580
|
+
|
|
581
|
+
config_path_str, agent_name = next(
|
|
582
|
+
(p, n) for k, p, n in AGENT_CHOICES if k == agent
|
|
583
|
+
)
|
|
584
|
+
config_path = Path(config_path_str).expanduser()
|
|
585
|
+
|
|
586
|
+
if agent == "claude":
|
|
587
|
+
_install_hook_logic(config_path, hook_bin)
|
|
588
|
+
elif agent == "codex":
|
|
589
|
+
_install_hook_logic_codex(config_path, hook_bin)
|
|
590
|
+
elif agent == "copilot":
|
|
591
|
+
_install_hook_logic_copilot(config_path, hook_bin)
|
|
592
|
+
|
|
593
|
+
typer.echo(f"\nHook installed for {agent_name}: {hook_bin}")
|
|
594
|
+
typer.echo(f"Config updated: {config_path}")
|
|
504
595
|
typer.echo()
|
|
505
596
|
typer.echo("Pre-downloading embedding model...")
|
|
506
597
|
try:
|
|
@@ -177,6 +177,11 @@ def create_app(db_path: str | None = None) -> FastAPI:
|
|
|
177
177
|
return {"status": "no_runs"}
|
|
178
178
|
return result
|
|
179
179
|
|
|
180
|
+
@app.get("/api/agent-breakdown")
|
|
181
|
+
def agent_breakdown():
|
|
182
|
+
store = _store()
|
|
183
|
+
return store.get_agent_breakdown()
|
|
184
|
+
|
|
180
185
|
@app.get("/api/version")
|
|
181
186
|
def version():
|
|
182
187
|
from memor import __version__
|
|
@@ -304,6 +304,12 @@
|
|
|
304
304
|
.badge-global::before { background: #a090ff; }
|
|
305
305
|
.badge-negative { background: rgba(232,84,84,0.12); color: var(--error); }
|
|
306
306
|
.badge-negative::before { background: var(--error); }
|
|
307
|
+
.badge-claude { background: var(--accent-dim); color: var(--accent); }
|
|
308
|
+
.badge-claude::before { background: var(--accent); }
|
|
309
|
+
.badge-codex { background: rgba(61,214,140,0.12); color: #3dd68c; }
|
|
310
|
+
.badge-codex::before { background: #3dd68c; }
|
|
311
|
+
.badge-copilot { background: rgba(100,160,255,0.12); color: #64a0ff; }
|
|
312
|
+
.badge-copilot::before { background: #64a0ff; }
|
|
307
313
|
|
|
308
314
|
.quality-bar { display: flex; height: 6px; border-radius: 3px; overflow: hidden; background: var(--surface3); width: 100%; min-width: 60px; }
|
|
309
315
|
.quality-fill { height: 100%; border-radius: 3px; transition: width 0.3s; }
|
|
@@ -398,6 +404,12 @@
|
|
|
398
404
|
</div>
|
|
399
405
|
</section>
|
|
400
406
|
|
|
407
|
+
<!-- ── Agent breakdown ─────────────────────────────────── -->
|
|
408
|
+
<section id="agent-section" style="display:none;">
|
|
409
|
+
<div class="section-label"><span class="dot"></span> Agent Breakdown</div>
|
|
410
|
+
<div class="metric-grid" id="agent-grid" style="grid-template-columns:repeat(auto-fit,minmax(180px,1fr));"></div>
|
|
411
|
+
</section>
|
|
412
|
+
|
|
401
413
|
<!-- ── Token ROI hero ─────────────────────────────────── -->
|
|
402
414
|
<section>
|
|
403
415
|
<div class="chart-card" id="roi-card" style="display:none;">
|
|
@@ -538,6 +550,7 @@
|
|
|
538
550
|
<thead>
|
|
539
551
|
<tr>
|
|
540
552
|
<th>Time</th>
|
|
553
|
+
<th>Agent</th>
|
|
541
554
|
<th>Project</th>
|
|
542
555
|
<th>Query</th>
|
|
543
556
|
<th>Hits</th>
|
|
@@ -595,6 +608,16 @@
|
|
|
595
608
|
return '<span class="badge ' + m[0] + '">' + m[1] + '</span>';
|
|
596
609
|
}
|
|
597
610
|
|
|
611
|
+
function agentBadge(agent) {
|
|
612
|
+
var map = {
|
|
613
|
+
claude: ['badge-claude', 'Claude'],
|
|
614
|
+
codex: ['badge-codex', 'Codex'],
|
|
615
|
+
copilot: ['badge-copilot', 'Copilot'],
|
|
616
|
+
};
|
|
617
|
+
var m = map[agent || 'claude'] || ['badge-claude', agent || 'claude'];
|
|
618
|
+
return '<span class="badge ' + m[0] + '">' + m[1] + '</span>';
|
|
619
|
+
}
|
|
620
|
+
|
|
598
621
|
function el(tag, attrs, inner) {
|
|
599
622
|
var e = document.createElement(tag);
|
|
600
623
|
for (var k in (attrs || {})) e.setAttribute(k, attrs[k]);
|
|
@@ -860,13 +883,14 @@
|
|
|
860
883
|
var tbody = document.getElementById('recalls-body');
|
|
861
884
|
tbody.innerHTML = '';
|
|
862
885
|
if (!data.length) {
|
|
863
|
-
tbody.innerHTML = '<tr><td colspan="
|
|
886
|
+
tbody.innerHTML = '<tr><td colspan="9" class="empty-state">No recall events yet.</td></tr>';
|
|
864
887
|
return;
|
|
865
888
|
}
|
|
866
889
|
data.forEach(function(row) {
|
|
867
890
|
var tr = el('tr', {});
|
|
868
891
|
tr.innerHTML =
|
|
869
892
|
'<td class="mono" style="white-space:nowrap;color:var(--text-muted)">' + relativeTime(row.timestamp) + '</td>' +
|
|
893
|
+
'<td>' + agentBadge(row.agent) + '</td>' +
|
|
870
894
|
'<td class="truncate mono" style="max-width:120px" title="' + esc(row.project) + '">' + esc(row.project) + '</td>' +
|
|
871
895
|
'<td class="truncate" style="max-width:220px" title="' + esc(row.query_preview) + '">' + esc(row.query_preview) + '</td>' +
|
|
872
896
|
'<td>' + (row.hits_count||0) + '</td>' +
|
|
@@ -1002,6 +1026,29 @@
|
|
|
1002
1026
|
});
|
|
1003
1027
|
}
|
|
1004
1028
|
|
|
1029
|
+
/* ── Agent breakdown ────────────────────────────────────── */
|
|
1030
|
+
function renderAgentBreakdown(data) {
|
|
1031
|
+
var section = document.getElementById('agent-section');
|
|
1032
|
+
var grid = document.getElementById('agent-grid');
|
|
1033
|
+
if (!data || data.length <= 1) { section.style.display = 'none'; return; }
|
|
1034
|
+
section.style.display = '';
|
|
1035
|
+
grid.innerHTML = '';
|
|
1036
|
+
var colors = { claude: 'var(--accent)', codex: '#3dd68c', copilot: '#64a0ff' };
|
|
1037
|
+
data.forEach(function(row) {
|
|
1038
|
+
var agent = row.agent || 'claude';
|
|
1039
|
+
var color = colors[agent] || 'var(--text-muted)';
|
|
1040
|
+
var hitRate = row.recalls > 0 ? ((row.hits / row.recalls) * 100) : 0;
|
|
1041
|
+
var card = el('div', {class: 'metric-card'});
|
|
1042
|
+
card.innerHTML =
|
|
1043
|
+
'<div class="metric-info">' +
|
|
1044
|
+
'<div class="metric-label" style="color:' + color + ';">' + esc(agent.charAt(0).toUpperCase() + agent.slice(1)) + '</div>' +
|
|
1045
|
+
'<div class="metric-value">' + fmt(row.recalls) + '</div>' +
|
|
1046
|
+
'<div class="metric-sub">' + fmtPct(hitRate) + ' hit rate · ' + fmtMs(row.avg_latency) + '</div>' +
|
|
1047
|
+
'</div>';
|
|
1048
|
+
grid.appendChild(card);
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1005
1052
|
/* ── Data loaders ──────────────────────────────────────── */
|
|
1006
1053
|
async function loadSummary() { try { renderSummary(await api('/api/summary')); } catch(e) { console.warn('summary',e); } }
|
|
1007
1054
|
async function loadProjects() { try { renderProjects(await api('/api/projects')); } catch(e) { console.warn('projects',e); } }
|
|
@@ -1012,6 +1059,7 @@
|
|
|
1012
1059
|
async function loadROI() { try { renderROI(await api('/api/roi')); } catch(e) { console.warn('roi',e); } }
|
|
1013
1060
|
async function loadROITrend() { try { renderROITrend(await api('/api/roi-trend')); } catch(e) { console.warn('roi-trend',e); } }
|
|
1014
1061
|
async function loadQuality() { try { renderQuality(await api('/api/quality')); } catch(e) { console.warn('quality',e); } }
|
|
1062
|
+
async function loadAgentBreakdown() { try { renderAgentBreakdown(await api('/api/agent-breakdown')); } catch(e) { console.warn('agent-breakdown',e); } }
|
|
1015
1063
|
async function loadRecalls() {
|
|
1016
1064
|
try {
|
|
1017
1065
|
var url = '/api/recalls?limit=50' + (projectFilter ? '&project=' + encodeURIComponent(projectFilter) : '');
|
|
@@ -1020,7 +1068,7 @@
|
|
|
1020
1068
|
}
|
|
1021
1069
|
|
|
1022
1070
|
async function refresh() {
|
|
1023
|
-
await Promise.allSettled([loadSummary(), loadProjects(), loadEfficiency(), loadSessionEfficiency(), loadHealth(), loadTrend(), loadRecalls(), loadROI(), loadROITrend(), loadQuality()]);
|
|
1071
|
+
await Promise.allSettled([loadSummary(), loadProjects(), loadEfficiency(), loadSessionEfficiency(), loadHealth(), loadTrend(), loadRecalls(), loadROI(), loadROITrend(), loadQuality(), loadAgentBreakdown()]);
|
|
1024
1072
|
document.getElementById('last-updated').textContent = new Date().toLocaleTimeString();
|
|
1025
1073
|
|
|
1026
1074
|
renderMiniBars('mb-chunks', null);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
2
|
+
"""Memor recall hook — works with Claude Code, Codex, and Copilot.
|
|
3
3
|
|
|
4
4
|
Tries to connect to the warm sidecar at ~/.memor/hook.sock.
|
|
5
5
|
Falls back to inline execution if sidecar is unavailable.
|
|
@@ -57,12 +57,8 @@ def _inline_fallback(request: dict) -> dict:
|
|
|
57
57
|
return handle_request(request)
|
|
58
58
|
except Exception as e:
|
|
59
59
|
print(json.dumps({"error": str(e)}), file=sys.stderr)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"hookEventName": "UserPromptSubmit",
|
|
63
|
-
"additionalContext": "",
|
|
64
|
-
}
|
|
65
|
-
}
|
|
60
|
+
from memor.hook_server import detect_agent, format_hook_response
|
|
61
|
+
return format_hook_response(detect_agent(request), "")
|
|
66
62
|
|
|
67
63
|
|
|
68
64
|
def main():
|
|
@@ -12,6 +12,26 @@ PID_PATH = Path.home() / ".memor" / "hook.pid"
|
|
|
12
12
|
DEFAULT_DB = str(Path.home() / ".memor" / "memor.db")
|
|
13
13
|
IDLE_TIMEOUT_S = 600
|
|
14
14
|
|
|
15
|
+
|
|
16
|
+
def detect_agent(req: dict) -> str:
|
|
17
|
+
event = req.get("hook_event_name", "")
|
|
18
|
+
if event == "userPromptSubmitted":
|
|
19
|
+
return "copilot"
|
|
20
|
+
if "model" in req or "permission_mode" in req:
|
|
21
|
+
return "codex"
|
|
22
|
+
return "claude"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def format_hook_response(agent: str, additional_context: str) -> dict:
|
|
26
|
+
if agent == "copilot":
|
|
27
|
+
return {"additionalContext": additional_context}
|
|
28
|
+
return {
|
|
29
|
+
"hookSpecificOutput": {
|
|
30
|
+
"hookEventName": "UserPromptSubmit",
|
|
31
|
+
"additionalContext": additional_context,
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
15
35
|
_embedder = None
|
|
16
36
|
_last_activity = 0.0
|
|
17
37
|
_session_injected: dict[str, set[str]] = {}
|
|
@@ -49,14 +69,11 @@ def handle_request(req: dict, *, db_path: str = DEFAULT_DB,
|
|
|
49
69
|
|
|
50
70
|
if embedder is _UNSET:
|
|
51
71
|
embedder = _get_embedder()
|
|
72
|
+
agent = detect_agent(req)
|
|
73
|
+
|
|
52
74
|
if embedder is None:
|
|
53
75
|
msg = _status_message("no_embedder", project, 0, 0, 0.0)
|
|
54
|
-
return {
|
|
55
|
-
"hookSpecificOutput": {
|
|
56
|
-
"hookEventName": "UserPromptSubmit",
|
|
57
|
-
"additionalContext": f"---\n{msg}",
|
|
58
|
-
}
|
|
59
|
-
}
|
|
76
|
+
return format_hook_response(agent, f"---\n{msg}")
|
|
60
77
|
|
|
61
78
|
from memor.query_complexity import route_query, Tier
|
|
62
79
|
|
|
@@ -71,15 +88,11 @@ def handle_request(req: dict, *, db_path: str = DEFAULT_DB,
|
|
|
71
88
|
project=project, query_preview=query[:100],
|
|
72
89
|
hits_count=0, top_score=0.0,
|
|
73
90
|
tokens_injected=0, latency_ms=0.0,
|
|
74
|
-
status="skipped_trivial", session_id=session_id
|
|
91
|
+
status="skipped_trivial", session_id=session_id,
|
|
92
|
+
agent=agent)
|
|
75
93
|
except Exception:
|
|
76
94
|
pass
|
|
77
|
-
return {
|
|
78
|
-
"hookSpecificOutput": {
|
|
79
|
-
"hookEventName": "UserPromptSubmit",
|
|
80
|
-
"additionalContext": f"---\n{msg}",
|
|
81
|
-
}
|
|
82
|
-
}
|
|
95
|
+
return format_hook_response(agent, f"---\n{msg}")
|
|
83
96
|
|
|
84
97
|
try:
|
|
85
98
|
env_max = int(os.environ.get("MEMOR_MAX_TOKENS", "0"))
|
|
@@ -113,19 +126,15 @@ def handle_request(req: dict, *, db_path: str = DEFAULT_DB,
|
|
|
113
126
|
project=project, query_preview=query[:100],
|
|
114
127
|
hits_count=result.hits_count, top_score=result.top_score,
|
|
115
128
|
tokens_injected=result.tokens_injected, latency_ms=result.latency_ms,
|
|
116
|
-
status=result.status, session_id=session_id
|
|
129
|
+
status=result.status, session_id=session_id,
|
|
130
|
+
agent=agent)
|
|
117
131
|
if result.hit_ids:
|
|
118
132
|
store.record_recall(result.hit_ids)
|
|
119
133
|
except Exception:
|
|
120
134
|
pass
|
|
121
135
|
|
|
122
136
|
additional_context = result.formatted_context or f"---\n{result.status_message}"
|
|
123
|
-
return
|
|
124
|
-
"hookSpecificOutput": {
|
|
125
|
-
"hookEventName": "UserPromptSubmit",
|
|
126
|
-
"additionalContext": additional_context,
|
|
127
|
-
}
|
|
128
|
-
}
|
|
137
|
+
return format_hook_response(agent, additional_context)
|
|
129
138
|
|
|
130
139
|
|
|
131
140
|
async def _handle_client(reader: asyncio.StreamReader,
|