"""Ad-hoc diagnostic: render the system prompt and inspect its JSON skeleton.
Builds a minimal :class:`PromptContextBuilder` context for a hard-coded test
message and channel, renders ``system_prompt.j2`` with
:class:`PromptRenderer`, then parses the rendered output as JSON and prints
the top-level structure (verifying the ``ROOT`` key is present and well
formed). Run directly (``python check_skeleton_remote.py``) to debug template
rendering or JSON-validity regressions in the prompt skeleton.
"""
import os
import sys
import json
import asyncio
import logging
from unittest.mock import MagicMock
sys.path.append("/root/stargazer-v3")
from prompt_context import PromptContextBuilder
from prompt_renderer import PromptRenderer
from platforms.base import IncomingMessage
from config import Config
[docs]
async def main():
"""Render the system prompt for a fixed test message and dump its JSON shape.
The async entry point for this diagnostic. It loads ``Config``, fabricates a
hard-coded ``IncomingMessage`` and a ``MagicMock`` platform, builds the prompt
context via :class:`PromptContextBuilder`, then sanitizes that context so it
will serialize: any ``MagicMock`` values are blanked, a couple of required
fields (``hosting_provider``, ``current_time``) are pinned to deterministic
test values, and the SWORD overlay variables are popped so the raw skeleton is
rendered. It then renders ``system_prompt.j2`` with :class:`PromptRenderer`,
parses the result with ``json.loads``, and prints the top-level keys plus the
structure under ``ROOT`` (or the rendered prefix when ``ROOT`` is missing). On
any render/parse failure it prints the exception and the sorted context keys
to aid debugging. Side effects are limited to building context (which may read
config/Redis-backed state) and writing to stdout. Invoked only from this
module's ``__main__`` block via :func:`asyncio.run`.
"""
cfg = Config.load()
msg = IncomingMessage(
platform="discord",
channel_id="1424991476668170351",
user_id="user1",
user_name="user1",
text="hello",
is_addressed=True
)
builder = PromptContextBuilder(cfg)
platform = MagicMock()
platform.name = "discord"
platform.bot_identity = {"platform": "discord", "user_id": "bot123", "display_name": "Stargazer"}
ctx = await builder.build(msg, platform)
# Clean/mock context to avoid Jinja undefined/MagicMock serialization issues
for k, v in list(ctx.items()):
if isinstance(v, MagicMock):
ctx[k] = ""
# Explicitly set required fields to avoid undefined errors
ctx["hosting_provider"] = "test-provider"
ctx["current_time"] = "2026-05-29T14:10:00Z"
# Remove overlay variables so we get raw skeleton
ctx.pop("_sword_pseudo_origins", None)
ctx.pop("_sword_overlay_active", None)
renderer = PromptRenderer("/root/stargazer-v3/system_prompt.j2")
try:
prompt = renderer.render(ctx)
parsed = json.loads(prompt)
print("Parsed JSON type:", type(parsed))
print("Top-level keys:", list(parsed.keys()))
if "ROOT" in parsed:
print("ROOT type:", type(parsed["ROOT"]))
if isinstance(parsed["ROOT"], list):
print("ROOT list len:", len(parsed["ROOT"]))
for item in parsed["ROOT"]:
if isinstance(item, dict):
print(" Item keys:", list(item.keys()))
else:
print("ROOT NOT FOUND in parsed JSON!")
print("Rendered prompt start:")
print(prompt[:500])
except Exception as e:
print("Rendering or parsing failed:", e)
print("Context keys:", sorted(list(ctx.keys())))
if __name__ == "__main__":
asyncio.run(main())