feat(memory): resolve paths in context reads
This commit is contained in:
@@ -9765,12 +9765,11 @@ def classify_memory_query(args):
|
|||||||
|
|
||||||
|
|
||||||
def get_memory_context(args):
|
def get_memory_context(args):
|
||||||
if args.get("path") or args.get("paths"):
|
|
||||||
raise RuntimeError("paths are index/routes only; resolve them with nap_node_by_path, then use node_id/uri inputs")
|
|
||||||
raw_node_ids = args.get("node_ids") or ([args["node_id"]] if args.get("node_id") else [])
|
raw_node_ids = args.get("node_ids") or ([args["node_id"]] if args.get("node_id") else [])
|
||||||
raw_uris = args.get("uris") or ([args["uri"]] if args.get("uri") else [])
|
raw_uris = args.get("uris") or ([args["uri"]] if args.get("uri") else [])
|
||||||
if not raw_node_ids and not raw_uris:
|
raw_paths = args.get("paths") or ([args["path"]] if args.get("path") else [])
|
||||||
raise RuntimeError("node_id, node_ids, uri, or uris is required")
|
if not raw_node_ids and not raw_uris and not raw_paths:
|
||||||
|
raise RuntimeError("path, paths, node_id, node_ids, uri, or uris is required")
|
||||||
max_nodes = max(1, min(int(args.get("max_nodes", 20)), 100))
|
max_nodes = max(1, min(int(args.get("max_nodes", 20)), 100))
|
||||||
depth = max(0, min(int(args.get("depth", 1)), 2))
|
depth = max(0, min(int(args.get("depth", 1)), 2))
|
||||||
default_view = "summary"
|
default_view = "summary"
|
||||||
@@ -9780,6 +9779,8 @@ def get_memory_context(args):
|
|||||||
queue.append(("node", get_node_by_id({"node_id": node_id})))
|
queue.append(("node", get_node_by_id({"node_id": node_id})))
|
||||||
for uri in raw_uris:
|
for uri in raw_uris:
|
||||||
queue.append(("node", node_by_uri({"uri": uri})["node"]))
|
queue.append(("node", node_by_uri({"uri": uri})["node"]))
|
||||||
|
for path in raw_paths:
|
||||||
|
queue.append(("path", normalize_node_path(path)))
|
||||||
nodes = []
|
nodes = []
|
||||||
edges = []
|
edges = []
|
||||||
seen_paths = set()
|
seen_paths = set()
|
||||||
@@ -11562,10 +11563,12 @@ def raw_tools():
|
|||||||
*kanban_workflow_tool_schemas(),
|
*kanban_workflow_tool_schemas(),
|
||||||
{
|
{
|
||||||
"name": "nap_context",
|
"name": "nap_context",
|
||||||
"description": "Fetch one or more nodes plus bounded outgoing links and backlinks for surrounding context.",
|
"description": "Resolve one or more paths, node IDs, or nap:// URIs and fetch bounded outgoing links and backlinks in one call.",
|
||||||
"inputSchema": {
|
"inputSchema": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"path": {"type": "string", "description": "Readable route to resolve internally; canonical identity is returned in the result."},
|
||||||
|
"paths": {"type": "array", "items": {"type": "string"}},
|
||||||
"node_id": {"type": "string"},
|
"node_id": {"type": "string"},
|
||||||
"node_ids": {"type": "array", "items": {"type": "string"}},
|
"node_ids": {"type": "array", "items": {"type": "string"}},
|
||||||
"uri": {"type": "string"},
|
"uri": {"type": "string"},
|
||||||
|
|||||||
@@ -329,8 +329,8 @@ def test_tools_include_node_by_path_descriptor(mod):
|
|||||||
assert "node_ids" in context_schema["properties"]
|
assert "node_ids" in context_schema["properties"]
|
||||||
assert "uri" in context_schema["properties"]
|
assert "uri" in context_schema["properties"]
|
||||||
assert "uris" in context_schema["properties"]
|
assert "uris" in context_schema["properties"]
|
||||||
assert "path" not in context_schema["properties"]
|
assert "path" in context_schema["properties"]
|
||||||
assert "paths" not in context_schema["properties"]
|
assert "paths" in context_schema["properties"]
|
||||||
|
|
||||||
related_schema = next(item for item in mod.tools() if item["name"] == "nap_find_related")["inputSchema"]
|
related_schema = next(item for item in mod.tools() if item["name"] == "nap_find_related")["inputSchema"]
|
||||||
assert "node_id" in related_schema["properties"]
|
assert "node_id" in related_schema["properties"]
|
||||||
@@ -599,6 +599,8 @@ def test_context_and_related_use_identity_inputs(mod):
|
|||||||
raise AssertionError(f"unexpected node_id {node_id}")
|
raise AssertionError(f"unexpected node_id {node_id}")
|
||||||
|
|
||||||
def fake_read_by_path(args, allow_agent=False):
|
def fake_read_by_path(args, allow_agent=False):
|
||||||
|
if args["path"] == "/notes/root":
|
||||||
|
return root
|
||||||
if args["path"] == "/notes/linked":
|
if args["path"] == "/notes/linked":
|
||||||
return linked
|
return linked
|
||||||
if args["path"] == "/notes/backlink":
|
if args["path"] == "/notes/backlink":
|
||||||
@@ -627,8 +629,8 @@ def test_context_and_related_use_identity_inputs(mod):
|
|||||||
assert related["target"]["full_path"] == "/notes/root"
|
assert related["target"]["full_path"] == "/notes/root"
|
||||||
assert {item["full_path"] for item in related["items"]} >= {"/notes/backlink", "/notes/linked"}
|
assert {item["full_path"] for item in related["items"]} >= {"/notes/backlink", "/notes/linked"}
|
||||||
|
|
||||||
with pytest.raises(RuntimeError, match="paths are index/routes only"):
|
path_context = mod.get_memory_context({"path": "/notes/root", "depth": 0, "view": "paths"})
|
||||||
mod.get_memory_context({"path": "/notes/root"})
|
assert [item["full_path"] for item in path_context["items"]] == ["/notes/root"]
|
||||||
with pytest.raises(RuntimeError, match="path is an index/route only"):
|
with pytest.raises(RuntimeError, match="path is an index/route only"):
|
||||||
mod.find_related_nodes({"path": "/notes/root"})
|
mod.find_related_nodes({"path": "/notes/root"})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user