Skip to content

Commit b98e68f

Browse files
committed
Add Topos shell and expand TRICK dashboard support
1 parent 72a8c19 commit b98e68f

92 files changed

Lines changed: 12025 additions & 579 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ADUC_launcher.bat

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ set "ADUC_DIR=%CHRONOS_ROOT%\Agents Dress Up Committee"
1616
set "DOCS_DIR=%CHRONOS_ROOT%\docs"
1717
set "CTX_FILE=%TEMP%\chronos_full_context.md"
1818
set "ADUC_TEMP_DIR=%TEMP%\ADUC"
19+
set "DIGEST_FILE=%CHRONOS_ROOT%\temp\docs_digest.txt"
20+
set "TRENDS_FILE=%CHRONOS_ROOT%\user\data\trends.md"
1921

2022
if /i "%ADUC_DASHBOARD%"=="1" (
2123
set "ADUC_NO_BROWSER=1"
@@ -66,23 +68,38 @@ echo. >> "%CTX_FILE%"
6668
echo You are running inside the Chronos Engine. The following is the reference manual for the system you control. >> "%CTX_FILE%"
6769
echo. >> "%CTX_FILE%"
6870

69-
:: Loop through docs
70-
for /r "%DOCS_DIR%" %%f in (*.md) do (
71-
set "file_path=%%f"
72-
echo Processing: !file_path!
73-
74-
:: Check if path contains "\Legal\" - simplistic string check
75-
set "is_legal=0"
76-
echo "!file_path!" | findstr /i "\\Legal\\" >nul && set "is_legal=1"
77-
78-
if "!is_legal!"=="0" (
79-
echo. >> "%CTX_FILE%"
80-
echo --- FILE: %%~nxf --- >> "%CTX_FILE%"
81-
echo. >> "%CTX_FILE%"
82-
type "%%f" >> "%CTX_FILE%"
83-
echo. >> "%CTX_FILE%"
84-
) else (
85-
echo Skipping Legal: %%~nxf
71+
if exist "%DIGEST_FILE%" (
72+
echo [Chronos] Using compact docs digest...
73+
type "%DIGEST_FILE%" >> "%CTX_FILE%"
74+
echo. >> "%CTX_FILE%"
75+
) else (
76+
:: Loop through docs
77+
for /r "%DOCS_DIR%" %%f in (*.md) do (
78+
set "file_path=%%f"
79+
echo Processing: !file_path!
80+
81+
:: Check if path contains "\Legal\" - simplistic string check
82+
set "is_legal=0"
83+
echo "!file_path!" | findstr /i "\\Legal\\" >nul && set "is_legal=1"
84+
85+
:: Skip docs that the watcher already injects separately
86+
set "is_runtime_injected=0"
87+
echo "!file_path!" | findstr /i "\\docs\\index.md" >nul && set "is_runtime_injected=1"
88+
echo "!file_path!" | findstr /i "\\docs\\agents\\trick.md" >nul && set "is_runtime_injected=1"
89+
90+
if "!is_legal!"=="0" (
91+
if "!is_runtime_injected!"=="0" (
92+
echo. >> "%CTX_FILE%"
93+
echo --- FILE: %%~nxf --- >> "%CTX_FILE%"
94+
echo. >> "%CTX_FILE%"
95+
type "%%f" >> "%CTX_FILE%"
96+
echo. >> "%CTX_FILE%"
97+
) else (
98+
echo Skipping Runtime-Injected Doc: %%~nxf
99+
)
100+
) else (
101+
echo Skipping Legal: %%~nxf
102+
)
86103
)
87104
)
88105

@@ -102,6 +119,15 @@ for %%f in ("%PROFILE_DIR%\*.md") do (
102119
echo. >> "%CTX_FILE%"
103120
)
104121

122+
if exist "%TRENDS_FILE%" (
123+
echo [Chronos] Bundling Trends context...
124+
echo. >> "%CTX_FILE%"
125+
echo --- FILE: trends.md --- >> "%CTX_FILE%"
126+
echo. >> "%CTX_FILE%"
127+
type "%TRENDS_FILE%" >> "%CTX_FILE%"
128+
echo. >> "%CTX_FILE%"
129+
)
130+
105131
echo [Chronos] Context bundled to %CTX_FILE%
106132

107133
:: 2. Set Environment Variables

Agents Dress Up Committee/familiars/nia/docs/chronos-merge.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44
"enabled_by": ["env:ADUC_EXTERNAL_CONTEXT_FILE"],
55
"static_files": [
66
"docs/agents/chronos.md",
7-
"docs/index.md",
8-
"docs/agents/agents.md",
9-
"docs/agents/trick.md"
7+
"docs/agents/agents.md"
108
],
119
"dynamic_blocks": [
10+
"trick_runtime_query_guidance",
1211
"system_context_from:env:ADUC_EXTERNAL_CONTEXT_FILE",
1312
"chronos_docs_update_note"
1413
]

Agents Dress Up Committee/familiars/nia/docs/merge.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99
"meta.json",
1010
"docs/preferences.md",
1111
"docs/memories.md",
12-
"profile.json",
13-
"docs/agents/chronos.md"
12+
"profile.json"
1413
],
1514
"dynamic_blocks": [
1615
"current_date_time",

Agents Dress Up Committee/tools/cli_bridge_watcher.py

Lines changed: 127 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,47 @@ def save_familiar_doc_state(fam_id: str, mtimes: dict) -> None:
249249
write_json_atomic(FAMILIAR_DOCS_CACHE_PATH, cache)
250250

251251

252+
def _resolve_merge_file_ref(fam_id: str, ref: str) -> Path | None:
253+
raw = str(ref or "").strip().replace("\\", "/")
254+
if not raw:
255+
return None
256+
candidates = [
257+
FAMILIARS_DIR / fam_id / raw,
258+
fam_docs_dir(fam_id) / raw,
259+
BASE_DIR.parent / raw,
260+
BASE_DIR / raw,
261+
]
262+
seen = set()
263+
for cand in candidates:
264+
norm = str(cand.resolve()) if cand.exists() else str(cand)
265+
if norm in seen:
266+
continue
267+
seen.add(norm)
268+
if cand.exists() and cand.is_file():
269+
return cand
270+
return None
271+
272+
273+
def _load_merge_map(path: Path) -> dict:
274+
try:
275+
data = json.loads(read_text(path) or "{}")
276+
return data if isinstance(data, dict) else {}
277+
except Exception:
278+
return {}
279+
280+
281+
def _env_signal_enabled(signals) -> bool:
282+
if not isinstance(signals, list):
283+
return False
284+
for sig in signals:
285+
token = str(sig or "").strip()
286+
if token.lower().startswith("env:"):
287+
name = token.split(":", 1)[1].strip()
288+
if name and os.environ.get(name):
289+
return True
290+
return False
291+
292+
252293
def load_outfits_with_avatars(fam_id: str) -> str:
253294
"""Load outfits.md and resolve all referenced avatars.md files.
254295
@@ -438,9 +479,6 @@ def build_prompt(
438479
settings = read_json(SETTINGS_PATH, {})
439480
if bool(settings.get("disable_familiar_cache", False)):
440481
should_inject_fam = True
441-
agent = read_text(fdocs / "agent.md").strip() if should_inject_fam else ""
442-
personality = read_text(fdocs / "personality.md").strip() if should_inject_fam else ""
443-
coding = read_text(fdocs / "coding.md").strip() if should_inject_fam else ""
444482
greet = read_text(fdocs / "greet.md").strip() if should_inject_fam else ""
445483
profile = read_text(fdir / "profile.json").strip() if should_inject_fam else ""
446484
affection_global = read_text(BASE_DIR / "docs" / "agents" / "affection_system.md").strip() if should_inject_fam else ""
@@ -465,27 +503,51 @@ def build_prompt(
465503
current_datetime = datetime.now().strftime("%A, %B %d, %Y at %H:%M")
466504

467505
parts = []
468-
# Only inject heavy familiar docs when new/changed; otherwise keep a tiny stub.
506+
merge_map = _load_merge_map(fdocs / "merge.json")
507+
merge_phase = "first_prompt" if should_inject_fam else "per_message"
508+
merge_phase_cfg = merge_map.get(merge_phase, {}) if isinstance(merge_map, dict) else {}
469509
watched_labels = ", ".join(sorted(familiar_docs_targets(fam_id).keys()))
510+
injected_static = False
511+
512+
def _format_static_ref(ref: str, content: str) -> str:
513+
low = str(ref or "").strip().replace("\\", "/").lower()
514+
if low.endswith("docs/coding.md"):
515+
return "[Coding Support]\n" + content
516+
if low.endswith("meta.json"):
517+
return "[Familiar Identity]\n" + content
518+
if low.endswith("docs/locations.md"):
519+
return "[Available Locations]\n" + content
520+
if low.endswith("profile.json"):
521+
return "[User Profile]\n" + content
522+
if low.endswith("docs/preferences.md"):
523+
return "[User Preferences (Strongly Preferred)]\n" + content
524+
if low.endswith("docs/memories.md"):
525+
return "[Permanent Memories]\n" + content
526+
if low.endswith("docs/agents/chronos.md"):
527+
return "[Chronos Protocols]\n" + content
528+
if low.endswith("docs/agents/agents.md"):
529+
return "[Chronos Agent Guide]\n" + content
530+
return content
531+
470532
if should_inject_fam:
471-
if agent:
472-
parts.append(agent)
473-
if personality:
474-
parts.append(personality)
475-
if coding:
476-
parts.append("[Coding Support]\n" + coding)
477-
if meta_json:
478-
parts.append("[Familiar Identity]\n" + meta_json)
479-
if locations_md:
533+
for ref in (merge_phase_cfg.get("static_files") or []):
534+
path = _resolve_merge_file_ref(fam_id, str(ref))
535+
if not path:
536+
continue
537+
content = read_text(path).strip()
538+
if not content:
539+
continue
540+
parts.append(_format_static_ref(str(ref), content))
541+
injected_static = True
542+
if locations_md and "docs/locations.md" not in [str(x) for x in (merge_phase_cfg.get("static_files") or [])]:
480543
parts.append("[Available Locations]\n" + locations_md)
481544
if fam_note:
482545
parts.append("[Familiar Docs Update]\n" + fam_note)
483-
# Persist mtimes after a successful inject
484546
try:
485547
save_familiar_doc_state(fam_id, fam_mtimes)
486548
except Exception:
487549
pass
488-
else:
550+
if not should_inject_fam:
489551
parts.append("[Familiar Context Cached]\nNo changes since last inject. Watched: " + watched_labels)
490552

491553
# Inject Current Date/Time
@@ -514,47 +576,59 @@ def build_prompt(
514576
if immersive_on and lore:
515577
parts.append("[Immersive Lore Enabled]\n" + lore)
516578

517-
# --- Chronos / External Context Injection ---
518-
# Only if ADUC_EXTERNAL_CONTEXT_FILE is set (Chronos Mode)
519-
ext_context_path = os.environ.get("ADUC_EXTERNAL_CONTEXT_FILE")
520-
if ext_context_path and os.path.isfile(ext_context_path):
521-
# 1. ALWAYS inject Chronos Protocol when in Chronos Mode (not cached!)
522-
chronos_proto = read_text(BASE_DIR / "docs" / "agents" / "chronos.md").strip()
523-
if chronos_proto:
524-
parts.append("[Chronos Protocols]\n" + chronos_proto)
525-
chronos_index = read_text(BASE_DIR.parent / "docs" / "INDEX.md").strip()
526-
if chronos_index:
527-
parts.append("[Chronos Docs Index]\n" + chronos_index)
528-
trick_protocol = read_text(BASE_DIR.parent / "docs" / "agents" / "trick.md").strip()
529-
if trick_protocol:
530-
parts.append("[TRICK Protocol]\n" + trick_protocol)
531-
532-
# 2. Inject External System Context (The Manual) only when first/changed
533-
try:
534-
should_ext, mtime_val = external_context_should_inject(ext_context_path)
535-
except Exception:
536-
should_ext, mtime_val = True, None
537-
if should_ext:
538-
try:
539-
sys_ctx = read_text(Path(ext_context_path)).strip()
540-
if sys_ctx:
541-
parts.append("[System Context]\n" + sys_ctx)
542-
except Exception:
543-
pass
544-
if mtime_val is not None:
579+
# --- Chronos / External Context Injection (declarative) ---
580+
optional_cfg = (merge_map.get("optional") or {}) if isinstance(merge_map, dict) else {}
581+
chronos_mode_cfg = optional_cfg.get("chronos_mode") if isinstance(optional_cfg, dict) else {}
582+
if isinstance(chronos_mode_cfg, dict) and _env_signal_enabled(chronos_mode_cfg.get("enabled_by")):
583+
cfg_ref = chronos_mode_cfg.get("config")
584+
cfg_path = _resolve_merge_file_ref(fam_id, str(cfg_ref)) if cfg_ref else None
585+
chronos_merge = _load_merge_map(cfg_path) if cfg_path else {}
586+
for ref in (chronos_merge.get("static_files") or []):
587+
path = _resolve_merge_file_ref(fam_id, str(ref))
588+
if not path:
589+
continue
590+
content = read_text(path).strip()
591+
if not content:
592+
continue
593+
parts.append(_format_static_ref(str(ref), content))
594+
for block in (chronos_merge.get("dynamic_blocks") or []):
595+
token = str(block or "").strip()
596+
if token == "trick_runtime_query_guidance":
597+
parts.append(
598+
"[TRICK Runtime Guidance]\n"
599+
"TRICK is a runtime UI-control protocol. Do not assume dashboard elements from memory.\n"
600+
"When you need UI capabilities, query them at runtime via the `trick` command or the TRICK registry.\n"
601+
"Use the protocol docs for command syntax, not as a full element inventory."
602+
)
603+
elif token.startswith("system_context_from:env:"):
604+
env_name = token.split(":", 2)[2].strip()
605+
ext_context_path = os.environ.get(env_name)
606+
if ext_context_path and os.path.isfile(ext_context_path):
607+
try:
608+
should_ext, mtime_val = external_context_should_inject(ext_context_path)
609+
except Exception:
610+
should_ext, mtime_val = True, None
611+
if should_ext:
612+
try:
613+
sys_ctx = read_text(Path(ext_context_path)).strip()
614+
if sys_ctx:
615+
parts.append("[System Context]\n" + sys_ctx)
616+
except Exception:
617+
pass
618+
if mtime_val is not None:
619+
try:
620+
save_external_context_mtime(mtime_val)
621+
except Exception:
622+
pass
623+
else:
624+
parts.append("[System Context Cached]\nUnchanged external context at: " + str(ext_context_path))
625+
elif token == "chronos_docs_update_note":
545626
try:
546-
save_external_context_mtime(mtime_val)
627+
doc_note = chronos_doc_change_note()
628+
if doc_note:
629+
parts.append("[Chronos Docs Update]\n" + doc_note)
547630
except Exception:
548631
pass
549-
else:
550-
parts.append("[System Context Cached]\nUnchanged external context at: " + str(ext_context_path))
551-
# Detect Chronos doc changes (avoids re-merging full docs each turn)
552-
try:
553-
doc_note = chronos_doc_change_note()
554-
if doc_note:
555-
parts.append("[Chronos Docs Update]\n" + doc_note)
556-
except Exception:
557-
pass
558632
# --------------------------------------------
559633

560634
if affection_global:
@@ -663,8 +737,6 @@ def build_prompt(
663737
"dev_nsfw_override": bool(settings.get("dev_nsfw_override", False)),
664738
}
665739
parts.append("[NSFW Policy]\n" + json.dumps(policy, ensure_ascii=False))
666-
if profile:
667-
parts.append("[User Profile]\n" + profile)
668740

669741
# Affection Style Policy based on hearts + consent + boundaries
670742
try:
@@ -807,14 +879,6 @@ def _tier_from_hearts(h: float) -> str:
807879
if outfits_txt:
808880
parts.append("[Available Outfits]\n" + outfits_txt)
809881

810-
# Inject preferences if present
811-
if preferences:
812-
parts.append("[User Preferences]\n" + preferences)
813-
814-
# Inject permanent memories if present
815-
if memories:
816-
parts.append("[Permanent Memories]\n" + memories)
817-
818882
merged = "\n\n".join(parts)
819883
instruction = (
820884
"You are roleplaying this Familiar. Respond to the USER in character. "

0 commit comments

Comments
 (0)