memleaf 0.2.95__tar.gz → 0.2.96__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.95 → memleaf-0.2.96}/CHANGELOG.md +25 -0
- {memleaf-0.2.95/src/memleaf.egg-info → memleaf-0.2.96}/PKG-INFO +2 -2
- {memleaf-0.2.95 → memleaf-0.2.96}/README.en.md +1 -1
- {memleaf-0.2.95 → memleaf-0.2.96}/README.md +1 -1
- {memleaf-0.2.95 → memleaf-0.2.96}/pyproject.toml +1 -1
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/__init__.py +1 -1
- memleaf-0.2.96/src/memleaf/body_preservation.py +112 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/hermes_provider/plugin.yaml +1 -1
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_execution.py +5 -2
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_semantics.py +44 -9
- {memleaf-0.2.95 → memleaf-0.2.96/src/memleaf.egg-info}/PKG-INFO +2 -2
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf.egg-info/SOURCES.txt +1 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/LICENSE +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/MANIFEST.in +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/acceptance-evidence-guide.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/automatic-processing-route.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/body-compaction.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/candidate-reconciliation.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/capture-budget-design.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/config-migrations.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/core-refactor.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/development-closeout.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/evidence-retention.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/explicit-memory-update.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/extraction-latency.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/failed-run-recovery.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/gate-evidence-boundary.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/general-processing.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/hermes-mcp-runtime.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/hermes-provider-compatibility.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/hermes-source-comparison-context.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/host-acceptance-runbook.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/immutable-release-assets.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/incremental-commit-contract.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/incremental-execution.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/incremental-native-comparison.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/incremental-partial-recovery.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/incremental-planner-preview.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/incremental-runtime-contract.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/incremental-scope-registration.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/incremental-selected-retention.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/installed-artifact-verification.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/memory-lifecycle-tools.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/memory-state-contract.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/migration-preflight.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/processing-quality-acceptance.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/public-query-integrity.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/query-performance.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/remember-incremental-route.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/runtime-state-retention.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/semantic-extraction-protocol.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/source-work-contract.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/docs/v0.2.26-processing-status.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/examples/README.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/examples/basic_usage.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/examples/incremental_acceptance.json +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/examples/mcp_stdio.ndjson +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/examples/query_benchmark.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/install.ps1 +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/install.sh +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/setup.cfg +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/__main__.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/acceptance.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/adapters/__init__.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/adapters/antigravity.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/adapters/base.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/adapters/codex.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/adapters/hermes.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/admission.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/batch_review.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/budget.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/capture.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/cli.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/compaction.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/config.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/create_coordinator.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/credentials.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/evidence_budget.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/evidence_policy.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/evidence_structure.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/evidence_syntax.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/explicit_text_source.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/extraction_budget.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/extraction_capability.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/extraction_work_state.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/frontmatter.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/hermes_provider/README.md +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/hermes_provider/__init__.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/hermes_provider/_mcp_client.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/hermes_provider/_provider.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/hermes_provider/_shared.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/hermes_provider/evidence_budget.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/hermes_provider/provider_compatibility.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/hermes_runtime.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/historical_context.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/host_events.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/host_retention.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/host_runtime.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/host_turn_identity.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/inbox.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_commit.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_dates.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_explicit.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_failed_recovery.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_journal.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_merge.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_native.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_partial.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_preview.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_prompts.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_protocol.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_recovery.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_run_state.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_runtime.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_scopes.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/incremental_selection.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/index.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/inspection.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/installer.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/legacy_update_journal.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/lifecycle_maintenance.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/llm/__init__.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/llm/base.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/llm/claude_compatible.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/llm/gemini.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/llm/openai_compatible.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/llm/router.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/llm/thinking.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/locking.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/mcp_server.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/memory_commit.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/memory_planner.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/memory_retraction.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/memory_update.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/memory_writer.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/migration.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/model_capabilities.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/model_discovery.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/model_execution.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/models.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/native_index.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/native_registration.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/parallel_model.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/planning_candidates.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/planning_context.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/process_common.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/process_jobs.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/process_journal.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/process_owner.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/processing.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/processing_route.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/prompts.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/provenance.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/provider_compatibility.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/query_clock.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/query_progress.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/query_scan.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/receipt_codec.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/recording_policy.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/redaction.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/remember_route.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/retention.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/retrieval.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/retrieval_gate.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/retrieval_lifecycle.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/runtime_retention.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/scope_maintenance.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/scope_state.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/semantic_maintenance.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/semantic_protocol.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/service.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/single_pass_memory_planner.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/single_pass_plan.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/source_policy.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/state_layout.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/subprocess_flags.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/summary_batch.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/target_reconciliation.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/turn_audit.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/turn_plan.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/update_coordinator.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/update_review.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/validation.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf/vault.py +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf.egg-info/dependency_links.txt +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf.egg-info/entry_points.txt +0 -0
- {memleaf-0.2.95 → memleaf-0.2.96}/src/memleaf.egg-info/top_level.txt +0 -0
|
@@ -5,6 +5,31 @@ All notable changes to memleaf are documented here.
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
## 0.2.96 — 2026-10-06
|
|
9
|
+
|
|
10
|
+
### Preserve existing information when replacing memory bodies
|
|
11
|
+
|
|
12
|
+
- Expose omitted old prose to semantic review for UPDATE and every MERGE
|
|
13
|
+
member. Require dispositions bound to the final body or new user evidence;
|
|
14
|
+
boolean body approval alone cannot erase existing information. Unconfirmed
|
|
15
|
+
replacements remain DEFERRED with the previous memory preserved.
|
|
16
|
+
- Allow the existing review to repair the full body while retaining candidate
|
|
17
|
+
identity, evidence and other fields. Check the final replacement, accept valid
|
|
18
|
+
redundant coverage, and isolate invalid optional maintenance corrections from
|
|
19
|
+
independently valid decisions. Protect manual partial repairs as well.
|
|
20
|
+
- Reuse the existing review request for ongoing actions; add a second review
|
|
21
|
+
only where a previously unreviewed fact update could omit existing prose.
|
|
22
|
+
Ordinary fact additions and repeated no-change turns remain single-request.
|
|
23
|
+
No third review, automatic retry or request-budget increase is added.
|
|
24
|
+
- Validation: 122 affected checks and isolated frozen-candidate replays passed.
|
|
25
|
+
The final three live Hermes turns preserved unchanged requirements, avoided
|
|
26
|
+
duplicate writes and applied only an explicitly withdrawn requirement:
|
|
27
|
+
five Memleaf requests, 30,821 observed tokens, no issues or unresolved items.
|
|
28
|
+
Intermediate development failures were preserved separately; historical raw
|
|
29
|
+
review responses were not reconstructed. Equivalence still relies on semantic
|
|
30
|
+
review, while Core verifies complete coverage and source/quote bindings.
|
|
31
|
+
|
|
32
|
+
|
|
8
33
|
## 0.2.95 — 2026-10-05
|
|
9
34
|
|
|
10
35
|
### Preserve turn identity around internal Hermes continuations
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memleaf
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.96
|
|
4
4
|
Summary: A local-first Markdown memory core for AI agents
|
|
5
5
|
Author: memleaf contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,7 +23,7 @@ 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.
|
|
26
|
+
> **版本:0.2.96。**
|
|
27
27
|
> 自动提炼和复核共用同一条“未来记忆价值”标准:模型综合未来复用、信息增量、再次读取时的直接可用性和忘记成本,只保留对未来理解、判断或行动有实质影响的最小核心;没有明确价值的信息不提炼,不按具体业务场景硬编码排除。
|
|
28
28
|
> 提炼先比较旧事项中的编号、目标、进展、责任和期限;补全未知信息也应维护原事项,另建独立待办不能替代项目事实更新。确认重复的记忆在现有处理请求中合并,保留历史与来源;项目和独立任务保持各自生命周期,Core 不按标题强行合并。
|
|
29
29
|
> 新请求兼容等价的字段表示;未知执行人保持 `null`,新增或变更负责人和期限需要真实来源;等待条件在正文维护,不再提炼 `waiting_on`。行动及相关字段经过有界语义复核,提炼与复核共用每份工作的最多五次模型请求额度,成功即停止;复核失败不写入。来源时间用于解析相对日期,不补造事实日期。
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[中文](README.md) · [PyPI](https://pypi.org/project/memleaf/) · [GitHub](https://github.com/miffyblueboo/memleaf)
|
|
6
6
|
|
|
7
|
-
> **Version: 0.2.
|
|
7
|
+
> **Version: 0.2.96.**
|
|
8
8
|
> Automatic extraction and review share one future-value standard: the model weighs likely reuse, information gain, direct usability when read again, and the cost of forgetting. It keeps only the smallest core that can materially help future understanding, decisions, or actions; information without clear value is not extracted, and no business-specific exclusion rule is hard-coded.
|
|
9
9
|
> Extraction compares existing identifiers, objectives, progress, responsibility and deadlines first. Filling an unknown also maintains the original item; a separate task does not replace updating shared project facts. Confirmed duplicates can be merged in the existing processing requests with their sources and history preserved. Independent project and task lifecycles remain separate; Core does not merge matching titles.
|
|
10
10
|
> New requests accept equivalent field representations. Unknown executors remain `null`; new or changed responsibility and deadlines require actual source evidence. Dependencies belong in the body; `waiting_on` is no longer extracted. Proposed actions and related fields undergo bounded semantic verification within a shared five-request limit per work item, stopping on success; failed verification blocks writes. Source time resolves relative dates without inventing factual dates.
|
|
@@ -4,7 +4,7 @@
|
|
|
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.
|
|
7
|
+
> **版本:0.2.96。**
|
|
8
8
|
> 自动提炼和复核共用同一条“未来记忆价值”标准:模型综合未来复用、信息增量、再次读取时的直接可用性和忘记成本,只保留对未来理解、判断或行动有实质影响的最小核心;没有明确价值的信息不提炼,不按具体业务场景硬编码排除。
|
|
9
9
|
> 提炼先比较旧事项中的编号、目标、进展、责任和期限;补全未知信息也应维护原事项,另建独立待办不能替代项目事实更新。确认重复的记忆在现有处理请求中合并,保留历史与来源;项目和独立任务保持各自生命周期,Core 不按标题强行合并。
|
|
10
10
|
> 新请求兼容等价的字段表示;未知执行人保持 `null`,新增或变更负责人和期限需要真实来源;等待条件在正文维护,不再提炼 `waiting_on`。行动及相关字段经过有界语义复核,提炼与复核共用每份工作的最多五次模型请求额度,成功即停止;复核失败不写入。来源时间用于解析相对日期,不补造事实日期。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Local-first Markdown memory core for AI agents."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.2.
|
|
3
|
+
__version__ = "0.2.96"
|
|
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
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""Account for omitted old prose without guessing which facts remain valid.
|
|
2
|
+
|
|
3
|
+
Text fragments are comparison aids, not a parser for facts. The existing
|
|
4
|
+
semantic review judges equivalence or an authorized change; Core checks that
|
|
5
|
+
every omission has a real, source-bound disposition for the final candidate.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _compact(text):
|
|
13
|
+
return re.sub(r"\s+", "", text)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def omissions(row, original):
|
|
17
|
+
if not isinstance(row, dict):
|
|
18
|
+
return []
|
|
19
|
+
action = row.get("action")
|
|
20
|
+
action = action.strip().upper() if isinstance(action, str) else ""
|
|
21
|
+
if action not in {"UPDATE", "MERGE"}:
|
|
22
|
+
return []
|
|
23
|
+
patch = row.get("patch")
|
|
24
|
+
if not isinstance(patch, dict):
|
|
25
|
+
return []
|
|
26
|
+
# Retraction erases the stored body even when the model omits patch.body.
|
|
27
|
+
body = "" if patch.get("validity") == "retracted" else patch.get("body")
|
|
28
|
+
if not isinstance(body, str):
|
|
29
|
+
return []
|
|
30
|
+
refs = [row.get("target")]
|
|
31
|
+
if action == "MERGE" and isinstance(row.get("duplicates"), list):
|
|
32
|
+
refs.extend(row["duplicates"])
|
|
33
|
+
refs = [ref.strip() for ref in refs if isinstance(ref, str)]
|
|
34
|
+
new = _compact(body)
|
|
35
|
+
missing = []
|
|
36
|
+
seen = set()
|
|
37
|
+
for memory in original.get("memories", []):
|
|
38
|
+
if memory.get("ref") not in refs or memory.get("validity", "valid") != "valid":
|
|
39
|
+
continue
|
|
40
|
+
old = memory.get("body", "")
|
|
41
|
+
if not isinstance(old, str):
|
|
42
|
+
continue
|
|
43
|
+
# Language-neutral punctuation/line boundaries. No names, keywords or
|
|
44
|
+
# expected facts influence the comparison. Short fragments count too.
|
|
45
|
+
for text in re.split(r"[。!?!?;;\n,,]+|(?<=\.)\s+", old):
|
|
46
|
+
text = text.strip()
|
|
47
|
+
key = (memory["ref"], text)
|
|
48
|
+
if text and _compact(text) not in new and key not in seen:
|
|
49
|
+
missing.append({"target": key[0], "old": text})
|
|
50
|
+
seen.add(key)
|
|
51
|
+
return missing
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def covered(row, original, coverage=None):
|
|
55
|
+
"""Missing/malformed proofs defer this proposal, never erase the head."""
|
|
56
|
+
missing = omissions(row, original)
|
|
57
|
+
if not missing:
|
|
58
|
+
return True
|
|
59
|
+
if not isinstance(coverage, list):
|
|
60
|
+
return False
|
|
61
|
+
expected = {(part["target"], part["old"]) for part in missing}
|
|
62
|
+
# A reviewer may restore a fragment and still include its proof. Check
|
|
63
|
+
# against the real old fragments, not an exact output-count convention.
|
|
64
|
+
all_old = omissions({**row, "patch": {"body": ""}}, original)
|
|
65
|
+
allowed = {(part["target"], part["old"]) for part in all_old}
|
|
66
|
+
verified = set()
|
|
67
|
+
body = "" if row["patch"].get("validity") == "retracted" else row["patch"].get("body", "")
|
|
68
|
+
evidence = {e["ref"]: e for e in original.get("evidence", [])}
|
|
69
|
+
for proof in coverage:
|
|
70
|
+
if not isinstance(proof, dict):
|
|
71
|
+
return False
|
|
72
|
+
key = (proof.get("target"), proof.get("old"))
|
|
73
|
+
if not all(isinstance(value, str) for value in key) or key not in allowed or key in verified:
|
|
74
|
+
return False
|
|
75
|
+
if set(proof) == {"target", "old", "body"}:
|
|
76
|
+
quote = proof["body"]
|
|
77
|
+
if not isinstance(quote, str) or not quote.strip() or quote not in body:
|
|
78
|
+
return False
|
|
79
|
+
elif set(proof) == {"target", "old", "source"}:
|
|
80
|
+
selection = proof["source"]
|
|
81
|
+
if not isinstance(selection, dict) or set(selection) != {"ref", "text"}:
|
|
82
|
+
return False
|
|
83
|
+
if not isinstance(selection["ref"], str):
|
|
84
|
+
return False
|
|
85
|
+
event = evidence.get(selection.get("ref"))
|
|
86
|
+
quote = selection.get("text")
|
|
87
|
+
# An assistant suggestion cannot authorize discarding user facts.
|
|
88
|
+
if (event is None or event.get("use") != "new" or event.get("role") != "user"
|
|
89
|
+
or event["ref"] not in row.get("evidence", [])
|
|
90
|
+
or not isinstance(quote, str) or not quote.strip() or quote not in event.get("text", "")):
|
|
91
|
+
return False
|
|
92
|
+
else:
|
|
93
|
+
return False
|
|
94
|
+
verified.add(key)
|
|
95
|
+
return expected <= verified
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def defer_unreviewed(response, snapshot):
|
|
99
|
+
"""A manual partial repair has no model reviewer; preserve unsafe heads."""
|
|
100
|
+
from .incremental_semantics import envelope
|
|
101
|
+
from .validation import parse_strict_json
|
|
102
|
+
from .incremental_protocol import compile_incremental
|
|
103
|
+
import json
|
|
104
|
+
draft = envelope(parse_strict_json(response))
|
|
105
|
+
original = snapshot.model_input()
|
|
106
|
+
for i, row in enumerate(draft["items"]):
|
|
107
|
+
if (omissions(row, original)
|
|
108
|
+
and not compile_incremental(json.dumps({"items": [row]}), snapshot)["issues"]):
|
|
109
|
+
draft["items"][i] = {"action": "DEFERRED", "evidence": row.get("evidence", []),
|
|
110
|
+
"reason": "missing_context",
|
|
111
|
+
"need": "The body replacement has unverified omissions from the previous memory."}
|
|
112
|
+
return json.dumps(draft, ensure_ascii=False, separators=(",", ":"))
|
|
@@ -232,11 +232,14 @@ def _drive(service, run_id, token, backend, calls, metric_ordinals):
|
|
|
232
232
|
return public_result(run, calls=calls[0], metric_ordinals=metric_ordinals)
|
|
233
233
|
if run["status"] in {"response_ready", "committing"}:
|
|
234
234
|
try:
|
|
235
|
+
if (run.get("partial_used") and run.get("partial_recovery", {}).get("mode") == "repair"):
|
|
236
|
+
from .body_preservation import defer_unreviewed
|
|
237
|
+
run["response"] = defer_unreviewed(run["response"], snapshot)
|
|
235
238
|
compiled = compile_incremental(run["response"], snapshot)
|
|
236
239
|
from .incremental_semantics import needs_review, review_request
|
|
237
240
|
if (not (run.get("partial_used") and run.get("partial_recovery", {}).get("mode") == "repair")
|
|
238
241
|
and run.get("semantic_stage") != "reviewed"
|
|
239
|
-
and needs_review(compiled, run["response"])):
|
|
242
|
+
and needs_review(compiled, run["response"], snapshot)):
|
|
240
243
|
if run["reserved_requests"] >= MAX_INCREMENTAL_REQUESTS:
|
|
241
244
|
_finish(service, processed, run, "blocked", "semantic_review_budget_exhausted")
|
|
242
245
|
return public_result(run, calls=calls[0], metric_ordinals=metric_ordinals)
|
|
@@ -391,7 +394,7 @@ def _drive(service, run_id, token, backend, calls, metric_ordinals):
|
|
|
391
394
|
elif not run.get("partial_used"):
|
|
392
395
|
try:
|
|
393
396
|
from .incremental_semantics import needs_review
|
|
394
|
-
run["semantic_review_required"] = needs_review(compile_incremental(response, snapshot), response)
|
|
397
|
+
run["semantic_review_required"] = needs_review(compile_incremental(response, snapshot), response, snapshot)
|
|
395
398
|
except (ValueError, TypeError):
|
|
396
399
|
run["semantic_review_required"] = False
|
|
397
400
|
save_run(service, processed, run)
|
|
@@ -10,8 +10,10 @@ from copy import deepcopy
|
|
|
10
10
|
import json
|
|
11
11
|
|
|
12
12
|
from .validation import parse_strict_json, ModelOutputError
|
|
13
|
+
from .body_preservation import omissions, covered
|
|
13
14
|
|
|
14
|
-
REVIEW_SYSTEM = """
|
|
15
|
+
REVIEW_SYSTEM = """核验拟写入的记忆及持续行动。original_input 是唯一事实和权限来源;draft 是待审候选,不能当作事实。返回 JSON 对象,必填 decisions,值为数组;每项有 item(整数)、keep(布尔值)、field_support(对象)。按输入 fields_to_review 的实际字段填 field_support,不能复制其他事项的字段名。
|
|
16
|
+
存在 body_omissions 时,keep:true 的 UPDATE/MERGE 必须逐项说明省略的去向;仅 body:true 不足以通过。body_omissions 按 item 列出拟议正文中不再原样出现的旧片段(比较辅助,不表示已经失效)。逐项核对完整含义,不能因主题相同、进展重复或用户未再次提及就删除。需要补回或修正文句时,直接在 decision 增加 body(修正后的完整正文字符串),field_support.body=true;不必复制 action、target、evidence,也不要把该 target 放入 updates。Core 沿用该候选的身份、证据和其他字段;已有 replace 方式仍可用,但不能同时使用 body 和 replace。对最终 UPDATE/MERGE(包括 body、replace 和 updates 修正)的剩余省略片段,在对应 decision/updates 项增加 body_coverage 数组:每项 {"target":"旧目标ref","old":"旧片段原文","body":"最终正文中完整承接该片段含义的逐字引文"},或 {"target":"旧目标ref","old":"旧片段原文","source":{"ref":"new用户证据ref","text":"明确纠正/撤回该内容的逐字引文"}}。body 引文必须完整等价且真实存在于最终正文;不能只引用旧目标中的文字却忘了将它写入修正正文。source 不能引用旧上下文或助手建议。修正后原样保留的片段无需列入。MERGE 对所有被合并目标逐项核对,撤回整个目标也需明确用户依据。无法确认则 keep:false;不要猜测或提供主题相符但实际无关的引文。没有剩余省略时省略 body_coverage。
|
|
15
17
|
每个 draft.items 都必须有且只有一个 decision,item 是从 0 开始的位置。keep 判断该事项本身是否由原文确立且持续值得保留。临时操作及助手额外建议不能产生用户长期待办,原话只证明另一个操作时 keep:false。独立事实不因其他候选有误而拒绝。
|
|
16
18
|
keep:true 时,field_support 必须逐个列出候选 memory/patch 中的业务字段,每个布尔值判断该字段的拟议值是否受来源支持;不列 responsibility_basis、effective、at、reopen 等引用/控制字段。没有 replace 的 NO_CHANGE/DEFERRED/NO_MEMORY 的 field_support 为 {}。keep:false 时 field_support 为 {}。unverified_fields 是系统发现未能验证引用的可选责任字段,必须判为 false;不能补造引用。这不影响其他有依据的事实或任务。归属/客户尚未确定不自动表示行动被阻塞。
|
|
17
19
|
不能仅检查引文存在:必须判断原话是否确立该具体行动、责任、状态和期限。assistant 的建议/计划不能赋予 user 新义务。转发、协调、记录不等于本人执行;支持旧任务不等于接受新安排。
|
|
@@ -45,15 +47,23 @@ def fields(row):
|
|
|
45
47
|
return {key for key in payload if key not in _METADATA} if isinstance(payload, dict) else set()
|
|
46
48
|
|
|
47
49
|
|
|
48
|
-
def needs_review(compiled, response=None):
|
|
50
|
+
def needs_review(compiled, response=None, snapshot=None):
|
|
49
51
|
if response is not None:
|
|
50
52
|
rows = envelope(parse_strict_json(response))["items"]
|
|
53
|
+
original = snapshot.model_input() if snapshot is not None else None
|
|
54
|
+
update_ids = {op.get("target") for op in compiled["operations"] if op["action"] == "UPDATE"}
|
|
55
|
+
writable_updates = ({ref for ref, target in snapshot.state()["targets"].items()
|
|
56
|
+
if target["memory"]["memory_id"] in update_ids} if snapshot is not None else set())
|
|
51
57
|
actions = {str(row.get("action", "")).strip().upper() for row in rows if isinstance(row, dict)}
|
|
52
58
|
if "MERGE" in actions or {"UPDATE", "NO_CHANGE"} <= actions:
|
|
53
59
|
return True
|
|
54
60
|
for row in rows:
|
|
55
61
|
if not isinstance(row, dict):
|
|
56
62
|
continue
|
|
63
|
+
target = row.get("target")
|
|
64
|
+
if (original is not None and isinstance(target, str) and target.strip() in writable_updates
|
|
65
|
+
and omissions(row, original)):
|
|
66
|
+
return True
|
|
57
67
|
action = row.get("action")
|
|
58
68
|
action = action.strip().upper() if isinstance(action, str) else ""
|
|
59
69
|
payload = row.get("memory") if action == "CREATE" else row.get("patch")
|
|
@@ -118,10 +128,12 @@ def review_request(original, response, snapshot=None):
|
|
|
118
128
|
row["action"] = row["action"].strip().upper()
|
|
119
129
|
rows.append(row)
|
|
120
130
|
draft["items"] = rows
|
|
131
|
+
missing = [omissions(row, source) for row in rows]
|
|
121
132
|
return {"system": REVIEW_SYSTEM,
|
|
122
133
|
"user": json.dumps({"original_input": source, "draft": draft,
|
|
123
134
|
"fields_to_review": [sorted(fields(row)) for row in draft["items"]],
|
|
124
135
|
"unverified_fields": [unverified_fields(row, source) for row in draft["items"]],
|
|
136
|
+
**({"body_omissions": missing} if any(missing) else {}),
|
|
125
137
|
**({"invalid_representation_items": invalid} if invalid else {})},
|
|
126
138
|
ensure_ascii=False, separators=(",", ":"))}
|
|
127
139
|
|
|
@@ -164,7 +176,7 @@ def apply_review(request, response):
|
|
|
164
176
|
rejected.append(deepcopy(row))
|
|
165
177
|
for decision in decisions:
|
|
166
178
|
if (not isinstance(decision, dict) or not {"item", "keep", "field_support"} <= set(decision)
|
|
167
|
-
or set(decision) - {"item", "keep", "field_support", "replace"}):
|
|
179
|
+
or set(decision) - {"item", "keep", "field_support", "replace", "body", "body_coverage"}):
|
|
168
180
|
raise ValueError
|
|
169
181
|
i = decision["item"]
|
|
170
182
|
if type(i) is not int or not 0 <= i < len(rows) or i in positions or type(decision["keep"]) is not bool:
|
|
@@ -174,6 +186,14 @@ def apply_review(request, response):
|
|
|
174
186
|
if not isinstance(support, dict) or any(type(v) is not bool for v in support.values()):
|
|
175
187
|
raise ValueError
|
|
176
188
|
row = rows[i]
|
|
189
|
+
if "body" in decision:
|
|
190
|
+
if (not decision["keep"] or "replace" in decision
|
|
191
|
+
or i in data.get("invalid_representation_items", [])
|
|
192
|
+
or row.get("action") not in {"CREATE", "UPDATE", "MERGE"}
|
|
193
|
+
or "body" not in fields(row) or support.get("body") is not True
|
|
194
|
+
or not isinstance(decision["body"], str)):
|
|
195
|
+
raise ValueError
|
|
196
|
+
row["memory" if row["action"] == "CREATE" else "patch"]["body"] = decision["body"]
|
|
177
197
|
if "replace" in decision:
|
|
178
198
|
if i in data.get("invalid_representation_items", []) or not decision["keep"]:
|
|
179
199
|
raise ValueError
|
|
@@ -253,6 +273,9 @@ def apply_review(request, response):
|
|
|
253
273
|
if row["action"].upper() == "UPDATE" and not payload:
|
|
254
274
|
discard(row)
|
|
255
275
|
rows[i] = None
|
|
276
|
+
elif not covered(row, data["original_input"], decision.get("body_coverage")):
|
|
277
|
+
discard(row)
|
|
278
|
+
rows[i] = None
|
|
256
279
|
rows = [r for r in rows if r is not None]
|
|
257
280
|
additions = review.get("updates", [])
|
|
258
281
|
from .incremental_protocol import MAX_ITEMS
|
|
@@ -260,12 +283,24 @@ def apply_review(request, response):
|
|
|
260
283
|
raise ValueError
|
|
261
284
|
used = {row.get("target") for row in rows if isinstance(row, dict)}
|
|
262
285
|
for entry in additions:
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
286
|
+
try:
|
|
287
|
+
if (not isinstance(entry, dict) or not {"row", "field_support"} <= set(entry)
|
|
288
|
+
or set(entry) - {"row", "field_support", "body_coverage"}):
|
|
289
|
+
raise ValueError
|
|
290
|
+
row = _maintenance_update(entry["row"], entry["field_support"], data["original_input"])
|
|
291
|
+
if row["target"] in used:
|
|
292
|
+
raise ValueError
|
|
293
|
+
except (KeyError, TypeError, ValueError):
|
|
294
|
+
# Optional correction is not an authority grant. Reject it
|
|
295
|
+
# explicitly without erasing independently valid decisions.
|
|
296
|
+
rows.append({"action": "DEFERRED", "evidence": [e["ref"] for e in data["original_input"]["evidence"]
|
|
297
|
+
if e["use"] == "new"], "reason": "missing_context",
|
|
298
|
+
"need": "The additional maintenance correction is not source-verified."})
|
|
299
|
+
continue
|
|
300
|
+
if covered(row, data["original_input"], entry.get("body_coverage")):
|
|
301
|
+
rows.append(row)
|
|
302
|
+
else:
|
|
303
|
+
discard(row)
|
|
269
304
|
used.add(row["target"])
|
|
270
305
|
for rejected_row in rejected:
|
|
271
306
|
# The same review can supply a complete, independently validated
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memleaf
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.96
|
|
4
4
|
Summary: A local-first Markdown memory core for AI agents
|
|
5
5
|
Author: memleaf contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,7 +23,7 @@ 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.
|
|
26
|
+
> **版本:0.2.96。**
|
|
27
27
|
> 自动提炼和复核共用同一条“未来记忆价值”标准:模型综合未来复用、信息增量、再次读取时的直接可用性和忘记成本,只保留对未来理解、判断或行动有实质影响的最小核心;没有明确价值的信息不提炼,不按具体业务场景硬编码排除。
|
|
28
28
|
> 提炼先比较旧事项中的编号、目标、进展、责任和期限;补全未知信息也应维护原事项,另建独立待办不能替代项目事实更新。确认重复的记忆在现有处理请求中合并,保留历史与来源;项目和独立任务保持各自生命周期,Core 不按标题强行合并。
|
|
29
29
|
> 新请求兼容等价的字段表示;未知执行人保持 `null`,新增或变更负责人和期限需要真实来源;等待条件在正文维护,不再提炼 `waiting_on`。行动及相关字段经过有界语义复核,提炼与复核共用每份工作的最多五次模型请求额度,成功即停止;复核失败不写入。来源时间用于解析相对日期,不补造事实日期。
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|