ReMe/reme4/steps/file_io/frontmatter_delete.py
jinliyl a4efc0f776
refactor(reme4): restructure steps packages (#258)
* fix(bm25_index): 修正BM25索引计算中的文档长度归一化问题

修复了在计算BM25相似度时对文档长度进行不正确归一化的bug,确保所有查询都能得到准确的相关性评分。

* up

* up

* up

* up

* up

* up

* up

* up

* up

* up

* up

* up

* up

* up

* up

* up

* up

* refactor(steps): Rename and adjust indexing step logic

- Rename `scan_changes.py` and `reindex.py` to `clear_and_scan.py`
- Update implementation details of `ScanChangesStep` and `ClearAndScanStep`
- Modify the scheduling mechanism in `WatchChangesStep`
- Adjust step registration and parameter configuration in config files
- Update related tests to align with the new interface changes

* up

* feat(daily): replace daily CRUD operations with slug provisioning approach

* refactor(tests): migrate CRUD step tests from HTTP server to direct LocalFileStore

* up

* up

* up

* up

---------

Co-authored-by: huangsen <huangsen.huang@alibaba-inc.com>
2026-05-28 14:30:30 +08:00

65 lines
2.3 KiB
Python

"""``frontmatter_delete_step`` — remove keys from a markdown file's frontmatter.
Returns both ``deleted`` (keys that were present and removed) and
``missing`` (keys that weren't there) so the agent can tell whether
a no-op happened. The file is rewritten only when at least one key
is actually removed — calling delete with all-missing keys is a
zero-side-effect read.
``path`` is a path relative to the vault.
"""
from pathlib import Path
import frontmatter
from ..base_step import BaseStep
from ...components import R
@R.register("frontmatter_delete_step")
class FrontmatterDeleteStep(BaseStep):
"""Remove keys from a Markdown file's frontmatter."""
async def execute(self):
assert self.context is not None
path: str = self.context.get("path") or ""
assert path, "path is required"
keys = self.context.get("keys") or []
if isinstance(keys, str):
keys = [keys]
keys = list(keys)
target = (Path(self.file_store.vault_path or ".") / path).resolve()
if not target.is_file():
payload: dict = {"path": path, "error": "not found"}
elif target.suffix != ".md":
payload = {"path": path, "error": "not markdown"}
elif not keys:
payload = {"path": path, "error": "keys is empty"}
else:
post = frontmatter.loads(target.read_text(encoding="utf-8"))
deleted: list[str] = []
missing: list[str] = []
for k in keys:
if k in post.metadata:
del post.metadata[k]
deleted.append(k)
else:
missing.append(k)
if deleted:
target.write_text(frontmatter.dumps(post), encoding="utf-8")
payload = {
"path": path,
"deleted": deleted,
"missing": missing,
"frontmatter": dict(post.metadata),
}
if "error" in payload:
self.context.response.success = False
self.context.response.answer = f"Error: {payload['error']}"
else:
self.context.response.success = True
self.context.response.answer = f"Deleted {len(payload['deleted'])} key(s) from {path}"
self.context.response.metadata.update(payload)