kore-memory 3.0.1__tar.gz → 3.0.2__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.
- {kore_memory-3.0.1 → kore_memory-3.0.2}/CHANGELOG.md +49 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/PKG-INFO +1 -1
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/auth.py +7 -1
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/compressor.py +3 -2
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/config.py +1 -1
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/context_assembler.py +4 -3
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/filesystem_watcher.py +9 -1
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/main.py +3 -3
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/mcp_server.py +18 -3
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/repository/memory.py +196 -186
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/repository/search.py +4 -2
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/templates/dashboard.html +47 -14
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/vector_index.py +11 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/pyproject.toml +1 -1
- {kore_memory-3.0.1 → kore_memory-3.0.2}/sdk/js/package.json +1 -1
- {kore_memory-3.0.1 → kore_memory-3.0.2}/start.sh +3 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_api.py +27 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/.coveragerc +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/.github/workflows/benchmark.yml +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/.github/workflows/build-sdk.yml +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/.github/workflows/ci.yml +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/.github/workflows/publish.yml +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/.gitignore +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/CONTRIBUTING.md +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/LICENSE +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/MIGRATION-v0.6.md +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/README.md +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/article-devto.md +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/assets/favicon.svg +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/assets/logo.svg +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/docs/coding-memory-mode.md +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/docs/competitive-analysis-2025.md +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/docs/quickstart-v2.1.md +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/docs/v1.0-roadmap.md +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/examples/async_usage.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/examples/basic_usage.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/examples/langchain_example.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/hatch_build.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore-daemon.sh +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/__init__.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/acl.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/analytics.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/audit.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/auto_tuner.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/cli.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/client.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/conflict_detector.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/consolidation.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/dashboard.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/database.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/decay.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/embedder.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/events.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/filesystem_overlay.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/integrations/__init__.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/integrations/crewai.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/integrations/entities.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/integrations/langchain.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/integrations/openai_agents.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/integrations/pydantic_ai.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/models.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/plugins.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/policy_engine.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/privacy.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/py.typed +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/ranking.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/repository/__init__.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/repository/entity.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/repository/graph.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/repository/lifecycle.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/repository/sessions.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/scorer.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/structured.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/summarizer.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/kore_memory/welcome.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/presets/claude-code/README.md +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/presets/claude-code/mcp.json +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/presets/claude-code-coding.md +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/presets/cursor/README.md +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/presets/cursor/mcp.json +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/requirements.txt +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/scripts/assert_benchmarks.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/scripts/import_memory.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/sdk/js/.gitignore +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/sdk/js/README.md +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/sdk/js/package-lock.json +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/sdk/js/src/client.ts +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/sdk/js/src/errors.ts +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/sdk/js/src/index.ts +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/sdk/js/src/types.ts +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/sdk/js/tests/client.test.ts +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/sdk/js/tests/errors.test.ts +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/sdk/js/tests/helpers.ts +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/sdk/js/tsconfig.json +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/sdk/js/tsup.config.ts +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/sdk/js/vitest.config.ts +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/__init__.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/benchmarks/__init__.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/benchmarks/conftest_bench.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/benchmarks/datasets/dataset_a_temporal.json +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/benchmarks/datasets/dataset_b_conflicts.json +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/benchmarks/datasets/dataset_c_coding.json +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/benchmarks/datasets/dataset_d_graph.json +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/benchmarks/datasets/dataset_e_context.json +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/benchmarks/datasets/loaders.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/benchmarks/test_benchmarks.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/conftest.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_audit.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_auth_events.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_auto_tuner.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_cli.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_client.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_client_sync.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_conflict_detection.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_coverage_gaps.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_crewai.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_dashboard.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_entities.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_langchain.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_m1_graph_entity.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_m2_structured_memory.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_m3a_session_consolidation.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_mcp.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_policy_engine.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_ranking_engine.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_sessions.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_v11_fixes.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_v12_features.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_v21_temporal.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_v2_features.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_wave3_graph.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_wave3_overlay.py +0 -0
- {kore_memory-3.0.1 → kore_memory-3.0.2}/tests/test_wave3_watcher.py +0 -0
|
@@ -11,6 +11,55 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
+
## [3.0.2] - 2026-04-28
|
|
15
|
+
|
|
16
|
+
### Theme: "Hardening & Bug Sweep"
|
|
17
|
+
|
|
18
|
+
Comprehensive bug-fixing release: 24 fixes across backend, dashboard, security, and infrastructure. No breaking changes.
|
|
19
|
+
|
|
20
|
+
### Fixed — Backend (Critical)
|
|
21
|
+
|
|
22
|
+
- **Data corruption in compressor**: `DELETE FROM memory_relations WHERE source_id = target_id` was unscoped — deleted ALL self-relations globally instead of only the newly merged record. Now scoped to `(new_id, new_id)`.
|
|
23
|
+
- **save_memory_batch bypassed entire pipeline**: Batch save was missing privacy filter, title generation, content_hash, structured extraction (facts/concepts/narrative), entity extraction, conflict detection, dedup, session_id, and all v2.1/M2 fields. Refactored with shared `_prepare_memory()` helper — full parity with single save.
|
|
24
|
+
- **Race condition in dedup (TOCTOU)**: Dedup check and INSERT were in separate transactions. Two concurrent identical saves could both pass the check. Now merged into a single transaction.
|
|
25
|
+
- **ZeroDivisionError in RRF fusion**: Setting `KORE_RRF_W_FTS=0` caused crash when that stream had results. Added `or 1.0` fallback.
|
|
26
|
+
- **search_by_tag returned incomplete data**: Missing `title`, `invalidated_at`, `compressed_into`, and all structured fields in SELECT. `_row_to_record` silently returned nulls.
|
|
27
|
+
- **assert in context_assembler**: Token budget invariant used `assert` (disabled with `python -O`). Replaced with `if/raise ValueError`.
|
|
28
|
+
|
|
29
|
+
### Fixed — Security
|
|
30
|
+
|
|
31
|
+
- **Auth bypass behind reverse proxy**: `_is_local()` checked only `request.client.host`, which is the proxy's IP (127.0.0.1) when behind nginx/Caddy. Now detects `X-Forwarded-For`/`X-Real-IP` headers and requires API key when proxy is detected.
|
|
32
|
+
- **MCP import no size limit**: Docstring said "max 500" but code passed full list. Added `memories[:500]` truncation.
|
|
33
|
+
- **Search query DoS vector**: `/search` had no `max_length` on query parameter. Added `max_length=1000`.
|
|
34
|
+
- **CSP redundancy**: Removed `'unsafe-inline'` from `script-src` (redundant when nonce is present).
|
|
35
|
+
|
|
36
|
+
### Fixed — Infrastructure
|
|
37
|
+
|
|
38
|
+
- **VectorIndex memory leak**: Legacy in-memory cache grew unbounded (one entry per agent, all embeddings in RAM). Added LRU eviction with max 20 agents.
|
|
39
|
+
- **Timer leak in filesystem_watcher**: `stop_all()` stopped observers but didn't cancel pending debounce timers. Timers could fire after shutdown, causing DB operations on closed connections.
|
|
40
|
+
- **init_db() at import time in MCP server**: Any `import kore_memory.mcp_server` triggered full DB initialization. Replaced with lazy `_ensure_db()` using double-check locking.
|
|
41
|
+
|
|
42
|
+
### Fixed — Dashboard
|
|
43
|
+
|
|
44
|
+
- **Tab lost on refresh**: No URL state persistence. Added `location.hash` routing — tab survives refresh and browser back/forward.
|
|
45
|
+
- **Memories page empty for agents without relations**: Default view used `/graph/hubs` (requires relations). Changed to `/search?q=*`.
|
|
46
|
+
- **Relations section permanently broken**: `loadRelations(data.results)` where `/analytics` has no `results` field. Now fetches memories via `/search`.
|
|
47
|
+
- **Graph detail panel permanently broken after X close**: Inline `style.display='none'` overrode CSS class. Fixed to use `classList.remove('open')`.
|
|
48
|
+
- **Graph animation CPU leak**: `requestAnimationFrame` loop ran at 60fps on hidden canvas after navigating away. Now cancelled on page change.
|
|
49
|
+
- **HiDPI mouse coordinates wrong**: `screenToGraph()` used `canvas.width` (physical pixels) instead of `canvas.offsetWidth` (CSS pixels). Hover/drag/click hit wrong nodes on Retina displays.
|
|
50
|
+
- **Edit from graph detail race condition**: `setTimeout(300ms)` guess for API load. Now opens modal directly with node data.
|
|
51
|
+
- **NaN decay display**: `decay_score * 100` crashed on null. Defaults to 1.0.
|
|
52
|
+
- **No pagination indicator**: Added "Showing X of Y" when `has_more` is true.
|
|
53
|
+
- **Edit modal ignored tags**: Tags field was visible but values discarded on save. Now sends tags via API.
|
|
54
|
+
- **Session memories appended duplicates**: Clicking "View" multiple times appended cards. Now replaces existing detail.
|
|
55
|
+
- **Inline event handlers violated CSP**: `onmouseover`/`onmouseout` replaced with CSS `:hover`.
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- Test: batch/single save parity test verifying structured fields (title, content_hash, memory_type) are populated identically.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
14
63
|
## [3.0.0] - 2026-04-15
|
|
15
64
|
|
|
16
65
|
### Theme: "Cognitive Runtime + Coding Vertical GA"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kore-memory
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.2
|
|
4
4
|
Summary: The memory layer that thinks like a human: remembers what matters, forgets what doesn't, and never calls home.
|
|
5
5
|
Project-URL: Homepage, https://github.com/auriti-labs/kore-memory
|
|
6
6
|
Project-URL: Documentation, https://auritidesign.it/docs
|
|
@@ -64,7 +64,13 @@ def _is_local(request: Request) -> bool:
|
|
|
64
64
|
# "testclient" only in explicit test environments
|
|
65
65
|
if os.getenv("KORE_TEST_MODE", "0") == "1":
|
|
66
66
|
trusted.add("testclient")
|
|
67
|
-
|
|
67
|
+
if client_host not in trusted:
|
|
68
|
+
return False
|
|
69
|
+
# Detect reverse proxy: if X-Forwarded-For is present, the real client
|
|
70
|
+
# is NOT local — require auth even if socket peer is localhost
|
|
71
|
+
if request.headers.get("X-Forwarded-For") or request.headers.get("X-Real-IP"):
|
|
72
|
+
return False
|
|
73
|
+
return True
|
|
68
74
|
|
|
69
75
|
|
|
70
76
|
def _local_only_mode() -> bool:
|
|
@@ -362,9 +362,10 @@ def _merge_cluster(cluster: list[dict], agent_id: str = "default") -> int | None
|
|
|
362
362
|
WHERE target_id IN ({placeholders})""",
|
|
363
363
|
[new_id, *ids],
|
|
364
364
|
)
|
|
365
|
-
# Remove any self-relations created by the relink
|
|
365
|
+
# Remove any self-relations created by the relink (scoped to new_id only)
|
|
366
366
|
conn.execute(
|
|
367
|
-
"DELETE FROM memory_relations WHERE source_id = target_id",
|
|
367
|
+
"DELETE FROM memory_relations WHERE source_id = ? AND target_id = ?",
|
|
368
|
+
(new_id, new_id),
|
|
368
369
|
)
|
|
369
370
|
|
|
370
371
|
# Mark originals as compressed
|
|
@@ -100,9 +100,10 @@ def assemble_context(
|
|
|
100
100
|
tokens_used += tokens_est
|
|
101
101
|
|
|
102
102
|
# Verifica invariante TOKEN-BUDGET BOUNDED
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
if tokens_used > req.budget_tokens:
|
|
104
|
+
raise ValueError(
|
|
105
|
+
f"INVARIANTE VIOLATO: budget_tokens_used ({tokens_used}) > budget_tokens ({req.budget_tokens})"
|
|
106
|
+
)
|
|
106
107
|
|
|
107
108
|
# Carica conflitti tra le memorie selezionate (invariante #3)
|
|
108
109
|
selected_ids = [m.id for m in selected]
|
|
@@ -62,6 +62,7 @@ class _WatcherEntry:
|
|
|
62
62
|
self.include_extra_md = include_extra_md
|
|
63
63
|
self.max_depth = max_depth
|
|
64
64
|
self.observer: Any = None
|
|
65
|
+
self.handler: Any = None
|
|
65
66
|
self.started_at: str = datetime.now(UTC).isoformat()
|
|
66
67
|
self.events_processed: int = 0
|
|
67
68
|
|
|
@@ -103,12 +104,18 @@ class _WatcherRegistry:
|
|
|
103
104
|
]
|
|
104
105
|
|
|
105
106
|
def stop_all(self) -> int:
|
|
106
|
-
"""Ferma tutti i watcher — chiamato al shutdown del server."""
|
|
107
|
+
"""Ferma tutti i watcher e cancella i timer pendenti — chiamato al shutdown del server."""
|
|
107
108
|
with self._lock:
|
|
108
109
|
entries = list(self._watchers.values())
|
|
109
110
|
self._watchers.clear()
|
|
110
111
|
count = 0
|
|
111
112
|
for entry in entries:
|
|
113
|
+
# Cancel pending debounce timers to prevent post-shutdown DB operations
|
|
114
|
+
if entry.handler:
|
|
115
|
+
with entry.handler._timers_lock:
|
|
116
|
+
for timer in entry.handler._timers.values():
|
|
117
|
+
timer.cancel()
|
|
118
|
+
entry.handler._timers.clear()
|
|
112
119
|
if entry.observer:
|
|
113
120
|
try:
|
|
114
121
|
entry.observer.stop()
|
|
@@ -277,6 +284,7 @@ def start_watcher(
|
|
|
277
284
|
observer.start()
|
|
278
285
|
|
|
279
286
|
entry.observer = observer
|
|
287
|
+
entry.handler = handler
|
|
280
288
|
_registry.add(entry)
|
|
281
289
|
|
|
282
290
|
logger.info("Watcher avviato: base_path=%s agent=%s", resolved, agent_id)
|
|
@@ -189,7 +189,7 @@ class SecurityHeadersMiddleware(BaseHTTPMiddleware):
|
|
|
189
189
|
"default-src 'self'; "
|
|
190
190
|
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; "
|
|
191
191
|
"font-src 'self' https://fonts.gstatic.com; "
|
|
192
|
-
f"script-src 'nonce-{nonce}'
|
|
192
|
+
f"script-src 'nonce-{nonce}'; "
|
|
193
193
|
"connect-src 'self'; "
|
|
194
194
|
"img-src 'self' data:; "
|
|
195
195
|
"frame-ancestors 'none'"
|
|
@@ -315,7 +315,7 @@ def save_batch(
|
|
|
315
315
|
@app.get("/search", response_model=MemorySearchResponse)
|
|
316
316
|
def search(
|
|
317
317
|
request: Request,
|
|
318
|
-
q: str = Query(..., min_length=1, description="Search query (any language)"),
|
|
318
|
+
q: str = Query(..., min_length=1, max_length=1000, description="Search query (any language)"),
|
|
319
319
|
limit: int = Query(5, ge=1, le=20),
|
|
320
320
|
cursor: str | None = Query(None, description="Opaque pagination cursor"),
|
|
321
321
|
category: str | None = Query(None),
|
|
@@ -1119,7 +1119,7 @@ def shared_memories(
|
|
|
1119
1119
|
@app.get("/stream/search")
|
|
1120
1120
|
async def stream_search(
|
|
1121
1121
|
request: Request,
|
|
1122
|
-
q: str = Query(..., min_length=1, description="Search query"),
|
|
1122
|
+
q: str = Query(..., min_length=1, max_length=1000, description="Search query"),
|
|
1123
1123
|
limit: int = Query(10, ge=1, le=50),
|
|
1124
1124
|
_: str = _Auth,
|
|
1125
1125
|
agent_id: str = _Agent,
|
|
@@ -46,8 +46,20 @@ logger = logging.getLogger(__name__)
|
|
|
46
46
|
_SERVER_START_TIME = _time.monotonic()
|
|
47
47
|
_SESSION_TIMESTAMP = datetime.now().strftime("%Y%m%d-%H%M%S")
|
|
48
48
|
|
|
49
|
-
#
|
|
50
|
-
|
|
49
|
+
# DB initialized lazily on first operation (not at import time)
|
|
50
|
+
_db_initialized = False
|
|
51
|
+
_db_init_lock = threading.Lock()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _ensure_db() -> None:
|
|
55
|
+
global _db_initialized
|
|
56
|
+
if _db_initialized:
|
|
57
|
+
return
|
|
58
|
+
with _db_init_lock:
|
|
59
|
+
if not _db_initialized:
|
|
60
|
+
init_db()
|
|
61
|
+
_db_initialized = True
|
|
62
|
+
|
|
51
63
|
|
|
52
64
|
mcp = FastMCP(
|
|
53
65
|
"Kore Memory",
|
|
@@ -65,6 +77,7 @@ _session_lock = threading.Lock()
|
|
|
65
77
|
|
|
66
78
|
def _get_or_create_session(agent_id: str) -> str:
|
|
67
79
|
"""Restituisce la session_id corrente per l'agent, creandola se necessario."""
|
|
80
|
+
_ensure_db()
|
|
68
81
|
if agent_id in _agent_sessions:
|
|
69
82
|
return _agent_sessions[agent_id]
|
|
70
83
|
with _session_lock:
|
|
@@ -401,7 +414,7 @@ def memory_import(
|
|
|
401
414
|
Import memories from a list of dicts. Each item must have at least 'content'.
|
|
402
415
|
Optional fields: category, importance. Maximum 500 memories.
|
|
403
416
|
"""
|
|
404
|
-
count = import_memories(memories, agent_id=_sanitize_agent_id(agent_id))
|
|
417
|
+
count = import_memories(memories[:500], agent_id=_sanitize_agent_id(agent_id))
|
|
405
418
|
return {"imported": count, "message": f"{count} memories imported"}
|
|
406
419
|
|
|
407
420
|
|
|
@@ -833,6 +846,8 @@ def _add_health_route() -> None:
|
|
|
833
846
|
def main():
|
|
834
847
|
import argparse
|
|
835
848
|
|
|
849
|
+
_ensure_db()
|
|
850
|
+
|
|
836
851
|
parser = argparse.ArgumentParser(description="Kore MCP Server")
|
|
837
852
|
parser.add_argument(
|
|
838
853
|
"--transport",
|