Files
markitect-main/markitect/helper/knowledge.py
tegwick 69e2ec25ff feat(helper): add interactive Q&A helper command
Add `markitect helper <QUESTION>` CLI command that answers questions
about markitect using its own documentation as LLM context. Uses
OpenRouter with openrouter/aurora-alpha by default; model is
configurable via --model flag or MARKITECT_HELPER_MODEL env var.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 23:28:20 +01:00

100 lines
3.1 KiB
Python

"""
Knowledge loader for the markitect helper.
Reads markitect's own documentation files and returns them as a
concatenated string for use as LLM context.
"""
import importlib
from pathlib import Path
from typing import List
# Docs to load relative to the project root, in priority order.
_DOC_PATHS: List[str] = [
"INTRODUCTION.md",
"docs/CLI_TUTORIAL.md",
"docs/PROJECT_STRUCTURE.md",
"docs/SCHEMA_MANAGEMENT_GUIDE.md",
"docs/PLUGIN_SYSTEM.md",
"docs/ERROR_HANDLING_STRATEGY.md",
"docs/architecture/CAPABILITIES_ARCHITECTURE.md",
"docs/architecture/caching-system.md",
"docs/ASSET_MANAGEMENT_USER_GUIDE.md",
"docs/graphql_interface.md",
"examples/content-generator/TUTORIAL.md",
"examples/infospace-with-history/TUTORIAL.md",
]
# Glob patterns (relative to project root) for additional docs.
_DOC_GLOBS: List[str] = [
"docs/user-guides/*.md",
]
# Modules whose docstrings to include.
_MODULE_DOCSTRINGS: List[str] = [
"markitect.prompts",
"markitect.llm",
]
def _find_project_root() -> Path:
"""Return the markitect project root directory.
Walks up from this file (markitect/helper/knowledge.py) to find the
directory that contains ``markitect/`` as a package *and* has a
``pyproject.toml`` or ``INTRODUCTION.md``.
"""
candidate = Path(__file__).resolve().parent.parent.parent
# Verify we landed in the right place.
if (candidate / "pyproject.toml").exists() or (candidate / "INTRODUCTION.md").exists():
return candidate
# Fallback: try CWD.
cwd = Path.cwd()
if (cwd / "markitect").is_dir():
return cwd
return candidate
def collect_knowledge() -> str:
"""Load markitect documentation and return as a single string.
Reads documentation files from the project root, concatenates them
with section headers, and appends relevant module docstrings.
Missing files are silently skipped.
"""
root = _find_project_root()
sections: List[str] = []
# Fixed-path documents.
for rel_path in _DOC_PATHS:
filepath = root / rel_path
if filepath.is_file():
try:
content = filepath.read_text(encoding="utf-8")
sections.append(f"## {rel_path}\n\n{content}")
except OSError:
continue
# Glob-pattern documents.
for pattern in _DOC_GLOBS:
for filepath in sorted(root.glob(pattern)):
if filepath.is_file():
rel = filepath.relative_to(root)
try:
content = filepath.read_text(encoding="utf-8")
sections.append(f"## {rel}\n\n{content}")
except OSError:
continue
# Module docstrings.
for mod_name in _MODULE_DOCSTRINGS:
try:
mod = importlib.import_module(mod_name)
if mod.__doc__:
sections.append(f"## Module: {mod_name}\n\n{mod.__doc__.strip()}")
except ImportError:
continue
return "\n\n---\n\n".join(sections)