Dateien nach "app/core" hochladen
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 3s
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 3s
This commit is contained in:
parent
a686bdbeaf
commit
290b271cf6
|
|
@ -1,162 +1,149 @@
|
||||||
"""
|
"""
|
||||||
chunk_payload.py — mindnet core payload builders
|
chunk_payload.py
|
||||||
Version: 1.3.1 (2025-11-08)
|
Version: 1.4.2
|
||||||
|
Description:
|
||||||
|
Builds the payloads for *chunks* of a note destined for the Qdrant "chunks" collection.
|
||||||
|
- Defensive against both dict-like and attribute-like chunk objects.
|
||||||
|
- Accepts extra/legacy arguments via *args / **kwargs (e.g., vault_root, type_defaults).
|
||||||
|
- Ensures "retriever_weight" is present in every chunk payload, derived from the note.
|
||||||
|
- Preserves common chunk metadata (idx, offsets, tokens, section info, etc.).
|
||||||
|
- Tolerates legacy third positional parameter.
|
||||||
|
|
||||||
Purpose
|
Public API:
|
||||||
-------
|
make_chunk_payloads(parsed_note, chunks, *_, retriever_weight=None, vault_root=None, type_defaults=None, **__)
|
||||||
Build robust chunk payloads for Qdrant upserts.
|
|
||||||
This function is intentionally flexible about its signature to remain
|
|
||||||
compatible with different callers.
|
|
||||||
|
|
||||||
Contract
|
|
||||||
--------
|
|
||||||
make_chunk_payloads(note, chunks, *args, **kwargs) -> List[Dict[str, Any]]
|
|
||||||
|
|
||||||
Each returned item contains at least:
|
|
||||||
- note_id (str)
|
|
||||||
- title (str)
|
|
||||||
- type (str)
|
|
||||||
- path (str or None)
|
|
||||||
- tags (List[str])
|
|
||||||
- chunk_index (int)
|
|
||||||
- text (str)
|
|
||||||
- retriever_weight (float or None) # if available
|
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from pathlib import Path
|
from typing import Any, Dict, Iterable, List, Optional
|
||||||
from typing import Any, Dict, Iterable, List, Mapping, Optional, Sequence, Union
|
|
||||||
|
|
||||||
|
def _as_dict(obj: Any) -> Dict[str, Any]:
|
||||||
|
if isinstance(obj, dict):
|
||||||
|
return obj
|
||||||
|
out = {}
|
||||||
|
for key in (
|
||||||
|
"frontmatter", "fm", "meta",
|
||||||
|
"note_id", "id",
|
||||||
|
"title", "type", "tags", "aliases",
|
||||||
|
"created", "updated", "date",
|
||||||
|
"abs_path", "path", "rel_path",
|
||||||
|
):
|
||||||
|
if hasattr(obj, key):
|
||||||
|
out[key] = getattr(obj, key)
|
||||||
|
return out
|
||||||
|
|
||||||
def _get(obj: Any, key: str, default: Any = None) -> Any:
|
def _get(obj: Any, *keys: str, default: Any=None):
|
||||||
if obj is None:
|
if isinstance(obj, dict):
|
||||||
|
for k in keys:
|
||||||
|
if k in obj:
|
||||||
|
return obj[k]
|
||||||
return default
|
return default
|
||||||
if isinstance(obj, Mapping):
|
for k in keys:
|
||||||
return obj.get(key, default)
|
if hasattr(obj, k):
|
||||||
return getattr(obj, key, default)
|
return getattr(obj, k)
|
||||||
|
return default
|
||||||
|
|
||||||
|
def _as_list(val):
|
||||||
def _get_frontmatter(note: Any) -> Mapping[str, Any]:
|
if val is None:
|
||||||
fm = _get(note, "frontmatter", {})
|
|
||||||
if isinstance(fm, Mapping):
|
|
||||||
return fm
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
def _resolve_retriever_weight(explicit: Any, fm: Mapping[str, Any]) -> Optional[float]:
|
|
||||||
def to_float(v: Any) -> Optional[float]:
|
|
||||||
try:
|
|
||||||
if v is None:
|
|
||||||
return None
|
|
||||||
return float(v)
|
|
||||||
except Exception:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if explicit is not None:
|
|
||||||
return to_float(explicit)
|
|
||||||
|
|
||||||
if "retriever_weight" in fm:
|
|
||||||
return to_float(fm.get("retriever_weight"))
|
|
||||||
|
|
||||||
retr = fm.get("retriever")
|
|
||||||
if isinstance(retr, Mapping) and "weight" in retr:
|
|
||||||
return to_float(retr.get("weight"))
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def _to_rel_path(abs_path: Optional[Union[str, Path]], vault_root: Optional[Union[str, Path]]) -> Optional[str]:
|
|
||||||
if abs_path is None:
|
|
||||||
return None
|
return None
|
||||||
|
if isinstance(val, (list, tuple)):
|
||||||
|
return list(val)
|
||||||
|
if isinstance(val, str):
|
||||||
|
return [val]
|
||||||
try:
|
try:
|
||||||
p = Path(abs_path)
|
return list(val)
|
||||||
if vault_root:
|
|
||||||
try:
|
|
||||||
rp = p.relative_to(Path(vault_root))
|
|
||||||
return str(rp)
|
|
||||||
except Exception:
|
|
||||||
return str(p)
|
|
||||||
return str(p)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
return str(abs_path)
|
return [val]
|
||||||
|
|
||||||
|
def _coerce_float(val: Any, default: float) -> float:
|
||||||
def _coerce_chunks(chunks_obj: Any) -> List[Any]:
|
if val is None:
|
||||||
"""Accept lists of dicts/objects or generators; coerce to list safely."""
|
return float(default)
|
||||||
if chunks_obj is None:
|
|
||||||
return []
|
|
||||||
if isinstance(chunks_obj, list):
|
|
||||||
return chunks_obj
|
|
||||||
try:
|
try:
|
||||||
return list(chunks_obj)
|
return float(val)
|
||||||
except Exception:
|
except Exception:
|
||||||
return []
|
return float(default)
|
||||||
|
|
||||||
|
|
||||||
def _get_chunk_text(c: Any) -> str:
|
|
||||||
for key in ("text", "chunk", "body", "content"):
|
|
||||||
v = _get(c, key)
|
|
||||||
if isinstance(v, str) and v.strip():
|
|
||||||
return v
|
|
||||||
# last resort: string repr
|
|
||||||
return str(c) if c is not None else ""
|
|
||||||
|
|
||||||
|
def _clean(d: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
return {k: v for k, v in d.items() if v is not None}
|
||||||
|
|
||||||
def make_chunk_payloads(
|
def make_chunk_payloads(
|
||||||
*args: Any,
|
parsed_note: Any,
|
||||||
**kwargs: Any,
|
chunks: Iterable[Any],
|
||||||
|
*_, # legacy extra positional parameters tolerated
|
||||||
|
retriever_weight: Optional[float] = None,
|
||||||
|
vault_root: Optional[str] = None,
|
||||||
|
type_defaults: Optional[Dict[str, Dict[str, Any]]] = None,
|
||||||
|
**__, # ignore unexpected kwargs
|
||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""
|
nd = _as_dict(parsed_note)
|
||||||
Flexible signature for backward/forward compatibility.
|
fm = _get(nd, "frontmatter", "fm", "meta", default={}) or {}
|
||||||
Expected positional args:
|
|
||||||
args[0] -> note (ParsedNote or Mapping)
|
|
||||||
args[1] -> chunks (Iterable)
|
|
||||||
args[2] -> (optional) config/ignored
|
|
||||||
Recognized kwargs:
|
|
||||||
- vault_root: base path for relative paths (optional)
|
|
||||||
- retriever_weight: explicit override (optional)
|
|
||||||
"""
|
|
||||||
if not args:
|
|
||||||
raise TypeError("make_chunk_payloads(note, chunks, *_) requires at least (note, chunks).")
|
|
||||||
|
|
||||||
note = args[0]
|
note_id = _get(nd, "note_id", "id") or fm.get("id")
|
||||||
chunks = args[1] if len(args) > 1 else kwargs.get("chunks")
|
title = _get(nd, "title") or fm.get("title")
|
||||||
chunks_list = _coerce_chunks(chunks)
|
ntype = _get(nd, "type") or fm.get("type") or "concept"
|
||||||
|
|
||||||
vault_root = kwargs.get("vault_root")
|
# Effective path for source reference
|
||||||
explicit_weight = kwargs.get("retriever_weight")
|
abs_path = _get(nd, "abs_path", "path")
|
||||||
|
rel_path = _get(nd, "rel_path")
|
||||||
|
if vault_root and abs_path and not rel_path:
|
||||||
|
try:
|
||||||
|
from pathlib import Path
|
||||||
|
rel_path = str(Path(abs_path).resolve().relative_to(Path(vault_root).resolve()))
|
||||||
|
except Exception:
|
||||||
|
rel_path = _get(nd, "path") or abs_path
|
||||||
|
|
||||||
fm = _get_frontmatter(note)
|
# Effective chunk_profile
|
||||||
|
chunk_profile = fm.get("chunk_profile")
|
||||||
|
if not chunk_profile and type_defaults and ntype in type_defaults:
|
||||||
|
chunk_profile = type_defaults[ntype].get("chunk_profile")
|
||||||
|
|
||||||
note_id = _get(note, "note_id") or _get(note, "id") or fm.get("id")
|
# Resolve retriever_weight once at note level, apply to all chunks
|
||||||
title = _get(note, "title") or fm.get("title")
|
if retriever_weight is None:
|
||||||
ntype = _get(note, "type") or fm.get("type")
|
retriever_weight = (
|
||||||
tags = _get(note, "tags") or fm.get("tags") or []
|
fm.get("retriever_weight")
|
||||||
if not isinstance(tags, list):
|
or (fm.get("retriever", {}) or {}).get("weight")
|
||||||
tags = list(tags) if tags else []
|
|
||||||
|
|
||||||
path_val = _get(note, "path") or _get(note, "abs_path") or fm.get("path")
|
|
||||||
rweight = _resolve_retriever_weight(explicit_weight, fm)
|
|
||||||
|
|
||||||
base = {
|
|
||||||
"note_id": note_id,
|
|
||||||
"title": title,
|
|
||||||
"type": ntype,
|
|
||||||
"tags": tags,
|
|
||||||
"path": _to_rel_path(path_val, vault_root),
|
|
||||||
"retriever_weight": rweight,
|
|
||||||
}
|
|
||||||
|
|
||||||
payloads: List[Dict[str, Any]] = []
|
|
||||||
for idx, ch in enumerate(chunks_list):
|
|
||||||
text = _get_chunk_text(ch)
|
|
||||||
item = dict(base)
|
|
||||||
item.update(
|
|
||||||
{
|
|
||||||
"chunk_index": idx,
|
|
||||||
"text": text,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
payloads.append(item)
|
if retriever_weight is None and type_defaults and ntype in type_defaults:
|
||||||
|
retriever_weight = type_defaults[ntype].get("retriever_weight")
|
||||||
|
|
||||||
return payloads
|
retriever_weight = _coerce_float(retriever_weight, default=1.0)
|
||||||
|
|
||||||
|
out: List[Dict[str, Any]] = []
|
||||||
|
for i, ch in enumerate(chunks):
|
||||||
|
cd = ch if isinstance(ch, dict) else {}
|
||||||
|
# Basic fields with many aliases
|
||||||
|
chunk_id = _get(ch, "chunk_id", "id", default=None)
|
||||||
|
idx = _get(ch, "idx", "index", default=i)
|
||||||
|
text = _get(ch, "text", "content", "body", "chunk_text", default=None)
|
||||||
|
char_start = _get(ch, "char_start", "start", "begin", default=None)
|
||||||
|
char_end = _get(ch, "char_end", "end", "stop", default=None)
|
||||||
|
token_count = _get(ch, "token_count", "tokens", "n_tokens", default=None)
|
||||||
|
section = _get(ch, "section", "heading", default=None)
|
||||||
|
section_path = _get(ch, "section_path", "hpath", default=None)
|
||||||
|
|
||||||
|
payload = _clean({
|
||||||
|
"note_id": note_id,
|
||||||
|
"title": title,
|
||||||
|
"type": ntype,
|
||||||
|
"path": rel_path or abs_path,
|
||||||
|
"chunk_profile": chunk_profile,
|
||||||
|
"retriever_weight": retriever_weight,
|
||||||
|
|
||||||
|
"chunk_id": chunk_id or (f"{note_id}#ch{idx}" if note_id is not None else None),
|
||||||
|
"chunk_index": idx,
|
||||||
|
"text": text,
|
||||||
|
"char_start": char_start,
|
||||||
|
"char_end": char_end,
|
||||||
|
"token_count": token_count,
|
||||||
|
"section": section,
|
||||||
|
"section_path": section_path,
|
||||||
|
})
|
||||||
|
|
||||||
|
# If the chunk object carries an existing mapping of extra metadata, preserve it.
|
||||||
|
if isinstance(ch, dict):
|
||||||
|
# Avoid overwriting the fields we already normalized
|
||||||
|
extras = {k: v for k, v in ch.items() if k not in payload and v is not None}
|
||||||
|
if extras:
|
||||||
|
payload.update(extras)
|
||||||
|
|
||||||
|
out.append(payload)
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
|
||||||
|
|
@ -1,139 +1,133 @@
|
||||||
"""
|
"""
|
||||||
note_payload.py — mindnet core payload builders
|
note_payload.py
|
||||||
Version: 1.3.1 (2025-11-08)
|
Version: 1.4.2
|
||||||
|
Description:
|
||||||
|
Builds the payload for a *note* document destined for the Qdrant "notes" collection.
|
||||||
|
- Defensive against both dict-like and attribute-like "ParsedNote" inputs.
|
||||||
|
- Accepts extra/legacy arguments via *args / **kwargs (e.g., vault_root, type_defaults).
|
||||||
|
- Ensures "retriever_weight" is always present in the payload (float), resolved as:
|
||||||
|
kwarg retriever_weight > frontmatter.retriever_weight > frontmatter.retriever.weight >
|
||||||
|
type_defaults[type].retriever_weight > 1.0
|
||||||
|
- Preserves common metadata fields expected downstream.
|
||||||
|
|
||||||
Purpose
|
Public API:
|
||||||
-------
|
make_note_payload(parsed_note, *_, retriever_weight=None, vault_root=None, type_defaults=None, **__)
|
||||||
Build a robust, forward-compatible note payload for Qdrant upserts.
|
|
||||||
This module is intentionally defensive:
|
|
||||||
- Accepts both dict-like "parsed note" objects and dataclass/objects with attributes.
|
|
||||||
- Tolerates extra kwargs from different callers (e.g., `vault_root`, `prefix`, etc.).
|
|
||||||
- Ensures `retriever_weight` is resolved and present in the payload if available.
|
|
||||||
|
|
||||||
Contract
|
|
||||||
--------
|
|
||||||
make_note_payload(note, **kwargs) -> Dict[str, Any]
|
|
||||||
|
|
||||||
Expected minimal fields in returned payload:
|
|
||||||
- note_id (str)
|
|
||||||
- title (str)
|
|
||||||
- type (str)
|
|
||||||
- path (str or None) # relative to vault_root when provided
|
|
||||||
- tags (List[str])
|
|
||||||
- retriever_weight (float or None) # if available
|
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from pathlib import Path
|
from typing import Any, Dict, Optional
|
||||||
from typing import Any, Dict, Iterable, List, Mapping, Optional, Union
|
|
||||||
|
|
||||||
|
def _as_dict(obj: Any) -> Dict[str, Any]:
|
||||||
|
if isinstance(obj, dict):
|
||||||
|
return obj
|
||||||
|
# Try common attribute names to build a dict view
|
||||||
|
out = {}
|
||||||
|
for key in (
|
||||||
|
"frontmatter", "fm", "meta",
|
||||||
|
"note_id", "id",
|
||||||
|
"title", "type", "tags", "aliases",
|
||||||
|
"created", "updated", "date",
|
||||||
|
"abs_path", "path", "rel_path",
|
||||||
|
):
|
||||||
|
if hasattr(obj, key):
|
||||||
|
out[key] = getattr(obj, key)
|
||||||
|
return out
|
||||||
|
|
||||||
def _get(obj: Any, key: str, default: Any = None) -> Any:
|
def _get(obj: Any, *keys: str, default: Any=None):
|
||||||
"""Try to read `key` from mapping or attribute; else default."""
|
"""Get first existing key/attribute from obj."""
|
||||||
if obj is None:
|
if isinstance(obj, dict):
|
||||||
|
for k in keys:
|
||||||
|
if k in obj:
|
||||||
|
return obj[k]
|
||||||
return default
|
return default
|
||||||
if isinstance(obj, Mapping):
|
|
||||||
return obj.get(key, default)
|
|
||||||
# attribute access
|
# attribute access
|
||||||
return getattr(obj, key, default)
|
for k in keys:
|
||||||
|
if hasattr(obj, k):
|
||||||
|
return getattr(obj, k)
|
||||||
|
return default
|
||||||
|
|
||||||
|
def _as_list(val):
|
||||||
def _get_frontmatter(note: Any) -> Mapping[str, Any]:
|
if val is None:
|
||||||
fm = _get(note, "frontmatter", {})
|
|
||||||
if isinstance(fm, Mapping):
|
|
||||||
return fm
|
|
||||||
return {} # be safe
|
|
||||||
|
|
||||||
|
|
||||||
def _resolve_retriever_weight(explicit: Any, fm: Mapping[str, Any]) -> Optional[float]:
|
|
||||||
"""
|
|
||||||
Priority:
|
|
||||||
1) explicit kwarg retriever_weight
|
|
||||||
2) frontmatter['retriever_weight']
|
|
||||||
3) frontmatter['retriever']['weight']
|
|
||||||
"""
|
|
||||||
def to_float(v: Any) -> Optional[float]:
|
|
||||||
try:
|
|
||||||
if v is None:
|
|
||||||
return None
|
|
||||||
return float(v)
|
|
||||||
except Exception:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if explicit is not None:
|
|
||||||
return to_float(explicit)
|
|
||||||
|
|
||||||
if "retriever_weight" in fm:
|
|
||||||
return to_float(fm.get("retriever_weight"))
|
|
||||||
|
|
||||||
retr = fm.get("retriever")
|
|
||||||
if isinstance(retr, Mapping) and "weight" in retr:
|
|
||||||
return to_float(retr.get("weight"))
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def _to_rel_path(abs_path: Optional[Union[str, Path]], vault_root: Optional[Union[str, Path]]) -> Optional[str]:
|
|
||||||
if abs_path is None:
|
|
||||||
return None
|
return None
|
||||||
|
if isinstance(val, (list, tuple)):
|
||||||
|
return list(val)
|
||||||
|
if isinstance(val, str):
|
||||||
|
return [val]
|
||||||
try:
|
try:
|
||||||
p = Path(abs_path)
|
return list(val) # best-effort
|
||||||
if vault_root:
|
|
||||||
try:
|
|
||||||
rp = p.relative_to(Path(vault_root))
|
|
||||||
return str(rp)
|
|
||||||
except Exception:
|
|
||||||
return str(p)
|
|
||||||
return str(p)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
return str(abs_path)
|
return [val]
|
||||||
|
|
||||||
|
def _coerce_float(val: Any, default: float) -> float:
|
||||||
|
if val is None:
|
||||||
|
return float(default)
|
||||||
|
try:
|
||||||
|
return float(val)
|
||||||
|
except Exception:
|
||||||
|
return float(default)
|
||||||
|
|
||||||
|
def _clean(d: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
return {k: v for k, v in d.items() if v is not None}
|
||||||
|
|
||||||
def make_note_payload(
|
def make_note_payload(
|
||||||
note: Any,
|
parsed_note: Any,
|
||||||
*args, # tolerate older/other callers
|
*_, # ignore legacy extra positional args for backward compatibility
|
||||||
**kwargs: Any,
|
retriever_weight: Optional[float] = None,
|
||||||
|
vault_root: Optional[str] = None,
|
||||||
|
type_defaults: Optional[Dict[str, Dict[str, Any]]] = None,
|
||||||
|
**__, # ignore any unexpected kwargs
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""
|
nd = _as_dict(parsed_note)
|
||||||
Build a normalized note payload for Qdrant.
|
fm = _get(nd, "frontmatter", "fm", "meta", default={}) or {}
|
||||||
Unknown kwargs are ignored to keep the function forward-compatible.
|
|
||||||
|
|
||||||
Recognized kwargs:
|
note_id = _get(nd, "note_id", "id") or fm.get("id")
|
||||||
- vault_root: base path to make `path` relative (optional)
|
title = _get(nd, "title") or fm.get("title")
|
||||||
- retriever_weight: explicit override (optional)
|
ntype = _get(nd, "type") or fm.get("type") or "concept"
|
||||||
"""
|
|
||||||
vault_root = kwargs.get("vault_root")
|
|
||||||
explicit_weight = kwargs.get("retriever_weight")
|
|
||||||
|
|
||||||
fm = _get_frontmatter(note)
|
# Path handling
|
||||||
|
abs_path = _get(nd, "abs_path", "path")
|
||||||
|
rel_path = _get(nd, "rel_path")
|
||||||
|
if vault_root and abs_path and not rel_path:
|
||||||
|
try:
|
||||||
|
from pathlib import Path
|
||||||
|
rel_path = str(Path(abs_path).resolve().relative_to(Path(vault_root).resolve()))
|
||||||
|
except Exception:
|
||||||
|
rel_path = _get(nd, "path") or abs_path
|
||||||
|
|
||||||
note_id = _get(note, "note_id") or _get(note, "id")
|
# Tags / aliases
|
||||||
if not note_id:
|
tags = _as_list(_get(nd, "tags") or fm.get("tags"))
|
||||||
# Try from frontmatter
|
aliases = _as_list(_get(nd, "aliases") or fm.get("aliases"))
|
||||||
note_id = fm.get("id")
|
|
||||||
|
|
||||||
title = _get(note, "title") or fm.get("title")
|
# Created/Updated
|
||||||
ntype = _get(note, "type") or fm.get("type")
|
created = _get(nd, "created", "date") or fm.get("created") or fm.get("date")
|
||||||
|
updated = _get(nd, "updated") or fm.get("updated")
|
||||||
|
|
||||||
tags = _get(note, "tags") or fm.get("tags") or []
|
# Chunk profile (effective)
|
||||||
if not isinstance(tags, list):
|
chunk_profile = fm.get("chunk_profile")
|
||||||
tags = list(tags) if tags else []
|
if not chunk_profile and type_defaults and ntype in type_defaults:
|
||||||
|
chunk_profile = type_defaults[ntype].get("chunk_profile")
|
||||||
|
|
||||||
path_val = _get(note, "path") or _get(note, "abs_path") or fm.get("path")
|
# Retriever weight resolution (ensures it is present)
|
||||||
|
if retriever_weight is None:
|
||||||
|
retriever_weight = (
|
||||||
|
fm.get("retriever_weight")
|
||||||
|
or (fm.get("retriever", {}) or {}).get("weight")
|
||||||
|
)
|
||||||
|
if retriever_weight is None and type_defaults and ntype in type_defaults:
|
||||||
|
retriever_weight = type_defaults[ntype].get("retriever_weight")
|
||||||
|
|
||||||
payload: Dict[str, Any] = {
|
retriever_weight = _coerce_float(retriever_weight, default=1.0)
|
||||||
|
|
||||||
|
payload = _clean({
|
||||||
"note_id": note_id,
|
"note_id": note_id,
|
||||||
|
"id": note_id, # keep both, many downstream tools expect 'id'
|
||||||
"title": title,
|
"title": title,
|
||||||
"type": ntype,
|
"type": ntype,
|
||||||
"tags": tags,
|
"tags": tags,
|
||||||
"path": _to_rel_path(path_val, vault_root),
|
"aliases": aliases,
|
||||||
"retriever_weight": _resolve_retriever_weight(explicit_weight, fm),
|
"created": created,
|
||||||
}
|
"updated": updated,
|
||||||
|
"path": rel_path or abs_path,
|
||||||
# Also surface explicit frontmatter fields (non-conflicting) if present
|
"chunk_profile": chunk_profile,
|
||||||
for k in ("status", "created", "updated"):
|
"retriever_weight": retriever_weight,
|
||||||
v = fm.get(k)
|
})
|
||||||
if v is not None and k not in payload:
|
|
||||||
payload[k] = v
|
|
||||||
|
|
||||||
return payload
|
return payload
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user