mirror of
https://github.com/agentscope-ai/ReMe.git
synced 2026-09-23 00:43:18 +00:00
- Add file_graph import to component registry - Register FILE_GRAPH enum in ComponentEnum - Implement BaseFileGraph integration in LinkedFileParser - Replace FileEdge with FileLink for better semantic clarity - Add lazy resolution of file_graph from app_context - Update file watcher logging to reflect links instead of edges refactor: streamline MCP transport layer architecture - Remove redundant step shells from reme2/mcp/steps/ - Consolidate all @R.register components to reme2.memory package - Update server.py to import reme2.memory directly - Revise README.md to document new architecture - Simplify module dependencies and import structure
73 lines
2.7 KiB
Python
73 lines
2.7 KiB
Python
"""memory_lint — read-only projection of the Maintainer's lint findings.
|
|
|
|
Tier A surface for the Maintainer service. The host agent calls this
|
|
to discover what's wrong with the vault (broken wikilinks, schema
|
|
violations, stem collisions) and decides what to do with each finding
|
|
using the existing memory_* write primitives.
|
|
|
|
Equivalent to invoking `Maintainer.execute(ops=["lint"], dry_run=True)`
|
|
but with a focused response shape and a tighter parameter surface — the
|
|
agent doesn't need to know about decay/merge/split knobs.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from ..component import R
|
|
from ..component.base_step import BaseStep
|
|
from ..component.runtime_response import _set_answer
|
|
from ..enumeration import ComponentEnum
|
|
|
|
|
|
@R.register("memory_lint")
|
|
class MemoryLint(BaseStep):
|
|
"""Run the Maintainer's lint pass and surface findings only.
|
|
|
|
Inputs (RuntimeContext, all optional):
|
|
target_prefix (str): restrict scan to relpaths starting with
|
|
this prefix (e.g. "events/2026-05-09/").
|
|
|
|
Output (context.response.answer):
|
|
{
|
|
"scanned": int, # files inspected
|
|
"findings": [LintFinding, ...], # each {path, kind, detail}
|
|
"target_prefix": str,
|
|
"ran_at": iso,
|
|
}
|
|
"""
|
|
|
|
async def execute(self):
|
|
assert self.context is not None
|
|
target_prefix = str(self.context.get("target_prefix") or "")
|
|
|
|
# Delegate to a Maintainer step. Force ops=["lint"] + dry_run so
|
|
# we never mutate. The Maintainer reads these from the context
|
|
# and produces a full audit; we narrow the response shape below.
|
|
if getattr(self, "_maintainer", None) is None:
|
|
self._maintainer = R.get(ComponentEnum.STEP, "maintainer")(
|
|
app_context=self.app_context,
|
|
)
|
|
self.context["ops"] = ["lint"]
|
|
self.context["dry_run"] = True
|
|
self.context["target_prefix"] = target_prefix
|
|
await self._maintainer(self.context)
|
|
|
|
# The Maintainer wrote a full audit to context.response.answer
|
|
# (proposed/plan/applied/skipped/failed/...). For lint, all the
|
|
# action lives in `proposed` (LintFindings never get applied or
|
|
# dropped). Reshape into a focused response.
|
|
import json
|
|
|
|
raw = self.context.response.answer
|
|
audit = json.loads(raw) if isinstance(raw, str) else (raw or {})
|
|
findings = audit.get("proposed") or []
|
|
|
|
_set_answer(
|
|
self.context,
|
|
{
|
|
"scanned": audit.get("scanned", 0),
|
|
"findings": findings,
|
|
"target_prefix": target_prefix,
|
|
"ran_at": audit.get("ran_at", ""),
|
|
},
|
|
)
|
|
self.context.response.success = True
|