mirror of
https://github.com/agentscope-ai/ReMe.git
synced 2026-10-03 02:24:31 +00:00
* feat: rename working_dir to vault_dir and update documentation - Rename working_dir to vault_dir across the application - Update documentation to reflect vault_dir instead of working_dir - Change FileFrontMatter title field to name field - Update .gitignore to include vault directory - Modify file path descriptions to reference vault instead of working_dir - Update related configuration and property names accordingly * refactor(steps): rename working_path to vault_path in CRUD operations - Rename parameter from `working_path` to `vault_path` in `resolve_path` function - Update all usages in append, edit, read, and write steps to use `self.vault_path` - Update documentation comments to reflect the new parameter name - Update docstring in read.py to mention `vault_dir` instead of `vault` test(chunked_file_parser): update frontmatter field from title to name - Change frontmatter field from `title` to `name` in test cases - Update comment in background steps test to reference `vault_path` instead of `working_path` * refactor(schema): remove unused ResourceEntry import * feat(file_graph): add link scope filtering to get_inlinks/get_outlinks * feat(file-store): add scope parameter to link methods
91 lines
3 KiB
Python
91 lines
3 KiB
Python
"""Read a markdown file from vault_dir, with line-range slicing and byte-truncation."""
|
|
|
|
from ._file_io import (
|
|
NON_MD_WARNING,
|
|
gate_md,
|
|
resolve_path,
|
|
read_file_safe,
|
|
truncate_text_output,
|
|
)
|
|
from ..base_step import BaseStep
|
|
from ...components import R
|
|
|
|
|
|
@R.register("read_step")
|
|
class ReadStep(BaseStep):
|
|
"""Read a markdown file. Optional `start_line`/`end_line` for ranged reads."""
|
|
|
|
def _fail(self, message: str, **meta) -> None:
|
|
assert self.context is not None
|
|
self.context.response.success = False
|
|
self.context.response.answer = f"Error: {message}"
|
|
if meta:
|
|
self.context.response.metadata.update(meta)
|
|
|
|
async def execute(self): # pylint: disable=too-many-return-statements
|
|
assert self.context is not None
|
|
raw = str(self.context.get("path") or "")
|
|
start_line = self.context.get("start_line")
|
|
end_line = self.context.get("end_line")
|
|
|
|
target, err = resolve_path(self.vault_path, raw)
|
|
if err:
|
|
self._fail(err)
|
|
return None
|
|
|
|
target, is_md = gate_md(target)
|
|
if not is_md:
|
|
self.logger.info(f"[{self.name}] {NON_MD_WARNING} path={target}")
|
|
|
|
for label, value in (("start_line", start_line), ("end_line", end_line)):
|
|
if value is None:
|
|
continue
|
|
try:
|
|
int(value)
|
|
except (TypeError, ValueError):
|
|
self._fail(f"{label} must be an integer, got {value!r}")
|
|
return None
|
|
|
|
if not target.exists():
|
|
self._fail(f"file {target} does not exist", path=str(target))
|
|
return None
|
|
if not target.is_file():
|
|
self._fail(f"path {target} is not a file", path=str(target))
|
|
return None
|
|
|
|
try:
|
|
content = await read_file_safe(target)
|
|
except Exception as e:
|
|
self._fail(f"read failed: {e}", path=str(target))
|
|
return None
|
|
|
|
all_lines = content.split("\n")
|
|
total = len(all_lines)
|
|
s = max(1, int(start_line) if start_line is not None else 1)
|
|
e = min(total, int(end_line) if end_line is not None else total)
|
|
|
|
if s > total:
|
|
self._fail(
|
|
f"start_line {s} exceeds file length ({total} lines)",
|
|
path=str(target),
|
|
total_lines=total,
|
|
)
|
|
return None
|
|
if s > e:
|
|
self._fail(f"start_line ({s}) > end_line ({e})", path=str(target))
|
|
return None
|
|
|
|
selected = "\n".join(all_lines[s - 1 : e])
|
|
text = truncate_text_output(
|
|
selected,
|
|
start_line=s,
|
|
total_lines=total,
|
|
file_path=str(target),
|
|
)
|
|
|
|
self.context.response.success = True
|
|
self.context.response.answer = text
|
|
self.logger.info(
|
|
f"[{self.name}] read path={target} lines={s}-{e}/{total} bytes={len(text.encode('utf-8'))}",
|
|
)
|
|
return self.context.response
|