memleaf 0.2.3__tar.gz → 0.2.4__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.
- {memleaf-0.2.3 → memleaf-0.2.4}/CHANGELOG.md +9 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/PKG-INFO +3 -3
- {memleaf-0.2.3 → memleaf-0.2.4}/README.en.md +2 -2
- {memleaf-0.2.3 → memleaf-0.2.4}/README.md +2 -2
- {memleaf-0.2.3 → memleaf-0.2.4}/pyproject.toml +1 -1
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/__init__.py +1 -1
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/hermes_provider/__init__.py +1 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/hermes_provider/plugin.yaml +1 -1
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/processing.py +20 -4
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/prompts.py +16 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf.egg-info/PKG-INFO +3 -3
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_hermes_provider.py +38 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_pypi_install.py +1 -1
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_stage_b1.py +17 -2
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_stage_c1_mcp.py +1 -1
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_stage_c3_packaging.py +1 -1
- {memleaf-0.2.3 → memleaf-0.2.4}/IMPLEMENTATION_PLAN.md +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/LICENSE +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/MANIFEST.in +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/RELEASE_CHECKLIST.md +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/examples/README.md +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/examples/basic_usage.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/examples/mcp_stdio.ndjson +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/install.ps1 +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/install.sh +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/setup.cfg +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/__main__.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/adapters/__init__.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/adapters/antigravity.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/adapters/base.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/adapters/codex.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/adapters/hermes.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/budget.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/capture.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/cli.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/compaction.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/config.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/credentials.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/frontmatter.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/hermes_provider/README.md +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/host_events.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/host_runtime.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/inbox.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/index.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/installer.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/llm/__init__.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/llm/base.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/llm/claude_compatible.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/llm/gemini.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/llm/openai_compatible.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/llm/router.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/locking.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/mcp_server.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/memory_writer.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/model_discovery.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/models.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/native_index.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/redaction.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/retrieval.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/retrieval_gate.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/scope_maintenance.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/scope_state.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/service.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/validation.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf/vault.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf.egg-info/SOURCES.txt +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf.egg-info/dependency_links.txt +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf.egg-info/entry_points.txt +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/src/memleaf.egg-info/top_level.txt +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/__init__.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_admission_noise.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_codex_install.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_codex_native_cli.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_context_budget.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_credential_safety.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_cross_host_acceptance.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_hermes_stdio_transport.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_host_events.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_host_runtime_contract.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_install.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_maintenance_v2.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_model_discovery.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_retrieval_gate.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_retrieval_v2.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_session_lineage.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_stage_a.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_stage_b2a.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_stage_b2b.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_stage_b3a_commit.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_stage_b3a_contract.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_stage_b3b_native_context.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_stage_b3b_native_index.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_stage_b3b_scope.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_stage_b3c_retrieval.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_stage_b3d_scope_maintenance.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_stage_c2_init.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_upgrade_preserves_vault.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_v2_gate_limits.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_v2_host_flow.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_v2_mcp_flow.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_v2_nomatch_semantics.py +0 -0
- {memleaf-0.2.3 → memleaf-0.2.4}/tests/test_v2_search_gate_acceptance.py +0 -0
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to memleaf are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.2.4 — 2026-09-01
|
|
6
|
+
|
|
7
|
+
- Give `relative_time` retries explicit, actionable correction instructions so
|
|
8
|
+
the summarizer recalculates one-off dates from evidence timestamps, removes
|
|
9
|
+
relative wording, and resolves conflicting parenthesized dates before the
|
|
10
|
+
strict validator accepts the memory.
|
|
11
|
+
- Preserve the `relative_time` validation detail across the Hermes provider
|
|
12
|
+
boundary instead of degrading it to `other_schema_violation` in diagnostics.
|
|
13
|
+
|
|
5
14
|
## 0.2.3 — 2026-09-01
|
|
6
15
|
|
|
7
16
|
- Preserve capture event timestamps in extraction prompts and resolve one-off
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memleaf
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: A local-first Markdown memory core for AI agents
|
|
5
5
|
Author: memleaf contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,8 +23,8 @@ Dynamic: license-file
|
|
|
23
23
|
|
|
24
24
|
[English](README.en.md) · [PyPI](https://pypi.org/project/memleaf/) · [GitHub](https://github.com/miffyblueboo/memleaf)
|
|
25
25
|
|
|
26
|
-
> **当前版本:0.2.
|
|
27
|
-
> 核心库、Vault、stdio MCP Server、初始化 CLI、模型路由、提炼流程、受控检索协议和宿主适配器已经实现。memleaf 0.2.
|
|
26
|
+
> **当前版本:0.2.4。**
|
|
27
|
+
> 核心库、Vault、stdio MCP Server、初始化 CLI、模型路由、提炼流程、受控检索协议和宿主适配器已经实现。memleaf 0.2.4 通过 PyPI 分发。
|
|
28
28
|
> **当前版本支持 Hermes 和 Codex。** Antigravity(反重力)不检测、不安装、不配置。
|
|
29
29
|
|
|
30
30
|
## 项目定位
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
[中文](README.md) · [PyPI](https://pypi.org/project/memleaf/) · [GitHub](https://github.com/miffyblueboo/memleaf)
|
|
6
6
|
|
|
7
|
-
> **Version: 0.2.
|
|
8
|
-
> The core library, Vault, stdio MCP server, initialization CLI, model routing, memory extraction, controlled retrieval protocol, and host adapters are implemented. memleaf 0.2.
|
|
7
|
+
> **Version: 0.2.4.**
|
|
8
|
+
> The core library, Vault, stdio MCP server, initialization CLI, model routing, memory extraction, controlled retrieval protocol, and host adapters are implemented. memleaf 0.2.4 is distributed through PyPI.
|
|
9
9
|
> **The current release supports Hermes and Codex.** Antigravity is not detected, installed, or configured.
|
|
10
10
|
|
|
11
11
|
## Project scope
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
[English](README.en.md) · [PyPI](https://pypi.org/project/memleaf/) · [GitHub](https://github.com/miffyblueboo/memleaf)
|
|
6
6
|
|
|
7
|
-
> **当前版本:0.2.
|
|
8
|
-
> 核心库、Vault、stdio MCP Server、初始化 CLI、模型路由、提炼流程、受控检索协议和宿主适配器已经实现。memleaf 0.2.
|
|
7
|
+
> **当前版本:0.2.4。**
|
|
8
|
+
> 核心库、Vault、stdio MCP Server、初始化 CLI、模型路由、提炼流程、受控检索协议和宿主适配器已经实现。memleaf 0.2.4 通过 PyPI 分发。
|
|
9
9
|
> **当前版本支持 Hermes 和 Codex。** Antigravity(反重力)不检测、不安装、不配置。
|
|
10
10
|
|
|
11
11
|
## 项目定位
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Local-first Markdown memory core for AI agents."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.2.
|
|
3
|
+
__version__ = "0.2.4"
|
|
4
4
|
|
|
5
5
|
from .config import DEFAULT_CONFIG, default_config, load_config, save_config
|
|
6
6
|
from .frontmatter import FrontmatterError, dump_frontmatter, dump_yaml, load_yaml, parse_frontmatter
|
|
@@ -30,7 +30,14 @@ from .locking import atomic_write_json, atomic_write_text, read_json
|
|
|
30
30
|
from .memory_writer import MemoryWriter
|
|
31
31
|
from .models import Memory, utc_now
|
|
32
32
|
from .native_index import NativeIndexer
|
|
33
|
-
from .prompts import
|
|
33
|
+
from .prompts import (
|
|
34
|
+
JSON_CORRECTION,
|
|
35
|
+
RELATIVE_TIME_CORRECTION,
|
|
36
|
+
GATE_SYSTEM,
|
|
37
|
+
SUMMARIZE_SYSTEM,
|
|
38
|
+
gate_prompt,
|
|
39
|
+
summarize_prompt,
|
|
40
|
+
)
|
|
34
41
|
from .redaction import redact_text
|
|
35
42
|
from .retrieval import candidate_matches_query, filter_by_scope, normalize_term
|
|
36
43
|
from .scope_state import ScopeError, normalize_scopes, register_scope_nodes
|
|
@@ -463,6 +470,15 @@ class Processor:
|
|
|
463
470
|
return reason
|
|
464
471
|
return None
|
|
465
472
|
|
|
473
|
+
@staticmethod
|
|
474
|
+
def _correction_instruction(error: BaseException) -> Optional[str]:
|
|
475
|
+
hint = Processor._safe_correction_hint(error)
|
|
476
|
+
if hint == "relative_time":
|
|
477
|
+
return RELATIVE_TIME_CORRECTION
|
|
478
|
+
if hint is not None:
|
|
479
|
+
return f"Previous output violated: {hint}."
|
|
480
|
+
return None
|
|
481
|
+
|
|
466
482
|
def _diagnostic_enabled(self) -> bool:
|
|
467
483
|
try:
|
|
468
484
|
config = self.service.vault.config()
|
|
@@ -620,10 +636,10 @@ class Processor:
|
|
|
620
636
|
except Exception:
|
|
621
637
|
pass
|
|
622
638
|
if self._allows_next_json_attempt(error, attempt_count):
|
|
623
|
-
hint = self._safe_correction_hint(error)
|
|
624
639
|
correction_prompt = prompt + "\n\n" + JSON_CORRECTION
|
|
625
|
-
|
|
626
|
-
|
|
640
|
+
instruction = self._correction_instruction(error)
|
|
641
|
+
if instruction is not None:
|
|
642
|
+
correction_prompt += f"\n{instruction}"
|
|
627
643
|
continue
|
|
628
644
|
raise
|
|
629
645
|
try:
|
|
@@ -195,6 +195,22 @@ JSON_CORRECTION = (
|
|
|
195
195
|
)
|
|
196
196
|
|
|
197
197
|
|
|
198
|
+
RELATIVE_TIME_CORRECTION = (
|
|
199
|
+
"Previous output violated: relative_time. Re-read the evidence events and use "
|
|
200
|
+
"the timestamp of the event supporting each date as the anchor; recompute "
|
|
201
|
+
"each one-off relative date from that timestamp and the stated weekday "
|
|
202
|
+
"semantics. In the summary title and body, every one-off calendar date must "
|
|
203
|
+
"be written only as YYYY-MM-DD: remove forms such as today/tomorrow/yesterday, "
|
|
204
|
+
"今天/明天/昨天, 本周三/这周三/下周三/上周三, and this/next/last Wednesday. "
|
|
205
|
+
"If a relative weekday is followed by a parenthesized numeric date and they "
|
|
206
|
+
"conflict, trust the event timestamp plus the weekday meaning, replace the "
|
|
207
|
+
"numeric date with the computed YYYY-MM-DD, and remove the relative wording "
|
|
208
|
+
"and conflicting parenthetical date. Do not guess when no supporting timestamp "
|
|
209
|
+
"exists; omit or defer the date-dependent detail. Recurring schedules such as "
|
|
210
|
+
"每天、每周三, or every Wednesday are allowed. Return only the strict JSON object."
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
|
|
198
214
|
COMPACT_SYSTEM = """You are memleaf's memory compactor. Return JSON only.
|
|
199
215
|
Merge only the supplied low-priority memories when they express compatible
|
|
200
216
|
information. Return an object with a memories array; [] is a safe no-op.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memleaf
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: A local-first Markdown memory core for AI agents
|
|
5
5
|
Author: memleaf contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,8 +23,8 @@ Dynamic: license-file
|
|
|
23
23
|
|
|
24
24
|
[English](README.en.md) · [PyPI](https://pypi.org/project/memleaf/) · [GitHub](https://github.com/miffyblueboo/memleaf)
|
|
25
25
|
|
|
26
|
-
> **当前版本:0.2.
|
|
27
|
-
> 核心库、Vault、stdio MCP Server、初始化 CLI、模型路由、提炼流程、受控检索协议和宿主适配器已经实现。memleaf 0.2.
|
|
26
|
+
> **当前版本:0.2.4。**
|
|
27
|
+
> 核心库、Vault、stdio MCP Server、初始化 CLI、模型路由、提炼流程、受控检索协议和宿主适配器已经实现。memleaf 0.2.4 通过 PyPI 分发。
|
|
28
28
|
> **当前版本支持 Hermes 和 Codex。** Antigravity(反重力)不检测、不安装、不配置。
|
|
29
29
|
|
|
30
30
|
## 项目定位
|
|
@@ -1717,6 +1717,44 @@ class HermesProviderTests(unittest.TestCase):
|
|
|
1717
1717
|
self.assertIsNotNone(fields)
|
|
1718
1718
|
self.assertEqual(fields[4], "invalid_update_target")
|
|
1719
1719
|
|
|
1720
|
+
def test_relative_time_validation_detail_is_preserved_and_logged(self) -> None:
|
|
1721
|
+
value = {
|
|
1722
|
+
"isError": True,
|
|
1723
|
+
"structuredContent": {
|
|
1724
|
+
"error": {
|
|
1725
|
+
"code": "model_invalid_response",
|
|
1726
|
+
"stage": "summarize",
|
|
1727
|
+
"validation_reason": "schema_violation",
|
|
1728
|
+
"validation_detail": "relative_time",
|
|
1729
|
+
"attempt_count": 3,
|
|
1730
|
+
}
|
|
1731
|
+
},
|
|
1732
|
+
}
|
|
1733
|
+
fields = provider_module._mcp_error_fields(value)
|
|
1734
|
+
self.assertIsNotNone(fields)
|
|
1735
|
+
self.assertEqual(fields[4], "relative_time")
|
|
1736
|
+
error = provider_module._MCPToolError(
|
|
1737
|
+
code="model_invalid_response",
|
|
1738
|
+
stage="summarize",
|
|
1739
|
+
validation_reason="schema_violation",
|
|
1740
|
+
validation_detail="relative_time",
|
|
1741
|
+
attempt_count=3,
|
|
1742
|
+
)
|
|
1743
|
+
self.assertEqual(error.validation_detail, "relative_time")
|
|
1744
|
+
|
|
1745
|
+
provider = self.provider(
|
|
1746
|
+
responses=[
|
|
1747
|
+
{"stored": True},
|
|
1748
|
+
{"stored": True},
|
|
1749
|
+
value,
|
|
1750
|
+
]
|
|
1751
|
+
)
|
|
1752
|
+
with patch.object(provider_module.logger, "info") as info:
|
|
1753
|
+
provider.sync_turn("visible user", "visible assistant", session_id="relative-time-session")
|
|
1754
|
+
output = "\n".join(call.args[0] % call.args[1:] for call in info.call_args_list)
|
|
1755
|
+
self.assertIn("validation_detail=relative_time", output)
|
|
1756
|
+
self.assertIn("attempt_count=3", output)
|
|
1757
|
+
|
|
1720
1758
|
def test_capture_failure_skips_process_and_does_not_escape_provider(self) -> None:
|
|
1721
1759
|
provider = self.provider(responses=[{"stored": True}, RuntimeError("capture unavailable")])
|
|
1722
1760
|
with patch.object(provider_module.logger, "warning") as warning:
|
|
@@ -39,7 +39,7 @@ class PyPIInstallTests(unittest.TestCase):
|
|
|
39
39
|
|
|
40
40
|
self.assertTrue(target.is_dir())
|
|
41
41
|
self.assertFalse(target.is_symlink())
|
|
42
|
-
self.assertIn("version: 0.2.
|
|
42
|
+
self.assertIn("version: 0.2.4", (target / "plugin.yaml").read_text(encoding="utf-8"))
|
|
43
43
|
|
|
44
44
|
def test_windows_hermes_paths_follow_official_native_layout(self) -> None:
|
|
45
45
|
with tempfile.TemporaryDirectory(prefix="memleaf-win-paths-") as temporary:
|
|
@@ -9,7 +9,13 @@ from unittest import mock
|
|
|
9
9
|
from memleaf import Memleaf
|
|
10
10
|
from memleaf.config import default_config, load_config, save_config
|
|
11
11
|
from memleaf.inbox import complete_turns, parse_inbox
|
|
12
|
-
from memleaf.prompts import
|
|
12
|
+
from memleaf.prompts import (
|
|
13
|
+
GATE_SYSTEM,
|
|
14
|
+
RELATIVE_TIME_CORRECTION,
|
|
15
|
+
SUMMARIZE_SYSTEM,
|
|
16
|
+
gate_prompt,
|
|
17
|
+
summarize_prompt,
|
|
18
|
+
)
|
|
13
19
|
from memleaf.validation import ModelOutputError
|
|
14
20
|
from memleaf.index import event_key, turn_key
|
|
15
21
|
from memleaf.llm import (
|
|
@@ -204,7 +210,11 @@ class StageB1Test(unittest.TestCase):
|
|
|
204
210
|
"status": "active",
|
|
205
211
|
}
|
|
206
212
|
|
|
207
|
-
responses = [
|
|
213
|
+
responses = [
|
|
214
|
+
json.dumps(gate),
|
|
215
|
+
json.dumps(summary("在本周三(9/3)前完成。")),
|
|
216
|
+
json.dumps(summary("在2026-09-02前完成。")),
|
|
217
|
+
]
|
|
208
218
|
calls = []
|
|
209
219
|
|
|
210
220
|
def callback(prompt, **kwargs):
|
|
@@ -231,6 +241,11 @@ class StageB1Test(unittest.TestCase):
|
|
|
231
241
|
self.assertEqual(len(calls), 3)
|
|
232
242
|
self.assertEqual([purpose for _, purpose in calls], ["gate", "summarize", "summarize"])
|
|
233
243
|
self.assertIn(anchor, calls[0][0])
|
|
244
|
+
self.assertIn(RELATIVE_TIME_CORRECTION, calls[2][0])
|
|
245
|
+
self.assertIn("event supporting each date as the anchor", calls[2][0])
|
|
246
|
+
self.assertIn("every one-off calendar date must be written only as YYYY-MM-DD", calls[2][0])
|
|
247
|
+
self.assertIn("parenthesized numeric date", calls[2][0])
|
|
248
|
+
self.assertIn("trust the event timestamp plus the weekday meaning", calls[2][0])
|
|
234
249
|
self.assertIn("Previous output violated: relative_time.", calls[2][0])
|
|
235
250
|
memory = self.service.read(result["memory_ids"][0])
|
|
236
251
|
self.assertIsNotNone(memory)
|
|
@@ -104,7 +104,7 @@ class StageC1MCPTest(unittest.TestCase):
|
|
|
104
104
|
testcase.assertEqual(result["resultType"], "complete")
|
|
105
105
|
testcase.assertEqual(
|
|
106
106
|
result["_meta"]["io.modelcontextprotocol/serverInfo"],
|
|
107
|
-
{"name": "memleaf", "version": "0.2.
|
|
107
|
+
{"name": "memleaf", "version": "0.2.4"},
|
|
108
108
|
)
|
|
109
109
|
return result
|
|
110
110
|
|
|
@@ -24,7 +24,7 @@ class StageC3PackagingTests(unittest.TestCase):
|
|
|
24
24
|
|
|
25
25
|
def test_project_metadata_and_version_export(self) -> None:
|
|
26
26
|
self.assertEqual(self.project["name"], "memleaf")
|
|
27
|
-
self.assertEqual(self.project["version"], "0.2.
|
|
27
|
+
self.assertEqual(self.project["version"], "0.2.4")
|
|
28
28
|
self.assertEqual(self.project["requires-python"], ">=3.11")
|
|
29
29
|
self.assertEqual(self.project["dependencies"], [])
|
|
30
30
|
self.assertEqual(self.project["license"], "MIT")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|