Files
fidelity-ai-workspace/scripts/mattermost-proxy/read-context.py

242 lines
8.3 KiB
Python
Executable File

#!/usr/bin/env python3
"""Read local Mattermost mirror evidence for agent prompts.
The proxy mirror under the active profile inbox is the preferred Mattermost
evidence source when present. This reader gives commands a stable way to load a
small focused view and fall back to the older sync artifacts when the mirror is
not available.
"""
from __future__ import annotations
import argparse
import json
import os
import shlex
import sys
from datetime import date, datetime, timedelta
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT / "scripts" / "aiw"))
import profile as aiw_profile # noqa: E402
DEFAULT_PROFILE = os.getenv("AIW_PROJECT_PROFILE", "fidelity")
MIRROR_DIR = aiw_profile.inbox_dir(DEFAULT_PROFILE, root=ROOT) / "mattermost-mirror"
LEGACY_LATEST = aiw_profile.inbox_dir(DEFAULT_PROFILE, root=ROOT) / "mattermost-latest.md"
LEGACY_GENERATED = ROOT / "scripts" / "mattermost" / "generated" / "mattermost_context.jsonl"
LOCAL_ENV = Path(__file__).resolve().parent / ".env"
def configure_profile_paths(profile: str) -> None:
global MIRROR_DIR, LEGACY_LATEST
inbox = aiw_profile.inbox_dir(profile, root=ROOT)
MIRROR_DIR = inbox / "mattermost-mirror"
LEGACY_LATEST = inbox / "mattermost-latest.md"
def load_local_env(path: Path = LOCAL_ENV) -> None:
"""Load simple KEY=VALUE pairs from the connector-local .env.
Existing process environment values win. This keeps the reusable reader
project-agnostic while allowing each workspace/profile to provide its own
channel filters without hardcoding them in Python.
"""
if not path.is_file():
return
for raw_line in path.read_text(encoding="utf-8").splitlines():
line = raw_line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
if line.startswith("export "):
line = line[len("export ") :].strip()
key, value = line.split("=", 1)
key = key.strip()
value = value.strip()
if not key or key in os.environ:
continue
try:
parsed = shlex.split(value, comments=False, posix=True)
value = parsed[0] if parsed else ""
except ValueError:
value = value.strip('"\'')
os.environ[key] = value
def previous_workday(today: date) -> date:
day = today - timedelta(days=1)
while day.weekday() >= 5:
day -= timedelta(days=1)
return day
def daily_by_date_path(day: date) -> Path:
return MIRROR_DIR / "by-date" / f"{day:%Y}" / f"{day:%m}" / f"{day:%Y-%m-%d}.jsonl"
def print_file(path: Path) -> bool:
if path.is_file() and path.stat().st_size > 0:
print(path.read_text(encoding="utf-8"))
return True
return False
def read_jsonl(path: Path) -> list[dict]:
records = []
if not path.is_file():
return records
for line in path.read_text(encoding="utf-8").splitlines():
line = line.strip()
if not line:
continue
try:
records.append(json.loads(line))
except json.JSONDecodeError:
continue
return records
def parse_channels(raw: str | None) -> set[str]:
if not raw:
env_raw = os.getenv("AIW_MATTERMOST_CONTEXT_CHANNELS", "") or os.getenv(
"AIW_MATTERMOST_PROJECT_CHANNELS", ""
)
raw = env_raw
if not raw:
return set()
return {item.strip() for item in raw.split(",") if item.strip()}
def filter_channels(records: list[dict], channels: set[str] | None) -> list[dict]:
if not channels:
return records
lowered = {channel.lower() for channel in channels}
return [
record
for record in records
if str(record.get("channel_name", "")).lower() in lowered
or str(record.get("channel_id", "")).lower() in lowered
]
def trim_records(records: list[dict], limit: int | None) -> list[dict]:
if limit is None or limit <= 0 or len(records) <= limit:
return records
return records[-limit:]
def print_jsonl(records: list[dict]) -> bool:
if not records:
return False
for record in records:
print(json.dumps(record, ensure_ascii=False, sort_keys=True))
return True
def fallback() -> None:
if print_file(LEGACY_LATEST):
return
if print_file(LEGACY_GENERATED):
return
print("No Mattermost context available.")
def mode_latest() -> None:
print("## Mattermost mirror latest context")
if print_file(MIRROR_DIR / "latest.md"):
return
records = read_jsonl(MIRROR_DIR / "latest.jsonl")
if print_jsonl(records):
return
print("No proxy mirror latest context available; checking configured sync artifacts.")
fallback()
def print_records_section(title: str, records: list[dict], limit: int | None = None) -> bool:
print(title)
records = trim_records(records, limit)
if print_jsonl(records):
return True
print("No matching Mattermost mirror records.")
return False
def mode_previous_workday(today_raw: str | None, channels: set[str] | None = None, limit: int | None = None) -> None:
today = datetime.strptime(today_raw, "%Y-%m-%d").date() if today_raw else date.today()
day = previous_workday(today)
path = daily_by_date_path(day)
records = filter_channels(read_jsonl(path), channels)
if print_records_section(f"## Mattermost mirror previous-workday context ({day.isoformat()})", records, limit):
return
if channels:
print("Filtered to project channels: " + ", ".join(sorted(channels)))
print("No proxy mirror previous-workday project context available; not falling back to broad latest context.")
def mode_standup(today_raw: str | None, channels: set[str], limit: int | None) -> None:
"""Print a compact standup-focused view.
Standup mode intentionally avoids latest.md because latest.md is a bounded
global window and can contain stale or unrelated channels. Use date-bucketed
mirror files filtered to known project channels instead.
"""
today = datetime.strptime(today_raw, "%Y-%m-%d").date() if today_raw else date.today()
day = previous_workday(today)
previous_records = filter_channels(read_jsonl(daily_by_date_path(day)), channels)
today_records = filter_channels(read_jsonl(daily_by_date_path(today)), channels)
print("## Mattermost mirror standup context")
if channels:
print("Filtered to configured context channels: " + ", ".join(sorted(channels)))
else:
print("No context channel filter configured; using all mirrored date-bucket records.")
print_records_section(f"\n### Previous workday ({day.isoformat()})", previous_records, limit)
print_records_section(f"\n### Today so far ({today.isoformat()})", today_records, limit)
def mode_focused() -> None:
records = read_jsonl(MIRROR_DIR / "latest.jsonl")
if not records:
records = read_jsonl(LEGACY_GENERATED)
if not records:
print("No Mattermost context available.")
return
manager_names = {"jeff", "jeff.dewitte"}
manager_records = [record for record in records if str(record.get("username", "")).lower() in manager_names]
focused = manager_records[-10:] if manager_records else records[-15:]
print_jsonl(focused)
def main() -> None:
load_local_env()
parser = argparse.ArgumentParser()
parser.add_argument("--profile", default=DEFAULT_PROFILE)
parser.add_argument("--mode", choices=["latest", "previous-workday", "standup", "focused"], default="latest")
parser.add_argument("--today", default="")
parser.add_argument(
"--channels",
default="",
help="Comma-separated channel names or IDs. Defaults to AIW_MATTERMOST_CONTEXT_CHANNELS from environment/.env when set.",
)
parser.add_argument("--limit", type=int, default=80, help="Max records per section; use 0 for no limit.")
args = parser.parse_args()
configure_profile_paths(args.profile)
channels = parse_channels(args.channels or None)
limit = args.limit if args.limit > 0 else None
if args.mode == "latest":
mode_latest()
elif args.mode == "previous-workday":
mode_previous_workday(args.today or None, channels=None, limit=limit)
elif args.mode == "standup":
mode_standup(args.today or None, channels, limit)
elif args.mode == "focused":
mode_focused()
if __name__ == "__main__":
main()